<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발자로 전향중</title>
    <link>https://hobinsky.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Fri, 26 Jun 2026 19:44:21 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>hovinee</managingEditor>
    <item>
      <title>리팩터링 2판 3장 - 코드에서 나는 악취 2탄</title>
      <link>https://hobinsky.tistory.com/141</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.4 긴 매개변수 목록&lt;/h4&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;723&quot; data-origin-height=&quot;658&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJQ9qS/btsLuYu2scn/4djkL0vWNLZEFgy2MX5w9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJQ9qS/btsLuYu2scn/4djkL0vWNLZEFgy2MX5w9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJQ9qS/btsLuYu2scn/4djkL0vWNLZEFgy2MX5w9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJQ9qS%2FbtsLuYu2scn%2F4djkL0vWNLZEFgy2MX5w9K%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;723&quot; height=&quot;658&quot; data-origin-width=&quot;723&quot; data-origin-height=&quot;658&quot;/&gt;&lt;/span&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;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;716&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7PeKY/btsLsP0L9ly/L6dDNtebcc9q2NAc0vm4Vk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7PeKY/btsLsP0L9ly/L6dDNtebcc9q2NAc0vm4Vk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7PeKY/btsLsP0L9ly/L6dDNtebcc9q2NAc0vm4Vk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7PeKY%2FbtsLsP0L9ly%2FL6dDNtebcc9q2NAc0vm4Vk%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;716&quot; height=&quot;690&quot; data-origin-width=&quot;716&quot; data-origin-height=&quot;690&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;722&quot; data-origin-height=&quot;755&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rgw42/btsLvU6MgoM/OMO6LaBc3f1zjvXLL34Gk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rgw42/btsLvU6MgoM/OMO6LaBc3f1zjvXLL34Gk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rgw42/btsLvU6MgoM/OMO6LaBc3f1zjvXLL34Gk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frgw42%2FbtsLvU6MgoM%2FOMO6LaBc3f1zjvXLL34Gk0%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;722&quot; height=&quot;755&quot; data-origin-width=&quot;722&quot; data-origin-height=&quot;755&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;3.5 전역 데이터&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;전역 데이터는 코드베이스 어디에서든 건드릴 수 있고 값을 누가 바꿨는지 찾아낼 메커니즘이 없다는게 문제다. 이를 방지하기 위해 우리가 사용하는 대표적인 리팩터링은 &lt;b&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;717&quot; data-origin-height=&quot;332&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyjdt8/btsLsp8ObAI/ZCO9s7itNuA69cfXawbFnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyjdt8/btsLsp8ObAI/ZCO9s7itNuA69cfXawbFnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyjdt8/btsLsp8ObAI/ZCO9s7itNuA69cfXawbFnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcyjdt8%2FbtsLsp8ObAI%2FZCO9s7itNuA69cfXawbFnk%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;717&quot; height=&quot;332&quot; data-origin-width=&quot;717&quot; data-origin-height=&quot;332&quot;/&gt;&lt;/span&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;710&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bojRyQ/btsLu4WsxKQ/6xnKawfMLaDVIGDUjVcrs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bojRyQ/btsLu4WsxKQ/6xnKawfMLaDVIGDUjVcrs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bojRyQ/btsLu4WsxKQ/6xnKawfMLaDVIGDUjVcrs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbojRyQ%2FbtsLu4WsxKQ%2F6xnKawfMLaDVIGDUjVcrs0%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;734&quot; height=&quot;710&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;710&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;541&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmyEk4/btsLuZ1PsuK/TSc2FsPqE9eGKB4TitKjU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmyEk4/btsLuZ1PsuK/TSc2FsPqE9eGKB4TitKjU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmyEk4/btsLuZ1PsuK/TSc2FsPqE9eGKB4TitKjU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmyEk4%2FbtsLuZ1PsuK%2FTSc2FsPqE9eGKB4TitKjU0%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;720&quot; height=&quot;541&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;541&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ScOMg/btsLsZB1Ox4/klWDHPlRRzlewDMAI6Ymwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ScOMg/btsLsZB1Ox4/klWDHPlRRzlewDMAI6Ymwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ScOMg/btsLsZB1Ox4/klWDHPlRRzlewDMAI6Ymwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FScOMg%2FbtsLsZB1Ox4%2FklWDHPlRRzlewDMAI6Ymwk%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;708&quot; height=&quot;478&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;478&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;3.6 가변 데이터&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;함수형 프로그래밍에서는 데이터는 절대 변하지 않고, 데이터를 변경하려면 반드시 변경하려는 값에 대항하는 복사본을 만들어서 반환한다는 개념을 기본적으로 삼고 있다. &lt;b&gt;변수 캡슐화하기&lt;/b&gt;를 적용하여 정해놓은 함수를 거쳐야만 값을 수정할 수 있도록하면 값이 어떻게 수정되는지 감시하거나 개선하기 쉽다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;API를 만들 때는 &lt;b&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;741&quot; data-origin-height=&quot;496&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cH5ai1/btsLv51q9sf/N6bIRyUQo8fC7fV5K10op0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cH5ai1/btsLv51q9sf/N6bIRyUQo8fC7fV5K10op0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cH5ai1/btsLv51q9sf/N6bIRyUQo8fC7fV5K10op0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcH5ai1%2FbtsLv51q9sf%2FN6bIRyUQo8fC7fV5K10op0%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;741&quot; height=&quot;496&quot; data-origin-width=&quot;741&quot; data-origin-height=&quot;496&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;556&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTYzbj/btsLuH1sHep/7CJQkM9UwyC5gTRAXB7KsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTYzbj/btsLuH1sHep/7CJQkM9UwyC5gTRAXB7KsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTYzbj/btsLuH1sHep/7CJQkM9UwyC5gTRAXB7KsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTYzbj%2FbtsLuH1sHep%2F7CJQkM9UwyC5gTRAXB7KsK%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;732&quot; height=&quot;556&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;556&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;739&quot; data-origin-height=&quot;675&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uj3BG/btsLt4pwrQx/ctaI9jFdo2Ovmw3V8okW70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uj3BG/btsLt4pwrQx/ctaI9jFdo2Ovmw3V8okW70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uj3BG/btsLt4pwrQx/ctaI9jFdo2Ovmw3V8okW70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fuj3BG%2FbtsLt4pwrQx%2FctaI9jFdo2Ovmw3V8okW70%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;739&quot; height=&quot;675&quot; data-origin-width=&quot;739&quot; data-origin-height=&quot;675&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <author>hovinee</author>
      <guid isPermaLink="true">https://hobinsky.tistory.com/141</guid>
      <comments>https://hobinsky.tistory.com/141#entry141comment</comments>
      <pubDate>Tue, 24 Dec 2024 18:47:44 +0900</pubDate>
    </item>
    <item>
      <title>리팩터링 2판 3장 - 코드에서 나는 악취 1탄</title>
      <link>https://hobinsky.tistory.com/140</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1 기이한 이름&lt;/h4&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 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;3.2 중복 코드&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;한 클래스에 딸린 두 메서드가 똑같은 표현식을 사용하는 경우가 있다. 이럴 때는 &lt;b&gt;함수 추출하기&lt;/b&gt;를 써서 양쪽 모두 추출된 메서드를 호출하게 바꾸면 된다. 코드가&amp;nbsp; 비슷하긴 한데 완전히 똑같지는 않다면 &lt;b&gt;문장 슬라이드하기&lt;/b&gt;로 비슷한 부분을 한곳에 모아 추출하기를 더 쉽게 적용할 수 있는지 살펴본다. 같은 부모로부터 파생된 서브 클래스들에 코드가 중복되어 있다면, 각자 따로 호출되지 않도록 &lt;b&gt;메서드 올리기&lt;/b&gt;를 적용해 부모로 옮긴다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문장 슬라이드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1735001831322&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 리팩토링 전
const OrderProcess = () =&amp;gt; {
  const processOrder = () =&amp;gt; {
    validateOrder();
    const price = calculatePrice();
    sendEmail();
    const tax = calculateTax();
    saveToDatabase(price, tax);
  };

  return &amp;lt;button onClick={processOrder}&amp;gt;주문 처리&amp;lt;/button&amp;gt;;
};

// 리팩토링 후 (관련 있는 로직을 모음)
const OrderProcess = () =&amp;gt; {
  const processOrder = () =&amp;gt; {
    // 검증 관련
    validateOrder();
    
    // 금액 계산 관련
    const price = calculatePrice();
    const tax = calculateTax();
    
    // 주문 완료 처리
    sendEmail();
    saveToDatabase(price, tax);
  };

  return &amp;lt;button onClick={processOrder}&amp;gt;주문 처리&amp;lt;/button&amp;gt;;
};&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;b&gt;메서드 올리기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드 올리기(Pull Up Method)는 중복된 로직을 상위로 올려서 재사용하는 리팩토링 패턴&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735001970306&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 중복된 로직을 상위 컴포넌트로
const withAuth = (WrappedComponent) =&amp;gt; {
  return (props) =&amp;gt; {
    const checkAuth = () =&amp;gt; {
      // 공통 인증 로직
    };

    return &amp;lt;WrappedComponent {...props} checkAuth={checkAuth} /&amp;gt;;
  };
};

// 각 컴포넌트에서 사용
const ProfilePage = withAuth(Profile);
const SettingsPage = withAuth(Settings);

// 공통 로직을 훅으로 추출
const useAuth = () =&amp;gt; {
  const checkAuth = () =&amp;gt; {
    // 공통 인증 로직
  };
  
  return { checkAuth };
};

// 각 컴포넌트에서 사용
const Profile = () =&amp;gt; {
  const { checkAuth } = useAuth();
  // ...
};

const Settings = () =&amp;gt; {
  const { checkAuth } = useAuth();
  // ...
};

// 공통 로직을 Context Provider로
const AuthProvider = ({ children }) =&amp;gt; {
  const checkAuth = () =&amp;gt; {
    // 공통 인증 로직
  };

  return (
    &amp;lt;AuthContext.Provider value={{ checkAuth }}&amp;gt;
      {children}
    &amp;lt;/AuthContext.Provider&amp;gt;
  );
};

// 하위 컴포넌트에서 사용
const Profile = () =&amp;gt; {
  const { checkAuth } = useContext(AuthContext);
  // ...
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;3.3 긴 함수&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;함수가 길수록 이해하기 어렵다. 짧은 함수로 구성된 코드를 이해하기 쉽게 만다는 가장 확실한 방법은 좋은 이름이다. 함수 이름을 잘 지어두면 본문 코드를 볼 이유가 사라진다. 그러기 위해서는 훨씬 적극적으로 함수를 쪼개야 한다. 주석을 달아야 할 만한 부분은 무조건 함수로 만든다. 그 함수 본문에는 원래 주석으로 설명하려던 코드가 담기고, 함수 이름은 동작 방식이 아닌 의도가 드러나게 짓는다. 즉 무엇을 하는지 코드가 잘 설명해주지 못할수록 함수로 만드는게 유리하다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;함수를 짧게 만드는 99%는 함수 추출하기가 차지한다. 그렇다면 &lt;b&gt;임시 변수를 질의 함수로 바꾸기&lt;/b&gt;로 임시 변수의 수를, &lt;b&gt;매개변수 객체 만들기&lt;/b&gt;와&lt;b&gt; 객체 똥째로 넘기기로&lt;/b&gt; 매개변수의 수를 줄일 수 있을 것이다. 이 리팩터링들을 적용해도 임시 변수와 매개변수가 너무 많다면 &lt;b&gt;함수를 명령으로 바꾸기&lt;/b&gt;를 고려해보자&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735002744067&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;각각의 리팩토링 패턴을 React 예제로 설명해드리겠습니다:

임시 변수를 질의 함수로 바꾸기

typescriptCopy// Before: 임시 변수 사용
const OrderSummary = ({ order }) =&amp;gt; {
  const basePrice = order.quantity * order.itemPrice;
  const discountLevel = basePrice &amp;gt; 1000 ? 0.95 : 1;
  const finalPrice = basePrice * discountLevel;

  return &amp;lt;div&amp;gt;최종 가격: {finalPrice}&amp;lt;/div&amp;gt;;
};

// After: 질의 함수로 변경
const OrderSummary = ({ order }) =&amp;gt; {
  const getBasePrice = () =&amp;gt; order.quantity * order.itemPrice;
  const getDiscountLevel = () =&amp;gt; getBasePrice() &amp;gt; 1000 ? 0.95 : 1;
  const getFinalPrice = () =&amp;gt; getBasePrice() * getDiscountLevel();

  return &amp;lt;div&amp;gt;최종 가격: {getFinalPrice()}&amp;lt;/div&amp;gt;;
};

매개변수 객체 만들기

typescriptCopy// Before: 많은 매개변수
const ShippingInfo = ({ street, city, state, country, zipCode }) =&amp;gt; {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;{street}&amp;lt;/p&amp;gt;
      &amp;lt;p&amp;gt;{city}, {state}&amp;lt;/p&amp;gt;
      &amp;lt;p&amp;gt;{country} {zipCode}&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

// After: 객체로 묶기
interface Address {
  street: string;
  city: string;
  state: string;
  country: string;
  zipCode: string;
}

const ShippingInfo = ({ address }: { address: Address }) =&amp;gt; {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;{address.street}&amp;lt;/p&amp;gt;
      &amp;lt;p&amp;gt;{address.city}, {address.state}&amp;lt;/p&amp;gt;
      &amp;lt;p&amp;gt;{address.country} {address.zipCode}&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

객체 통째로 넘기기

typescriptCopy// Before: 객체에서 필요한 값만 추출해서 전달
const UserProfile = ({ user }) =&amp;gt; {
  return &amp;lt;ProfileDetails 
    name={user.name}
    email={user.email}
    phone={user.phone}
  /&amp;gt;;
};

// After: 객체를 통째로 전달
const UserProfile = ({ user }) =&amp;gt; {
  return &amp;lt;ProfileDetails user={user} /&amp;gt;;
};

함수를 명령으로 바꾸기 (Command Pattern)

typescriptCopy// Before: 복잡한 함수
const OrderProcessor = ({ order }) =&amp;gt; {
  const processOrder = () =&amp;gt; {
    const basePrice = calculateBasePrice();
    const taxes = calculateTaxes(basePrice);
    const shipping = calculateShipping(basePrice);
    const totalPrice = basePrice + taxes + shipping;
    // ... 더 많은 복잡한 로직
  };

  return &amp;lt;button onClick={processOrder}&amp;gt;주문 처리&amp;lt;/button&amp;gt;;
};

// After: 명령 객체로 변환
class OrderCommand {
  constructor(order) {
    this.order = order;
  }

  calculateBasePrice() {
    // base price 계산 로직
  }

  calculateTaxes(basePrice) {
    // tax 계산 로직
  }

  calculateShipping(basePrice) {
    // shipping 계산 로직
  }

  execute() {
    const basePrice = this.calculateBasePrice();
    const taxes = this.calculateTaxes(basePrice);
    const shipping = this.calculateShipping(basePrice);
    return basePrice + taxes + shipping;
  }
}

const OrderProcessor = ({ order }) =&amp;gt; {
  const processOrder = () =&amp;gt; {
    const command = new OrderCommand(order);
    return command.execute();
  };

  return &amp;lt;button onClick={processOrder}&amp;gt;주문 처리&amp;lt;/button&amp;gt;;&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;</description>
      <author>hovinee</author>
      <guid isPermaLink="true">https://hobinsky.tistory.com/140</guid>
      <comments>https://hobinsky.tistory.com/140#entry140comment</comments>
      <pubDate>Tue, 24 Dec 2024 18:14:46 +0900</pubDate>
    </item>
    <item>
      <title>리팩터링 2판 2장 - 리팩터링 원칙 2탄</title>
      <link>https://hobinsky.tistory.com/139</link>
      <description>&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;&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 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코드 소유권&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;코드의 소유권은 팀에 두는 것이다. 팀원이라면 누구나 팀이 소유한 코드를 수정할 수 있게 한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;브랜치&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;지속적인 통합 (CI) 또는 트렁크 기반 개발 (TBD)를 따라 모든 팀원이 하루에 최소 한 번은 마스터와 통합한다.머지의 복잡도를 줄일 수 있을 뿐 아니라 리팩터링과의 궁합도 좋다. 기능별 브랜치가 가져오는 리팩터링 부담은 너무나 크다. CI를 적용하는 편이 소프트웨어를 배포하는 데 훨씬 효과적이라는 객관적 증거가 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;테스팅&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;리팩터링은 단계별 변경 폭이 작아서 도중에 발생한 오류의 원인이 될만한 코드 범위가 넓지 않다. 원인을 못찾더라도 버전 관리 시스템을 이용하여 가장 최근에 정상 작동하던 상태로 되돌리면 된다. 핵심은 오류를 빨리 잡는데 있다. 리팩터링을 하기 위해서는 자가 테스트 코드를 마련해야 한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;테스트 코드는 리팩터링을 할 수 있게 해줄 뿐만 아니라 새 기능 추가도 훨씬 안전하게 진행할 수 있도록 도와준다. 리팩터링 과정에서 버그가 생길 위험이 아주 크다는 불안감을 해소할수 있다. 테스트 코드는 꼭 필요해서라기보다는 갖춰두면 유용하다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;자가 테스트 코드는 통합과정에서 발생하는 의미 충돌을 잡는 메커니즘으로 활용할 수 있어서 자연스럽게 CI와도 밀접하게 연관된다. CI에 통합된 테스트는 지속적인 배포 (CD)의 핵심이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;레거시 코드&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;테스트를 보강한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>hovinee</author>
      <guid isPermaLink="true">https://hobinsky.tistory.com/139</guid>
      <comments>https://hobinsky.tistory.com/139#entry139comment</comments>
      <pubDate>Fri, 20 Dec 2024 18:42:09 +0900</pubDate>
    </item>
    <item>
      <title>리팩터링 2판 2장 - 리팩터링 원칙 1탄</title>
      <link>https://hobinsky.tistory.com/138</link>
      <description>&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;b&gt;두개의모자&lt;/b&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;b&gt;리팩터링을 하면 버그를 쉽게 찾을 수 있다.&lt;/b&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;b&gt;언제 리팩터링을 해야할까 (&lt;/b&gt;&lt;b&gt;3의 법칙)&lt;/b&gt;&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;2. 비슷한 일을 두 번째로 하게 되면(중복이 생겼다는 사실에 당황스럽겠지만), 일단 계속 진행한다.&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;&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;리팩터링하기 가장 좋은 시점은 코드베이스에 기능을 새로 추가하기 직전이다. &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 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이해를 위한: 리팩터링&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;코드의 의도가 명확하게 드러나도록 한다. 조건부 로직의 구조가 이상하지 않은지 함수 이름을 잘못 정해서 실제로하는 일을 파악하는 데 오래 걸리지 않는지 등등&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;쓰레기 줍기 리팩터링&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;로직이 쓸데없이 복잡하거나 똑같은 함수가 여러개일 경우 간단히 수정할 수 있는 일은 끝내고 시간이 좀 걸리는 일은 짧은 메모만 남긴 다음 하던 일을 끝내고 나서 처리한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;계획된 리팩터링과 수시로 하는 리팩터링&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;리팩터링 일젖ㅇ을 따로 잡아두지 않고, 기능을 추가하거나 버그를 잡는 동안 리팩터링도 함께 한다. 보기 싫은 코드를 발견하면 리팩터링을 하자. &lt;b&gt;그런데 잘 작성된 코드 역시 수많은 리팩터링을 거쳐야한다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;리팩터링을 하지 말아야 할때&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;지저분한 코드를 발견해도 굳이 수정할 필요가 없다면 리팩터링하지 않는다. 내부 동작을 이해해야 할 시점에 리팩터링 효과를 볼 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;리팩터링 하는 것보다 처음부터 새로 작성하는게 쉬울 때도 리팩터링하지 않는다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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>Book</category>
      <author>hovinee</author>
      <guid isPermaLink="true">https://hobinsky.tistory.com/138</guid>
      <comments>https://hobinsky.tistory.com/138#entry138comment</comments>
      <pubDate>Fri, 20 Dec 2024 18:29:40 +0900</pubDate>
    </item>
    <item>
      <title>리팩터링 2판 1장 - 첫 번째 예시 3탄</title>
      <link>https://hobinsky.tistory.com/137</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1-8 다형성을 활용해 계산 코드 재구성하기&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;*다형성(Polymorphism)**은 객체지향 프로그래밍(OOP)의 핵심 개념 중 하나로, &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;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;b&gt;&quot;동물&quot;이라는 공통된 행동&lt;/b&gt;: 모두 소리를 낼 수 있음.&lt;/li&gt;
&lt;li&gt;하지만, 각 동물마다 소리는 다름:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개: &quot;멍멍&quot;&lt;/li&gt;
&lt;li&gt;고양이: &quot;야옹&quot;&lt;/li&gt;
&lt;li&gt;소: &quot;음메&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 React를 쓰기 때문에..&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;React에서 다형성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React에서는 &lt;b&gt;클래스 기반이 아닌 함수형 컴포넌트&lt;/b&gt;를 사용하면서, 다형성을 &lt;b&gt;컴포지션(Composition)&lt;/b&gt;, &lt;b&gt;조건부 렌더링&lt;/b&gt;, &lt;b&gt;동적 매핑&lt;/b&gt;을 통해 구현합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React에서 다형성은 다음과 같이 사용할 수 있습니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;공통 컴포넌트에 props를 전달하여 동작을 변경&lt;/b&gt;.&lt;/li&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;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2JBhW/btsLiI7nHFC/U5vlmkh6KSDFfApmhh6i3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2JBhW/btsLiI7nHFC/U5vlmkh6KSDFfApmhh6i3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2JBhW/btsLiI7nHFC/U5vlmkh6KSDFfApmhh6i3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2JBhW%2FbtsLiI7nHFC%2FU5vlmkh6KSDFfApmhh6i3K%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;595&quot; height=&quot;700&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;700&quot;/&gt;&lt;/span&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;예를 들어 amountFor() 함수를 보면 연극 장르에 따라 계산 방식이 달라진다. 이런 형태의 조건부 로직은 코드 수정 횟수가 늘어날수록 골칫거리로 전락하기 쉽다. 이를 방지하려면 프로그래밍 언어가 제공하는 &lt;b&gt;구조적인 요소&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;&lt;b&gt;책에서 이해한 바를 GPT한테 질문했다.&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;635&quot; data-origin-height=&quot;299&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bF7cZH/btsLmJ66FzQ/6LAQkzDuEUUpvk9pI8v2Pk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bF7cZH/btsLmJ66FzQ/6LAQkzDuEUUpvk9pI8v2Pk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bF7cZH/btsLmJ66FzQ/6LAQkzDuEUUpvk9pI8v2Pk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbF7cZH%2FbtsLmJ66FzQ%2F6LAQkzDuEUUpvk9pI8v2Pk%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;635&quot; height=&quot;299&quot; data-origin-width=&quot;635&quot; data-origin-height=&quot;299&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;593&quot; data-origin-height=&quot;351&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u17Ws/btsLof4sIlq/qiXtAJtQIhHmhEVDNAwEpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u17Ws/btsLof4sIlq/qiXtAJtQIhHmhEVDNAwEpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u17Ws/btsLof4sIlq/qiXtAJtQIhHmhEVDNAwEpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu17Ws%2FbtsLof4sIlq%2FqiXtAJtQIhHmhEVDNAwEpk%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;593&quot; height=&quot;351&quot; data-origin-width=&quot;593&quot; data-origin-height=&quot;351&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;593&quot; data-origin-height=&quot;730&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xw1UR/btsLoo79sNX/skT8zADJmLkKkLjKNw68kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xw1UR/btsLoo79sNX/skT8zADJmLkKkLjKNw68kK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xw1UR/btsLoo79sNX/skT8zADJmLkKkLjKNw68kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxw1UR%2FbtsLoo79sNX%2FskT8zADJmLkKkLjKNw68kK%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;593&quot; height=&quot;730&quot; data-origin-width=&quot;593&quot; data-origin-height=&quot;730&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;590&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WktfJ/btsLnlq3GD9/KqkD5kTaZZHvHYLTmMqI8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WktfJ/btsLnlq3GD9/KqkD5kTaZZHvHYLTmMqI8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WktfJ/btsLnlq3GD9/KqkD5kTaZZHvHYLTmMqI8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWktfJ%2FbtsLnlq3GD9%2FKqkD5kTaZZHvHYLTmMqI8k%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;612&quot; height=&quot;590&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;590&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Book</category>
      <author>hovinee</author>
      <guid isPermaLink="true">https://hobinsky.tistory.com/137</guid>
      <comments>https://hobinsky.tistory.com/137#entry137comment</comments>
      <pubDate>Wed, 18 Dec 2024 17:22:14 +0900</pubDate>
    </item>
    <item>
      <title>리팩터링 2판 1장 - 첫 번째 예시 2탄</title>
      <link>https://hobinsky.tistory.com/136</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1탄을 작성하기 위해 2시간 가량 집중해서 정독했는데 느낀점은 지금까지 나는 어떻게 코드를 짰던걸까? 하는 의문점이 들었다..기능을 돌아가게 하는것도 중요하지만 리팩터링을 하며 수정이 용이하고 확장 가능한 설계를 하는것이 얼마나 중요한가를 깨닫게 되었다. 정확하게는 리팩터링은 어떻게 하는것인가의 기준이 생기기 시작했다.&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탄의 시작은 책 내용 기준 1.5 중간 점검: 난무하는 중첩 함수부터이다.&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;지금까지는 프로그림의 논리적인인 요소를 파악하기 쉽도록 코드의 구조를 보강하는데 주안점을 두고 리팩터링을 했다면 이제 HTML 버전을 만드는 작업을 살펴보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=&amp;gt; 해당 부분은 텍스트로만 봤을 때는 이해가 잘안되었다.&amp;nbsp;&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;b&gt;계산 코드가 분리됐다&lt;/b&gt;:&lt;br /&gt;데이터 처리나 비즈니스 로직 같은 복잡한 계산 작업은 별도의 파일이나 함수로 정리되어 있다는 의미입니다.&lt;br /&gt;즉, HTML을 작성할 때는 **&quot;화면에 표시할 데이터만 신경 쓰면 된다&quot;**는 뜻입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;HTML 코드만 작성하면 된다&lt;/b&gt;:&lt;br /&gt;계산된 결과를 기반으로 &lt;b&gt;UI를 출력하는 역할만 수행&lt;/b&gt;한다는 의미입니다. UI 코드에 로직이 섞이지 않으므로 간단한 구조로 유지할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 나는 react를 사용해왔기 때문에 선언형프로그램에 익숙해져있어서 당연하게 사용해왔던 것이다. 그럼 이참에 한번 집고 넘어가면 좋겠다.&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;1. &lt;b&gt;명령형 프로그래밍(JavaScript의 기본 방식)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명령형 프로그래밍에서는 개발자가 &lt;b&gt;UI를 업데이트하기 위한 모든 단계를 명시적으로 작성&lt;/b&gt;해야 합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;예: 클릭 카운트를 증가시키는 기능&lt;/h4&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1733973021914&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;javascript
코드 복사
let count = 0; // 요소 가져오기
const button = document.querySelector(&quot;#button&quot;);
const display = document.querySelector(&quot;#display&quot;);
// 클릭 이벤트 핸들러 추가
button.addEventListener(&quot;click&quot;, () =&amp;gt; {
count += 1;
// 상태를 업데이트
display.textContent = `Count: ${count}`;
// UI를 업데이트 });&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;여기서 중요한 점&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;count라는 상태를 수동으로 관리해야 합니다.&lt;/li&gt;
&lt;li&gt;DOM 요소(display)를 직접 가져와야 하며, 상태가 변경될 때마다 명령을 내려 UI를 갱신해야 합니다.&lt;/li&gt;
&lt;li&gt;모든 동작이 명시적으로 작성되어야 하므로 코드가 장황해지고, 복잡한 애플리케이션에서는 관리가 어려워질 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. &lt;b&gt;선언형 프로그래밍(React의 접근 방식)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React는 선언형 방식을 사용하여 상태와 UI를 자연스럽게 연결합니다.&lt;br /&gt;개발자는 **&quot;무엇을 렌더링할지&quot;**에만 집중하면 되고, UI 갱신은 React가 알아서 처리합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;동일한 예를 React로 작성하면:&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;jsx&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1733973047583&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;코드 복사
import React, { useState } from &quot;react&quot;; 
const App = () =&amp;gt; {
const [count, setCount] = useState(0); 

return ( &amp;lt;div&amp;gt; &amp;lt;p&amp;gt;Count: {count}&amp;lt;/p&amp;gt;
&amp;lt;button onClick={() =&amp;gt; setCount(count + 1)}&amp;gt;Click Me&amp;lt;/button&amp;gt; 
&amp;lt;/div&amp;gt; ); };&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 중요한 점:&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;count 상태를 관리하면 React가 DOM을 자동으로 갱신합니다.&lt;/li&gt;
&lt;li&gt;UI 갱신 로직을 명시적으로 작성하지 않아도 됩니다.&lt;/li&gt;
&lt;li&gt;코드는 간결하고 직관적입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. &lt;b&gt;명령형 vs 선언형 비교&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특징 명령형 (JavaScript) vs 선언형 (React)&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;초점&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&quot;어떻게 할지(How)&quot;를 명시적으로 작성&lt;/td&gt;
&lt;td&gt;&quot;무엇을 할지(What)&quot;를 선언적으로 정의&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;UI 갱신 방식&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;DOM을 직접 조작&lt;/td&gt;
&lt;td&gt;상태를 기반으로 UI 자동 갱신&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;코드 가독성&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;복잡하고 장황해질 수 있음&lt;/td&gt;
&lt;td&gt;간결하고 직관적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;유지보수성&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;상태와 UI 갱신 로직이 분리되지 않아 관리 어려움&lt;/td&gt;
&lt;td&gt;상태와 UI를 독립적으로 관리 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;적용 예&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;순수 JavaScript, jQuery 등&lt;/td&gt;
&lt;td&gt;React, Vue.js, Angular (선언형 프레임워크)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. &lt;b&gt;결론&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 JavaScript는 명령형 프로그래밍 스타일에 기반을 두고 있습니다. 이는 단순한 작업에는 적합하지만, 복잡한 애플리케이션에서는 관리와 유지보수가 어려울 수 있습니다. React는 선언형 스타일을 통해 UI 갱신과 상태 관리를 자동화하여, 코드를 더 간결하고 직관적으로 작성할 수 있게 도와줍니다.&amp;nbsp;따라서 React와 같은 선언형 프레임워크는 명령형 JavaScript의 단점을 극복하기 위해 등장했다고 볼 수 있어요.   생각해보면 버츄얼돔의 사용이 엄청난 변화가 맞는거같다.&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;책에서 얘기하는건 텍스트 버전과 (api, db 저장, 텍스트 출력 등), HTML 버전을 똑가은 계산 함수로 사용하게 만들고 싶다고 나와있다. 선호하는 방식은 &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;1. 두 단계로 나누는 것이다. 첫 단계에서는 statement() 즉 최상단 함수의 데이터를 처리하고 다음 단계는 앞서 처리한 결과를 텍스트느 HTML로 표현하자 단계를 쪼개려면 중첩 함수들을 &lt;b&gt;함수 추출하기&lt;/b&gt;로 뽑아내야된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 본문 전체를 별도 함수로 추출하고 두 단계 사이의 중간 데이터 구조 역할을 할 객체를 만들어서 인수로 전달한다. 즉&amp;nbsp; 2개의 매개변수를 전달할 필요가 없음으로 statementData = invoice.customer 이런식으로 하나로 통합시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react에서 useState 사용 data 객체를 통일시키는것과 비슷한거같다. ( 불필요한 매개변수를 줄이면 함수의 사용이 단순해지고, 읽기와 이해가 쉬워진다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. &lt;b&gt;함수 옮기기!&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중첩함수였던 playfor을 최상단으로 옮김&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1733979751072&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;statementData.performances = invice.performance.map(enrichPerformance)


function enrichPerformance (aPerformance) {
	const result = Object.assign({}, aPerformance) // 얕은 복사 수행 (불변성) 원시값만 변경
	....
    result.play = playfor(result) 
    return result
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 위처럼 변수의 인라인을 객체를 생성하여 저장시킴으로써&amp;nbsp; statementData {} 안에 play, amount, volumeCredits 등등을 객체로 추가할 수 있다. 그럼 statement 최상위 함수에서 statementData set이 형성되고 매개변수로 전달했을 때 데이터만 가져와서 사용 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 그러면 아래와 같이 첫 단계인 statement에 필요한 데이터 처리에 해당하는 코드를 모두 별도 함수로 빼낸다.&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;blob&quot; data-origin-width=&quot;729&quot; data-origin-height=&quot;537&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boNSTd/btsLfwz2oWx/Yyf3e122zd5OKhFkJ7SpR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boNSTd/btsLfwz2oWx/Yyf3e122zd5OKhFkJ7SpR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boNSTd/btsLfwz2oWx/Yyf3e122zd5OKhFkJ7SpR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboNSTd%2FbtsLfwz2oWx%2FYyf3e122zd5OKhFkJ7SpR1%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;729&quot; height=&quot;537&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;729&quot; data-origin-height=&quot;537&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Book</category>
      <author>hovinee</author>
      <guid isPermaLink="true">https://hobinsky.tistory.com/136</guid>
      <comments>https://hobinsky.tistory.com/136#entry136comment</comments>
      <pubDate>Fri, 13 Dec 2024 17:09:09 +0900</pubDate>
    </item>
    <item>
      <title>리팩터링 2판 1장 - 첫 번째 예시 1탄</title>
      <link>https://hobinsky.tistory.com/135</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;어느덧 개발자로 커리어를 쌓아간지 2년이 지났다. 뭐 일단 아무것도 모르는 신입에서 주니어로에서 0.1% 나아진 기분이다. 진행하던 프로젝트가 커지고 코드 퀄리티를 고민하게 되면서 캡슐화, 추상화, 컴포넌트 분리, 렌더링, 사이드 이펙트 등등 기초적인 코드와 리액트가 어떻게 사용되어야 좋은 코드인지 검색 또는 인강으로만 찾아봤지 책을 읽어볼 생각은 못했다..(핑계) 그러다 어느 블로그를 보고 이 책을 알게 되었고 이제부턴 나의 코드 교과서처럼 사용하기 위해 정리를 시작한다. 난 기본적으로 하나의 뿌리를 제대로 심는걸 좋아한다.&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;책의 코드를 복사해서 넣고 이게 어떤 쓰임새인지 등등 정리를 해도 안볼걸 알기 때문에 개념을 위주로 기록을 할 예정이다. 그리고 개념을 바탕삼아 향후 코드를 짤때는 최대한 적용 할 것이다. 모든 것의 목적은 좋은 코드를 짜는 것이고 나중에 이직을 위한 밑거름이 될 것이라 생각해서이다. 그럼 24년 12월 겨울을 시작하여&amp;nbsp; 끝까지 진행해보겠다. 우선 책의 서론에서 1~4장까지 꼼꼼히 읽고 이후부터는 빠르게 훑어보라는 가이드가 있으니 1~4장은 꼼꼼히 읽어보겠다.&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;/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;1. 코드 분석을 통해 얻은 정보는 휘발성이 강하다. 내 머리속 지우개.. 그렇기 때문에 잊지 않기 위해서는 재빨리 코드에 반영해야한다. 코드 조각을 별도 함수로 추출하는 방식으로 앞서 파악한 정보를 코드에 반영하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이 글을 반문하면 어떤 코드를 봤을 때 잊어버릴 수 있겠다 싶은 내용은 함수를 추출하자! =&amp;gt; 함수 추출하기!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 함수를 추출하고 나면 추출된 함수 코드를 자세히 들여다 보면서 지금보다 명확하게 표현할 수 있는 간단한 방법을 검토한다. (예시: thisAmount =&amp;gt; result 변경) 함수의 반환 값은 항상 result (고민..)를 쓴다. 그러면 그 변수의 역할을 알 수 있다. 테스트하고 커밋!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. &lt;b&gt;임시변수를 질의함수로 바꾸기! &lt;/b&gt;매개변수가 루프돌때는 필요하지만 개별적으로 얻을 때는 필요없다..&lt;/p&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;p data-ke-size=&quot;size16&quot;&gt;! 즉 의도가 더욱 명확해지는 코드를 짤 수 있게 되었따. 이부분은 추후 더 알아보자&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;5. &lt;b&gt;함수 선언 바꾸기!&lt;/b&gt;를 할때 이름을 짓는 과정은 쉽지 않다. 그러니 나중에 떠오르면 그때 바꿔도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. &lt;b&gt;반복분쪼개기! &lt;/b&gt;를 통해 반복문을 둘로 나눈다. 그리고 &lt;b&gt;문장 슬라이드하기&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;- 반복문 쪼개기로 변수 값을 누적시키는 부분을 분리한다.&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;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;</description>
      <category>Book</category>
      <author>hovinee</author>
      <guid isPermaLink="true">https://hobinsky.tistory.com/135</guid>
      <comments>https://hobinsky.tistory.com/135#entry135comment</comments>
      <pubDate>Thu, 12 Dec 2024 11:36:12 +0900</pubDate>
    </item>
    <item>
      <title>Nextjs14 + jest + msw 도입기</title>
      <link>https://hobinsky.tistory.com/134</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 만들었던 서비스는 기능 테스트가 없었음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스의 규모가 점점 커짐에 따라 테스트 기능의 필요성을 느꼈고 새로 시작된 프로젝트에서는 테스트의 필요성을 느꼈다. 그러나 유닛 테스트를 하나하나 하기에는 불필요하다 느꼈고 BDD 방법론을 따라 사용자 중심의 통합 테스트를 진행하기로 함.&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;우선 jest 및 react-testing-library 설치!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nextjs.org/docs/app/building-your-application/testing/jest&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nextjs.org/docs/app/building-your-application/testing/jest&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1730421438569&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Testing: Jest | Next.js&quot; data-og-description=&quot;Learn how to set up Jest with Next.js for Unit Testing and Snapshot Testing.&quot; data-og-host=&quot;nextjs.org&quot; data-og-source-url=&quot;https://nextjs.org/docs/app/building-your-application/testing/jest&quot; data-og-url=&quot;https://nextjs.org/docs/app/building-your-application/testing/jest&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Fd7PR/hyXsQxHF2x/weN11wFX9LELsgf84lvTI0/img.png?width=843&amp;amp;height=441&amp;amp;face=0_0_843_441,https://scrap.kakaocdn.net/dn/0Moao/hyXpoW7L5g/Xgon9tvdbVjZUQFXuoR6G0/img.png?width=843&amp;amp;height=441&amp;amp;face=0_0_843_441&quot;&gt;&lt;a href=&quot;https://nextjs.org/docs/app/building-your-application/testing/jest&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nextjs.org/docs/app/building-your-application/testing/jest&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Fd7PR/hyXsQxHF2x/weN11wFX9LELsgf84lvTI0/img.png?width=843&amp;amp;height=441&amp;amp;face=0_0_843_441,https://scrap.kakaocdn.net/dn/0Moao/hyXpoW7L5g/Xgon9tvdbVjZUQFXuoR6G0/img.png?width=843&amp;amp;height=441&amp;amp;face=0_0_843_441');&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;Testing: Jest | Next.js&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Learn how to set up Jest with Next.js for Unit Testing and Snapshot Testing.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nextjs.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식문서에 잘 나와있으므로 설치하고 yarn test 실행하여 잘되면 설치 완료!&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;Tip: 뭔말인지 잘모르겠으면 Quickstart로 레포지토리를 생성하고 설정 파일과 package.json 의존성 패키지만 가져오면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;291&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pFmha/btsKqXySVww/0hQ1bRz0kkDUWENQhwCNJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pFmha/btsKqXySVww/0hQ1bRz0kkDUWENQhwCNJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pFmha/btsKqXySVww/0hQ1bRz0kkDUWENQhwCNJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpFmha%2FbtsKqXySVww%2F0hQ1bRz0kkDUWENQhwCNJk%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;692&quot; height=&quot;291&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;291&quot;/&gt;&lt;/span&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;다음은 msw 설치!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/msw&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.npmjs.com/package/msw&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1730421643347&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;msw&quot; data-og-description=&quot;Seamless REST/GraphQL API mocking library for browser and Node.js.. Latest version: 2.6.0, last published: 3 days ago. Start using msw in your project by running &amp;#96;npm i msw&amp;#96;. There are 343 other projects in the npm registry using msw.&quot; data-og-host=&quot;www.npmjs.com&quot; data-og-source-url=&quot;https://www.npmjs.com/package/msw&quot; data-og-url=&quot;https://www.npmjs.com/package/msw&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/SVtDm/hyXpBCdpTg/YkQAWdaU4iOvEp5w0kDn30/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/urLIR/hyXs3DNSzF/eMrVNeDquI5iUYymrerVIK/img.png?width=2260&amp;amp;height=472&amp;amp;face=0_0_2260_472&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/msw&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.npmjs.com/package/msw&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/SVtDm/hyXpBCdpTg/YkQAWdaU4iOvEp5w0kDn30/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/urLIR/hyXs3DNSzF/eMrVNeDquI5iUYymrerVIK/img.png?width=2260&amp;amp;height=472&amp;amp;face=0_0_2260_472');&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;msw&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Seamless REST/GraphQL API mocking library for browser and Node.js.. Latest version: 2.6.0, last published: 3 days ago. Start using msw in your project by running `npm i msw`. There are 343 other projects in the npm registry using msw.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.npmjs.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;Nextjs는 ssr을 지원하기 때문에 mocking할 때 server와 client 설정을 분리해야된다. 하지만 이건 test가 아닌 페이지에서 api를 모킹해야 될때고 테스트용도라면 client는 필요없다. nodejs 환경이기 때문에!&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;191&quot; data-origin-height=&quot;143&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdmq2j/btsKq4xXNbH/u3YaA35KWRVPySVeCWMz3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdmq2j/btsKq4xXNbH/u3YaA35KWRVPySVeCWMz3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdmq2j/btsKq4xXNbH/u3YaA35KWRVPySVeCWMz3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbdmq2j%2FbtsKq4xXNbH%2Fu3YaA35KWRVPySVeCWMz3k%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;191&quot; height=&quot;143&quot; data-origin-width=&quot;191&quot; data-origin-height=&quot;143&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;server.ts&lt;/p&gt;
&lt;pre id=&quot;code_1730421960737&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;import { setupServer } from 'msw/node'
import { handlers } from './handler'

export const server = setupServer(...handlers)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;handler.ts&lt;/p&gt;
&lt;pre id=&quot;code_1730421984295&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// src/shared/api/mocks/handler.ts
import { http, HttpResponse } from 'msw'
import { MOCKDATA } from './data'

export const handlers = [
  http.get('https://examples.com/meta/room-info/all', () =&amp;gt; {
    return HttpResponse.json(MOCKDATA)
  }),
]&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;data.ts&lt;/p&gt;
&lt;pre id=&quot;code_1730422008425&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export const MOCKDATA = {
  success: true,
  worlds: [
    {
      id: '1',
      hostId: 'host123',
      mapType: 'Plaza',
      title: 'Virtual Plaza',
      desc: 'A beautiful virtual plaza for social gatherings.',
      customObjectInfos: [],
    },
    {
      id: '2',
      hostId: 'host456',
      mapType: 'Meeting',
      title: 'Meeting Room A',
      desc: 'Private meeting room for teams.',
      customObjectInfos: [],
    },
  ],
}&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;앞에서 말했듯 broswer과 index는 test가 아닌 브라우저에서 사용할 때 필요함!&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;nextjs에서 msw를 사용할 때 따로 해주어야할 설정이 있다! jest 2.xx 버전을 사용할 경우&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1730422585232&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const nextJest = require('next/jest')

const createJestConfig = nextJest({
  // Provide the path to your Next.js app to load next.config.js and .env files in your test environment
  dir: './',
})

// Add any custom config to be passed to Jest
const customJestConfig = {
  setupFilesAfterEnv: ['&amp;lt;rootDir&amp;gt;/jest.setup.js'],
  testEnvironment: 'jest-fixed-jsdom', //ReferenceError: TextEncoder is not defined
  testEnvironmentOptions: {
    customExportConditions: [''],
  }, //Cannot find module &amp;lsquo;msw/node&amp;rsquo; (JSDOM)
}

// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = createJestConfig(customJestConfig)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm jest-fixed-jsdom 설치 후 수정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 cannot find module 'msw/nodw'가 나올 경우 testEnviromentOptions 추가 해주면 된다. 이유는 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LPA7U/btsKsdtHsie/NgU4jTziaQLgDrT4NAh2ok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LPA7U/btsKsdtHsie/NgU4jTziaQLgDrT4NAh2ok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LPA7U/btsKsdtHsie/NgU4jTziaQLgDrT4NAh2ok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLPA7U%2FbtsKsdtHsie%2FNgU4jTziaQLgDrT4NAh2ok%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;595&quot; height=&quot;252&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1730422698648&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { render, screen } from '@testing-library/react'
import '@testing-library/jest-dom'
import { server } from 'shared/api/mocks/server'
import { WorldPreview } from 'entities/world/world-preview'
import { WorldDetails } from 'shared/api/world'
import userEvent from '@testing-library/user-event'

import mockRouter from 'next-router-mock'
import { MemoryRouterProvider } from 'next-router-mock/MemoryRouterProvider'

jest.mock('next/router', () =&amp;gt; jest.requireActual('next-router-mock'))

describe('HomePage Component', () =&amp;gt; {
  beforeAll(() =&amp;gt; server.listen())
  afterEach(() =&amp;gt; server.resetHandlers())
  afterAll(() =&amp;gt; server.close())

  it('월드리스트 보여주고 클릭시 해당 페이지 라우팅', async () =&amp;gt; {
    // `Home` 컴포넌트 렌더링
    const response = await fetch('https://examples.com/meta/room-info/all')
    const data = await response.json()

    render(
      &amp;lt;div&amp;gt;
        {data.worlds.map((world: WorldDetails) =&amp;gt; (
          &amp;lt;WorldPreview key={world.id} world={world} /&amp;gt;
        ))}
      &amp;lt;/div&amp;gt;,
      { wrapper: MemoryRouterProvider },
    )

    expect(screen.getByText('Virtual Plaza')).toBeInTheDocument()
    expect(screen.getByText('Meeting Room A')).toBeInTheDocument()

    // `data-testid`를 가진 링크 요소를 찾기
    const linkElement = screen.getByTestId(`world-${data.worlds[0].id}`)

    // 링크 클릭
    await userEvent.click(linkElement)

    // 클릭 시 페이지 라우팅
    expect(mockRouter.asPath).toEqual(
      `/world/${data.worlds[0].id}?mapType=${data.worlds[0].mapType}`,
    )
  })
})&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;&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;458&quot; data-origin-height=&quot;105&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/droBjg/btsKtjfwPRA/2iKycYEkd6XjjEtOGX7Ez0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/droBjg/btsKtjfwPRA/2iKycYEkd6XjjEtOGX7Ez0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/droBjg/btsKtjfwPRA/2iKycYEkd6XjjEtOGX7Ez0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdroBjg%2FbtsKtjfwPRA%2F2iKycYEkd6XjjEtOGX7Ez0%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;458&quot; height=&quot;105&quot; data-origin-width=&quot;458&quot; data-origin-height=&quot;105&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래처럼 처음 페이지 진입시 모킹 데이터를 통해 원하는 텍스트가 있는지 확인하고 next-router-mock을 설치하여 링크 클릭시 원하는 링크로 진입하는 것까지 확인했다. 생각보다 삽질을 많이했지만 앞으로는 안정성있는 서비스를 위해 통합테스트를 실행해야겠다..&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;***번외 if 서버컴포넌트에서 데이터를 모킹하고 싶다면?&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nextjs에서는 다음과 같은 설정을 해야된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. root 부분에 instrumentation.ts 파일을 만들고 해당 코드 입력&lt;/p&gt;
&lt;pre id=&quot;code_1730423079864&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;//test가 아닌 page에서 모킹할 때
export async function register() {
  if (process.env.NEXT_RUNTIME === 'nodejs') {
    const { server } = await import('shared/api/mocks/server')
    server.listen({ onUnhandledRequest: 'bypass' })
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;304&quot; data-origin-height=&quot;91&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oHgvU/btsKseF6tQu/epmgzcBfWkhLUd0Jhv8ed1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oHgvU/btsKseF6tQu/epmgzcBfWkhLUd0Jhv8ed1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oHgvU/btsKseF6tQu/epmgzcBfWkhLUd0Jhv8ed1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoHgvU%2FbtsKseF6tQu%2FepmgzcBfWkhLUd0Jhv8ed1%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;304&quot; height=&quot;91&quot; data-origin-width=&quot;304&quot; data-origin-height=&quot;91&quot;/&gt;&lt;/span&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;2. next.config.mjs에 아래와 같이 설정&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;589&quot; data-origin-height=&quot;87&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s97Sy/btsKrNWuDne/iUJhkipTfOyyLriPRnvTbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s97Sy/btsKrNWuDne/iUJhkipTfOyyLriPRnvTbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s97Sy/btsKrNWuDne/iUJhkipTfOyyLriPRnvTbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs97Sy%2FbtsKrNWuDne%2FiUJhkipTfOyyLriPRnvTbK%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;589&quot; height=&quot;87&quot; data-origin-width=&quot;589&quot; data-origin-height=&quot;87&quot;/&gt;&lt;/span&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;3. 서비스 워커 설치&lt;/p&gt;
&lt;pre class=&quot;fortran&quot; style=&quot;background-color: #f6f9fc; color: #000000; text-align: left;&quot;&gt;&lt;code&gt;npx msw init public/ --save&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;214&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dcDy00/btsKtmpEKJc/Vtw34Z8WDlLutNLKGjGjl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dcDy00/btsKtmpEKJc/Vtw34Z8WDlLutNLKGjGjl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dcDy00/btsKtmpEKJc/Vtw34Z8WDlLutNLKGjGjl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdcDy00%2FbtsKtmpEKJc%2FVtw34Z8WDlLutNLKGjGjl1%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;662&quot; height=&quot;214&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;214&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;394&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZXfqY/btsKtcANfuc/JSe5TUV7xCt3kB9CcQNJS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZXfqY/btsKtcANfuc/JSe5TUV7xCt3kB9CcQNJS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZXfqY/btsKtcANfuc/JSe5TUV7xCt3kB9CcQNJS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZXfqY%2FbtsKtcANfuc%2FJSe5TUV7xCt3kB9CcQNJS0%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;480&quot; height=&quot;394&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;394&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Nextjs</category>
      <author>hovinee</author>
      <guid isPermaLink="true">https://hobinsky.tistory.com/134</guid>
      <comments>https://hobinsky.tistory.com/134#entry134comment</comments>
      <pubDate>Fri, 1 Nov 2024 10:18:57 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 삼총사 - 브루트포스(완전탐색)</title>
      <link>https://hobinsky.tistory.com/133</link>
      <description>&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;604&quot; data-origin-height=&quot;365&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ci7wv/btsJWovNbcL/iZl20uZO0Jjtirkjm5sIV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ci7wv/btsJWovNbcL/iZl20uZO0Jjtirkjm5sIV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ci7wv/btsJWovNbcL/iZl20uZO0Jjtirkjm5sIV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCi7wv%2FbtsJWovNbcL%2FiZl20uZO0Jjtirkjm5sIV0%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;604&quot; height=&quot;365&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;365&quot;/&gt;&lt;/span&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;pre id=&quot;code_1728262409935&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution(number) {
    var answer = 0;
  
    // 첫 번째 학생 선택
    for (let i = 0; i &amp;lt; number.length - 2; i++) {
        // 두 번째 학생 선택
        for (let j = i + 1; j &amp;lt; number.length - 1; j++) {
            // 세 번째 학생 선택
            for (let k = j + 1; k &amp;lt; number.length; k++) {
                // 세 학생의 번호 합이 0인지 확인
                if (number[i] + number[j] + number[k] === 0) {
                    answer++;
                }
            }
        }
    }
    return answer;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>자료구조&amp;amp;알고리즘</category>
      <author>hovinee</author>
      <guid isPermaLink="true">https://hobinsky.tistory.com/133</guid>
      <comments>https://hobinsky.tistory.com/133#entry133comment</comments>
      <pubDate>Mon, 7 Oct 2024 18:53:38 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 크기가 작은 부분 문자열 - 슬라이딩 윈도우</title>
      <link>https://hobinsky.tistory.com/132</link>
      <description>&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;838&quot; data-origin-height=&quot;436&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6L8q8/btsJUa57jP8/4uJDY3F2HcxbY4IQF9K5iK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6L8q8/btsJUa57jP8/4uJDY3F2HcxbY4IQF9K5iK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6L8q8/btsJUa57jP8/4uJDY3F2HcxbY4IQF9K5iK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6L8q8%2FbtsJUa57jP8%2F4uJDY3F2HcxbY4IQF9K5iK%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;838&quot; height=&quot;436&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;436&quot;/&gt;&lt;/span&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;pre id=&quot;code_1728018086424&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution(t, p) {
    let count = 0;
    let pLen = p.length;
    let pNum = parseInt(p); // p를 숫자로 변환
    
    for (let i = 0; i &amp;lt;= t.length - pLen; i++) {
        let subStr = t.slice(i, i + pLen); // t에서 p와 같은 길이의 부분 문자열 추출
        let subNum = parseInt(subStr); // 부분 문자열을 숫자로 변환
        
        if (subNum &amp;lt;= pNum) {
            count++; // p보다 작거나 같으면 카운트
        }
    }
    
    return count;
}

console.log(solution(&quot;3141592&quot;, &quot;271&quot;)); // 출력: 2&lt;/code&gt;&lt;/pre&gt;</description>
      <category>자료구조&amp;amp;알고리즘</category>
      <author>hovinee</author>
      <guid isPermaLink="true">https://hobinsky.tistory.com/132</guid>
      <comments>https://hobinsky.tistory.com/132#entry132comment</comments>
      <pubDate>Fri, 4 Oct 2024 19:01:32 +0900</pubDate>
    </item>
  </channel>
</rss>