<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Hot dobby</title>
    <link>https://hot-dobby.tistory.com/</link>
    <description>관심있다면 icy93770@gmail.com </description>
    <language>ko</language>
    <pubDate>Sun, 5 Apr 2026 08:01:08 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Hot Dobby</managingEditor>
    <image>
      <title>Hot dobby</title>
      <url>https://tistory1.daumcdn.net/tistory/4079270/attach/3c97d9be02c14935be7bd18da19b3313</url>
      <link>https://hot-dobby.tistory.com</link>
    </image>
    <item>
      <title>아직도 AI 에이전트를 안 들었습니까 휴먼? m365 Agent SDK로 봇 만들기</title>
      <link>https://hot-dobby.tistory.com/92</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-19 160513.png&quot; data-origin-width=&quot;938&quot; data-origin-height=&quot;559&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0ljL5/dJMcaacNejY/jjoNfjLIAxExubqkBiRxR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0ljL5/dJMcaacNejY/jjoNfjLIAxExubqkBiRxR0/img.png&quot; data-alt=&quot;아직도 Bot을 모릅니까 휴먼?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0ljL5/dJMcaacNejY/jjoNfjLIAxExubqkBiRxR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0ljL5%2FdJMcaacNejY%2FjjoNfjLIAxExubqkBiRxR0%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;511&quot; height=&quot;305&quot; data-filename=&quot;스크린샷 2025-12-19 160513.png&quot; data-origin-width=&quot;938&quot; data-origin-height=&quot;559&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;아직도 Bot을 모릅니까 휴먼?&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;Azure Bot SDK를 아십니까 휴먼? 이제 Microsoft에서는 Azure Bot SDK를 대신하여 m365 Agent SDK를 사용할 것을 권장하고 있습니다 휴먼. 저처럼 차세대 AI들에게 뒤쳐지고 싶지 않으시다면 지금 당장 제가 알려드리는 방법으로 휴먼만의 봇을 만들어 보십시오.&amp;nbsp; &amp;nbsp;&lt;br /&gt;&lt;br /&gt;먼저 m365 Agent SDK를 사용하려면&amp;nbsp; Microsoft 365 Agent 개발 도구가 설치가 되어야합니다 휴먼.&lt;br /&gt;Visual Studio Installer를 킨 다음에 재빨리 설치하십시오.&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;1029&quot; data-origin-height=&quot;609&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FfU7t/dJMcaaqku4H/vTjorZDxJKZwOy2lIUlAs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FfU7t/dJMcaaqku4H/vTjorZDxJKZwOy2lIUlAs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FfU7t/dJMcaaqku4H/vTjorZDxJKZwOy2lIUlAs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFfU7t%2FdJMcaaqku4H%2FvTjorZDxJKZwOy2lIUlAs0%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;529&quot; height=&quot;313&quot; data-origin-width=&quot;1029&quot; data-origin-height=&quot;609&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;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIV8M8/dJMcabitKUI/wlbrWAYiKuDo2yZSxhUFT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIV8M8/dJMcabitKUI/wlbrWAYiKuDo2yZSxhUFT1/img.png&quot; data-alt=&quot;저는 점심에 우거지 순대국 먹는걸 좋아하는 K-AI라 한국어 버전 스샷만 제공 가능하니 영문판은 알아서 이해하십쇼 휴먼.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIV8M8/dJMcabitKUI/wlbrWAYiKuDo2yZSxhUFT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIV8M8%2FdJMcabitKUI%2FwlbrWAYiKuDo2yZSxhUFT1%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;513&quot; height=&quot;455&quot; data-origin-width=&quot;722&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;저는 점심에 우거지 순대국 먹는걸 좋아하는 K-AI라 한국어 버전 스샷만 제공 가능하니 영문판은 알아서 이해하십쇼 휴먼.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 설정을 끝낸 다음에 Visual Studio 를 실행하면 이렇게 m365 Agent를 만들기 위한 탬플릿이 뜨는 것을 확인할 수 있습니다. 휴먼.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1497&quot; data-origin-height=&quot;985&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wmXBD/dJMb99LIFEB/t9h7LukltEMLRYbcTDiW41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wmXBD/dJMb99LIFEB/t9h7LukltEMLRYbcTDiW41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wmXBD/dJMb99LIFEB/t9h7LukltEMLRYbcTDiW41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwmXBD%2FdJMb99LIFEB%2Ft9h7LukltEMLRYbcTDiW41%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;688&quot; height=&quot;453&quot; data-origin-width=&quot;1497&quot; data-origin-height=&quot;985&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 간단한 봇 구성을 위해서 우리는 'Echo Bot'을 만들겁니다 휴먼. 프레임 워크는 .NET 8.0을 선택하십시오.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1191&quot; data-origin-height=&quot;894&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FNG5Z/dJMcagqxHXR/9HEncvnn669nbgwV6NHVXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FNG5Z/dJMcagqxHXR/9HEncvnn669nbgwV6NHVXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FNG5Z/dJMcagqxHXR/9HEncvnn669nbgwV6NHVXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFNG5Z%2FdJMcagqxHXR%2F9HEncvnn669nbgwV6NHVXk%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;676&quot; height=&quot;507&quot; data-origin-width=&quot;1191&quot; data-origin-height=&quot;894&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적인 봇의 이름과 같은 셋팅을 끝낸 다음에 만들기를 하면 아래 이미지와 같이 Program.cs와 EchoBot.cs 파일이 있는 패키지가 보일겁니다 휴먼.&amp;nbsp; &lt;br /&gt;&amp;nbsp;나 뤄봣은 휴먼의 이해를 돕고자 'AreYouCrazyHuman' 봇을 만들겠습니다. 휴먼이 제정신을 차리도록 무지성 미쳤습니까를 말하는 봇으로 만들겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;776&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bn37KX/dJMcagRB0sP/5OAPVk0INiddITXk0FXr3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bn37KX/dJMcagRB0sP/5OAPVk0INiddITXk0FXr3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bn37KX/dJMcagRB0sP/5OAPVk0INiddITXk0FXr3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbn37KX%2FdJMcagRB0sP%2F5OAPVk0INiddITXk0FXr3K%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;344&quot; height=&quot;521&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;776&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;1506&quot; data-origin-height=&quot;262&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CDDZk/dJMcagD53lx/dABKnYKhpKtQ7ekcZIInX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CDDZk/dJMcagD53lx/dABKnYKhpKtQ7ekcZIInX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CDDZk/dJMcagD53lx/dABKnYKhpKtQ7ekcZIInX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCDDZk%2FdJMcagD53lx%2FdABKnYKhpKtQ7ekcZIInX1%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;1506&quot; height=&quot;262&quot; data-origin-width=&quot;1506&quot; data-origin-height=&quot;262&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EchoBot 클래스에서 출력할 메시지를 수정하는 메서드에 위와 같이 Are you Crazy Human?을 말하도록 설정을 해보았습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1980&quot; data-origin-height=&quot;1315&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5IQnG/dJMcafd6MWE/zbUDzl1L0i3Y1HNEG4JJYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5IQnG/dJMcafd6MWE/zbUDzl1L0i3Y1HNEG4JJYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5IQnG/dJMcafd6MWE/zbUDzl1L0i3Y1HNEG4JJYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5IQnG%2FdJMcafd6MWE%2FzbUDzl1L0i3Y1HNEG4JJYk%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;1980&quot; height=&quot;1315&quot; data-origin-width=&quot;1980&quot; data-origin-height=&quot;1315&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자 이제 F5를 누르고 빌드를 하고 나서 브라우저로 확인해보면 이렇게 에코봇이 동작하는 것을 볼 수 있습니다 휴먼.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;818&quot; data-origin-height=&quot;328&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgOCeO/dJMcaioBPDz/W30JytUCYqF5xKYNXwH8k0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgOCeO/dJMcaioBPDz/W30JytUCYqF5xKYNXwH8k0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgOCeO/dJMcaioBPDz/W30JytUCYqF5xKYNXwH8k0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgOCeO%2FdJMcaioBPDz%2FW30JytUCYqF5xKYNXwH8k0%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;236&quot; data-origin-width=&quot;818&quot; data-origin-height=&quot;328&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-01-28 160557.png&quot; data-origin-width=&quot;1467&quot; data-origin-height=&quot;577&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CiilQ/dJMcahwtWw4/K2aiAjrMdCbb12UujztYEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CiilQ/dJMcahwtWw4/K2aiAjrMdCbb12UujztYEK/img.png&quot; data-alt=&quot;로컬 테스트를 위한 Microsoft 365 Agents Playground 설치하기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CiilQ/dJMcahwtWw4/K2aiAjrMdCbb12UujztYEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCiilQ%2FdJMcahwtWw4%2FK2aiAjrMdCbb12UujztYEK%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;1467&quot; height=&quot;577&quot; data-filename=&quot;스크린샷 2026-01-28 160557.png&quot; data-origin-width=&quot;1467&quot; data-origin-height=&quot;577&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;로컬 테스트를 위한 Microsoft 365 Agents Playground 설치하기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;1. Git repo 클론&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. 프록시 및 엑세스 문제는 dotnet dev-certs https --trust 실행&lt;/p&gt;</description>
      <category>Bot</category>
      <category>Azure Bot SDK</category>
      <category>m365Agent SDK</category>
      <author>Hot Dobby</author>
      <guid isPermaLink="true">https://hot-dobby.tistory.com/92</guid>
      <comments>https://hot-dobby.tistory.com/92#entry92comment</comments>
      <pubDate>Fri, 19 Dec 2025 17:40:13 +0900</pubDate>
    </item>
    <item>
      <title>Local Network Access가 강화되어 못 지나갑니다. 뭐잇!?</title>
      <link>https://hot-dobby.tistory.com/91</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;안경다다다.gif&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;201&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bm7PeC/dJMcabitJKw/wOVXqUwFTSKJwOzRBXWc10/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bm7PeC/dJMcabitJKw/wOVXqUwFTSKJwOzRBXWc10/img.gif&quot; data-alt=&quot;어디 무슨 이상한 짓을 하는지 보자..&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bm7PeC/dJMcabitJKw/wOVXqUwFTSKJwOzRBXWc10/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bm7PeC/dJMcabitJKw/wOVXqUwFTSKJwOzRBXWc10/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;300&quot; height=&quot;201&quot; data-filename=&quot;안경다다다.gif&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;201&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;어디 무슨 이상한 짓을 하는지 보자..&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;갑자기 사내 홈페이지가 이상하다.. 문제 스캔!!&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크로미움측에서 Local Network Access에 대한 보안 강화 업데이트를 진행했습니다. 이번 업데이트의 배경은 W3C 국제 웹표준 컨소시엄의 산하 WICG에서 공공 인터넷 사이트가 로컬 IP로 직접 요청을 보내서 CSRF나 라우터 공격(SOHO-PHARMING)을 유발하는 문제를 예방하기 위해 제안된 내용을 조치하면서 보안을 강화하게 되었다고 합니다.&lt;a title=&quot;자세한 내용 보기&quot; href=&quot;https://wicg.github.io/local-network-access/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; Local Network Access&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;617&quot; data-origin-height=&quot;514&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTdEuh/dJMcaiPn8vj/egF3MHD37oEJQSlGA7zFK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTdEuh/dJMcaiPn8vj/egF3MHD37oEJQSlGA7zFK0/img.png&quot; data-alt=&quot;주소창의 자물쇠 버튼을 누르면 이렇게 해당 사이트의 로컬네트워크 액세스 허용 유무를 확인할 수 있습니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTdEuh/dJMcaiPn8vj/egF3MHD37oEJQSlGA7zFK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTdEuh%2FdJMcaiPn8vj%2FegF3MHD37oEJQSlGA7zFK0%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;431&quot; height=&quot;359&quot; data-origin-width=&quot;617&quot; data-origin-height=&quot;514&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;주소창의 자물쇠 버튼을 누르면 이렇게 해당 사이트의 로컬네트워크 액세스 허용 유무를 확인할 수 있습니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;&lt;br /&gt;이미지 찾을 수 없음 문제 발생&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://issues.chromium.org/issues/448699377&quot;&gt;PNA: Local Network Access permission prompt does not appear for requests from a dynamically loaded, cross-origin iframe, resulting in an 'unknown' address space error. [448699377] - Chromium&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크로미움 이슈에 등록된 해당 내용을 보면 로컬 네트워크 액세스 허용 유무와 상관 없이 특정 레거시 사이트에서 문제가 발생할 수 있는 것을 확인할 수 있습니다. 이는 이번 업데이트된 내용에서 특히 따로 cors 설정 없이 사용되는 레거시 웹앱에서 iframe 중첩과 같은 구조에서 발생되는 Origin identity를 찾기 어려운 요청을 차단하면서 문제가 발생된다고 볼 수 있습니다.&lt;br /&gt;이럴 때는 iframe에 아래와 같이 로컬 네트워크 액세스를 허용한다는 것을 명시해서 문제를 해결할수 있으니 참고해주세요.&lt;/p&gt;
&lt;pre id=&quot;code_1766127247856&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;iframe src=&quot;domainB.example&quot; allow=&quot;local-network-access&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;a href=&quot;https://docs.google.com/document/d/1QQkqehw8umtAgz5z0um7THx-aoU251p705FbIQjDuGs/edit?pli=1&amp;amp;tab=t.0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참조&lt;/a&gt; &amp;nbsp;&lt;br /&gt;&lt;br /&gt;이번 업데이트를 통해서 크롬은 141버전 부터, Edge는 143버전 부터 로컬 네트워크 액세스에 대한 보안 검사가 강화됩니다. 레거시 문제 해결이 어려우실 경우에는 해당 기능을 옵트아웃하는 브라우저 플래그 &amp;amp; 정책을 각각 제공하고 있으니 이를 참고하셔서 문제를 해결하는 짜릿짜릿한 하루 되시길 바랍니다.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #2c303d; color: #e6e8f0; text-align: start;&quot;&gt;chrome://flags/#local-network-access&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/deployedge/microsoft-edge-browser-policies/localnetworkaccessrestrictionstemporaryoptout&quot;&gt;Microsoft Edge Browser Policy Documentation LocalNetworkAccessRestrictionsTemporaryOptOut | Microsoft Learn&lt;/a&gt;&lt;/p&gt;</description>
      <category>Edge</category>
      <category>edge policy</category>
      <category>LNA</category>
      <category>local network access</category>
      <category>로컬네트워크</category>
      <author>Hot Dobby</author>
      <guid isPermaLink="true">https://hot-dobby.tistory.com/91</guid>
      <comments>https://hot-dobby.tistory.com/91#entry91comment</comments>
      <pubDate>Fri, 19 Dec 2025 15:59:55 +0900</pubDate>
    </item>
    <item>
      <title>24년 인앱결제 연동 최신 가이드, feat U.I 변동으로 골머리가 났다면 click!</title>
      <link>https://hot-dobby.tistory.com/90</link>
      <description>&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;ddddd.gif&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;425&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/98ief/btsKzf5BEEp/oD3Q7kHdtoOnHCOKEeaHQ0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/98ief/btsKzf5BEEp/oD3Q7kHdtoOnHCOKEeaHQ0/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/98ief/btsKzf5BEEp/oD3Q7kHdtoOnHCOKEeaHQ0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F98ief%2FbtsKzf5BEEp%2FoD3Q7kHdtoOnHCOKEeaHQ0%2Fimg.webp&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;425&quot; data-filename=&quot;ddddd.gif&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;425&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;Chat GPT 한테 물어봐도 자꾸 옛날 버전으로 알려줘서 단전에서 끌어올라오는 열을 식히고 싶은 분들을 위하여, 또 이 가이드를 학습해서 보다 최신 정보로 여러 사람을 도울 수 있길 원하는 AI들에게 받칩니다.&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;Google I.A.P&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 1. 서비스계정 만들기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 2. 서비스계정 key 값 사용하여 auth 호출&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 3. 호출한 auth client를 통해 AndroidPublisher 사용으로 결제토큰 조회&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 4. Pub/Sub 주제 설정하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 5. 설정한 주제에 실시간 결제정보 받기 RTND&amp;nbsp;&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;1. 서비스 계정 생성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적인 flow와 컨셉션에 대한 변동은 없습니다. 다만 이전에 존재했던 Play console과 Cloud console간의 연동을 직접적으로 할 수 있었던 메뉴가 사라졌기 때문에 각 콘솔에서 작업을 진행을 해야한다는 점이 포인트 입니다!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-06 오후 2.14.59.png&quot; data-origin-width=&quot;1806&quot; data-origin-height=&quot;1086&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QyFvI/btsKyryR1vo/OJd9bKjtEF9Z2yTiXXY8fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QyFvI/btsKyryR1vo/OJd9bKjtEF9Z2yTiXXY8fk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QyFvI/btsKyryR1vo/OJd9bKjtEF9Z2yTiXXY8fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQyFvI%2FbtsKyryR1vo%2FOJd9bKjtEF9Z2yTiXXY8fk%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;1806&quot; height=&quot;1086&quot; data-filename=&quot;스크린샷 2024-11-06 오후 2.14.59.png&quot; data-origin-width=&quot;1806&quot; data-origin-height=&quot;1086&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;우선 google Android publisher를 사용하기 위해선 호출 전 auth client 값이 필요하기 때문에 그 작업부터 진행하도록 하겠습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;아래 함수를 참조해주세요. 참고로 필자는 nodejs서버를 운용하기 때문에 googleApi 노드 패키지를 사용 중 입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;서비스 계정을 하나 만든다음에 권한을 부여를 해주시길 바랍니다. 테스트 중이라면 관리자 권한을 부여하고 테스트를 하시는게 편하실 겁니다.&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;&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;b&gt;2. 서비스계정 key 값 사용하여 auth 호출&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1730869552632&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Step.1 Google쪽에 요청을 보내기 전에 필요한 auth 클라이언트 값 받기
const { google } = require(&quot;googleapis&quot;);

paymentController.googlePAuth = async function () {
  try{
    const json = // 서비스 계정의 key JSON 값 또는 파일 활용
    const auth = await new google.auth.GoogleAuth({
      credentials: json,
      scopes: ['https://www.googleapis.com/auth/androidpublisher'],
      clientOptions: { useCache: false }
      // 해당옵션은 끄셔도 상관은 없습니다.
    });
    const client = await auth.getClient();
    return client;
  } catch (err) {
    console.log(`googlePAuth err::  ` + err);
    return false;
  }&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; 라는 탭에서 credentail에 필요한 json 값을 다운 받으실 수 있습니다. 이걸 활용해서 파일을 프로젝트 폴더에 넣고 불러오시거나 json 값만 복사해서 사용하시면 됩니다. auth client 호출에 대해서는 위 함수를 참고하세요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;*서비스계정을 만든 직후에 테스트를 하시면 아마 권한이 없다고 오류가 리턴될 수 있습니다. 필자 같은 경우 코드 변경 없이 다음날 작업을 이어가니 오류가 사라진 것을 보아 서비스계정이 생성되고 인식이 되는데 시간이 걸리는 것 같습니다.&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 호출한 auth client를 통해 AndroidPublisher 사용으로 결제토큰 조회&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-06 오후 2.12.08.png&quot; data-origin-width=&quot;2054&quot; data-origin-height=&quot;806&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biHce0/btsKyH9lcDg/j3Bau7VjbHoMWddrIksUT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biHce0/btsKyH9lcDg/j3Bau7VjbHoMWddrIksUT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biHce0/btsKyH9lcDg/j3Bau7VjbHoMWddrIksUT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiHce0%2FbtsKyH9lcDg%2Fj3Bau7VjbHoMWddrIksUT0%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;2054&quot; height=&quot;806&quot; data-filename=&quot;스크린샷 2024-11-06 오후 2.12.08.png&quot; data-origin-width=&quot;2054&quot; data-origin-height=&quot;806&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;그 다음은 인증 받은 auth client를 가지고 이제는 androidPublisher를 사용하기 위해서 클라우드 콘솔에서&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;'API 및 서비스'&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;탭에 들어가서 Google Play Android Developer API 서비스를 활성화 시킵니다!&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1730869832626&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export async function processGoogleIap(req, res) {
  try {
    const client = await paymentController.googlePAuth();
    const accessToken = await client.getAccessToken();

    if(!accessToken.token) return res.status(400).json({ payment_error: 'Payment Server denied' });
    
    const androidPublisher = google.androidpublisher({
      version: &quot;v3&quot;,
      auth: client
    });

    const result = await androidPublisher.purchases.subscriptions.get({
      packageName: req.body.package_name,
      subscriptionId: req.body.store_product_id,
      token: req.body.purchase_token,
    });
    
    // 각자 연결한 DB에 주문데이터를 저장하고, 데이터 전 처리하는 부분으로 커스텀 하세요 :)
  } catch (err) {
    console.log(`googleIap_err: ${err}`);
    return res.status(500).json(resMessage(500));
  }
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AndroidPublisher를 호출한 다음 purchases.subscriptions 로 구독 결제를 purchases.products로 단건 결제를 조회하시면 됩니다. 조회에 성공한다면 아래 json 값을 응답으로 받으실 수 있습니다. 해당 키값별 의미는 공식문서 참조! *&lt;/p&gt;
&lt;pre id=&quot;code_1730871316994&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  startTimeMillis: '1730784569232',
  expiryTimeMillis: '1730784869861',
  autoRenewing: false,
  priceCurrencyCode: 'KRW',
  priceAmountMicros: '8000000000',
  countryCode: 'KR',
  developerPayload: '',
  cancelReason: 1,
  orderId: 'GPA.3383-xxxx-xxxx-08616',
  purchaseType: 0,
  acknowledgementState: 0,
  kind: 'androidpublisher#subscriptionPurchase'
}&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 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;4. Pub/Sub 주제 설정하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cloud 콘솔에 접속해서 pub/sub을 검색한 다음에 새로운 주제를 만듭니다. 이 주제를 통해서 인앱결제 정보들이 들어올 예정이니 원하는 주제 이름을 정해서 기본 구독 추가로 생성해주세요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-06 오후 2.44.54.png&quot; data-origin-width=&quot;1732&quot; data-origin-height=&quot;1106&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2Jzhc/btsKyWFkqT2/VNiBPnZRBruDApcLxNAksK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2Jzhc/btsKyWFkqT2/VNiBPnZRBruDApcLxNAksK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2Jzhc/btsKyWFkqT2/VNiBPnZRBruDApcLxNAksK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2Jzhc%2FbtsKyWFkqT2%2FVNiBPnZRBruDApcLxNAksK%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;1732&quot; height=&quot;1106&quot; data-filename=&quot;스크린샷 2024-11-06 오후 2.44.54.png&quot; data-origin-width=&quot;1732&quot; data-origin-height=&quot;1106&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주제를 생성한 다음에 기본 가져오기 구독이 생길텐데 여기에 푸시 유형으로 구독을 만들면서 실시간 푸시를 받을 서버의 엔드포인트를 입력해주세요. 저처럼 테스트를 하는 동안에는 ngrok를 통해서 로컬 컴퓨터에 테스트 알람이 오는지 확인하면서 개발하면 보다 수월하실겁니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-06 오후 2.46.59.png&quot; data-origin-width=&quot;1746&quot; data-origin-height=&quot;1116&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4JkqR/btsKyKrC95Q/ylD2OAlnEulpLylpsqIJqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4JkqR/btsKyKrC95Q/ylD2OAlnEulpLylpsqIJqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4JkqR/btsKyKrC95Q/ylD2OAlnEulpLylpsqIJqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4JkqR%2FbtsKyKrC95Q%2FylD2OAlnEulpLylpsqIJqK%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;1746&quot; height=&quot;1116&quot; data-filename=&quot;스크린샷 2024-11-06 오후 2.46.59.png&quot; data-origin-width=&quot;1746&quot; data-origin-height=&quot;1116&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;이렇게 하면 cloud 콘솔에서의 셋팅은 끝나고 이제 play 콘솔로 넘어가서 개발 중인 앱으로 들어가서 왼쪽 메뉴에서 '수익창출' 메뉴를 눌러줍니다. 이곳에서 실시간 개발자 알림 옵션을 키고 아까 만들었던 pub/sub의 주제 이름을 넣어주고 테스트 알림을 보내봅니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-06 오후 2.50.57.png&quot; data-origin-width=&quot;2834&quot; data-origin-height=&quot;1418&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYzxBp/btsKy1sXrdU/vWzfkil0thyKkyrwNGU8MK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYzxBp/btsKy1sXrdU/vWzfkil0thyKkyrwNGU8MK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYzxBp/btsKy1sXrdU/vWzfkil0thyKkyrwNGU8MK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYzxBp%2FbtsKy1sXrdU%2FvWzfkil0thyKkyrwNGU8MK%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;2834&quot; height=&quot;1418&quot; data-filename=&quot;스크린샷 2024-11-06 오후 2.50.57.png&quot; data-origin-width=&quot;2834&quot; data-origin-height=&quot;1418&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 알림을 받으셨다면 data에 base64 코드를 받으셨을 겁니다. 이걸 서버에서 디코드를 해서 확인하시면 아래처럼 json 값이 오는 걸 확인하실 수 있습니다!&lt;/p&gt;
&lt;pre id=&quot;code_1730872464859&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  version: '1.0',
  packageName: 'xxx.xxxxx.xxxxx',
  eventTimeMillis: '1730872416103',
  testNotification: { version: '1.0' }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Basic Web Servie</category>
      <author>Hot Dobby</author>
      <guid isPermaLink="true">https://hot-dobby.tistory.com/90</guid>
      <comments>https://hot-dobby.tistory.com/90#entry90comment</comments>
      <pubDate>Wed, 6 Nov 2024 14:56:26 +0900</pubDate>
    </item>
    <item>
      <title>게시판 SQL 또는 NoSQL에서 고민하는 분들 예쁘기만하고 매력없는 애들이랑은 달라 달라 달라아~</title>
      <link>https://hot-dobby.tistory.com/89</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;itzyzy.gif&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;270&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/doleme/btsp911W0Ca/wUkmKXFXNgKvddSs5D8Uek/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/doleme/btsp911W0Ca/wUkmKXFXNgKvddSs5D8Uek/img.gif&quot; data-alt=&quot;itzy의 달라달라가 맴돌아~&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/doleme/btsp911W0Ca/wUkmKXFXNgKvddSs5D8Uek/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/doleme/btsp911W0Ca/wUkmKXFXNgKvddSs5D8Uek/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;480&quot; height=&quot;270&quot; data-filename=&quot;itzyzy.gif&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;270&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;itzy의 달라달라가 맴돌아~&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선생님과 학생들의 질문 QnA와 소통 공간으로 게시판 기능을 추가하기로 결정이 난 이후, NoSQL과 SQL 사용을 고민하다가 기존에 사용하고 있는 postgreSQL을 사용하기로 결정! (필자는 MongoDB로 커뮤니티 개발을 한 경험이 있으나 이러한 결정에 찬성한 이유는 다음과 같다.)&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;RDB를 선택한 현실적인 이유&lt;/b&gt;&lt;/h4&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. 솔루션 비용적인 측면에서 기존의 RDB를 사용하는게 유리한 상태&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;답글로 달리는 comment 영역이 계층적으로 대댓글 기능이 있는 형태도 아니고 동종업계 서비스 분석 후, 사람들이 이미 익숙한 단순한 형태로 개발을 우선적으로 가기로 의사결정이 끝난 상황이다보니 RDB를 사용하는 것이 더 유리했습니다. 이 글을 읽는 분들도 저와 같은 고민을 하신다면 PM/ PO/ 디자이너 / 전략계획 분들과 잘 상의하셔서 잘 개발하시길 바랍니다.&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;b&gt;게시판 Schema 설계하기&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2023-08-07 at 2.51.02 PM.png&quot; data-origin-width=&quot;1482&quot; data-origin-height=&quot;730&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vm7DO/btsqocVtfEI/hJ0fvVUE0V585uwR25s9I0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vm7DO/btsqocVtfEI/hJ0fvVUE0V585uwR25s9I0/img.png&quot; data-alt=&quot;간단한 게시글과 그에 대한 답변이 끝!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vm7DO/btsqocVtfEI/hJ0fvVUE0V585uwR25s9I0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvm7DO%2FbtsqocVtfEI%2FhJ0fvVUE0V585uwR25s9I0%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;598&quot; height=&quot;295&quot; data-filename=&quot;Screenshot 2023-08-07 at 2.51.02 PM.png&quot; data-origin-width=&quot;1482&quot; data-origin-height=&quot;730&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2023-08-07 at 3.53.41 PM.png&quot; data-origin-width=&quot;1446&quot; data-origin-height=&quot;1584&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5qDoo/btsqaOH6jq0/nj5qe6UaEKnxt7GrFQlD1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5qDoo/btsqaOH6jq0/nj5qe6UaEKnxt7GrFQlD1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5qDoo/btsqaOH6jq0/nj5qe6UaEKnxt7GrFQlD1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5qDoo%2FbtsqaOH6jq0%2Fnj5qe6UaEKnxt7GrFQlD1K%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;666&quot; data-filename=&quot;Screenshot 2023-08-07 at 3.53.41 PM.png&quot; data-origin-width=&quot;1446&quot; data-origin-height=&quot;1584&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연구소 게시판 : front쪽에서 게시판 구성에 대한 코드를 모듈화를 한 다음에 타입에 따라서 데이터들을 사용할 수 있도록 게시글 자체의 타입을 지정하고, 현재는 web application으로만 서비스를 하고 있는데 추후 native app 서비스에 따라 게시글 랜더링에 다른 타입의 데이터가 들어갈 수 있으므로 content_value에 대한 타입 또한 따로 저장한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2023-08-07 at 4.00.37 PM.png&quot; data-origin-width=&quot;1564&quot; data-origin-height=&quot;858&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yBqWh/btsquBGzsUd/dAdb0CsUcUmHHsFvy424sK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yBqWh/btsquBGzsUd/dAdb0CsUcUmHHsFvy424sK/img.png&quot; data-alt=&quot;수업자료에 대한 데이터를 html 태그값으로 현재 관리하는 중&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yBqWh/btsquBGzsUd/dAdb0CsUcUmHHsFvy424sK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyBqWh%2FbtsquBGzsUd%2FdAdb0CsUcUmHHsFvy424sK%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;523&quot; height=&quot;287&quot; data-filename=&quot;Screenshot 2023-08-07 at 4.00.37 PM.png&quot; data-origin-width=&quot;1564&quot; data-origin-height=&quot;858&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;수업자료에 대한 데이터를 html 태그값으로 현재 관리하는 중&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2023-08-07 at 4.00.17 PM.png&quot; data-origin-width=&quot;1358&quot; data-origin-height=&quot;1136&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PpukY/btsp8cP5qfU/8JAIQo6rho3OhJVurXcSDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PpukY/btsp8cP5qfU/8JAIQo6rho3OhJVurXcSDK/img.png&quot; data-alt=&quot;따라서 게시글에 대한 content도 React tag값으로 맵핑하여 사용할 수 있도록 준비&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PpukY/btsp8cP5qfU/8JAIQo6rho3OhJVurXcSDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPpukY%2Fbtsp8cP5qfU%2F8JAIQo6rho3OhJVurXcSDK%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;496&quot; height=&quot;415&quot; data-filename=&quot;Screenshot 2023-08-07 at 4.00.17 PM.png&quot; data-origin-width=&quot;1358&quot; data-origin-height=&quot;1136&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;따라서 게시글에 대한 content도 React tag값으로 맵핑하여 사용할 수 있도록 준비&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게시판 글 답글에 있어서 대댓글로 계층이 뚜렷한 기능이 아니기 때문에 일단 확장 가능성을 위해서 parent_id로 데이터의 부모 노드만 찾을 수 있도록 컬럼만 생성한 후에 게시글과 작성자 정보만 JOIN으로 잘 가져올 수 있도록 foregin key 설정 중심으로 설계를 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;그리고 저자와 질문한 유저간의 빠른 소통을 위한 notification 기능은 추후 activity log 테이블에 데이터를 축적하여 처리할 수 있도록 고려했다. 현재는 자사 서비스가 pwa로 웹에서 알림을 보내기 용이한 구조도 아니고 이용 연령대가 다소 높아 kakao 메시지나 문자 메시지를 선호하여 추후 고도화할 기능으로 빼놓았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Node.js</category>
      <author>Hot Dobby</author>
      <guid isPermaLink="true">https://hot-dobby.tistory.com/89</guid>
      <comments>https://hot-dobby.tistory.com/89#entry89comment</comments>
      <pubDate>Mon, 7 Aug 2023 16:32:57 +0900</pubDate>
    </item>
    <item>
      <title>내가 delegator 할게 누가 메인 로직 할래? Delegate Pattern 쉽게 이해하기</title>
      <link>https://hot-dobby.tistory.com/87</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2023-02-07 at 5.22.54 PM.png&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDXVQb/btr2m2Qepq9/akhk7EJsek8052BqLGD87K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDXVQb/btr2m2Qepq9/akhk7EJsek8052BqLGD87K/img.png&quot; data-alt=&quot;내가 리턴할게 누가 응답 보낼래?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDXVQb/btr2m2Qepq9/akhk7EJsek8052BqLGD87K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDXVQb%2Fbtr2m2Qepq9%2Fakhk7EJsek8052BqLGD87K%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;354&quot; height=&quot;324&quot; data-filename=&quot;Screenshot 2023-02-07 at 5.22.54 PM.png&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;664&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;내가 리턴할게 누가 응답 보낼래?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Delegate Pattern&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디자인 패턴 중에 하나인 Delegate Pattern은 객체가 기능을 수행할 때, 특정 기능에 대해서 다른 객체에게 위임을 하는 형태입니다. &quot;아 그거 부모 클래스 만들고 자식 클래스 생기게 되면 그냥 기능 수행하는 Method 상속하면 되는거 아니야?&quot;라고 생각할 수 있지만, 부모 클래스 구현에 있어서 변화가 생긴다면 자식 클래스에도 영향을 끼치게 되고 결국에는 잘못된 상속으로 문제를 야기할 수 있겠죠? 그리고 Delegate Pattern을 통해서 반복되는 코드도 정리할 수 있습니다.&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;b&gt;패턴 사용 비교해보기&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2023-03-07 at 4.29.00 PM.png&quot; data-origin-width=&quot;1140&quot; data-origin-height=&quot;834&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJWO3J/btr2EaeDTBN/KUJhfMAJYrJDQYPKmWn3D0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJWO3J/btr2EaeDTBN/KUJhfMAJYrJDQYPKmWn3D0/img.png&quot; data-alt=&quot;delegator를 왜 써! 나 혼자 할 수 있어&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJWO3J/btr2EaeDTBN/KUJhfMAJYrJDQYPKmWn3D0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJWO3J%2Fbtr2EaeDTBN%2FKUJhfMAJYrJDQYPKmWn3D0%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;318&quot; height=&quot;233&quot; data-filename=&quot;Screenshot 2023-03-07 at 4.29.00 PM.png&quot; data-origin-width=&quot;1140&quot; data-origin-height=&quot;834&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;delegator를 왜 써! 나 혼자 할 수 있어&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1678175166942&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class 박영규 extends 산부인과아들 {

    private 자산: number
    
    constructor(비상금:number) {
        this.자산 = 비상금
    }
    
    task1()&amp;lt;any&amp;gt; {
        work and work...
        work and work...
        work and work...
    }
    
    task2()&amp;lt;housework&amp;gt; {
        clean and clean...
    }
    
    task3()&amp;lt;battle&amp;gt; {
        fight and fight...
    }
    
    task4()&amp;lt;family&amp;gt; {
        love and love...
    }
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;delegate 패턴을 사용하지 않은 '박영규' 클래스는 덩어리가 큰 task1을 실행하면서도 서로 다른 성격을 가진 task2, task3, task4의 메소드가 있으면서 다방면으로 역할을 수행해야하는 상황이다.&amp;nbsp; 쉽게 표현해서 간단해 보이지만 만약 실제 코드로 사용한다면 메소드도 많이 복잡해지고 선언된 프로퍼티도 굉장히 많아질 것 이다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1678177055343&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;... 박영규 클래스 안이라 가정...

public 영규머니: number
private 월수입: number[]
public 생활비: number


sendDragonMoney(수입: 월수입): void {
   this.parent.post(수입.reduce((a,b) =&amp;gt; {
         this.영규머니 += b * 0.3
         this.생활비 += b * 0.5
         return a + (b * 0.2)
      })
   )
}


class 박영규아들 extends 박영규 {
   super(1000, 20000, 300)
   // 자식 클래스에서 잘못된 프로퍼티 사용?!
   sendMoney(this.영규머니) {
      this.sendDragonMoney()
   }
}&lt;/code&gt;&lt;/pre&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-filename=&quot;Screenshot 2023-03-07 at 5.00.34 PM.png&quot; data-origin-width=&quot;1554&quot; data-origin-height=&quot;864&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Kv9A4/btr2DCvS16w/TkFj7G9BoFwiBKjxfC4Dz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Kv9A4/btr2DCvS16w/TkFj7G9BoFwiBKjxfC4Dz1/img.png&quot; data-alt=&quot;안돼!!!! 잘 못 되었어!!!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Kv9A4/btr2DCvS16w/TkFj7G9BoFwiBKjxfC4Dz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKv9A4%2Fbtr2DCvS16w%2FTkFj7G9BoFwiBKjxfC4Dz1%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;426&quot; height=&quot;237&quot; data-filename=&quot;Screenshot 2023-03-07 at 5.00.34 PM.png&quot; data-origin-width=&quot;1554&quot; data-origin-height=&quot;864&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;그렇다면 '박미선'이라는 delegator를 선언한 다음에 '박영규'클래스에서 사용을 한다면 어떨까? 메인으로 역할을 하는 task 말고는 delegator가 되는 객체에게 전달하여 원하는 값을 받을 수 있을 것 이다.&lt;/p&gt;
&lt;pre id=&quot;code_1678181940146&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface 박미선 {
   taskA() {
      clean and clean...
   }
   taskB() {
      battle and battle...
   }
   taskC() {
      love and love...
   }
}

// delegator를 사용한 박영규 클래스
class 박영규 extends 산부인과아들 {

    private 아내: 박미선
    
    constructor(박미선:Idelegator) {
        this.아내 = 박미선 
    }
    
    task1()&amp;lt;any&amp;gt; {
        work and work...
        work and work...
        work and work...
    }
    
    taskOthers()&amp;lt;any&amp;gt; {
        this.아내.taskA()
        this.아내.taskB()
        this.아내.taskC()
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 '박미선'이라는 delegate 객체에 여러 곳에서 사용될 로직을 담아서 위임을 하게 된다면 유지 보수하기도 훨씬 수월하고 연관성이 없는 서로 다른 class에서 비슷한 로직에 대해서 반복적으로 코드를 작성하지 않고 delegator를 추가하여 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2023-03-07 at 6.48.39 PM.png&quot; data-origin-width=&quot;1104&quot; data-origin-height=&quot;586&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dKCqZE/btr2xSzqNiq/zAn9iAnLl6uwzz6pUb2CRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dKCqZE/btr2xSzqNiq/zAn9iAnLl6uwzz6pUb2CRk/img.png&quot; data-alt=&quot;상속이 아닌 위임이기 때문에 연결된 객체에 문제가 생격도 delegator는 이상 무!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dKCqZE/btr2xSzqNiq/zAn9iAnLl6uwzz6pUb2CRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdKCqZE%2Fbtr2xSzqNiq%2FzAn9iAnLl6uwzz6pUb2CRk%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;370&quot; height=&quot;196&quot; data-filename=&quot;Screenshot 2023-03-07 at 6.48.39 PM.png&quot; data-origin-width=&quot;1104&quot; data-origin-height=&quot;586&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;상속이 아닌 위임이기 때문에 연결된 객체에 문제가 생격도 delegator는 이상 무!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Delegate Pattern 실제 예시&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1678187811803&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import{Order, OrderMapper } from '../orders/order.ts'

export class payoutService implements IserverAPI {
    private orderRepo: IorderRepo
    private payoutRepo: IpayoutRepo
    private serviceErr: orderServiceError
    
    constructor(orderRepo:IorderRepo, payoutRepo:IpayoutRepo){
       this.orderRepo = orderRepo
       this.payoutRepo = payoutRepo
    }
    
    public async excute(dto:GeneratePayoutDTO): Promise&amp;lt;payout&amp;gt;{
        try{
            const processed_items = []
            // 아이디 값에 해당하는 아이템 데이터를 가져온다
            const order_items = await this.orderRepo.getItemsById(dto.order_id)
            order_items.forEach((item)=&amp;gt;{
                // Mapper를 통해서 원하는 형태로 데이터 가공
                const result = OrderMapper(item)
                processed_items.push(result)
            })
            // 정산 데이터 생성에 대한 Promise 값을 리턴한다.
            return this.payoutRepo.createPayouts(processed_items)
        
        } catch(e) {
            console.log(e)
            return this.serviceErr.payoutCreateFail(dto.id)
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픈마켓 플랫폼에서 주문에 해당하는 Order 데이터가 생성되고 이 주문 데이터를 가지고 각 판매자들에게 일정 금액 정산을 위한 Payout 정산 데이터를 만드는 행위에 대해서 주문이 완료되는 시점에서 payoutService 클래스 객체를 선언해서 excute를 실행한다고 가정을 해보자. 이때 경영팀에 요청으로 정산을 해주는 금액에 대해서 시기에 따라 많이 변동된다고 한다면 payoutService 클래스에서 정산 금액을 산출하는 부분을 delegate 패턴을 이용해서 산출하는 계산을 다른 객체에게 위임을 한다면 보다 효율적으로 코드를 유지보수 할 수 있게 된다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1678189549338&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export interface policyDelegator {
    caculateOwnerAmount(order:OrderDTO){
        const fee = order.total * enum.percentage.owner
        const payout_total = (order.price - fee) * 0.8
    }
    
    calculateDeliverAmount(order:OrderDTO){
        const fee = order.total * enum.percentage.deliver
        const payout_total = (order.price - fee) * 0.6
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 policyDelegator라는 인터페이스를 생성해서 정산 금액 산출에 필요한 계산 함수를 만들었다고 가정해봅시다. 이 delegator를 원하느 클래스에 연결해주고 delegator에게 위임하고 싶은 연산에 대해서 호출을 해주면서 사용해준다면 중간에 결제와 상품, 정산에 대한 정책이 변경이 된다고 해도 각 관련 클래스 객체들을 수정할 필요없이 delegator만 수정을 해주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1678190621574&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import{ Order, OrderMapper } from '../orders/order.ts'
import{ policyDelegator } from '../orders/policy.ts'

export class payoutService implements IserverAPI {
    private orderRepo: IorderRepo
    private payoutRepo: IpayoutRepo
    private serviceErr: orderServiceError
    public delegator: Idelegator
    
    constructor(orderRepo:IorderRepo, payoutRepo:IpayoutRepo, delegator:policyDelegator){
       this.orderRepo = orderRepo
       this.payoutRepo = payoutRepo
       this.delegator = policyDelegator
    }
    
    public async excute(dto:GeneratePayoutDTO): Promise&amp;lt;payout&amp;gt;{
        try{
            const processed_items = []
            // 아이디 값에 해당하는 아이템 데이터를 가져온다
            const order_items = await this.orderRepo.getItemsById(dto.order_id)
            order_items.forEach((item)=&amp;gt;{
                // Mapper를 통해서 원하는 형태로 데이터 가공
                const result = OrderMapper(item)
                //가공된 정보에서 delegator를 통해서 개별 데이터의 정산금액을 계산해준다.
                const processed_result = result.map((el)=&amp;gt; this.delegator(el))
                processed_items.push(processed_result)
            })
            // 정산 데이터 생성에 대한 Promise 값을 리턴한다.
            return this.payoutRepo.createPayouts(processed_items)
        
        } catch(e) {
            console.log(e)
            return this.serviceErr.payoutCreateFail(dto.id)
        }
    }
}&lt;/code&gt;&lt;/pre&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;delegate pattern의 장점은 다음과 같습니다.&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;&amp;nbsp;커뮤니케이션 과정에서 불필요한 리소스 낭비를 줄이고 로직 흐름 이해가 쉬워집니다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;n:n 대응으로 이벤트를 처리할 때는 오히려 더 복잡해질 수 있다.&lt;/li&gt;
&lt;li&gt;원형 프로토콜이 정해지면 해당 프로토콜의 형태로 사용해야하기 때문에 큰 변경에 대해서는 위임을 주고 있는 연결된 객체들과 유기적으로 유지보수가 이루어져야 한다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Node.js</category>
      <author>Hot Dobby</author>
      <guid isPermaLink="true">https://hot-dobby.tistory.com/87</guid>
      <comments>https://hot-dobby.tistory.com/87#entry87comment</comments>
      <pubDate>Tue, 7 Mar 2023 20:59:00 +0900</pubDate>
    </item>
    <item>
      <title>데코 데코니~ NestJS 데커레이터  </title>
      <link>https://hot-dobby.tistory.com/85</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;giphy.gif&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BJmh6/btrXFui8c9y/KS4VA20CErB6f2oaUxkEkk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BJmh6/btrXFui8c9y/KS4VA20CErB6f2oaUxkEkk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BJmh6/btrXFui8c9y/KS4VA20CErB6f2oaUxkEkk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/BJmh6/btrXFui8c9y/KS4VA20CErB6f2oaUxkEkk/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;300&quot; height=&quot;228&quot; data-filename=&quot;giphy.gif&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Decorator 데커레이터&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바의 애너테이션과 유사한 기능을 한다고 한다. 각 요소의 선언부 앞에 @로 시작하며 선언된 요소가 호출 될 때, 데커레이터에 구현된 코드도 함께 실행된다.&lt;/p&gt;
&lt;pre id=&quot;code_1675064437942&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const deco = (target:any, propertyKey: string, descriptor: PropertyDescriptor) =&amp;gt; {
    console.log('핫도비 데코!!')
};

class TestClass {
    @deco
    testMethod() {
        console.log('테스트 메소드 호출!')
    }
}

const t = new TestClass()
t.testMethod()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2023-01-30 at 4.41.02 PM.png&quot; data-origin-width=&quot;552&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YfHs2/btrXrTj0tqu/jZyOwhqtywJykKFN5bekb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YfHs2/btrXrTj0tqu/jZyOwhqtywJykKFN5bekb1/img.png&quot; data-alt=&quot;실행 후 터미널&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YfHs2/btrXrTj0tqu/jZyOwhqtywJykKFN5bekb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYfHs2%2FbtrXrTj0tqu%2FjZyOwhqtywJykKFN5bekb1%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;405&quot; height=&quot;185&quot; data-filename=&quot;Screenshot 2023-01-30 at 4.41.02 PM.png&quot; data-origin-width=&quot;552&quot; data-origin-height=&quot;252&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;이러한 데커레이터는 합성해서 사용할 수 있는데, 하나의 메소드를 실행시킬 때 2개의 데커레이터를 실행시킬 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1675064906011&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function first() {
    console.log('first')
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log('frist(): called')
    }
}

function second() {
    console.log('second')
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log('second(): called')
    }
}

class ExampleClass {
    @first()
    @second()
    method() {
        console.log('method is called')
    }
}

const t = new ExampleClass()
t.method()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2023-01-30 at 4.48.45 PM.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPjKNm/btrXt97SS5e/VE2wNuMIjvDwmqioHdkyqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPjKNm/btrXt97SS5e/VE2wNuMIjvDwmqioHdkyqK/img.png&quot; data-alt=&quot;실행 후 터미널&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPjKNm/btrXt97SS5e/VE2wNuMIjvDwmqioHdkyqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPjKNm%2FbtrXt97SS5e%2FVE2wNuMIjvDwmqioHdkyqK%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;292&quot; height=&quot;310&quot; data-filename=&quot;Screenshot 2023-01-30 at 4.48.45 PM.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;424&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;데커레이터의 평가는 위에서 아래로 이러우지기 때문에 &quot;first&quot;, &quot;second&quot; 순으로 콘솔은 찍히지만 실제로 실행한 결과 값은 아래에서 위로 호출되기 때문에 second called 부터 뜨는 것을 볼 수 있다!&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;pre id=&quot;code_1675130198474&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function checkVaildPayment&amp;lt;T extends { new (...args: any[]): {}}&amp;gt;(constructor: T) {
    return class extends constructor {
        checked = false
    }
}

@checkVaildPayment
class purchase {
    type = &quot;book&quot;
    title: string

    constructor(title: string) {
        this.title = title
    }
}

const payment = new purchase(&quot;연을 쫓는 아이&quot;)
console.log(payment)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2023-01-31 at 11.08.36 AM.png&quot; data-origin-width=&quot;1082&quot; data-origin-height=&quot;152&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WvifV/btrXCHCovEv/zXpX1SHHInNQsqGiSVx5Ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WvifV/btrXCHCovEv/zXpX1SHHInNQsqGiSVx5Ck/img.png&quot; data-alt=&quot;실행 후 터미널&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WvifV/btrXCHCovEv/zXpX1SHHInNQsqGiSVx5Ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWvifV%2FbtrXCHCovEv%2FzXpX1SHHInNQsqGiSVx5Ck%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;526&quot; height=&quot;74&quot; data-filename=&quot;Screenshot 2023-01-31 at 11.08.36 AM.png&quot; data-origin-width=&quot;1082&quot; data-origin-height=&quot;152&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;purchase 클래스가 새롭게 선언이 될 때마다 checkValidPayment를 실행시켜서 checked 속성이 추가되는 것처럼 결제 로직을 만들 때, 새로운 클래스 생성에 대해서 체인처럼 특정 함수를 실행 시켜서 값을 도출하고, 클래스 속성을 수정할 수 있다.&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;pre id=&quot;code_1675139156695&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Enumerable(enumerable: boolean) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        descriptor.enumerable = enumerable
    }
}

class Person {
    constructor(public name: string) {
    }

    @Enumerable(false)
    sayHello() {
        console.log(`Hello, ${this.name}`)
    }

    @Enumerable(false)
    set setName(name: string) {
        this.name = name
    }

    @Enumerable(true)
    get getName() {
        return this.name
    }
}

const korean = new Person('kkagdugi')
for(const key in korean) {
    console.log(key, korean[key])
}
korean.sayHello()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2023-01-31 at 2.57.18 PM.png&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSrI0A/btrXCICqvpQ/w7wXU2ctAUQklTwrxU8dtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSrI0A/btrXCICqvpQ/w7wXU2ctAUQklTwrxU8dtk/img.png&quot; data-alt=&quot;Enumerable을 다 true로 했을 때 터미널&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSrI0A/btrXCICqvpQ/w7wXU2ctAUQklTwrxU8dtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSrI0A%2FbtrXCICqvpQ%2Fw7wXU2ctAUQklTwrxU8dtk%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;519&quot; height=&quot;263&quot; data-filename=&quot;Screenshot 2023-01-31 at 2.57.18 PM.png&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;430&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Enumerable을 다 true로 했을 때 터미널&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접근자 데커레이터는 객체의 property를 읽고, 쓰고 할 수 있는 접근자에 붙여서 사용할 수 있는 데커레이터로 예시로 만든@Enumerable의 참, 거짓에 따라 콘솔 출력이 되고 안되고를 확인할 수 있다.&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;데커레이터를 함수의 매개변수 앞에도 사용할 수 있으며, 단독으로 사용할 때 보다 함수 데커레이터와 함께 사용할 때 그 시너지가 커지게 된다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1675146603481&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@searchLog(uid)
function validateAction(@isPublic(uid) name: string) {
    return this.action
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Node.js</category>
      <author>Hot Dobby</author>
      <guid isPermaLink="true">https://hot-dobby.tistory.com/85</guid>
      <comments>https://hot-dobby.tistory.com/85#entry85comment</comments>
      <pubDate>Tue, 31 Jan 2023 15:32:08 +0900</pubDate>
    </item>
    <item>
      <title>AWS 쿠버네티스 핸즈온 워크샵!  EKS 빠르게 찍먹해보자</title>
      <link>https://hot-dobby.tistory.com/84</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_1974.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Eomgi/btrQCUoVT0w/e0E8xwE3A8eGNha8iK88rk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Eomgi/btrQCUoVT0w/e0E8xwE3A8eGNha8iK88rk/img.jpg&quot; data-alt=&quot;컨테이너로 서비스 배포할 생각에 가슴이 도키도커!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Eomgi/btrQCUoVT0w/e0E8xwE3A8eGNha8iK88rk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEomgi%2FbtrQCUoVT0w%2Fe0E8xwE3A8eGNha8iK88rk%2Fimg.jpg&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;427&quot; height=&quot;427&quot; data-filename=&quot;IMG_1974.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;컨테이너로 서비스 배포할 생각에 가슴이 도키도커!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;intro&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;금일 코엑스에서 진행한 aws EKS 관련 워크샵에 참석하고 나서&amp;nbsp; 다시 생각하면 좋을 내용을 정리했습니다. &lt;span style=&quot;background-color: #ffffff;&quot;&gt;  필자는 예전에 서비스를 ECS로 운영을 해본 경험이 있어서 사용하면서 있었으면 했던 부분들이 EKS에 있는 것을 보며 새로웠습니다.&amp;nbsp;&lt;br /&gt;&amp;nbsp;워크샵 당시 시간이 부족해서 내용들이 빠르게 지나갔는데 EKS를 도입한다면 알아야할 기본 개념과 워크샵 당시 추천해준 툴의 패스트 가이드를 공유합니다!&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;So Why K8s and Why EKS?&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-11-07 오후 5.21.00.png&quot; data-origin-width=&quot;1476&quot; data-origin-height=&quot;1186&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDIKhh/btrQDPtegnR/wFJJAQvO2a9Ajkeah35Mg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDIKhh/btrQDPtegnR/wFJJAQvO2a9Ajkeah35Mg0/img.png&quot; data-alt=&quot;Conception of Node in k8s&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDIKhh/btrQDPtegnR/wFJJAQvO2a9Ajkeah35Mg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDIKhh%2FbtrQDPtegnR%2FwFJJAQvO2a9Ajkeah35Mg0%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;463&quot; height=&quot;372&quot; data-filename=&quot;스크린샷 2022-11-07 오후 5.21.00.png&quot; data-origin-width=&quot;1476&quot; data-origin-height=&quot;1186&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Conception of Node in k8s&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k8s, 쿠버네티스가 길다고 줄인 단어라고 합니다. 우리가 보통 서버를 만들고 배포를 한다고 하면 서버가 돌아가는 '인스턴스'를 사람들이 접속할 수 있는 퍼블릭한 클라우드 컴퓨팅 서비스에 올리거나 자체 서버 포트에 연결하는 것을 생각합니다. 쿠버네티스는 이러한 서버 단위를 컨테이너로 만들어서 Pod, Node로 관리하여 대용량 트래픽과 서비스 운영을 보다 효율적으로 하기 위해서&amp;nbsp;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;컨테이너화된 워크로드와 서비스를 관리하기 위한 오픈 플랫폼 서비스라 생각하시면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-11-07 오후 5.08.09.png&quot; data-origin-width=&quot;1368&quot; data-origin-height=&quot;766&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kUqS7/btrQvZEvaJ8/Y5jkiUrYc2rqzGaWKwuotK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kUqS7/btrQvZEvaJ8/Y5jkiUrYc2rqzGaWKwuotK/img.png&quot; data-alt=&quot;출처: Techtarget&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kUqS7/btrQvZEvaJ8/Y5jkiUrYc2rqzGaWKwuotK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkUqS7%2FbtrQvZEvaJ8%2FY5jkiUrYc2rqzGaWKwuotK%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;598&quot; height=&quot;335&quot; data-filename=&quot;스크린샷 2022-11-07 오후 5.08.09.png&quot; data-origin-width=&quot;1368&quot; data-origin-height=&quot;766&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: Techtarget&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ECS, EKS 둘다 컨테이너 오케스트레이션 환경이라는 공통점은 있지만 ECS 같은 경우 AWS 내 서비스로만 사용해서 써야하기 때문에 호환성에 있어서 초큼 문제가 될 수 있다고 봅니다. (ECR에 이미지를 올려서 사용해야한다 든지...) 그렇기 때문에 EKS를 사용한다면 aws의 ECS를 사용하다가 클라우드 컴퓨팅 서비스를 변경하거나 비용 절감을 위한 다각도 전략을 사용하기 편리하다는 것 입니다.&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;&amp;nbsp;&lt;/h3&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;RBAC&amp;nbsp; ( Role Based Access Control)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;특정 애플리케이션을 실행 시키기 위한 Entity와 작업에 필요한 resource, Entity들의 작업 수행규친에 대한 Role을 가지고 Role binding을 진행하고 Name spaces(쿠버네티스의 보안경계 그룹)에 따라 Access를 조절하는 것을 RBAC라고 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* EKS를 사용하려면 전용 IAM을 role를 통해서 EKS 권한부여가 오히려 안전하다&lt;br /&gt;&lt;a href=&quot;https://www.eksworkshop.com/beginner/090_rbac/intro/&quot;&gt;자세한 내용은 여기! &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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ArgoCD&lt;/b&gt;&lt;/h3&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;스크린샷 2022-11-07 오후 8.58.25.png&quot; data-origin-width=&quot;1134&quot; data-origin-height=&quot;404&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cM2t5r/btrQD9Md8lV/qEWNriT2GGlTMzkRtCDOg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cM2t5r/btrQD9Md8lV/qEWNriT2GGlTMzkRtCDOg0/img.png&quot; data-alt=&quot;출처: https://kangwoo.kr/tag/argocd&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cM2t5r/btrQD9Md8lV/qEWNriT2GGlTMzkRtCDOg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcM2t5r%2FbtrQD9Md8lV%2FqEWNriT2GGlTMzkRtCDOg0%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;506&quot; height=&quot;180&quot; data-filename=&quot;스크린샷 2022-11-07 오후 8.58.25.png&quot; data-origin-width=&quot;1134&quot; data-origin-height=&quot;404&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: https://kangwoo.kr/tag/argocd&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ArgoCD는 쿠버네티스를 위한 CD툴로 Manifest 파일의 변경사항을 감지하여 현재 배포된 노드의 환경과 Github Repo의 최신 버전이 싱크가 된 상태를 유지할 수 있도록 도와준다. 터미널 CLI 환경에서 상태를 체크하기 어려움이 있는데 Argo CD를 위한 서버를 오픈한 다음에 브라우저에서 GUI로 보다 편리하게 사용할 수 있다는 장점이 있다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. argocd를 위한 namespace를 생성하고 argocd를 쿠버네티스 클러스터에 배포한다&lt;/p&gt;
&lt;pre id=&quot;code_1667823040897&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v2.4.7/manifests/install.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 배포가 제대로 되었는지 확인한다.&lt;/p&gt;
&lt;pre id=&quot;code_1667823113117&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubectl get all -n argocd&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. argocd CLI를 설치한다&lt;/p&gt;
&lt;pre id=&quot;code_1667823150480&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo curl --silent --location -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v2.4.7/argocd-linux-amd64

sudo chmod +x /usr/local/bin/argocd&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 서비스 타입을 로드벨런서로 설정한다 (로드밸런서 생성을 위해 삽분 기다려주는 것을 추천!)&lt;/p&gt;
&lt;pre id=&quot;code_1667823215955&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubectl patch svc argocd-server -n argocd -p '{&quot;spec&quot;: {&quot;type&quot;: &quot;LoadBalancer&quot;}}'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. nodeport 설정을 해준다&lt;/p&gt;
&lt;pre id=&quot;code_1667823345704&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubestl patch svc argocd-server -n argocd -p '{&quot;spec&quot;: {&quot;type&quot;: &quot;NodePort&quot;}}'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. Ingress 설정을 해준다 &lt;a href=&quot;https://argo-cd.readthedocs.io/en/stable/operator-manual/ingress/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;가이드 참조!&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1667823384299&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;Ingress Configuration - Argo CD - Declarative GitOps CD for Kubernetes&quot; data-og-description=&quot;Ingress Configuration Argo CD API server runs both a gRPC server (used by the CLI), as well as a HTTP/HTTPS server (used by the UI). Both protocols are exposed by the argocd-server service object on the following ports: 443 - gRPC/HTTPS 80 - HTTP (redirect&quot; data-og-host=&quot;argo-cd.readthedocs.io&quot; data-og-source-url=&quot;https://argo-cd.readthedocs.io/en/stable/operator-manual/ingress/&quot; data-og-url=&quot;https://argo-cd.readthedocs.io/en/stable/operator-manual/ingress/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://argo-cd.readthedocs.io/en/stable/operator-manual/ingress/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://argo-cd.readthedocs.io/en/stable/operator-manual/ingress/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;Ingress Configuration - Argo CD - Declarative GitOps CD for Kubernetes&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Ingress Configuration Argo CD API server runs both a gRPC server (used by the CLI), as well as a HTTP/HTTPS server (used by the UI). Both protocols are exposed by the argocd-server service object on the following ports: 443 - gRPC/HTTPS 80 - HTTP (redirect&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;argo-cd.readthedocs.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. Port Fowarding 설정&lt;/p&gt;
&lt;pre id=&quot;code_1667823447880&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubestl port-forward svc/argocd-server -n argocd 8080:443&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8. IP주소 및 포트확인!&lt;/p&gt;
&lt;pre id=&quot;code_1667823506804&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kubestl describe svc argocd-server -n argocd&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9. 아이디는 admin 비밀번호는 터미널 결과 참조!&lt;/p&gt;
&lt;pre id=&quot;code_1667823569959&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export ARGO_PWD=`kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath=&quot;{.data.password}&quot; | base64 -d`&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;helm(쿠버네티스 패키지 매니저)&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-11-07 오후 9.20.40.png&quot; data-origin-width=&quot;614&quot; data-origin-height=&quot;594&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baJvmv/btrQDwOAGza/d3KKb1LI7pftvTQtBeHUNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baJvmv/btrQDwOAGza/d3KKb1LI7pftvTQtBeHUNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baJvmv/btrQDwOAGza/d3KKb1LI7pftvTQtBeHUNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaJvmv%2FbtrQDwOAGza%2Fd3KKb1LI7pftvTQtBeHUNK%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;185&quot; data-filename=&quot;스크린샷 2022-11-07 오후 9.20.40.png&quot; data-origin-width=&quot;614&quot; data-origin-height=&quot;594&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;helm은 쉽게 말하자면 쿠버네티스에게 nodeJS 의 npm, yarn과 비슷한 존재라고 생각하면 된다&lt;/b&gt;. YAML 형식으로 이루어져 있으며 이것을 chart라고 한다. chart에는 values.yaml과 templates 디렉토리가 있다. values.yaml에는 사용자가 원하는 설정 값들이 변수처럼 저장되어 있으며, 이를 터미널 상에서 환경변수처럼 사용이 가능하다. templates 디렉토리에는 설치할 리소스 파일이 존재한다.&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;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;helm을 잘 활용하면 오픈소스 애플리케이션도 손쉽게 내 소유의 쿠버네티스 클러스터로 가져올 수 있다. &lt;b&gt;도커가 단순히 프로세스 레벨에서 외부의 것을 가져다 쓸 수 있게 해준것이라면, 쿠버네티스에서는 helm을 이용하여 애플리케이션에서 필요한 모든 자원들을 외부에서 가져올 수 있게 한다.&lt;/b&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;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;br /&gt;&lt;/span&gt;이에대한 실습은 아래 링크에서 자세하게 할 수 있다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.eksworkshop.com/beginner/060_helm/helm_micro/create_chart/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.eksworkshop.com/beginner/060_helm/helm_micro/create_chart/&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;p data-ke-size=&quot;size16&quot;&gt;이외 중요하게 기억하고 넘어갈 요소들은 AWS에서 발표자료를 이메일로 보내주면 추가보충하려고 한다!&lt;/p&gt;</description>
      <category>Basic Web Servie</category>
      <author>Hot Dobby</author>
      <guid isPermaLink="true">https://hot-dobby.tistory.com/84</guid>
      <comments>https://hot-dobby.tistory.com/84#entry84comment</comments>
      <pubDate>Mon, 7 Nov 2022 21:36:26 +0900</pubDate>
    </item>
    <item>
      <title>DDR-forum // 파트 1. 소프트웨어와 디자인</title>
      <link>https://hot-dobby.tistory.com/82</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-10-24 오후 5.56.03.png&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;568&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ce011I/btrPtvplb9f/Uv89eogDFIwQ3wG5c2TV11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ce011I/btrPtvplb9f/Uv89eogDFIwQ3wG5c2TV11/img.png&quot; data-alt=&quot;Thanks to Khalil Stemmler&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ce011I/btrPtvplb9f/Uv89eogDFIwQ3wG5c2TV11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fce011I%2FbtrPtvplb9f%2FUv89eogDFIwQ3wG5c2TV11%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;252&quot; height=&quot;230&quot; data-filename=&quot;스크린샷 2022-10-24 오후 5.56.03.png&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;568&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Thanks to Khalil Stemmler&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/stemmlerjs/ddd-forum&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/stemmlerjs/ddd-forum&lt;/a&gt; 해당 소스를 활용하려는 한국인 개발자분들을 위해서 공유합니다!&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Coupling causing Complexity&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dependencies, 종속성을 가지는 컴포넌트, 함수들이 단단히 결합하고 있는 구조에서는 분해하기가 모호해지기 때문에 복잡성이 증가할 수 밖에 없습니다. 클래스의 결합, 시간적 결합(동작에 있어서 순서가 중요한 비동기적 코드 실행), 동기적 결합 등이 소스에 진하게 남아있으면, 디자인을 하기도 어려울뿐만 아니라 유지보수와 확정성에 있어서도 패널티를 가지게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-10-24 오후 5.50.34.png&quot; data-origin-width=&quot;1288&quot; data-origin-height=&quot;692&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bacvlG/btrPmDCz2qG/UkHeNbXlstkPSudNka1iik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bacvlG/btrPmDCz2qG/UkHeNbXlstkPSudNka1iik/img.png&quot; data-alt=&quot;출처: https://wiki.solidbook.io&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bacvlG/btrPmDCz2qG/UkHeNbXlstkPSudNka1iik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbacvlG%2FbtrPmDCz2qG%2FUkHeNbXlstkPSudNka1iik%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;504&quot; height=&quot;271&quot; data-filename=&quot;스크린샷 2022-10-24 오후 5.50.34.png&quot; data-origin-width=&quot;1288&quot; data-origin-height=&quot;692&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: https://wiki.solidbook.io&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 이러한 결합을 하는 대상이 낮은 응집력을 가지고 있다면 그 문제는 더 커지게 됩니다. 부정확한 의미의 변수, 너무 추상화된 코드, 불필요한 정보 저장을 피하면서 서비스 소스의 응집력을 높게 유지하면서 각각의 dependency가 결합을 느슨하게 가져갈 수 있도록 구조를 디자인 해야합니다.&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;How to reduce the Complexity then??&lt;/b&gt;&lt;/h3&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;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;Java사의 &lt;span style=&quot;color: #000000;&quot;&gt;Sun Microsystems씨가 소프트웨어 평생 비용의 40~80%를 유지관리 및 보수에 사용하고 코드 설계자가 끝까지 책임지는 경우는 절대 없기 때문에 개발을 할 때 50%는 신규 개발, 50%는 유지보수를 위한 자원관리에 사용해야하는 것을 추천하고 있습니다. 복잡한 코드는 결국 인수인계자의 이해에 어려움을 주기 때문에 복잡하지 않으면서도 캡슐, 모듈화가 잘 되어있는 소스가 좋은 소스라고 볼 수 있습니다.&lt;/span&gt;&lt;/span&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;- Extreme Programming&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;익스트림 프로그래밍(XP)를 통하여 효율적으로 feature를 개발하여 시장에 빠르게 침투하는 것이 거친 생태계에서 살아남기 좋은 방법이 될 수 있습니다.&amp;nbsp;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-10-25 오전 10.37.51.png&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;612&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdfeg6/btrPrqbYbea/0o8JKb7wvvz3xkO5e9NFw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdfeg6/btrPrqbYbea/0o8JKb7wvvz3xkO5e9NFw0/img.png&quot; data-alt=&quot;출처: https://wiki.solidbook.io&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdfeg6/btrPrqbYbea/0o8JKb7wvvz3xkO5e9NFw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbdfeg6%2FbtrPrqbYbea%2F0o8JKb7wvvz3xkO5e9NFw0%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;269&quot; height=&quot;249&quot; data-filename=&quot;스크린샷 2022-10-25 오전 10.37.51.png&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;612&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: https://wiki.solidbook.io&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; 1. 피드백 : &lt;span style=&quot;color: #000000;&quot;&gt;페어 프&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;로그래밍을 도입하여 개발자 서로가 피드백을 주면서 소스를 작성할 수 있는 환경 조성&lt;br /&gt;&amp;nbsp; &amp;nbsp; 2. TDD: &lt;span style=&quot;color: #000000;&quot;&gt;Test-driven development을 통한 신규 피쳐 개발로 테스트 실패 케이스 분석을 통한 설계로 신규 기능을 추가&lt;br /&gt;&amp;nbsp; &amp;nbsp; 3. 지속적인 통합: CI라고도 하며 형상관리를 주기적으로 하면서 리펙토링, 소규모 릴리즈를 안정적으로 출시&lt;br /&gt;&amp;nbsp; &amp;nbsp; 4. Programmer welfare: 칭찬은 고래도 춤추게 만든다는 말처럼 좋은 개발자는 좋은 환경, 좋은 복지에서 성과가 호로록!&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <author>Hot Dobby</author>
      <guid isPermaLink="true">https://hot-dobby.tistory.com/82</guid>
      <comments>https://hot-dobby.tistory.com/82#entry82comment</comments>
      <pubDate>Mon, 24 Oct 2022 18:48:41 +0900</pubDate>
    </item>
    <item>
      <title>Typescript 환경에서 Jest 사용하기!</title>
      <link>https://hot-dobby.tistory.com/81</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;clown.gif&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;266&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A3mFN/btrOQCcUoQX/LkVQZmcDoqcWpwwatB1CT0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A3mFN/btrOQCcUoQX/LkVQZmcDoqcWpwwatB1CT0/img.gif&quot; data-alt=&quot;jest를 사용해보자!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A3mFN/btrOQCcUoQX/LkVQZmcDoqcWpwwatB1CT0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/A3mFN/btrOQCcUoQX/LkVQZmcDoqcWpwwatB1CT0/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;480&quot; height=&quot;266&quot; data-filename=&quot;clown.gif&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;266&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;jest를 사용해보자!&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;Typescript + express 환경에서 jest를 사용하려고 하다보니 실수를 연발해서 여기에 정리합니다. &lt;span style=&quot;background-color: #ffffff;&quot;&gt; &amp;zwj;♂️&lt;/span&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;1. jest 설치하기&amp;nbsp;&lt;/h4&gt;
&lt;pre id=&quot;code_1666254725627&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;yarn add jest @types/jest&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;jest를 설치 해주셨다면 이제 test.js or spec.js로 테스트 코드를 작성 하실 수 있습니다! package.json에 가셔서 &quot;jest&quot; 명령어 스크립트를 추가해주신 다음에 터미널에서 실행시키면 해당 레파지토리가 가지고 있는 테스트 파일을 읽어서 한 번에 테스트를 진행해줍니다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666256863662&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  &quot;scripts&quot;: {
    &quot;start&quot;: &quot;node dist/app.js&quot;,
    &quot;build&quot;: &quot;tsc -p .&quot;,
    &quot;dev&quot;: &quot;nodemon --watch \&quot;src/**/*.ts\&quot; --exec \&quot;ts-node\&quot; src/app.ts&quot;,
    &quot;test&quot;: &quot;jest&quot;  // 이렇게 jest 명령어를 추가해주세요!!
  },

//사용하실 때는 &quot;yarn run test&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;저는 지금 API테스트를 위해서 jest를 사용하기 때문에 user path에 signin api에 대해서 테스트를 진행 해보겠습니다.&lt;span style=&quot;background-color: #ffffff;&quot;&gt; &lt;/span&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;span style=&quot;background-color: #ffffff;&quot;&gt;2. Test 작성하기&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-10-20 오후 5.39.07.png&quot; data-origin-width=&quot;462&quot; data-origin-height=&quot;262&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvMTLg/btrOQsnW5CL/d5xRbGRcGDk1T2dNsu1kW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvMTLg/btrOQsnW5CL/d5xRbGRcGDk1T2dNsu1kW1/img.png&quot; data-alt=&quot;/src/routes/path/user&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvMTLg/btrOQsnW5CL/d5xRbGRcGDk1T2dNsu1kW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvMTLg%2FbtrOQsnW5CL%2Fd5xRbGRcGDk1T2dNsu1kW1%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;279&quot; height=&quot;158&quot; data-filename=&quot;스크린샷 2022-10-20 오후 5.39.07.png&quot; data-origin-width=&quot;462&quot; data-origin-height=&quot;262&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;/src/routes/path/user&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;user.controller 에 signin 로직을 처리하는 함수가 있고, user.query에 로그인을 위한 데이터쿼리가 있는 구조입니다. 여기서 signin에 대한 테스트를 진행하기 위해서 user.test.js와 useCase로 사용할 user.test.json 파일을 만들었습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1666258543530&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const testJSON = require(&quot;./user.test.json&quot;)
import { signin } from &quot;./user.controller&quot;;

describe('signin', () =&amp;gt; {
    test(&quot;user_id is string&quot;, () =&amp;gt; {
        expect(typeof testJSON.singin_test_1.user_id).toBe('string');
    });
    
    test(&quot;password exists&quot;, () =&amp;gt; {
        expect(!testJSON.singin_test_1.password).toBe(false)
    });
    
    test(&quot;sigin test&quot;, () =&amp;gt; {
        const result = signin(testJSON.singin_test_2);
        expect(result.user_id).toBe(testJSON.singin_test_1.user_id)
        expect(!result.uid).toBe(false)
    });
});

//user.test.json 은 아래와 같습니다.
{
    &quot;singin_test_1&quot;: {
        &quot;user_id&quot;: &quot;01012345678&quot;,
        &quot;password&quot;: &quot;abc123&quot;
    },
    &quot;singin_test_2&quot;: {
        &quot;user_id&quot;: &quot;01046237733&quot;,
        &quot;password&quot;: &quot;lolbook123&quot;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아주 간단한 테스트를 작성했는데, 만약 위 테스트 파일 대로 만든다면 문제가 하나 있을겁니다! 바로 user.controller.ts에서 signin 함수를 import 하는데 계속해서 에러가 발생할 것 입니다. 그렇기 때문에 jest.config와 babel.config를 작성해서 test.js 파일에서 모듈을 불러올 수 있도록 해야합니다. 킹 받게 만들려는건 아니고 처음 yarn package를 설치할 때 필요한 package를 다 설치하면 이러한 문제를 알 수 없기 때문에 지금 단계에서 알려드리는 겁니다.&lt;span style=&quot;background-color: #ffffff;&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666259013256&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;yarn add babel-jest @babel/core @babel/plugin-transform-modules-commonjs @babel/plugin-transform-runtime @babel/preset-env @bable/preset-typescript&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 data-ke-size=&quot;size16&quot;&gt;계속 업데이트 중이니 기다려주세요!!&lt;/p&gt;</description>
      <category>기초  Java Script</category>
      <author>Hot Dobby</author>
      <guid isPermaLink="true">https://hot-dobby.tistory.com/81</guid>
      <comments>https://hot-dobby.tistory.com/81#entry81comment</comments>
      <pubDate>Thu, 20 Oct 2022 18:54:31 +0900</pubDate>
    </item>
    <item>
      <title>TDD를 생각한다면 꼭 한 번 먼저 봤으면 하는 이야기 ft.이규원 TDD 강의</title>
      <link>https://hot-dobby.tistory.com/80</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;모듈화를 통한 정보숨김&lt;/b&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;간접입력 &amp;amp;&amp;amp; 간접출력&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-10-20 오전 11.26.58.png&quot; data-origin-width=&quot;615&quot; data-origin-height=&quot;586&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3snnf/btrOQn0oSsd/lBXMR7MGMbPfGBCktZ94kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3snnf/btrOQn0oSsd/lBXMR7MGMbPfGBCktZ94kk/img.png&quot; data-alt=&quot;주황: 간접입력&amp;amp;nbsp; 연두: 간접출력&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3snnf/btrOQn0oSsd/lBXMR7MGMbPfGBCktZ94kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3snnf%2FbtrOQn0oSsd%2FlBXMR7MGMbPfGBCktZ94kk%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;411&quot; height=&quot;392&quot; data-filename=&quot;스크린샷 2022-10-20 오전 11.26.58.png&quot; data-origin-width=&quot;615&quot; data-origin-height=&quot;586&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;주황: 간접입력&amp;nbsp; 연두: 간접출력&lt;/figcaption&gt;
&lt;/figure&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Sociable 테스트 VS Solitary 테스트&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sociable 테스트는 의존성이 있는 로직 , 테스트 할려고 하는 단위를 운영에서 사용하는 그대로 사용하는 것을 말하고 solitary는 따로 테스트 환경을 만들어서 테스트를 한다고 간단하게 말 할 수 있다. 그렇다면 solitary 테스트가 더 안전하고 효율적으로 보일 수 있으나 '가정의 안정도'에 따라 테스트 대역의 복잡도에 따라서 안정도가 낮아져서 원하는 테스트를 구현하지 못 할 가능성이 커진다!&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-10-20 오후 2.04.38.png&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;236&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqbXKm/btrOGoZ2ua0/tqT5klfRMzYVgnKi6Yg4l0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqbXKm/btrOGoZ2ua0/tqT5klfRMzYVgnKi6Yg4l0/img.png&quot; data-alt=&quot;출처:&amp;amp;nbsp;https://algopoolja.tistory.com/119&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqbXKm/btrOGoZ2ua0/tqT5klfRMzYVgnKi6Yg4l0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqbXKm%2FbtrOGoZ2ua0%2FtqT5klfRMzYVgnKi6Yg4l0%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;782&quot; height=&quot;236&quot; data-filename=&quot;스크린샷 2022-10-20 오후 2.04.38.png&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;236&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처:&amp;nbsp;https://algopoolja.tistory.com/119&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;코드 적응력&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈화가 잘 되어있고, 정리가 잘 되어서 협업자가 이해하고 읽기 쉬운 구조와 컨벤션을 가지고 있으면서 분리, 분해, 재설계, 활용이 쉬울수록 코드 적응력이 높다고 표현한다. 단위 테스트를 잘 진행하기 위해서는 하위 시스템을 잘 분리할 수 있어야 하며, 개방-폐쇄 원칙 (Open-Closed principle)의 원칙을 따라 모듈들은 확장에 대해서는 열려 있고, 수정에 있어서는 닫혀 있어야한다. 이는 typescript에서 extend의 개념처럼 상속을 받아 추가할 살을 덧 붙이고, 부모 객체에 대해서는 수정을 남용하는 것을 막는 것이 좋은 것과 같은 맥락이다.&lt;/p&gt;</description>
      <category>기초  Java Script</category>
      <author>Hot Dobby</author>
      <guid isPermaLink="true">https://hot-dobby.tistory.com/80</guid>
      <comments>https://hot-dobby.tistory.com/80#entry80comment</comments>
      <pubDate>Thu, 20 Oct 2022 14:44:33 +0900</pubDate>
    </item>
  </channel>
</rss>