<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>데브머리큐</title>
    <link>https://somedaycode.tistory.com/</link>
    <description>개발 지식을 한 올 한 올 모아 풍성하게!
somedaycode@gmail.com
https://github.com/somedaycode</description>
    <language>ko</language>
    <pubDate>Mon, 29 Jun 2026 19:18:00 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>devmomori</managingEditor>
    <image>
      <title>데브머리큐</title>
      <url>https://tistory1.daumcdn.net/tistory/5141284/attach/264c7fb2941145b3aaf5cbbb66891e87</url>
      <link>https://somedaycode.tistory.com</link>
    </image>
    <item>
      <title>Safari - new Date() 이슈</title>
      <link>https://somedaycode.tistory.com/32</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;크롬에서는 아래와 같은 코드가 잘 작동한다.&lt;/p&gt;
&lt;pre id=&quot;code_1664245753020&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;new Date('2022-09-27 09:00:00') // Tue Sep 27 2022 09:00:00 GMT+0900 (한국 표준시)
new Date('2022/09/27 09:00:00') // Tue Sep 27 2022 09:00:00 GMT+0900 (한국 표준시)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사파리에서는??&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( - ) 붙임표가 문제다&lt;/p&gt;
&lt;pre id=&quot;code_1664246746150&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;new Date('2022-09-27 09:00:00') // Invalid Date&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 바꿔주자.&lt;/p&gt;
&lt;pre id=&quot;code_1664246894285&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;new Date('2022/09/27 09:00:00')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Today I Learned</category>
      <category>new Date</category>
      <category>Safari</category>
      <author>devmomori</author>
      <guid isPermaLink="true">https://somedaycode.tistory.com/32</guid>
      <comments>https://somedaycode.tistory.com/32#entry32comment</comments>
      <pubDate>Tue, 27 Sep 2022 12:38:21 +0900</pubDate>
    </item>
    <item>
      <title>객체지향의 사실과 오해 - 객체 지도</title>
      <link>https://somedaycode.tistory.com/31</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 챕터는 글로 써 내려가는 것보다 그림을 통해 이해하는 게 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;길을 묻는 방법은 현재의 마을에서 다른 마을로 이동하는 현재의 요구만을 만족시킬 수 있다. 지도는 현재의 목적뿐만 아니라 다양한 목적을 위해 재사용될 수 있다. &lt;b&gt;즉 지도는 범용적이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;훌륭한 기능은 훌륭한 소프트웨어를 만들고 훌륭한 구조는 훌륭한 소프트웨어를 만들기 위한 필요조건이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게임 플레이어들은 게임 도메인을 캐릭터와 몬스터, 그리고 아이템 간의 관계로 표현한다. 중고 자동차 판매상은 구매되는 자동차와 판매되는 자동차의 교환으로 자동차 도메인을 바라본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;282&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdxTKN/btrMbz2fsqY/TBcp2nqcBuOY0eoTRcORWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdxTKN/btrMbz2fsqY/TBcp2nqcBuOY0eoTRcORWK/img.png&quot; data-alt=&quot;객사오 -&amp;amp;nbsp; 189쪽 그림&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdxTKN/btrMbz2fsqY/TBcp2nqcBuOY0eoTRcORWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdxTKN%2FbtrMbz2fsqY%2FTBcp2nqcBuOY0eoTRcORWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;659&quot; height=&quot;282&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;282&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;객사오 -&amp;nbsp; 189쪽 그림&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;코드의 구조가 도메인의 구조를 반영하기 때문에 도메인을 이해하면 코드를 이해하기가 수월해진다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;588&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJ1iLb/btrL9vfr7FH/WUMoSNsbtfNLUkQtBO5UOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJ1iLb/btrL9vfr7FH/WUMoSNsbtfNLUkQtBO5UOk/img.png&quot; data-alt=&quot;객사오 - 198쪽 그림&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJ1iLb/btrL9vfr7FH/WUMoSNsbtfNLUkQtBO5UOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJ1iLb%2FbtrL9vfr7FH%2FWUMoSNsbtfNLUkQtBO5UOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;684&quot; height=&quot;588&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;588&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;객사오 - 198쪽 그림&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템에 할당된 커다란 책임은 시스템 안의 작은 규모의 객체들이 수행해야 하는 더 작은 규모의 책임으로 세분화된다. 도메인 모델에 명시된 정기예금이나 계좌와 같은 개념을 상태와 행위를 관리하는 자율적인 객체로 간주한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이자 계산 기능이 변경되거나 추가되도 클래스와 클래스 간의 관계는 그대로 유지될 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXz6XJ/btrMadMaN7V/wNuMVnR5iH0FYLxTUVY4V0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXz6XJ/btrMadMaN7V/wNuMVnR5iH0FYLxTUVY4V0/img.png&quot; data-alt=&quot;객사오 - 204쪽 : 단리, 복리 이자를 계산할 수 있는 클래스 다이어그램&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXz6XJ/btrMadMaN7V/wNuMVnR5iH0FYLxTUVY4V0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXz6XJ%2FbtrMadMaN7V%2FwNuMVnR5iH0FYLxTUVY4V0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;636&quot; height=&quot;242&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;242&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;객사오 - 204쪽 : 단리, 복리 이자를 계산할 수 있는 클래스 다이어그램&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향의 가장 큰 장점은 도메인을 모델링하기 위한 기법과 도메인을 프로그래밍하기 위해 사용하는 기법이 동일하다는 점이다. - &lt;b&gt;연결 완전성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역방향 역시 성립할 수 있는데, &lt;b&gt;가역성&lt;/b&gt;이라 한다.&lt;/p&gt;</description>
      <category>Books/객체지향의 사실과 오해</category>
      <category>Til</category>
      <category>객체 지도</category>
      <category>객체지향과 사실과 오해</category>
      <category>도메인</category>
      <category>책 리뷰</category>
      <category>프론트엔드</category>
      <author>devmomori</author>
      <guid isPermaLink="true">https://somedaycode.tistory.com/31</guid>
      <comments>https://somedaycode.tistory.com/31#entry31comment</comments>
      <pubDate>Wed, 14 Sep 2022 21:29:46 +0900</pubDate>
    </item>
    <item>
      <title>객체지향의 사실과 오해 - 책임과 메시지</title>
      <link>https://somedaycode.tistory.com/30</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;여러 내용들이 가리키는 하나의 목적은 &lt;b&gt;소프트웨어의&lt;/b&gt; &lt;b&gt;유연한 변경, 즉 유지보수를 편하게 하는 것&lt;/b&gt;&lt;br&gt; &lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;자율성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;객체가 어떤 행동을 하는 유일한 이유는 다른 객체로부터 요청을 수신했기 때문이다. 요청을 처리하기 위해 객체가 수행하는 행동을 &lt;b&gt;책임&lt;/b&gt;이라고 한다. 자율적인 객체란 스스로의 의지와 판단에 따라 각자 맡은 책임을 수행하는 객체를 의미한다.&lt;br&gt; &lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1174&quot; data-origin-height=&quot;406&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cSgePB/btrLBxrIjEh/XwYmzzwWL5kUJbQKH512fK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cSgePB/btrLBxrIjEh/XwYmzzwWL5kUJbQKH512fK/img.png&quot; data-alt=&quot; 객사오 142쪽 - 그림 5.1 &quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cSgePB/btrLBxrIjEh/XwYmzzwWL5kUJbQKH512fK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcSgePB%2FbtrLBxrIjEh%2FXwYmzzwWL5kUJbQKH512fK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;599&quot; height=&quot;207&quot; data-origin-width=&quot;1174&quot; data-origin-height=&quot;406&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; 객사오 142쪽 - 그림 5.1 &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
  모자 장수는 왕에게 증언할 책임은 있지만, 증언을 위한 구체적인 방법이나 절차에 대해서는 최대한의 자유를 누린다. 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1174&quot; data-origin-height=&quot;370&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cycxUe/btrLDDZpd2Q/71HKyz01DkPUGfb6ALFHvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cycxUe/btrLDDZpd2Q/71HKyz01DkPUGfb6ALFHvK/img.png&quot; data-alt=&quot; 객사오 142쪽 - 그림 5.2 &quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cycxUe/btrLDDZpd2Q/71HKyz01DkPUGfb6ALFHvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcycxUe%2FbtrLDDZpd2Q%2F71HKyz01DkPUGfb6ALFHvK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;533&quot; height=&quot;168&quot; data-origin-width=&quot;1174&quot; data-origin-height=&quot;370&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; 객사오 142쪽 - 그림 5.2 &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
  여기서 문제는 여러 책임들이 모자 장수가 증언하기 위해 선택할 수 있는 자유의 범위를 지나치게 제한한다는 점이다. 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;br&gt;&lt;b&gt;두 번째 모자 장수는 자율적으로 책임을 수행할 수 없다. &lt;/b&gt;객체가 자율적이기 위해서는 객체에게 할당되는 책임의 수준 역시 자율적이어야 한다. 그러나 포괄적이고 추상적인 책임이 무조건 좋은 것은 아니다. 협력의 의도를 명확히 표현하는 것이 중요하다. 어떻게('How') 해야 하는 것보다 &lt;b&gt;무엇('What')을 해야하는가가 중요&lt;/b&gt;하다.&lt;br&gt; &lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;메시지&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;메시지를 가리키는 '증언하라'라는 부분을 메시지 이름이라고 한다. 추가적인 정보가 필요한 경우에는 메시지의 인자(argument)를 통해 추가 정보를 제공할 수 있다. ex) &lt;i&gt;&lt;u&gt;모자장수.증언(어제, 왕국)&lt;/u&gt;&lt;/i&gt;&lt;br&gt; &lt;br&gt;1장부터 4장까지 계속해서 언급해온 메시지 송신자와 수신자에 대해서 설명한다. 요약하면 메시지는 객체들이 서로 협력하기 위해 사용되는 유일한 의사소통 수단이다.&lt;br&gt; &lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;메서드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;모자 장수가 메시지를 처리하기 위해서 내부적으로 선택하는 방법을 &lt;b&gt;메서드&lt;/b&gt;라고 한다. 해당 메시지를 처리할 수 있는지 확인 후, 주어진 책임을 다하기 위해 메서드를 선택한다. 메서드는 클래스 안에 포함된 함수 또는 프로시저를 통해 구현된다. 어떻게 수행되는지는 명시되지 않으며, '무엇'이 실행되기를 바라는지만 명시한다. 어떤 메서드를 선택할 것인지는 전적으로 수신자의 결정에 좌우된다.&lt;br&gt; &lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;유연하고 확장 가능하고 재사용성이 높은 협력의 의미&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;송신자가 수신자에 대해 매우 적은 정보만 알고 있더라도 상호 협력이 가능하다는 사실은 설계의 품질에 큰 영향을 미친다.&lt;br&gt; &lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
 &lt;li&gt;유연한 협력: 송신자는 수신자에대해 어떤 가정도 하지 않는다. 수신자를 다른 타입의 객체로 대체하더라도 송신자는 알지 못한다. 유연하게 협력이 변경 가능하다.&lt;/li&gt;
 &lt;li&gt;확장 가능성 : 협력이 동작하는 방식은 변경될지라도 협력의 구조 자체는 변경되지 않는다. ex) 증언을 할 때 재판장에 참석하는 것이 아닌 동영상만 보낼 수 있는 객체&lt;/li&gt;
 &lt;li&gt;재사용성 : 재판이라는 협력을 누구에게나 적용할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;b&gt;메시지를 기반으로 한 두 객체 사이의 낮은 결합도가 설계를 유연하게 하고 확장 가능하며 재사용 가능하게 만든다.&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;인터페이스&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;특징&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
 &lt;li&gt;인터페이스의 사용법을 익히기만 하면 내부 구조나 동작 방식을 몰라도 쉽게 대상을 조작하거나 의사 전달이 가능하다.&lt;/li&gt;
 &lt;li&gt;인터페이스의 변경 없이 단순히 내부 구성이나 작동 방식을 변경하는 것은 사용자에게 어떤 영향도 미치지 않는다.&lt;/li&gt;
 &lt;li&gt;대상이 변경되더라도 동일한 인터페이스를 제공하기만 하면 아무런 문제 없이 상호작용 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;br&gt;메시지가 인터페이스를 결정한다. 객체가 어떤 메시지를 수신할 수 있는지가 객체가 제공하는 인터페이스의 모양을 빚는다.&lt;br&gt; &lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;인터페이스와 구현의 분리&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
 &lt;li&gt;좀 더 추상적인 인터페이스&lt;/li&gt;
 &lt;li&gt;최소 인터페이스&lt;/li&gt;
 &lt;li&gt;인터페이스와 구현 간에 차이가 있다는 점을 인식&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
  1. 상세한 수준의 메시지가 아닌 위에서 설명한 '증언하라'처럼 추상적인 수준의 메시지를 통해 수신자의 자율성을 보장한다. 
 &lt;br&gt;2. 외부에서 사용할 필요가 없는 인터페이스는 최대한 노출하지 않는다. 이를 통해 내부를 수정하더라도 외부에 미치는 영향을 최소화한다. 
 &lt;br&gt;3. 객체의 외부와 내부를 분리하는 것은 결국 객체의 공용 인터페이스와 구현을 명확하게 분리하라는 말과 동일하다. 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;인터페이스와 구현의 분리 원칙이 중요한 이유?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;소프트웨어는 &lt;b&gt;항상 변경&lt;/b&gt;되기 때문이다. 어떤 객체를 수정했을 때 발생하는&lt;b&gt; 사이드 이펙트를 예상하는 것은 어렵다. &lt;/b&gt;객체가 가져야 할 상태와 메서드 구현은 객체 내부에 속한다. 이 부분을 수정하더라도 객체 외부에 영향을 미쳐서는 안 된다. &lt;b&gt;객체 외부에 영향을 미치는 변경을 객체의 공용 인터페이스를 수정할 때뿐이다.&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;책임의 자율성이 협력의 품질을 결정한다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;책임의 적절한 추상화를 통한 협력의 단순화. 자율적인 책임은 협력을 단순하게 만든다. &lt;br&gt; &lt;br&gt;자율적인 책임은 모자 장수의 외부와 내부를 명확하게 분리한다. 왕은 증언하라 명령했지만 모자 장수가 내부적으로 어떻게 책임을 수행하는지는 볼 수 없다. 요청하는 객체가 몰라도 되는 사적인 부분이 객체 내부로 &lt;b&gt;캡슐화&lt;/b&gt;된다. 인터페이스와 구현이 분리된다.&lt;br&gt; &lt;br&gt;수행하는 내부적인 방법을 변경해도 외부에 영향을 미치지 않는다. 증언하는 방법은 변경해도 왕에게는 어떤 영향도 미치지 않는다. 그러나 자율적인 책임을 가질 수 없었던 세세한 증언 방법의 요청(시간 순서로, 목격 장면, 간결한 표현 등)은 하나라도 변경되게 된다면 협력이 무너지게 된다. 책임이 자율적일수록 변경에 의해 수정되어야 하는 범위가 좁아지고 명확해진다. 변경의 파급효과가 객체 내부로 &lt;b&gt;캡슐화&lt;/b&gt;되기 때문에 두 객체간의&lt;b&gt; 결합도&lt;/b&gt;가 낮아진다.&lt;br&gt; &lt;br&gt;자율적인 책임은 협력의 대상을 다양하게 선택할 수 있는 유연성을 제공한다. 모자 장수 이외에 앨리스나, 요리사가 증언을 하는 예시가 있다. 설계가 유연해지고 재사용성이 높아진다.&lt;br&gt; &lt;br&gt;객체의 역할을 이해하기 쉬워진다. '증인석 입장', '증언하다'라는 두 가지 책임을 가진 모자장수가 어떤 역할을 해야 하는지 명확히 알려준다. 객체의 응집도를 높은 상태로 유지하기가 쉬워진다.&lt;br&gt; &lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt; &lt;b&gt;책임이 자율적일수록&lt;/b&gt; 
 &lt;br&gt;적절하게 '추상화'되고, 
 &lt;br&gt;'응집도'가 높아지고, 
 &lt;br&gt;'결합도'가 낮아지며, 
 &lt;br&gt;'캡슐화'가 증진되고, 
 &lt;br&gt;'인터페이스와 구현이 명확히 분리'되고, 
 &lt;br&gt;'설계의 유연성과 재사용성이 향상'된다. 
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;br&gt; &lt;br&gt; &lt;/p&gt;</description>
      <category>Books/객체지향의 사실과 오해</category>
      <category>Til</category>
      <category>객사오</category>
      <category>객체지향</category>
      <category>객체지향의 사실과 오해</category>
      <category>주니어 개발자</category>
      <category>프론트엔드</category>
      <author>devmomori</author>
      <guid isPermaLink="true">https://somedaycode.tistory.com/30</guid>
      <comments>https://somedaycode.tistory.com/30#entry30comment</comments>
      <pubDate>Wed, 7 Sep 2022 15:59:21 +0900</pubDate>
    </item>
    <item>
      <title>[web.dev 장점 뽑아먹기]: Lighthouse CI로 웹 성능 모니터링 하기</title>
      <link>https://somedaycode.tistory.com/29</link>
      <description>&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;운영 중인 서비스의 &lt;a href=&quot;https://web.dev/vitals/&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;웹 바이탈(Web Vitals)&lt;/span&gt;&lt;/a&gt;과 전반적인 개선점을 주기적으로 체크하며 웹 성능을 모니터링을 해보자.&lt;br&gt; &lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;간단한 웹 성능 측정 방법 2가지&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot; style=&quot;text-align: left;&quot;&gt;먼저 간단한 방법 2가지를 알아보고 Lighthouse CI를 적용해보자.&lt;br&gt; &lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;개발자 도구 - Performance&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;개발자 도구를 열고 Performance 탭에 들어가 녹화를 시작하고 여러 가지 동작을 수행한 후 녹화 정지 버튼을 누르면 전반적인 지표들을 아래와 같이 볼 수 있다. 이를 통해 웹 페이지 로드(load) 시점에서 일어나는 블로킹(Blocking)을 해결하고 시각적으로 LCP, CLS 지점들을 확인해 볼 수 있다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;969&quot; data-origin-height=&quot;546&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cX6dPq/btrLb6HuDCC/sjoMKbFN9ikNLOCAEWcuk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cX6dPq/btrLb6HuDCC/sjoMKbFN9ikNLOCAEWcuk0/img.png&quot; data-alt=&quot; Developer Tool Web Performance &quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cX6dPq/btrLb6HuDCC/sjoMKbFN9ikNLOCAEWcuk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcX6dPq%2FbtrLb6HuDCC%2FsjoMKbFN9ikNLOCAEWcuk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;608&quot; height=&quot;343&quot; data-origin-width=&quot;969&quot; data-origin-height=&quot;546&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; Developer Tool Web Performance &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;br&gt; &lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;개발자 도구 - Lighthouse&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;Lighthouse는 별도로 어떤 동작을 수행하지 않아도 Analyze Page Load 버튼을 누르면 자동으로 보고서를 생성해준다. 아래와 같은 각 카테고리 별 지표들을 생성해주는데, 각 카테고리별 세부내용이 자세하게 표시되어 있어서 이를 바탕으로 운영 중인 서비스의 개선을 시작해 볼 수 있다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;211&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rwbRo/btrLfNNUHWr/hFHjhTBpYUcrtEEMi1kxK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rwbRo/btrLfNNUHWr/hFHjhTBpYUcrtEEMi1kxK0/img.png&quot; data-alt=&quot; Lighthouse Google.com Report : Performance, PWA, Best Practices, Accessibility, SEO &quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rwbRo/btrLfNNUHWr/hFHjhTBpYUcrtEEMi1kxK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrwbRo%2FbtrLfNNUHWr%2FhFHjhTBpYUcrtEEMi1kxK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;835&quot; height=&quot;211&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;211&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; Lighthouse Google.com Report : Performance, PWA, Best Practices, Accessibility, SEO &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;br&gt;위의 여러가지 방법들로 간단하게 웹 성능, 그리고 관련 지표들을 쉽게 확인할 수 있지만 매번 페이지에 접속해 개발자 도구를 열고 녹화 버튼을 누르거나 보고서를 생성하는 것은 꽤나 귀찮은 일이다. &lt;b&gt;어떻게 주기적으로 관련 리포트를 받아볼 수 있을까?&lt;/b&gt;&lt;br&gt; &lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;Lighthouse CI : 웹 성능 리포트 자동화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;두 번째 성능 측정 방법인 Lighthouse를 사용, 정확히는 &lt;b&gt;Lighthouse CI&lt;/b&gt;를 사용하여 CI(Continuous Integration)에서 보고서 생성을 자동화해보자.&lt;br&gt; &lt;br&gt;1. 프로젝트 구축&lt;br&gt;JavaScript, React, Vue, Nextjs 어떤 것이든 상관없다.&lt;/p&gt;
&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// Next.js로 프로젝트 구축
# yarn create next-app --typescript&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;br&gt;2. Lighthouse CI 설치 및 파일 추가&lt;/p&gt;
&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;/* install @lhci/cli */
# yarn global add @lhci/cli

/* root 경로에 lighthouserc.js 파일 생성 */
# touch lighthouserc.js&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;br&gt;3. Configuration 파일 작성&lt;/p&gt;
&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;module.exports = {
&amp;nbsp;&amp;nbsp;ci: {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;collect: {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;staticDistDir: './out',
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;url: ['http://localhost:3000'],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;numberOfRuns: 2,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 동적 페이지일 경우
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;startServerCommand: 'yarn start',
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assert: {},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;upload: {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 보고서가 최대 7일까지 저장되는 임시저장소
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// .lighthouseci/ 폴더 저장 및 Github status check
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;target: 'temporary-public-storage',
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;server: {},
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;wizard: {},
&amp;nbsp;&amp;nbsp;},
};&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt; &lt;/h4&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;collect에 대해 간단히 설명하자면, 다음과 같다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;Lighthouse를 n번 실행시키며 만들어진 보고서를 .lighthouseci/ 폴더에 저장한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt; 
 &lt;li&gt;staticDistDir: 사이트가 정적 사이트일 경우 ci.collect가 정적 파일들이 위치한 곳을 가리킨다.&amp;nbsp;&lt;br&gt; 
  &lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt; 
   &lt;li&gt;ex. dist(Vue), build(react), out(Next.js), public(gatsby)&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
 &lt;li&gt;url: lighthouse가 동작하게 될 URL, 여러 페이지를 확인하고 싶은 경우에는 배열 내부에 새로운 url을 계속 추가해주면 된다.&lt;/li&gt; 
 &lt;li&gt;numberOfRuns: lighthouse 실행 횟수&lt;/li&gt; 
 &lt;li&gt;startServerCommand: 서버 실행 명령어&lt;/li&gt; 
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;br&gt;lighthouse가 제공하는 지표 점수에 따라 '&lt;b&gt;주의'&lt;/b&gt; 혹은 &lt;b&gt;'에러'&lt;/b&gt;를 받고 싶다면 &lt;b&gt;assertion&lt;/b&gt;을 적용해주면 된다.&lt;/p&gt;
&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assert: {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertions: {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;'categories:performance': ['warn', {minScore: 1}],
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;'categories:accessibility': ['error', {minScore: 1}]
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;br&gt;CI 구성을 위해서 간단히 collect와 upload 옵션만 작성해주었다. Configuration 구성 요소들에 대해 더 자세하게 알고 싶다면 &lt;a href=&quot;https://github.com/GoogleChrome/lighthouse-ci/blob/main/docs/configuration.md&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;lighthouse-ci Github&lt;/span&gt;&lt;/a&gt;을 참고해보자.&lt;br&gt; &lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;로컬에서 테스트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;다음과 같이 명령어를 시작하면 configuration 파일을 기반으로 자동으로 리포트를 생성해준다.&lt;/p&gt;
&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// script comment to build
# yarn build

// lighthouce 실행
# lhci autorun&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt; &lt;/h4&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;Next.js로 프로젝트를 구성한 경우 &lt;/h4&gt;
&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// script comment to build
# yarn build (next build)

// next 정적 파일을 export
# yarn next export&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;br&gt;Next.js 내부에서 사용하는 이미지 최적화 Next/Image로 인해 오류가 날 텐데, 다음과 같이 외부 클라우드 이미지 최적화 loader를 사용하도록 설정해준다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
  참고:&lt;a href=&quot;https://nextjs.org/docs/api-reference/next/image#loader-configuration&quot; target=&quot;_blank&quot;&gt;&lt;span&gt; Loader Configuration&lt;/span&gt;&lt;/a&gt; 
&lt;/blockquote&gt;
&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;/** @type {import('next').NextConfig} */
module.exports = {
&amp;nbsp;&amp;nbsp;reactStrictMode: true,
&amp;nbsp;&amp;nbsp;images: {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;loader: 'imgix',
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;path: 'https:localhost:3000/',
&amp;nbsp;&amp;nbsp;},
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;이와 같이 설정 후,&lt;/p&gt;
&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// lighthouce 실행
# lhci autorun&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;br&gt;이렇게 나오면 로컬에서 lighthouse-ci는 성공이다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;485&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SlhBo/btrLbMJSpHo/cvigRsIFWIZom6WPyODDP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SlhBo/btrLbMJSpHo/cvigRsIFWIZom6WPyODDP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SlhBo/btrLbMJSpHo/cvigRsIFWIZom6WPyODDP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSlhBo%2FbtrLbMJSpHo%2FcvigRsIFWIZom6WPyODDP1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;485&quot; height=&quot;246&quot; data-origin-width=&quot;485&quot; data-origin-height=&quot;246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;br&gt; &lt;br&gt; &lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;GitHub Action + Lighthouse-CI&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;GitHub Action, Travis CI, Jenkins 등 많은 CI와 결합할 수 있는데, 여기선 Github Action을 사용한다.&lt;br&gt; &lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;GithHub App 설치 및 토큰 추가&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;a href=&quot;https://github.com/apps/lighthouse-ci&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://github.com/apps/lighthouse-ci&lt;/span&gt;&lt;/a&gt;&lt;br&gt;&lt;b&gt;설치 후 하단에 표시되는 토큰을 기억하자. &lt;/b&gt;&lt;br&gt; &lt;br&gt;해당 토큰을 통해 github이 lhci의 status를 체크할 수 있다.&lt;br&gt; &lt;br&gt;&lt;b&gt;프로젝트 Settings -&amp;gt; Sectets &amp;gt; Actions -&amp;gt; Repository secrets에 &lt;span style=&quot;color: #1A7F37;&quot;&gt;LHCI_GITHUB_APP_TOKEN &lt;span style=&quot;color: #000000;&quot;&gt;추가&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;152&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0rcKF/btrLbMpEv13/9rmb3kaEH5AT1K7jc16fLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0rcKF/btrLbMpEv13/9rmb3kaEH5AT1K7jc16fLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0rcKF/btrLbMpEv13/9rmb3kaEH5AT1K7jc16fLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0rcKF%2FbtrLbMpEv13%2F9rmb3kaEH5AT1K7jc16fLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;637&quot; height=&quot;129&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;152&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;workflows/ 파일 추가&lt;/h4&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// .github/workflows/lighthouse-ci.yml
name: light-house-CI
on: [ push ]
jobs:
  lighthouseci:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v1
        with:
          node-version: 17 // 사용할 노드 버전
      - run: yarn &amp;amp;&amp;amp; yarn global add @lhci/cli // 프로젝트 패키지 설치와 @lhci/cli 추가
      - run: yarn build &amp;amp;&amp;amp; yarn export  // next build &amp;amp; next export

      - name: run lighthouse CI
        env:
          LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
        run: |
          npx lhci autorun || echo &quot;fail&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;/p&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;push 후 GitHub Action 동작 확인&lt;/h4&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1057&quot; data-origin-height=&quot;386&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bODhG0/btrLfNgR2c8/GVaHgarWn5jyzYIgjKwxik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bODhG0/btrLfNgR2c8/GVaHgarWn5jyzYIgjKwxik/img.png&quot; data-alt=&quot; Github Action lighthouse-ci.yml 실행 확인 &quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bODhG0/btrLfNgR2c8/GVaHgarWn5jyzYIgjKwxik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbODhG0%2FbtrLfNgR2c8%2FGVaHgarWn5jyzYIgjKwxik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1057&quot; height=&quot;386&quot; data-origin-width=&quot;1057&quot; data-origin-height=&quot;386&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; Github Action lighthouse-ci.yml 실행 확인 &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;996&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tY6yq/btrLcIUIdqJ/DUwaDPDyQhtRxWMEUsQBIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tY6yq/btrLcIUIdqJ/DUwaDPDyQhtRxWMEUsQBIk/img.png&quot; data-alt=&quot; Github Action CI by lighthouse-ci.yml &quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tY6yq/btrLcIUIdqJ/DUwaDPDyQhtRxWMEUsQBIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtY6yq%2FbtrLcIUIdqJ%2FDUwaDPDyQhtRxWMEUsQBIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;609&quot; height=&quot;826&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;996&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; Github Action CI by lighthouse-ci.yml &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;br&gt;log에 보이는 report 링크를 들어가 보면 다음과 같이 나온다. (상단 캡처)&lt;br&gt; &lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;828&quot; data-origin-height=&quot;482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wFxxW/btrLgkk8OHW/FFgqRwGZfHqiddLxmlSafK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wFxxW/btrLgkk8OHW/FFgqRwGZfHqiddLxmlSafK/img.png&quot; data-alt=&quot; lighthouse-ci report &quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wFxxW/btrLgkk8OHW/FFgqRwGZfHqiddLxmlSafK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwFxxW%2FbtrLgkk8OHW%2FFFgqRwGZfHqiddLxmlSafK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;565&quot; height=&quot;329&quot; data-origin-width=&quot;828&quot; data-origin-height=&quot;482&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt; lighthouse-ci report &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;느낀 점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;CI에 lighthouse-ci를 추가해주니 지속적으로 웹 사이트의 성능을 측정할 수 있어서 성능 개선에 대한 경각심을 심어주기도 하고, 무엇보다 간편해서 좋았다. Lighthouse CI Server도 구축해주면 보고서를 장기간 보관할 수 있고 해당 보고서들을 시각화하여 지표로 보여주기도 하는데, 이를 통해 좀 더 효과적인 웹 성능 모니터링 시스템을 구축할 수 있지 않을까 생각한다.&lt;br&gt; &lt;br&gt;좀 더 찾아보니, &lt;a href=&quot;https://fe-developers.kakaoent.com/2022/220602-lighthouse-with-github-actions/&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;카카오 엔터 FE 기술 블로그에서&lt;/span&gt;&lt;/a&gt; 설명하는 PR 댓글로 ligthouse 보고서 상세 정보를 보여줄 수 있는 방법이 있는데 이 부분도 나중에 적용해 봐야겠다. &lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;참고자료&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
 &lt;li&gt;&lt;a href=&quot;https://web.dev/lighthouse-ci/#ci-setup&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;web.dev -Performance monitoring with Lighthouse CI&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href=&quot;https://github.com/GoogleChrome/lighthouse-ci&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;GitHub - GoogleChrom/lighthouse-ci&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발/장점 뽑아먹기</category>
      <category>github action</category>
      <category>lighthouse</category>
      <category>lighthouse-ci</category>
      <category>Til</category>
      <category>web.dev</category>
      <category>웹 성능 모니터링</category>
      <author>devmomori</author>
      <guid isPermaLink="true">https://somedaycode.tistory.com/29</guid>
      <comments>https://somedaycode.tistory.com/29#entry29comment</comments>
      <pubDate>Fri, 2 Sep 2022 18:50:31 +0900</pubDate>
    </item>
    <item>
      <title>객체지향의 사실과 오해 - 타입과 추상화 | 역할, 책임, 협력</title>
      <link>https://somedaycode.tistory.com/28</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;책을 읽으며 객체지향과 더불어&lt;b&gt; 하나의 컴포넌트가 가지게 되는 역할과 책임에 대해서 계속 생각하게 된다. &lt;/b&gt;재사용성이 가능한 컴포넌트를 만들기 위해서 작은 단위의 컴포넌트로 잘게 쪼개는 상황이 생기는데, 이때 조금 더 각각의 컴포넌트들이 역할과 책임을 작게 작게 가져가게 된다. 많은 설명이 개념 중심이라 배운 것들을 어디서 적용해볼지 고민도 많이 해봐야겠다. 결국에는 직접 설계하고 코드를 짜봐야 내 것이 되니깐...&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;코드를 빨리 짜는 것이 중요한 게 아니라 &lt;b&gt;유지보수성이 뛰어난 애플리케이션을 구축하기 위해서는 견고한 설계가 우선&lt;/b&gt;시 되어야 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;타입과 추상화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지하철 승객의 목적 : &lt;u&gt;하나의 역에서 다른 역으로 이동하는 것&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;승객이 원하는 것 :&amp;nbsp;&lt;u&gt;빠르게 목적지에 도착할 수 있는지를 직관적이고 단순하게 보여주는 것&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꼭 알아야하는 사실만 표현하고 몰라도 되는 정보는 무시함으로써 목적에 부합하는 지하철 노선도를 창조 -&amp;gt; &lt;b&gt;지하철 노선을 추상화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모든 경우에 추상화의 목적은 복잡성을 이해하기 쉬운 수준으로 단순화하는 것&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이상한 나라의 앨리스의 트럼프&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하트 여왕의 행렬에서 나오는 트럼프들을 계급, 나이 , 성격 등의 차이점은 무시하며 '트럼프'라는 유사성을 기반으로 추상화해서 바라봄'&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;713&quot; data-origin-height=&quot;545&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFQo67/btrK4FwSPue/oZEfgtjoTIsgeTQ4rMyR10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFQo67/btrK4FwSPue/oZEfgtjoTIsgeTQ4rMyR10/img.png&quot; data-alt=&quot;객체지향의 사실과 오해 82쪽 - 앨리스가 추상화한 등장인물들&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFQo67/btrK4FwSPue/oZEfgtjoTIsgeTQ4rMyR10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFQo67%2FbtrK4FwSPue%2FoZEfgtjoTIsgeTQ4rMyR10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;493&quot; height=&quot;377&quot; data-origin-width=&quot;713&quot; data-origin-height=&quot;545&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;객체지향의 사실과 오해 82쪽 - 앨리스가 추상화한 등장인물들&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;'기껏해야 트럼프에 불과해'&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;개념(concept)&lt;/b&gt;: 공통점을 기반으로 객체들을 묶기 위한 그릇&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;일반적으로 우리가 인식하고 있는 다양한 사물이나 객체에 적용할 수 있는 아이디어나 관념을 뜻한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;객체란 특정한 개념을 적용할 수 있는 구체적인 사물을 의미한다. 개념이 객체에 적용됐을 때 객체를 개념의 인스턴스라고 한다. (객사오 - 84쪽)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;개념의 세 가지 관점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;심볼(symbol)&lt;/b&gt;: 트럼프 (개념을 가리키는 이름이나 명칭)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;내연(intension)&lt;/b&gt;: 몸이 납작하고 두 손과 발은 네모 귀퉁이에 달려 있는 등장인물 (개념의 완전한 정의, 의미를 통해 개념에 속하는지 여부를 확인)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;외연(extension)&lt;/b&gt;: 정원사, 병사, 왕자, 공주, 하트 여왕 등 (개념에 속하는 모든 객체의 집합)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개념은 객체들의 복잡성을 극복하기 위한 추성화 도구이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;객체와 타입&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체는 데이터인가? NO&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;객체에서 중요한 것은 객체의 행동&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행동이 우선&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;객체가 어떤 행동을 하느냐에 따라 객체의 타입이 결정된다.&lt;/li&gt;
&lt;li&gt;객체의 타입은 객체의 내부 표현과는 아무런 상관이 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 타입에 속한 객체는 행동만 동일하다면 서로 다른 데이터를 가질 수 있다. 동일한 행동은 동일한 책임을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다형성&lt;/b&gt; : 동일한 요청에 대해 서로 다른 방식으로 응답할 수 있는 능력을 뜻함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;앨리스가 바라보는 인물들의 행동 방식이 트럼프 카드와 유사하다는 생각을 갖게 만들었고 '트럼프'라는 타입으로 분류했다.&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;762&quot; data-origin-height=&quot;104&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Welcg/btrK4D0bPva/JAkFLeHBM7m7wvr5aeOlU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Welcg/btrK4D0bPva/JAkFLeHBM7m7wvr5aeOlU1/img.png&quot; data-alt=&quot;객사오 95쪽&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Welcg/btrK4D0bPva/JAkFLeHBM7m7wvr5aeOlU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWelcg%2FbtrK4D0bPva%2FJAkFLeHBM7m7wvr5aeOlU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;762&quot; height=&quot;104&quot; data-origin-width=&quot;762&quot; data-origin-height=&quot;104&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;객사오 95쪽&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트럼프는 트럼프 인간을 포괄하는 좀 더 일반적인 개념 -&amp;gt; 두 개념 사이의 관계를 &lt;b&gt;일반화/특수화 &lt;/b&gt;관계라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 일반적인 타입 : 슈퍼타입 (Supertype)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 특수한 타입 : 서브타입 (Subtype)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 서브타입은 슈퍼타입의 행위와 호환되기 때문에 서브타입은 슈퍼타입을 대체할 수 있어야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;타입의 목적&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앨리스의 키가 변화할 때, 모든 경우의 값을 나열하는 것이 아니라 &lt;b&gt;단순히 키가 임의의 값을 가질 수 있다는 사실만을 생각&lt;/b&gt;하면 된다. - &lt;b&gt;변경되는 키라는 상태를 가진다고 단순화&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;이런 관점에서 타입은 추상화다&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체를 분류하는 기준은 타입 -&amp;gt; 타입을 나누는 기준은 행동 -&amp;gt; 객체 분류를 위해서 타입을 결정한 후 프로그래밍 언어를 이용해 &lt;b&gt;타입을 구현할 수 있는 한 가지 방법이 클래스&lt;/b&gt;라는 사실을 기억하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;역할, 책임, 협력&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;흔히 하는 실수&lt;/b&gt; : 협력이라는 문맥을 고려하지 않은 채 객체가 가져야 할 상태와 행동부터 고민하기 시작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;679&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mdtUr/btrK0Mw606f/nUviIdceX3JXeguQnJV3kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mdtUr/btrK0Mw606f/nUviIdceX3JXeguQnJV3kK/img.png&quot; data-alt=&quot;객사오 113쪽 - 왕과 하얀 토끼, 모자 장수 사이의 협력 관계 그림&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mdtUr/btrK0Mw606f/nUviIdceX3JXeguQnJV3kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmdtUr%2FbtrK0Mw606f%2FnUviIdceX3JXeguQnJV3kK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;584&quot; height=&quot;513&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;679&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;객사오 113쪽 - 왕과 하얀 토끼, 모자 장수 사이의 협력 관계 그림&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등장인물들이 특정한 요청을 받아들일 수 있는 이유는 그 요청에 대해 적절한 방식으로 응답하는 데 필요한 지식과 행동 방식을 가지고 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;책임과 메시지&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;각각의 등장인물들은 요청을 처리하기 위한 책임을 가지고 있음&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체의 책임을 이야기할 때는 일반적으로 외부에서 접근 가능한 공용 서비스의 관점에서 이야기한다. 책임은 객체의 공용 인터페이스를 구성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의할 점 :&amp;nbsp;&lt;/b&gt;책임과 메시지의 수준이 같지 않다. 책임은 객체가 협력에 참여하기 위해 수행해야 하는 행위를 상위 수준에서 개략적으로 서술한 것. &lt;b&gt;책임을 결정한 후 실제로 협력을 정제하면서 이를 메시지로 변환할 때는 하나의 책임이 여러 메시지로 분할되는 것이 일반적이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설계 초반에는 어떤 객체가 어떤 책임을 가지고 어떤 방식으로 서로 협력해야 하는지에 대한 개요를 아는 것만으로도 충분하다. 책임을 구현하는 방법에 대한 고민은 잠시 뒤로 미뤄도 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왕은 판사 / 모자 장수는 증인 - &lt;i&gt;왜 이렇게 불러서 상황을 복잡하게 만들어야 하나?&lt;/i&gt;&lt;i&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;역할이 재사용 가능하고 유연한 객체지향 설계를 낳는 매우 중요한 구성요소이기 때문이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림으로 보면 좀 더 이해가 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xqC64/btrK6RiBZGW/MYVrkVteWnnqA00G2P4rTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xqC64/btrK6RiBZGW/MYVrkVteWnnqA00G2P4rTk/img.png&quot; data-origin-width=&quot;776&quot; data-origin-height=&quot;843&quot; data-is-animation=&quot;false&quot; width=&quot;451&quot; height=&quot;490&quot; style=&quot;width: 31.6789%; margin-right: 10px;&quot; data-widthpercent=&quot;32.05&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xqC64/btrK6RiBZGW/MYVrkVteWnnqA00G2P4rTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxqC64%2FbtrK6RiBZGW%2FMYVrkVteWnnqA00G2P4rTk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;776&quot; height=&quot;843&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9YJ8p/btrK5w0nBP1/k1adQkbEk6A61ABEw2QPJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9YJ8p/btrK5w0nBP1/k1adQkbEk6A61ABEw2QPJ1/img.png&quot; data-origin-width=&quot;724&quot; data-origin-height=&quot;371&quot; data-is-animation=&quot;false&quot; style=&quot;width: 67.1584%;&quot; data-widthpercent=&quot;67.95&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9YJ8p/btrK5w0nBP1/k1adQkbEk6A61ABEw2QPJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9YJ8p%2FbtrK5w0nBP1%2Fk1adQkbEk6A61ABEw2QPJ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;724&quot; height=&quot;371&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;객사오 123쪽 - 유사한 세 개의 협력과 역할을 통한 단순화한 협력&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 역할의 개념을 사용하면 유사한 협력을 추상화해서 인지 과부하를 줄일 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;참고: 인지부하이론의 핵심은 &lt;b&gt;인간의 작동기억에는 한계&lt;/b&gt;가 있기 때문에 학습자에게 너무 많은 양의 정보를 한꺼번에 제공하면 인지적 과부하를 일으켜 &lt;b&gt;효과적인 학습을 방해&lt;/b&gt;하게 된다는 것이다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 객체들이 협력에 참여할 수 있기 때문에 협력이 좀 더 유연해지며 다양한 객체들이 동일한 협력에 참여할 수 있기 때문에 재사용성이 높아진다. &lt;b&gt;역할은 객체지향 설계의 단순성, 유연성, 재사용성을 뒷받침하는 핵심 개념이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로, 객체는 역할이 암시하는 책임보다 더 많은 책임을 질 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;왕은 재판도하고 국정도 돌본다.&lt;/li&gt;
&lt;li&gt;모자 장수는 증인이지만 모자를 판매하는 본질적인 책임이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;객체의 모양을 결정하는 협력&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템에 필요한 데이터를 저장하기 위해 객체가 존재한다? -&amp;gt; &lt;b&gt;NO&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체가 상태의 일부로 데이터를 포함하지만, &lt;b&gt;데이터는 단지 객체가 행위를 수행하는 데 필요한 재료&lt;/b&gt;일 뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스와 클래스 간의 관계를 표현하는 시스템의 정적인 측면에 중점 -&amp;gt; &lt;b&gt;NO&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;중요한 것은 협력에 참여하는 동적인 객체&lt;/b&gt;이며, 클래스는 단지 시스템에 필요한 객체를 표현하고 생성하기 위해 프로그래밍 언어가 제공하는 구현 메커니즘이라는 사실을 기억하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올바른 객체를 설계하기 위해서는 먼저 견고하고 깔끔한 협력을 설계해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;객체지향 설계 기법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책임-주도 설계 : 협력에 필요한 책임들을 식별하고 적합한 객체에게 책임을 할당&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디자인 패턴 : 반복적으로 사용하는 해결 방법을 정의해 놓은 설계 템플릿의 모음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트-주도 개발 : 테스트를 먼저 작성하고 테스트를 통과하는 구체적인 코드를 추가하면서 애플리케이션을 완성해가는 방식&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;테스트가 아니라, 설계를 위한 기법&lt;/b&gt;이다. 실제 목적은 구체적인 코드를 작성해나가면서 &lt;b&gt;역할, 책임, 협력을 식별하고 적합한지 피드백&lt;/b&gt; 받기 위함이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Books/객체지향의 사실과 오해</category>
      <category>Til</category>
      <category>객체지향의 사실과 오해</category>
      <category>역할</category>
      <category>주니어 개발자</category>
      <category>책리뷰</category>
      <category>책임</category>
      <category>추상화</category>
      <category>프론트엔드</category>
      <category>협력</category>
      <author>devmomori</author>
      <guid isPermaLink="true">https://somedaycode.tistory.com/28</guid>
      <comments>https://somedaycode.tistory.com/28#entry28comment</comments>
      <pubDate>Wed, 31 Aug 2022 19:54:49 +0900</pubDate>
    </item>
    <item>
      <title>MSW(Mock Service Worker)를 사용한 네트워크 단 API Mocking 테스트</title>
      <link>https://somedaycode.tistory.com/27</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;MSW(Mock Service Worker)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mswjs.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;MSW&lt;/b&gt;&lt;/a&gt;는 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Service_Worker_API/Using_Service_Workers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;서비스 워커(Service Worker)&lt;/a&gt;를 사용하여 실제 요청(Requests)을 중간에서 가로채 API를 Mocking 해주는 라이브러리이다. 기존의 라이브러리들과는 다르게 네트워크 단에서 실제로 요청을 주고받으며 테스트를 진행할 수 있는 장점이 있으며, REST API 및 GraphQL 모두 지원하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프런트엔드 개발에서 Mock API는 떼려야 뗄 수 없는 부분인 것 같다. 개발을 위한 목업 데이터 만들고 관련 로직과 컴포넌트를 만든다. API 개발을 기다리며 타입을 작성하고, 여러 가지 테스트를 진행한다. &lt;b&gt;여러 이슈들은 대부분이 잘못된 API를 호출하거나 에러 처리를 잘못하였을 때 발생&lt;/b&gt;하기 때문에 Mock API를 사용하여 디버깅을 해보는 것이 도움이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 운영에서 사용될 API 개발이 늦어지는 경우에도 이러한 목업 데이터를 활용하여 &lt;b&gt;개발 일정이 최대한 병렬적으로 수행&lt;/b&gt;될 수 있도록 하는 것이 &lt;b&gt;생산성을 높이는 데 도움&lt;/b&gt;을 주는 것 같다. &lt;b&gt;MSW&lt;/b&gt;는 별도의 목업 서버(JSON Server, etc.)를 구축하지 않아도 되고 실제 네트워크를 사용해 볼 수 있으며, API Mocking 로직들을 관리하는 데 좀 더 편한 것 이 큰 장점으로 다가오는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작성된 코드는 해당 레포를 참고하시면 됩니다.&lt;/p&gt;
&lt;figure id=&quot;og_1661193906731&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - somedaycode/msw-react-tutorial: MSW(Mock Service Worker)를 사용한 API Mocking Tutorial&quot; data-og-description=&quot;MSW(Mock Service Worker)를 사용한 API Mocking Tutorial - GitHub - somedaycode/msw-react-tutorial: MSW(Mock Service Worker)를 사용한 API Mocking Tutorial&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/somedaycode/msw-react-tutorial/tree/main/msw-react-vite&quot; data-og-url=&quot;https://github.com/somedaycode/msw-react-tutorial&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cw6kfB/hyPxocBJHx/LQPjw78xZKXyUnzcTsaSuK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/somedaycode/msw-react-tutorial/tree/main/msw-react-vite&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/somedaycode/msw-react-tutorial/tree/main/msw-react-vite&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cw6kfB/hyPxocBJHx/LQPjw78xZKXyUnzcTsaSuK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - somedaycode/msw-react-tutorial: MSW(Mock Service Worker)를 사용한 API Mocking Tutorial&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;MSW(Mock Service Worker)를 사용한 API Mocking Tutorial - GitHub - somedaycode/msw-react-tutorial: MSW(Mock Service Worker)를 사용한 API Mocking Tutorial&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기존의 API Mocking&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존의 API Mocking은 fetch 혹은 axios를 Jest.mock을 사용하여 진행하고는 했다. 실제로는 &lt;b&gt;네트워크 요청이 일어나지 않으며&lt;/b&gt; mockImplementation과 같은 Jest 내부 메서드를 사용하여 &lt;b&gt;요청과 응답이 일어난 것처럼&lt;/b&gt; 테스트를 작성했다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1661180157544&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  import mockAxios from &quot;jest-mock-axios&quot;;
  // mockAdapter from &quot;axios-mock-adapter&quot;;
  // const mockAxios = new MockAdapter(axios);
  import fetchUsers from './api';

  it(&quot;유저목록을 반환한다.&quot;, async () =&amp;gt; {
      const users = [
        { id: 1, name: &quot;somedaycode&quot; },
        { id: 2, name: &quot;devmomori&quot; },
      ];
      mockAxios.get.mockResolvedValueOnce(users);

      const result = await fetchUsers();

      expect(mockAxios.get).toHaveBeenCalledWith(`/users`);
      expect(result).toEqual(users);
    });&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;테스트코드가 늘어나면서 API Mocking을 위해서 mockAxios, MockingPromise와 같은 유틸 함수를 작성해서 관리하는 부분이 꽤 번거롭고 불편하게 느껴진다. 또한, 실제로 네트워크의 요청을 주고받는 것이 아니다 보니, HTTP 상태나 Error 처리에 대한 부분을 확인하기 위해서 추가적으로 작성되는 코드들이 많아지기도 하였다.&amp;nbsp;&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;MSW의 요청과 응답은 다음과 같이 이루어진다.&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;367&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ddQuF3/btrKhkN84dN/spKbfD5C3rAUrILFFGrsq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ddQuF3/btrKhkN84dN/spKbfD5C3rAUrILFFGrsq0/img.png&quot; data-alt=&quot;브라우저의 MSW&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ddQuF3/btrKhkN84dN/spKbfD5C3rAUrILFFGrsq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FddQuF3%2FbtrKhkN84dN%2FspKbfD5C3rAUrILFFGrsq0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;701&quot; height=&quot;367&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;367&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;브라우저의 MSW&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실제로도 mockServiceWorker.js 파일을 까 보면 다음과 같이 동작하는 것을 확인할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1661185910938&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// public/mockServiceWorker.js

self.addEventListener('fetch', async function (event) {
  const { clientId, request } = event
  const requestClone = request.clone() // 2. 요청 복제
  const getOriginalResponse = () =&amp;gt; fetch(requestClone)
  
  ...more
}

// MOCK_SUCCESS 확인
switch (clientMessage.type) {
  case 'MOCK_SUCCESS': {
    setTimeout(
      esolve.bind(this, createResponse(clientMessage)),
      clientMessage.payload.delay,
    )
   break
   
   ...more
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;설치&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1661183654816&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// MSW 패키지 설치
yarn add msw --dev

// 기존 프로젝트 Public 폴더에 서비스워커 생성
npx msw init &amp;lt;PUBLIC_DIR&amp;gt; --save
// npx msw init public/ --save&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 설치를 완료하면 mockServiceWorker.js 파일이 public 폴더에 만들어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;API Mocking 준비&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. '/users' HTTP GET 요청을 위한 핸들러 함수 작성&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;898&quot; data-origin-height=&quot;912&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s85AF/btrKekAWnRa/xjqoPsIXQlLEuEAHgfhXxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s85AF/btrKekAWnRa/xjqoPsIXQlLEuEAHgfhXxk/img.png&quot; data-alt=&quot;HTTP GET /users 데이터를 받기 위한 코드 작성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s85AF/btrKekAWnRa/xjqoPsIXQlLEuEAHgfhXxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs85AF%2FbtrKekAWnRa%2FxjqoPsIXQlLEuEAHgfhXxk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;703&quot; height=&quot;714&quot; data-origin-width=&quot;898&quot; data-origin-height=&quot;912&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;HTTP GET /users 데이터를 받기 위한 코드 작성&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 브라우저에서 API Mocking을 위한 Worker 셋업&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dakqyX/btrKlpOBSw9/3R3g35PzIexE70VDEP1UY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dakqyX/btrKlpOBSw9/3R3g35PzIexE70VDEP1UY0/img.png&quot; data-alt=&quot;브라우저에서 msw 사용을 위한 코드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dakqyX/btrKlpOBSw9/3R3g35PzIexE70VDEP1UY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdakqyX%2FbtrKlpOBSw9%2F3R3g35PzIexE70VDEP1UY0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;727&quot; height=&quot;341&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;424&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;브라우저에서 msw 사용을 위한 코드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. API Mocking 응답을 활용하기 위한 Users 컴포넌트 작성&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;934&quot; data-origin-height=&quot;1336&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b187nP/btrKi7IcILN/pWeQ64ibAujVkMrhOGabYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b187nP/btrKi7IcILN/pWeQ64ibAujVkMrhOGabYk/img.png&quot; data-alt=&quot;유저 목록을 불러오기 위한 User.tsx&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b187nP/btrKi7IcILN/pWeQ64ibAujVkMrhOGabYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb187nP%2FbtrKi7IcILN%2FpWeQ64ibAujVkMrhOGabYk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;694&quot; height=&quot;993&quot; data-origin-width=&quot;934&quot; data-origin-height=&quot;1336&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;유저 목록을 불러오기 위한 User.tsx&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 렌더링&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;index.tsx 파일에 다음과 같이 코드를 작성해줍니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1374&quot; data-origin-height=&quot;854&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eAmOtz/btrKejINfwa/g3JTVZrRDOCGMIjUT8AVqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eAmOtz/btrKejINfwa/g3JTVZrRDOCGMIjUT8AVqk/img.png&quot; data-alt=&quot;Index.tsx&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eAmOtz/btrKejINfwa/g3JTVZrRDOCGMIjUT8AVqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeAmOtz%2FbtrKejINfwa%2Fg3JTVZrRDOCGMIjUT8AVqk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;940&quot; height=&quot;584&quot; data-origin-width=&quot;1374&quot; data-origin-height=&quot;854&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Index.tsx&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실행 결과&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 리액트 앱을 실행시키면 개발자도구에서 다음과 같은 화면을 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1034&quot; data-origin-height=&quot;116&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vBtbt/btrKkmrc6Cn/fJAD9Pvk5iakhxYy0QkfmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vBtbt/btrKkmrc6Cn/fJAD9Pvk5iakhxYy0QkfmK/img.png&quot; data-alt=&quot;개발자 도구 확인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vBtbt/btrKkmrc6Cn/fJAD9Pvk5iakhxYy0QkfmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvBtbt%2FbtrKkmrc6Cn%2FfJAD9Pvk5iakhxYy0QkfmK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1487&quot; height=&quot;167&quot; data-origin-width=&quot;1034&quot; data-origin-height=&quot;116&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;개발자 도구 확인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Application -&amp;gt; Service Worker로 들어가 서비스 워커가 잘 설치되었는지도 확인해봅니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1045&quot; data-origin-height=&quot;351&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oSDqG/btrKi9F1cj6/skqmNRBppuL4KU29kMkPek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oSDqG/btrKi9F1cj6/skqmNRBppuL4KU29kMkPek/img.png&quot; data-alt=&quot;install Service Worker&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oSDqG/btrKi9F1cj6/skqmNRBppuL4KU29kMkPek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoSDqG%2FbtrKi9F1cj6%2FskqmNRBppuL4KU29kMkPek%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;961&quot; height=&quot;323&quot; data-origin-width=&quot;1045&quot; data-origin-height=&quot;351&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;install Service Worker&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;테스트 화면&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이제 한번 버튼을 눌러 API Mocking 된 응답이 잘 들어오는지 확인해봅니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;유저 목록을 불러올 때 서비스워커를 통해 네트워크 요청을 보내고 위에서 설정한 응답 값을 화면에 뿌리는 것을 확인할 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;msw_test.gif&quot; data-origin-width=&quot;830&quot; data-origin-height=&quot;524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDRdIm/btrKlqtcLMu/v2ENhic4sXayncr8yjkm6K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDRdIm/btrKlqtcLMu/v2ENhic4sXayncr8yjkm6K/img.gif&quot; data-alt=&quot;유저 목록을 불러오는 GIF&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDRdIm/btrKlqtcLMu/v2ENhic4sXayncr8yjkm6K/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bDRdIm/btrKlqtcLMu/v2ENhic4sXayncr8yjkm6K/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;830&quot; height=&quot;524&quot; data-filename=&quot;msw_test.gif&quot; data-origin-width=&quot;830&quot; data-origin-height=&quot;524&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;유저 목록을 불러오는 GIF&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;319&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dh0ikf/btrKkubMYY4/dXmAOEsoHuAJH00mC677z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dh0ikf/btrKkubMYY4/dXmAOEsoHuAJH00mC677z1/img.png&quot; data-alt=&quot;네트워크 탭 응답 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dh0ikf/btrKkubMYY4/dXmAOEsoHuAJH00mC677z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdh0ikf%2FbtrKkubMYY4%2FdXmAOEsoHuAJH00mC677z1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;566&quot; height=&quot;319&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;319&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;네트워크 탭 응답 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크 탭도 확인화면 Status Code 옆에 (from service worker)라고 표시되어 있는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;느낀 점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실제로도 MSW를 이용한 API Mocking은 러닝 커브가 낮았고, 간편하고 쉽게 API Mocking을 진행해 볼 수 있었습니다.&lt;/b&gt; 보다 쉽게 네트워크 단에서 API의 호출과 응답을 테스트 할 수 있다는 점이 애플리케이션 내부에 목업을 만들고 테스트를 진행하는 것에 비해 굉장히 매력적으로 느껴집니다. 더불어 이전에 테스트 코드를 진행하며 리소스를 찾는 데 어려움이 있었던 것에 비해서 &lt;b&gt;MSW는 Github에 여러가지 example 보일러 플레이트&lt;/b&gt;가 많기 때문에 다양한 프레임워크에서의 동작도 쉽게 확인할 수 있었습니다.&amp;nbsp; &lt;a href=&quot;https://github.com/vercel/next.js/tree/canary/examples/with-msw&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;vercel/Next.js의 MSW Example&lt;/a&gt;도 있으니 확인해보면 좋겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고문서&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://mswjs.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MSW 공식문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mswjs/msw&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MSW 깃헙&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;a href=&quot;https://github.com/somedaycode/msw-react-tutorial&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;코드 확인&lt;/a&gt;&lt;/h4&gt;</description>
      <category>개발/아티클</category>
      <category>mock api</category>
      <category>Mock Service Worker</category>
      <category>msw</category>
      <category>react</category>
      <category>Test</category>
      <category>Vite</category>
      <category>서비스워커</category>
      <category>테스트코드</category>
      <author>devmomori</author>
      <guid isPermaLink="true">https://somedaycode.tistory.com/27</guid>
      <comments>https://somedaycode.tistory.com/27#entry27comment</comments>
      <pubDate>Tue, 23 Aug 2022 03:46:00 +0900</pubDate>
    </item>
    <item>
      <title>객체지향의 사실과 오해 - 이상한 나라의 객체</title>
      <link>https://somedaycode.tistory.com/26</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;여러 개념들을 머릿속에서 잘 정립하지 않은 상태에서, 혹은 '개념을 정확히 이해하지 못한 채로 애플리케이션 설계를 하고 있지 않았나?' 반성해본다. 이전에는 뭉뚱그려서 자의적으로 해석했던 여러 개념들을 다시 한번 차곡차곡 정리할 수 있었다. 특히, 상태에 대한 개념과 애플리케이션 설계에서 행동을 중심으로 고민하고 프로그램을 설계해 나아가야 한다는 것이 굉장히 와닿았다. 같이 스터디를 한 친구들도 마찬가지인 것 같다. :) 잘못된 설계는 결국 많은 시간을 더 소요하도록 만드는데, 이런 가장 기본적인 개념이 설계를 함에 있어서 더 좋은 방향으로 가이드해주는 것이 아닐까?&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;들어가며,&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물체가 여러 부분으로 구성되어 있더라도 함께 움직일 경우 그 물체를 하나의 유기적인 단위로 인식한다. 세상을 더 작은 객체로 분해하는 것은 본질적인고 세상이 포함하고 있는 복잡성을 극복하기 위한 인간의 작은 몸부림이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 현실 세계와 소프트웨어 세계 사이의 유사성은 한계가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 중인 객체지향 애플리케이션의 내부를 들여다볼 수 있다면 겉으로는 우리가 알고 있는 세계와 유사해 보이지만 본질적으로는 이질적인 모습이 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;앨리스 객체&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책에서 이상한 나라의 앨리스 줄거리를 예시로 객체에 대해 설명&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문을 통과하기 위하여 자신의 키를 계속해서 변화 시킴&lt;/li&gt;
&lt;li&gt;결국 특정 시점의 앨리스의 상태란 특정 시점에서의 앨리스의 키를 의미&lt;/li&gt;
&lt;li&gt;키를 변화시킨 것은 앨리스의 행동&lt;/li&gt;
&lt;li&gt;앨리스의 행동에 따라 앨리스의 상태가 변화&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 어떤 행동의 성공 여부는 이전에 어떤 행동들이 발생했는지에 영향을 받는다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&amp;nbsp;문을 통과하려면 음료나 케이크를 먹는 행동이 선행되어야 함&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;상태, 행동, 식별자&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;객체의 다양한 특성을 효과적으로 설명을 하기 위해서는 객체를 &lt;b&gt;상태(state), 행동(behavior), 식별자(identity)&lt;/b&gt;를 지닌 실체로 보는것이 가장 효과적이다 - Booch 2007&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 객체의 상태는 단순한 값과 객체의 조합으로 표현된다. 상태를 구성하는 모든 특징을 객체의 &lt;b&gt;프로퍼티(property)&lt;/b&gt;라고 지칭한다. 객체와 객체 사이의 의미 있는 연결을 &lt;b&gt;링크(link)&lt;/b&gt;라고 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;99&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZVnu9/btrJTQmRomR/GAtDTPlumKD3lEX5RyNg31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZVnu9/btrJTQmRomR/GAtDTPlumKD3lEX5RyNg31/img.png&quot; data-alt=&quot;서로 연관이 있는 객체를 선으로 표시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZVnu9/btrJTQmRomR/GAtDTPlumKD3lEX5RyNg31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZVnu9%2FbtrJTQmRomR%2FGAtDTPlumKD3lEX5RyNg31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;530&quot; height=&quot;99&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;99&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;서로 연관이 있는 객체를 선으로 표시&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;99&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/coG6o9/btrJWWTt9p5/1ftpNI06RuMtFiK0Izodrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/coG6o9/btrJWWTt9p5/1ftpNI06RuMtFiK0Izodrk/img.png&quot; data-alt=&quot;변경된 상태로, 객체 간의 링크가 없을 때를 표현&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/coG6o9/btrJWWTt9p5/1ftpNI06RuMtFiK0Izodrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcoG6o9%2FbtrJWWTt9p5%2F1ftpNI06RuMtFiK0Izodrk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;530&quot; height=&quot;99&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;99&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;변경된 상태로, 객체 간의 링크가 없을 때를 표현&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 링크는 객체가 다른 객체를 참조할 수 있다는 것을 의미하고, 한 객체가 다른 객체의 식별자를 알고 있는 것으로 표현된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더불어, 객체의 상태는 저절로 변경되지 않는다. 객체가 취하는 행동이 객체 자신의 상태를 변경시키며 이런 행동은 &lt;b&gt;부수 효과(side effect)&lt;/b&gt;를 초래하는 것이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;예시) 앨리스가 케이크를 먹음 -&amp;gt; 키를 작게 변화 -&amp;gt; 케이크의 양을 줄임&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체의 행동은 상태를 변경시키지만 행동의 결과는 객체의 상태에 의존적이다. 음료를 마신 후의 앨리스의 키는 마시기 전보다 작아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;상태를 이용하여 객체의 행동을 쉽고 우아하게 표현하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[앨리스가 통과해야 하는 문의 크기는 40센티]&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;앨리스의 키가 40센티미터 이하라면 문을 통과할 수 있음&lt;/li&gt;
&lt;li&gt;문을 통과한 이후에는 앨리스의 위치가 정원으로 바뀌어야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;객체가 다른 객체는 메시지를 통해서만 의사소통할 수 있는 것을 기억하자.&amp;nbsp;&lt;/b&gt;객체가 어떤 행동을 하도록 만드는 것은 객체가 외부로부터 수신한 메시지다. 이를 통해 협력에 참여하고 상태를 변경한다. 객체의 행동을 통해 발생하는 결과는 &lt;b&gt;두 가지 관점&lt;/b&gt;에서 설명이 가능하다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 자신의 상태 변경&lt;/li&gt;
&lt;li&gt;행동 내에서 협력하는 다른 객체에 대한 메시지 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;135&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3NByl/btrJYfkKlBH/sDq5YDDa3jtrKXpX0tN4Ik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3NByl/btrJYfkKlBH/sDq5YDDa3jtrKXpX0tN4Ik/img.png&quot; data-alt=&quot;메시지를 통한 앨리스와 음료 사이의 협력 관계&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3NByl/btrJYfkKlBH/sDq5YDDa3jtrKXpX0tN4Ik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3NByl%2FbtrJYfkKlBH%2FsDq5YDDa3jtrKXpX0tN4Ik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;702&quot; height=&quot;135&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;135&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;메시지를 통한 앨리스와 음료 사이의 협력 관계&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메시지 송신자는 메시지 수신자의 상태 변경에 대해서는 전혀 알지 못한다. 이것이 캡슐화가 의미하는 것. &lt;/b&gt;상태를 외부에 노출시키지 않고 행동을 경계로 캡슐화하는 것은 객체의 자율성을 높이고 각 객체 간의 협력이 유연해지고 간결해질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체는 시간에 따라 변경되는 상태를 포함한다. 타입이 같은 두 객체의 상태가 완전히 똑같더라도 두 객체는 독립적인 별개의 객체이며, 이름이 같고 키가 동일한 두 사람이 함께 있다 하더라도 어떤 누구도 같은 사람이라고 생각하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;행동이 상태를 결정한다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;상태를 먼저 결정하고 행동을 나중에 결정하는 방법은 설계에 나쁜 영향을 끼친다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앨리스 객체 설계 시&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;상태 (키, 장소)를 추가 후 -&amp;gt; 행동에 대해 고민 ( X )&lt;/li&gt;
&lt;li&gt;행동 -&amp;gt; 상태 ( O )&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;WHY?&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;캡슐화를 저해한다.&lt;/li&gt;
&lt;li&gt;협력에 적합하지 못한 객체를 창조하게 된다. (상태를 먼저 고려한다는 것은 협력이라는 문맥에서 멀리 벗어난 채 객체를 설계하기 때문이다.)&lt;/li&gt;
&lt;li&gt;재사용성이 저하된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt; 은유와 객체&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현실 속의 객체와 소프트웨어 객체 사이의 가장 큰 차이점은? 현실 속에서의 수동적인 존재가 소프트웨어 객체로 구현될 때는 능동적으로 변한다는 것이다. (의인화)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현실 속의 전화기는 스스로 전화를 걸 수 없지만, 우리가 알고 있는 전화기라는 개념을 이용해 소프트웨어 객체를 묘사하면 그 객체가 전화를 걸 수 있다는 사실을 쉽게 이해하고 기억할 수 있게 된다. (은유)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Books/객체지향의 사실과 오해</category>
      <category>Til</category>
      <category>객체지향의 사실과 오해</category>
      <category>상태</category>
      <category>스터디</category>
      <category>애플리케이션 설계</category>
      <category>주니어 개발자</category>
      <category>캡슐화</category>
      <category>행동</category>
      <author>devmomori</author>
      <guid isPermaLink="true">https://somedaycode.tistory.com/26</guid>
      <comments>https://somedaycode.tistory.com/26#entry26comment</comments>
      <pubDate>Wed, 17 Aug 2022 21:05:13 +0900</pubDate>
    </item>
    <item>
      <title>객체지향의 사실과 오해 - 협력하는 객체들의 공동체</title>
      <link>https://somedaycode.tistory.com/25</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;객체란 현실 세계에 존재하는 사물에 대한 &lt;b&gt;추상화&lt;/b&gt;라는 것 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어플리케이션을 개발하면서 객체에 직접적으로 대응되는 실세계의 사물을 발견할 확률은 그다지 높지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향 설계의 핵심 사상인 '연결완전성'을 설명하는 데 적합한 틀을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;객체지향에서 가장 중요한 개념 세가지&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;역할&lt;/li&gt;
&lt;li&gt;책임&lt;/li&gt;
&lt;li&gt;협력&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1장에서 나오는 카페에서 커피를 주문 후 커피를 받기까지의 과정&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;191&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DIzB5/btrJq4RNpfv/4P2dU7x39iKD0ufybxPVJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DIzB5/btrJq4RNpfv/4P2dU7x39iKD0ufybxPVJ0/img.png&quot; data-alt=&quot;객체지향 사실과 오해 그림 1.2&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DIzB5/btrJq4RNpfv/4P2dU7x39iKD0ufybxPVJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDIzB5%2FbtrJq4RNpfv%2F4P2dU7x39iKD0ufybxPVJ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;666&quot; height=&quot;171&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;191&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;객체지향 사실과 오해 그림 1.2&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반적으로 하나의 문제를 해결하기 위해 다수의 사람 혹은 역할이 필요하다.&lt;/li&gt;
&lt;li&gt;한 사람에 대한 요청이 또 다른 사람에 대한 요청을 유발하는 것이 일반적이다.&lt;/li&gt;
&lt;li&gt;요청은 연쇄적이다.&lt;/li&gt;
&lt;li&gt;요청 받은 사람 또한 주어진 책임을 다하면서 지식이나 서비스를 제공한다. 요청의 방향과 반대 방향으로 연쇄적으로 전달된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;역할과 책임&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역할이라는 단어는 일반적으로 책임이라는 개념을 내포하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 선생님이라는 역할은 학생을 가르칠 책임이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;협력을 위해 특정한 역할을 맡고 적합한 책임을 수행한다는 것은 몇가지 개념을 제시한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 동일한 역할 수행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 손님은 캐시어가 누구든 상관없이 커피를 주문하고 받을 수만 있으면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 대체 가능성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 캐시어가 두명일 때 누가해도 상관없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 책임을 수행하는 방법은 자율적으로 선택&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 바리스타가 동일한 요청에 대하 서로 다른 방식으로 응답할 수 있는 능력 (다형성)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 한 사람이 동시에 여러 역할을 수행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 한 사람이 캐시어와 바리스타의 역할을 동시에 수행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실세계의 커피 주문과정을 통해 객체지향을 좀 더 쉽게 설명이 가능하다. 이렇기 때문에 실세계의 모방이라는 은유를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역할과 책임을 수행하며 협력하는 객체들&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;특정한 목표를 이루기 위해 협력하고, 책임을 수행하는 역할들 간의 연쇄적인 요청과 응답을 통해 목표를 달성한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;목표는 더 작은 책임으로 분할되고 책임을 수행할 수 있는 적절한 역할을 가진 사람에 의해 수행된다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체는 두 가지를 갖춰야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. '협력적' 이어야 함&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;외부의 도움을 무시한 채 모든 것을 스스로 처리하려고 하는 객체는 내부적인 복잡도에 의해 자멸하고 만다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. '자율적' 이어야 함&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;손님에게 음료를 주문하는 절차나, 바리스타에게 관련 내역을 전달하는 방법은 스스로 결정한다.&lt;/li&gt;
&lt;li&gt;&amp;nbsp;손님은 캐시어에게 어떤 방식으로 어떻게 주문을 바리스타에게 전달해야하는지 지시하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;상태와 행동을 함께 지닌 자율적인 객체&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행동을 하기 위해서는 필요한 상태를 함께 지니고 있어야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 내부와 외부를 명확하게 구분함으로써 스스로 결정하는 자율성을 가지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 구성된 어플리케이션은 유지보수가 쉽고 재사용성이 용이한 시스템을 구축할 수 있는 가능성을 제시해준다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;'Layer Architecture'가 문득 떠올랐다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향에서는 오직 한 가지 의사소통 수단만이 존재하는 데 그것을 메시지라 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전송하는 객체는 Sender - 수신하는 객체는 Receiver&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체가 수신된 메시지를 처리하는 방법을 &lt;b&gt;메서드(Method)&lt;/b&gt;라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향 프로그래밍 언어와 다른 프로그래밍 언어를 구분짓는 &lt;b&gt;핵심적인 특징은 메시지를 수신한 객체가 실행 시간(run-time)에 메서드를 선택할 수 있다&lt;/b&gt;는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부의 요청이 무엇인지 표현하는 메시지와 요청을 처리하기 위한 메서드를 분리하는 것은 객체의 자율성을 높이는 핵심 메커니즘이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 &lt;b&gt;캡슐화&lt;/b&gt;와도 관련이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;클래스와 객체 지향&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스가 객체지향 프로그래밍 언어의 관점에서 매우 중요한 구성요소 이지만 핵심을 이루는 중심 개념이라고 말하기에는 무리가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 프로토타입 기반의 객체지향 언어이며 클래스가 존재하지 않고(sugar syntax) 객체만이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;훌륭한 객체지향 설계자가 되기 위해서는 클래스의 관점에서 메시지를 주고받는 객체의 관점으로 사고의 중심을 전환해야한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스는 그저 협력 관계를 코드로 옮기는 도구일 뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스의 구조와 메서드가 아니라 &lt;b&gt;객체의 역할, 책임, 협력에 집중하자.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Books/객체지향의 사실과 오해</category>
      <category>Til</category>
      <category>객체</category>
      <category>객체지향의 사실과 오해</category>
      <category>정리</category>
      <category>클래스</category>
      <category>프로그래밍</category>
      <category>협력하는 객체들의 공동체</category>
      <author>devmomori</author>
      <guid isPermaLink="true">https://somedaycode.tistory.com/25</guid>
      <comments>https://somedaycode.tistory.com/25#entry25comment</comments>
      <pubDate>Wed, 10 Aug 2022 20:39:59 +0900</pubDate>
    </item>
    <item>
      <title>Nuxt3 Page 내부에 하나의 root element가 없을때 경고문 이슈 : Component inside &amp;lt;Transition&amp;gt; renders non-element root node that cannot be animated.</title>
      <link>https://somedaycode.tistory.com/24</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt를 사용하면서 발생한 에러.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;에러가 불친절해서 Nuxt github에 feature issue를 올렸다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;답변이 굉장히 빨랐는데, 관련 이슈를 훑어보니 비슷하게 생각하는 사람들이 몇몇 있었던 모양이다.&lt;/p&gt;
&lt;figure id=&quot;og_1660128525151&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Warn needs to be much more specific when there's no root element in &amp;lt;template&amp;gt; &amp;middot; Issue #6476 &amp;middot; nuxt/framework&quot; data-og-description=&quot;Describe the feature these are vue components in my pages directory // pages/index.vue &amp;lt;template&amp;gt; &amp;lt;h1&amp;gt;Home&amp;lt;/h1&amp;gt; &amp;lt;NuxtLink to=&amp;quot;some-route/1&amp;quot;&amp;gt;page 1&amp;lt;/NuxtLink&amp;gt;...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/nuxt/framework/issues/6476#event-7162497273&quot; data-og-url=&quot;https://github.com/nuxt/framework/issues/6476&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/e9znw/hyPoknXTam/Y2lbktMk8MkCId3mIVv9Bk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/nuxt/framework/issues/6476#event-7162497273&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/nuxt/framework/issues/6476#event-7162497273&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/e9znw/hyPoknXTam/Y2lbktMk8MkCId3mIVv9Bk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Warn needs to be much more specific when there's no root element in &amp;lt;template&amp;gt; &amp;middot; Issue #6476 &amp;middot; nuxt/framework&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Describe the feature these are vue components in my pages directory // pages/index.vue &amp;lt;template&amp;gt; &amp;lt;h1&amp;gt;Home&amp;lt;/h1&amp;gt; &amp;lt;NuxtLink to=&quot;some-route/1&quot;&amp;gt;page 1&amp;lt;/NuxtLink&amp;gt;...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nuxt에서도 이를 인지하고 있는 것인지 관련 PR이 올라와있다.&lt;/p&gt;
&lt;figure id=&quot;og_1660128878585&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;feat(nuxt): add warning in dev mode if layouts/pages do not have a single root node by danielroe &amp;middot; Pull Request #5469 &amp;middot; nuxt/f&quot; data-og-description=&quot;  Linked issue resolves #4598, resolves #6476 ❓ Type of change   Documentation (updates to the documentation or readme)   Bug fix (a non-breaking change that fixes an issue)   Enhancement (imp...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/nuxt/framework/pull/5469&quot; data-og-url=&quot;https://github.com/nuxt/framework/pull/5469&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/boB7b4/hyPpLc83A8/wlFgCWFBiLcVUWAQXuin10/img.png?width=1200&amp;amp;height=600&amp;amp;face=950_118_1058_236&quot;&gt;&lt;a href=&quot;https://github.com/nuxt/framework/pull/5469&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/nuxt/framework/pull/5469&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/boB7b4/hyPpLc83A8/wlFgCWFBiLcVUWAQXuin10/img.png?width=1200&amp;amp;height=600&amp;amp;face=950_118_1058_236');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;feat(nuxt): add warning in dev mode if layouts/pages do not have a single root node by danielroe &amp;middot; Pull Request #5469 &amp;middot; nuxt/f&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  Linked issue resolves #4598, resolves #6476 ❓ Type of change   Documentation (updates to the documentation or readme)   Bug fix (a non-breaking change that fixes an issue)   Enhancement (imp...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;route-link&amp;gt;와 같은 동작을 하는 &amp;lt;NuxtLink&amp;gt;를 사용하여 페이지 전환 후 param.id를 가져오는 단순한 코드다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1062&quot; data-origin-height=&quot;974&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/shoXj/btrJpS5y9A2/M0tccKdaw6T6sOkLq8xYu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/shoXj/btrJpS5y9A2/M0tccKdaw6T6sOkLq8xYu0/img.png&quot; data-alt=&quot;root element error code&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/shoXj/btrJpS5y9A2/M0tccKdaw6T6sOkLq8xYu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FshoXj%2FbtrJpS5y9A2%2FM0tccKdaw6T6sOkLq8xYu0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;588&quot; height=&quot;539&quot; data-origin-width=&quot;1062&quot; data-origin-height=&quot;974&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;root element error code&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 실행하면 다음과 같은 에러를 마주한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;runtime-core.esm-bundler.js:38 [Vue warn]: &lt;br /&gt;Component inside &amp;lt;&lt;b&gt;Transition&lt;/b&gt;&amp;gt; renders non-element root node that cannot be &lt;b&gt;animated&lt;/b&gt;. at &lt;br /&gt;&amp;lt;Index onVnodeUnmounted=fn&amp;lt;onVnodeUnmounted&amp;gt; ref=Ref&amp;lt; undefined &amp;gt; key=&quot;/&quot; &amp;gt; at &amp;lt;BaseTransition mode=&quot;out-in&quot; appear=false persisted=false ... &amp;gt; at &amp;lt;Transition name=&quot;page&quot; mode=&quot;out-in&quot; &amp;gt; at &amp;lt;RouterView name=undefined route=undefined &amp;gt; at &amp;lt;NuxtPage&amp;gt; at &amp;lt;App key=1 &amp;gt; at &amp;lt;NuxtRoot&amp;gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 내가 헷갈렸던 부분은 &lt;b&gt;'&amp;lt;Transition&amp;gt;' 과 'animated&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #24292f;&quot;&gt;' 라는 단어였는데, 애니메이션을 사용하지도 않았고 해당 에러를 찾아보니 애니메이션과 관련된 문서만 나와서 뭔가 싶었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #24292f;&quot;&gt;알고보니 단순히 index.vue에 엘리먼트를 감싸는 Root Element가 없어서 그랬던 것.. 아래와 같이 div로 감싸주면 해결된다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IoWZq/btrJp0vDfRX/QAXJSg6kPrEOYLEJk2sLp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IoWZq/btrJp0vDfRX/QAXJSg6kPrEOYLEJk2sLp0/img.png&quot; data-alt=&quot;root element should wrap others&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IoWZq/btrJp0vDfRX/QAXJSg6kPrEOYLEJk2sLp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIoWZq%2FbtrJp0vDfRX%2FQAXJSg6kPrEOYLEJk2sLp0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;623&quot; height=&quot;364&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;root element should wrap others&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;React를 사용하면 JSX expresstions must have one parent element. 라는 간단명료한 문구를 IDE에서 바로 확인이 가능한데 Vue의 경고는 조금 불친절한 부분이 있는 것 같다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Today I Learned</category>
      <category>jsx</category>
      <category>nuxt</category>
      <category>react</category>
      <category>Til</category>
      <category>Vue</category>
      <author>devmomori</author>
      <guid isPermaLink="true">https://somedaycode.tistory.com/24</guid>
      <comments>https://somedaycode.tistory.com/24#entry24comment</comments>
      <pubDate>Wed, 10 Aug 2022 18:24:11 +0900</pubDate>
    </item>
    <item>
      <title>'/deep/' selector is not working</title>
      <link>https://somedaycode.tistory.com/23</link>
      <description>&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;차트 라이브러리 개발 도중 마주친 에러 &lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;- vue2.x 사용&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;vue-cli-service build --target lib --name index [entry]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;뷰 컴포넌트를 라이브러리로 만든 후, 해당 라이브러리를 다른 서비스에서 사용하려했지만 다음과 같은 에러가 발생했다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: expected selector.

&amp;amp; /deep/ .class-name {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;br&gt;비슷한 문제를 스택오버플로우에서 발견&lt;/p&gt;
&lt;figure data-ke-type=&quot;opengraph&quot; data-og-title=&quot;The `/deep/` selector is not working using sass-loader in my VueJS application&quot; data-ke-align=&quot;alignCenter&quot; data-og-description=&quot;In my Vue 2.6.10 webpack application I am trying to add SASS as our team wants to migrate our legacy application from LESS to SCSS. In my package.json I have installed these to my devDependencies per&quot; data-og-host=&quot;stackoverflow.com&quot; data-og-source-url=&quot;https://stackoverflow.com/questions/67356599/the-deep-selector-is-not-working-using-sass-loader-in-my-vuejs-application&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/mvShP/hyO4MMbFjD/nkuQYkxfBoHy3h9A5PK0k1/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316&quot; data-og-url=&quot;https://stackoverflow.com/questions/67356599/the-deep-selector-is-not-working-using-sass-loader-in-my-vuejs-application&quot;&gt;
 &lt;a href=&quot;https://stackoverflow.com/questions/67356599/the-deep-selector-is-not-working-using-sass-loader-in-my-vuejs-application&quot; target=&quot;_blank&quot; data-source-url=&quot;https://stackoverflow.com/questions/67356599/the-deep-selector-is-not-working-using-sass-loader-in-my-vuejs-application&quot;&gt;
  &lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/mvShP/hyO4MMbFjD/nkuQYkxfBoHy3h9A5PK0k1/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316')&quot;&gt; 
  &lt;/div&gt;
  &lt;div class=&quot;og-text&quot;&gt;
   &lt;p class=&quot;og-title&quot;&gt;The `/deep/` selector is not working using sass-loader in my VueJS application&lt;/p&gt;
   &lt;p class=&quot;og-desc&quot;&gt;In my Vue 2.6.10 webpack application I am trying to add SASS as our team wants to migrate our legacy application from LESS to SCSS. In my package.json I have installed these to my devDependencies per&lt;/p&gt;
   &lt;p class=&quot;og-host&quot;&gt;stackoverflow.com&lt;/p&gt;
  &lt;/div&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;sass-loader에서 node-sass를 사용하도록 변경하면 해결할 수 있다.&lt;br&gt; &lt;br&gt;Vue Config 설정 변경&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;css: {
  loaderOptions: {
    sass: {
      implementation: require(&quot;node-sass&quot;),
    },
  },
},&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;br&gt;Dart Sass&lt;br&gt; &lt;br&gt;&lt;a href=&quot;https://github.com/sass/dart-sass#why-dart&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;- https://github.com/sass/dart-sass#why-dart&lt;/span&gt;&lt;/a&gt;&lt;br&gt; &lt;br&gt;node-sass&lt;br&gt;- &lt;a href=&quot;https://github.com/sass/node-sass&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://github.com/sass/node-sass&lt;/span&gt;&lt;/a&gt;&lt;br&gt; &lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;Deprecated 된 걸 쓸 이유가 있을까?&lt;/h3&gt;
&lt;figure data-ke-type=&quot;opengraph&quot; data-og-title=&quot;dart-sass does not support /deep/ selector · Issue #3399 · vuejs/vue-cli&quot; data-ke-align=&quot;alignCenter&quot; data-og-description=&quot;Version 3.4.0 Reproduction link https://github.com/lianzhao/vuecli-3.4 Environment info Environment Info: System: OS: macOS Sierra 10.12.4 CPU: (4) x64 Intel(R) Core(TM) i5-4278U CPU @ 2.60GHz Bina...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/vuejs/vue-cli/issues/3399#issuecomment-471476276&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cYhWA2/hyO5MKzNHi/BzeUjqyuBSOEmt9iWCaKUK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot; data-og-url=&quot;https://github.com/vuejs/vue-cli/issues/3399&quot;&gt;
 &lt;a href=&quot;https://github.com/vuejs/vue-cli/issues/3399&quot; target=&quot;_blank&quot; data-source-url=&quot;https://github.com/vuejs/vue-cli/issues/3399#issuecomment-471476276&quot;&gt;
  &lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cYhWA2/hyO5MKzNHi/BzeUjqyuBSOEmt9iWCaKUK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600')&quot;&gt; 
  &lt;/div&gt;
  &lt;div class=&quot;og-text&quot;&gt;
   &lt;p class=&quot;og-title&quot;&gt;dart-sass does not support /deep/ selector · Issue #3399 · vuejs/vue-cli&lt;/p&gt;
   &lt;p class=&quot;og-desc&quot;&gt;Version 3.4.0 Reproduction link https://github.com/lianzhao/vuecli-3.4 Environment info Environment Info: System: OS: macOS Sierra 10.12.4 CPU: (4) x64 Intel(R) Core(TM) i5-4278U CPU @ 2.60GHz Bina...&lt;/p&gt;
   &lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;
  &lt;/div&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;b&gt;::v-deep으로 모두 교체하여 해결&lt;/b&gt;&lt;br&gt; &lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;/b&gt;Vue3 에서는?&lt;/h3&gt;
&lt;figure data-ke-type=&quot;opengraph&quot; data-og-title=&quot;How do I use /deep/ or &gt;&gt;&gt; or ::v-deep in Vue.js?&quot; data-ke-align=&quot;alignCenter&quot; data-og-description=&quot;So, I've read here that in Vue.js, you can use /deep/ or &gt;&gt;&gt; in a selector in order to create style rules that apply to elements inside of child components. However, attempting to use this...&quot; data-og-host=&quot;stackoverflow.com&quot; data-og-source-url=&quot;https://stackoverflow.com/questions/48032006/how-do-i-use-deep-or-or-v-deep-in-vue-js&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/CqNoI/hyO5K7QcPx/HponykAd67fcVN6ijER2V0/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316&quot; data-og-url=&quot;https://stackoverflow.com/questions/48032006/how-do-i-use-deep-or-or-v-deep-in-vue-js&quot;&gt;
 &lt;a href=&quot;https://stackoverflow.com/questions/48032006/how-do-i-use-deep-or-or-v-deep-in-vue-js&quot; target=&quot;_blank&quot; data-source-url=&quot;https://stackoverflow.com/questions/48032006/how-do-i-use-deep-or-or-v-deep-in-vue-js&quot;&gt;
  &lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/CqNoI/hyO5K7QcPx/HponykAd67fcVN6ijER2V0/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316')&quot;&gt; 
  &lt;/div&gt;
  &lt;div class=&quot;og-text&quot;&gt;
   &lt;p class=&quot;og-title&quot;&gt;How do I use /deep/ or &amp;gt;&amp;gt;&amp;gt; or ::v-deep in Vue.js?&lt;/p&gt;
   &lt;p class=&quot;og-desc&quot;&gt;So, I've read here that in Vue.js, you can use /deep/ or &amp;gt;&amp;gt;&amp;gt; in a selector in order to create style rules that apply to elements inside of child components. However, attempting to use this...&lt;/p&gt;
   &lt;p class=&quot;og-host&quot;&gt;stackoverflow.com&lt;/p&gt;
  &lt;/div&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;br&gt;&lt;b&gt;:deep(.child-class)&lt;/b&gt; 로 사용!&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;b&gt;Vue2 : /deep/ 대신 ::v-deep을 사용하자&lt;/b&gt;&lt;br&gt;&lt;b&gt;Vue3 : :deep(.child-class) 를 사용하자&lt;br&gt;&lt;/b&gt;&lt;b&gt;&lt;br&gt;기존 프로젝트가 모두 /deep/으로 되어있어서 교체 후 테스트 하는 별도의 과정이 필요하지만, 이후를 생각하면 이게 더 낫다!&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
 &lt;li&gt;-컴포넌트 내부에서 스타일을 scoped로 제한하고 있다면 deep selector를 최대한 쓰지 않는게 유지보수가 편하다.&lt;/li&gt;
 &lt;li&gt;-정말 어쩔 수 없는 경우라면.. deep으로 하겠지만, 쉬운방법을 찾다보면 그게 쌓이고 쌓인다 .&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt; &lt;br&gt;Vue2, Vue3 같은 Vue인데 조금씩 너무 다르다..&lt;/p&gt;</description>
      <category>개발/Today I Learned</category>
      <category>/deep/</category>
      <category>::v-deep</category>
      <category>dart-sass</category>
      <category>node-sass</category>
      <category>sass</category>
      <category>vue build lib</category>
      <author>devmomori</author>
      <guid isPermaLink="true">https://somedaycode.tistory.com/23</guid>
      <comments>https://somedaycode.tistory.com/23#entry23comment</comments>
      <pubDate>Thu, 14 Jul 2022 19:57:56 +0900</pubDate>
    </item>
  </channel>
</rss>