<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Alphahacker Notes</title>
    <link>https://alphahackerhan.tistory.com/</link>
    <description>https://profile.amazing-han.com/</description>
    <language>ko</language>
    <pubDate>Thu, 16 Apr 2026 11:06:34 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>알파해커 테크노트</managingEditor>
    <image>
      <title>Alphahacker Notes</title>
      <url>https://tistory1.daumcdn.net/tistory/2645966/attach/6c10990b8ef14bd5b5741fdef15689ac</url>
      <link>https://alphahackerhan.tistory.com</link>
    </image>
    <item>
      <title>[패스트캠퍼스 + 온라인 강의 완강 후기] 시그니처 프론트엔드 : 웹 개발부터 웹앱까지 프론트엔드의 모든 것</title>
      <link>https://alphahackerhan.tistory.com/72</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;나는 그동안 백엔드 개발/운영을 메인으로 업무를 수행해왔다. 덕분에 프론트엔드 관련 작업은 접할 기회가 많지 않았었고, 종종 그런 것들이 엔지니어로서는 아쉽게 다가온 적이 있었다. 특히 요즘 시대 개발자 혹은 소프트웨어 엔지니어들은 특정 스택이나 사이드 쪽에만 국한되었을때 성장의 한계가 명확하다고 생각한다. 예전과는 다르게, 요즘은 다양한 클라우드 서비스와 프레임워크 그리고 AI 서비스를 통해, 누구나 쉽게 프론트 엔드나 백엔드를 생성/운영할 수 있게 되었기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난 더 늦어지기 전에 프론트엔드 학습을 제대로 한번 해봐야겠다는 생각을 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐면,&amp;nbsp;우선은 내가 현업에서 주로 백엔드만 할지라도  풀스택을 이해하고 있는 것과 아닌 것은 요구사항을 파악하고, 아키텍쳐를 도출하는데 있어서 많은 차이가 있을 거라 생각한다. 그리고, 앞으로 더 많은 기능을 AI나 SaaS가 대체하더라도 그 내부를 제대로 이해하고 있지 못한다면 제대로 활용할 수 없을 거라는 생각이었다.&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;AI, SaaS 서비스의 발전 속도 및 생성 속도는 눈부시게 빨랐다. 나는 더는 지체할 수 없었고, 인터넷 검색과 책을 일일이 열어서 파악하기에 직장인인 나는 시간이 많지 않았다. 떠먹기만 하면 되는 정리된 자료가 필요했고, 그렇게 패스트캠퍼스 강의를 찾게 되었다.&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;내가 찾은 것은 &quot;시그니쳐 프론트엔드: 웹 개발부터 웹앱까지 프론트엔드의 모든 것&quot;이라는 강의이다. 패스트캠퍼스에서 웹, 웹앱, 자바스크립트, 타입스크립트, 게다가 CS 기본지식까지 한번에 다 가르쳐주는 강의는 거의 이것이 유일하지 않나 싶다.&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-12-05 오전 10.49.42.png&quot; data-origin-width=&quot;1545&quot; data-origin-height=&quot;1283&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DYuTh/btsK73cp2f6/x6jqMUeyP7CcD7LoVX1ldk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DYuTh/btsK73cp2f6/x6jqMUeyP7CcD7LoVX1ldk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DYuTh/btsK73cp2f6/x6jqMUeyP7CcD7LoVX1ldk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDYuTh%2FbtsK73cp2f6%2Fx6jqMUeyP7CcD7LoVX1ldk%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;1545&quot; height=&quot;1283&quot; data-filename=&quot;스크린샷 2024-12-05 오전 10.49.42.png&quot; data-origin-width=&quot;1545&quot; data-origin-height=&quot;1283&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프론트엔드의 대표적인 라이브러리인 React 뿐만 아니라, (현재 프론트엔드 시장을 지배?하고 있는) Next.js도 배울 수 있고 Vercel을 통해 쉽게 배포하는 방법까지 학습할 수 있다.&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;배운 내용은 써먹어봐야 내것이 된다는 생각이 있어서, 나름대로 사이드프로젝트를 하나 만들어 Next.js로 구현도 해봤다. 아래 이미지와 같이 나의 커리어를 소개하는 웹 페이지를 생성해서 배포까지 완료했다.(https://profile.amazing-han.com/)&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-12-05 오전 10.14.44.png&quot; data-origin-width=&quot;1069&quot; data-origin-height=&quot;1079&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TH5jx/btsK8siHQCZ/H6egR2XFVqOSYH4qvDmFWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TH5jx/btsK8siHQCZ/H6egR2XFVqOSYH4qvDmFWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TH5jx/btsK8siHQCZ/H6egR2XFVqOSYH4qvDmFWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTH5jx%2FbtsK8siHQCZ%2FH6egR2XFVqOSYH4qvDmFWk%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;1069&quot; height=&quot;1079&quot; data-filename=&quot;스크린샷 2024-12-05 오전 10.14.44.png&quot; data-origin-width=&quot;1069&quot; data-origin-height=&quot;1079&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;&amp;nbsp;&lt;/div&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;div style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-12-05 오전 10.56.42.png&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;520&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkDMi0/btsK7LJSt0Y/E6wioAil8tyiTxGtYkdQhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkDMi0/btsK7LJSt0Y/E6wioAil8tyiTxGtYkdQhK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkDMi0/btsK7LJSt0Y/E6wioAil8tyiTxGtYkdQhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkDMi0%2FbtsK7LJSt0Y%2FE6wioAil8tyiTxGtYkdQhK%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;737&quot; height=&quot;520&quot; data-filename=&quot;스크린샷 2024-12-05 오전 10.56.42.png&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;520&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;앞서 얘기했듯이, 특정 스택의 기술을 이용해서 업무를 한다 하더라도, 다른 스택에 대한 지식, 그리고 더 넓게는 CS에 대한 기본적인 이해가 있어야 더 좋은 아키텍쳐 생성과 개발이 가능하다.&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-12-05 오전 10.57.00.png&quot; data-origin-width=&quot;719&quot; data-origin-height=&quot;658&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c35f5d/btsK6uh4w8U/zcjhEzVqCkuZikEWk2UJyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c35f5d/btsK6uh4w8U/zcjhEzVqCkuZikEWk2UJyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c35f5d/btsK6uh4w8U/zcjhEzVqCkuZikEWk2UJyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc35f5d%2FbtsK6uh4w8U%2FzcjhEzVqCkuZikEWk2UJyk%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;719&quot; height=&quot;658&quot; data-filename=&quot;스크린샷 2024-12-05 오전 10.57.00.png&quot; data-origin-width=&quot;719&quot; data-origin-height=&quot;658&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;이 모든 것을 하나의 강의에서 할 수 있다는 것은 수강해야 하는 입장에선 더할나위 없이 좋다.&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;수강 후기: 나는 본 강의를 통해, 풀스택 엔지니어로서 자신감이 더해졌다. 앞으로는 사이드 프로젝트로라도 프론트엔드 개발을 좀 더 자주 다양한 방식으로 수행할 것이고, 본 강의에 있는 내용을 통해 빠르게 적용 가능하다고 본다(학습 후 특정 지식을 잊었다면 언제든 다시 와서 볼 수 있는 것도 패스트 캠퍼스의 장점이다). 그 경험을 통해 현업에서도 좀 더 확장된 영역에서 비즈니스에 기여할 수 있게되길 기대한다.&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백엔드 개발자라면, 본 강의를 수강한 후 풀스택 엔지니어로서 한단계 더 나아가보자. 이제 프론트엔드 개발자가 되고 싶은 분이라면, 여기 있는 내용을 모두 습득하는 것만으로도 훌륭한 엔지니어가 될 수 있을 것이다.&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;&lt;/div&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;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;본 게시물은 패스트캠퍼스 수강 후기 이벤트 참여를 위해 작성되었습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>etc</category>
      <author>알파해커 테크노트</author>
      <guid isPermaLink="true">https://alphahackerhan.tistory.com/72</guid>
      <comments>https://alphahackerhan.tistory.com/72#entry72comment</comments>
      <pubDate>Thu, 5 Dec 2024 11:30:02 +0900</pubDate>
    </item>
    <item>
      <title>[React Native] Expo 프로젝트 생성시 App.js 파일이 없는 경우</title>
      <link>https://alphahackerhan.tistory.com/71</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Expo가 버전 업그레이드 후, App.js 파일이 없어졌다.&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;App.js를 사용하는 방식 대신 다른 방식으로 그 기능을 대체했는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존의 방식대로 사용하고 싶으면 expo 프로젝트를 생성할때 명령어를 아래와 같이 &quot;--template blank&quot; 옵션을 추가하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1727789082982&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npx create-expo-app {project_name} --template blank&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Frontend/React</category>
      <author>알파해커 테크노트</author>
      <guid isPermaLink="true">https://alphahackerhan.tistory.com/71</guid>
      <comments>https://alphahackerhan.tistory.com/71#entry71comment</comments>
      <pubDate>Tue, 1 Oct 2024 22:24:51 +0900</pubDate>
    </item>
    <item>
      <title>[React Native] npx expo start 했을때, EMFILE: too many open files 에러 발생했을때</title>
      <link>https://alphahackerhan.tistory.com/70</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;npx create-expo-app {project_name} 을 이용해서 expo 프로젝트를 생성한 후, npx expo start를 했을때 다음과 같은 에러 발생&lt;/p&gt;
&lt;pre id=&quot;code_1727785905635&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Error: EMFILE: too many open files, watch
    at FSEvent.FSWatcher._handle.onchange (node:internal/fs/watchers:207:21)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통은 아래 명령어로 해결된다고 함.&lt;/p&gt;
&lt;pre id=&quot;code_1727786039209&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew install watchman&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;watchman은 페이스북이 만든 파일모니터링 도구. 맥오에스만 지원되고 파일 모니터링 하면서 변화가 감지됐을때 특정 작업을 처리하는 용도로 사용. 와치맨을 사용하면 더욱 높은 성능으로 파일을 모니터링할 수 있어서 사용을 권장한다고 함.&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;패키지들을 삭제하고 재설치하고, 컴퓨터를 껐다가 켜도 안되서, 더 찾아보니 작업하고 있는 프로젝트 디렉토리에서 npm install을 해보라는 얘기가 있어서 해봤더니 해결됨.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;785&quot; data-origin-height=&quot;390&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dylcx2/btsJSuWVLir/MBX7HUFiWsPE87WEuXllw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dylcx2/btsJSuWVLir/MBX7HUFiWsPE87WEuXllw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dylcx2/btsJSuWVLir/MBX7HUFiWsPE87WEuXllw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdylcx2%2FbtsJSuWVLir%2FMBX7HUFiWsPE87WEuXllw1%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;785&quot; height=&quot;390&quot; data-origin-width=&quot;785&quot; data-origin-height=&quot;390&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Frontend/React</category>
      <author>알파해커 테크노트</author>
      <guid isPermaLink="true">https://alphahackerhan.tistory.com/70</guid>
      <comments>https://alphahackerhan.tistory.com/70#entry70comment</comments>
      <pubDate>Tue, 1 Oct 2024 22:09:47 +0900</pubDate>
    </item>
    <item>
      <title>Mac에서 Jenkins 실행시 docker-credential-osxkeychain 에러 해결 방법</title>
      <link>https://alphahackerhan.tistory.com/69</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;맥북(Mac OS)에서 Jenkins를 설치하고, docker 명령어를 실행하면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 &quot;docker-credential-osxkeychain&quot; 에러가 발생할 때가 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2724&quot; data-origin-height=&quot;1196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8EZDN/btsIy4sMWGL/cMpgv7ykTgsQ8XjMHwTyf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8EZDN/btsIy4sMWGL/cMpgv7ykTgsQ8XjMHwTyf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8EZDN/btsIy4sMWGL/cMpgv7ykTgsQ8XjMHwTyf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8EZDN%2FbtsIy4sMWGL%2FcMpgv7ykTgsQ8XjMHwTyf1%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;2724&quot; height=&quot;1196&quot; data-origin-width=&quot;2724&quot; data-origin-height=&quot;1196&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/docker/for-mac/issues/2131&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;어떤 글&lt;/a&gt;에는 아래 명령어로 해결할 수 있다고 했는데, 나의 경우에는 이것 만으로는 해결되지 않았다.&lt;/p&gt;
&lt;pre id=&quot;code_1721046121526&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew install docker-credential-helper&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;나의 경우에는 ~/.docker/config.json 내용을 수정함으로써 해결할 수 있었는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇듯 똑같은 Mac OS라도 해결이 되는 방법이 다양하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&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;Mac OS에서 해당 에러를 resolve 할 수 있는 방법들을 정리하면 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. docker-credential-helper 설치&lt;/p&gt;
&lt;pre id=&quot;code_1721046337242&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew install docker-credential-helper&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;2. docker-credential-helper가 잘 동작하는지 확인&lt;/p&gt;
&lt;pre id=&quot;code_1721046375017&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ docker-credential-osxkeychain version
0.6.4&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;3. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;~/.docker/config.json&lt;span&gt; 의 &quot;credsStore&quot; 값을 &quot;osxkeychain&quot;으로 변경&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1721046459019&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;auths&quot;: {
    &quot;https://index.docker.io/v1/&quot;: {}
  },
  &quot;credsStore&quot;: &quot;osxkeychain&quot;,
  &quot;experimental&quot;: &quot;enabled&quot;,
  &quot;stackOrchestrator&quot;: &quot;swarm&quot;
}&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;4. (위 방법이 안되면) ~/.docker/config.json&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;의 &quot;cred&lt;b&gt;s&lt;/b&gt;Store&quot;라는 key를 &quot;credStore&quot;로 변경&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1721046509010&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;auths&quot;: {
    &quot;https://index.docker.io/v1/&quot;: {}
  },
  &quot;credStore&quot;: &quot;osxkeychain&quot;,
  &quot;experimental&quot;: &quot;enabled&quot;,
  &quot;stackOrchestrator&quot;: &quot;swarm&quot;
}&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;5. Docker hub 로그인&lt;/p&gt;
&lt;pre id=&quot;code_1721046533572&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ docker login -u $USER
Password:
Login Succeeded&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Server System/CICD</category>
      <category>docker-credential-osxkeychain</category>
      <category>jenkins</category>
      <category>MacOS</category>
      <author>알파해커 테크노트</author>
      <guid isPermaLink="true">https://alphahackerhan.tistory.com/69</guid>
      <comments>https://alphahackerhan.tistory.com/69#entry69comment</comments>
      <pubDate>Mon, 15 Jul 2024 21:29:31 +0900</pubDate>
    </item>
    <item>
      <title>좋은 소프트웨어란 (1)</title>
      <link>https://alphahackerhan.tistory.com/68</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기능 &amp;gt; 구조?&lt;/li&gt;
&lt;li&gt;기능 &amp;lt; 구조?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 아키텍쳐란 무엇이며, 우리가 왜 이것에 대한 고민을 해야할까. 소프트웨어를 작성하는데 있어서 구성 요소를 크게 나누자면, 기능과 구조가 있다고 볼 수 있다. 소프트웨어 아키텍쳐란, 이 중 &amp;ldquo;구조&amp;rdquo;에 해당하는 이야기이다.&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;ldquo;기능&amp;rdquo;을 구현하는 것이 중요할까, 소프트웨어의 &amp;ldquo;구조&amp;rdquo;를 잘 설계하는 것이 중요할까. 책 &amp;lsquo;리팩토링&amp;rsquo;의 저자이자 세계적인 소프트웨어 공학자인 마틴 파울러는 결국은 구조가 중요하다는 이야기를 한적이 있다.&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;a href=&quot;https://youtu.be/4E1BHTvhB7Y&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://youtu.be/4E1BHTvhB7Y&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=4E1BHTvhB7Y&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/bcUuhP/hyWll0r2a1/4PV9KAXvRxLEMK3Q6IIRD1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=680_82_986_414&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;[마틴 파울러] 소프트웨어 아키텍처의 중요성 (한글 자막)&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/4E1BHTvhB7Y&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자에게 제공하고자 하는 기능을 구현하는 것(즉, 소프트웨어 개발의 요구사항을 만족하는 것)은 당연히 중요한 일이다. 그러나 지속 가능한 서비스라면, 한번의 기능 개발로 끝나지는 않을 것이다. 최초의 기능 개발 이후, 새로운 요구 사항이 들어오고, 그에 따라 기능이 추가되거나 수정하는 과정을 반복하게 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 만약에 구조가 그야말로 엉망인 코드의 수정은 어떨까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한번쯤 소프트웨어 개발을 해본 사람이라면, 구조가 좋지 않은 코드를 수정하는 일이 얼마나 힘든 것인지 알 것이다. 심지어는 본인이 작성한 코드임에도 불구하고 오랜만에 봤다면 그 구조를 스스로 다시 파악하는 것 조차 어렵다. 뿐만 아니라, 수정을 한 후에도 내가 수정한 부분으로 인해 코드의 다른 영역이 영향을 받지 않을까 걱정하게 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 소프트웨어 개발팀에서 주로 하는 일이 뭔지 생각해보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;유지 보수 &amp;rarr; 기능 추가 / 버그 수정 / 성능 개선 &amp;rarr; 코드 읽기 / 이해하기 / 수정 or 추가 하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마도 많은 경우 남의 코드 혹은 내가 작성한 코드를 읽고, 이해한 후 수정하고, 테스트 하는 일일 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1982&quot; data-origin-height=&quot;843&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/T6VGD/btsHWASQyv5/PvWqVjgUFRhLYwgbNIotM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/T6VGD/btsHWASQyv5/PvWqVjgUFRhLYwgbNIotM0/img.png&quot; data-alt=&quot;출처: https://martinfowler.com/bliki/DesignStaminaHypothesis.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/T6VGD/btsHWASQyv5/PvWqVjgUFRhLYwgbNIotM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FT6VGD%2FbtsHWASQyv5%2FPvWqVjgUFRhLYwgbNIotM0%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;1982&quot; height=&quot;843&quot; data-origin-width=&quot;1982&quot; data-origin-height=&quot;843&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: https://martinfowler.com/bliki/DesignStaminaHypothesis.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 마틴 파울러는 좋은 구조의 코드는 시간이 지날수록 기능을 추가하는데 시간이 적게 소요되기 때문에 장기적으로 기능보다 구조가 더 중요할 수 있다고 말한다. 그리고 그것이 소프트웨어 개발을 통해 사업을 하는 입장에서 &amp;ldquo;경제적인&amp;rdquo; 관점으로 따져봤을 때도 더 이득이라고 본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 요즘같이 클라우드 환경에서 소프트웨어를 개발하는 경우라면 더더욱 클라우드에서 제공하는 인프라 서비스를 잘 활용하기 위해 소프트웨어의 구조가 강조될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(다음 편에서 계속...)&lt;/p&gt;</description>
      <category>Server System/Software Architecture</category>
      <category>Development</category>
      <category>Martin Fowler</category>
      <category>software</category>
      <category>Software Architecture</category>
      <category>Software Engineering</category>
      <category>마틴파울러</category>
      <category>소프트웨어</category>
      <category>소프트웨어 개발</category>
      <category>소프트웨어 아키텍쳐</category>
      <category>소프트웨어 엔지니어링</category>
      <author>알파해커 테크노트</author>
      <guid isPermaLink="true">https://alphahackerhan.tistory.com/68</guid>
      <comments>https://alphahackerhan.tistory.com/68#entry68comment</comments>
      <pubDate>Wed, 12 Jun 2024 22:30:16 +0900</pubDate>
    </item>
    <item>
      <title>클린 아키텍쳐 vs 헥사고날 아키텍쳐 (3)</title>
      <link>https://alphahackerhan.tistory.com/67</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://alphahackerhan.tistory.com/65&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2024.06.03 - [Server System/Software Architecture] - 클린 아키텍쳐 vs 헥사고날 아키텍쳐 (1)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1717937683816&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;클린 아키텍쳐 vs 헥사고날 아키텍쳐 (1)&quot; data-og-description=&quot;클린아키텍쳐를 처음 소개한 Bob Martin의 블로그(blog entry about Clean Architecture)에 다음과 같은 말이 나온다(https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html).&amp;quot;The diagram at the top of this article [&quot; data-og-host=&quot;alphahackerhan.tistory.com&quot; data-og-source-url=&quot;https://alphahackerhan.tistory.com/65&quot; data-og-url=&quot;https://alphahackerhan.tistory.com/65&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b9kPOz/hyWg9tiGep/z5T0fMMQU3w5fT8RnL2qu0/img.png?width=235&amp;amp;height=86&amp;amp;face=0_0_235_86,https://scrap.kakaocdn.net/dn/28PiE/hyWg6wwKQh/Uhvz1nUmk8yI25tuCQgSL1/img.png?width=235&amp;amp;height=86&amp;amp;face=0_0_235_86,https://scrap.kakaocdn.net/dn/bFQ4dQ/hyWljOxpoI/rL5PsuoZObBTnqf9hlcHGk/img.png?width=330&amp;amp;height=263&amp;amp;face=0_0_330_263&quot;&gt;&lt;a href=&quot;https://alphahackerhan.tistory.com/65&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://alphahackerhan.tistory.com/65&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b9kPOz/hyWg9tiGep/z5T0fMMQU3w5fT8RnL2qu0/img.png?width=235&amp;amp;height=86&amp;amp;face=0_0_235_86,https://scrap.kakaocdn.net/dn/28PiE/hyWg6wwKQh/Uhvz1nUmk8yI25tuCQgSL1/img.png?width=235&amp;amp;height=86&amp;amp;face=0_0_235_86,https://scrap.kakaocdn.net/dn/bFQ4dQ/hyWljOxpoI/rL5PsuoZObBTnqf9hlcHGk/img.png?width=330&amp;amp;height=263&amp;amp;face=0_0_330_263');&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;클린 아키텍쳐 vs 헥사고날 아키텍쳐 (1)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;클린아키텍쳐를 처음 소개한 Bob Martin의 블로그(blog entry about Clean Architecture)에 다음과 같은 말이 나온다(https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html).&quot;The diagram at the top of this article [&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;alphahackerhan.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://alphahackerhan.tistory.com/66&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2024.06.05 - [Server System/Software Architecture] - 클린 아키텍쳐 vs 헥사고날 아키텍쳐 (2)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1717937700505&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;클린 아키텍쳐 vs 헥사고날 아키텍쳐 (2)&quot; data-og-description=&quot;2024.06.03 - [Server System/Software Architecture] - 클린 아키텍쳐 vs 헥사고날 아키텍쳐 (1)&amp;nbsp;클린 아키텍쳐 vs 헥사고날 아키텍쳐 (1)클린아키텍쳐를 처음 소개한 Bob Martin의 블로그(blog entry about Clean Architectur&quot; data-og-host=&quot;alphahackerhan.tistory.com&quot; data-og-source-url=&quot;https://alphahackerhan.tistory.com/66&quot; data-og-url=&quot;https://alphahackerhan.tistory.com/66&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cUpv2a/hyWg46BwZy/gkitX6PWrA7Mir5H2P9DkK/img.png?width=800&amp;amp;height=580&amp;amp;face=0_0_800_580,https://scrap.kakaocdn.net/dn/b2m4jb/hyWhaZ35dT/o8XWsIOH96S3KZNQ9pcXAk/img.png?width=800&amp;amp;height=580&amp;amp;face=0_0_800_580,https://scrap.kakaocdn.net/dn/dhn3xY/hyWg3miFXi/HvKcPBzdzBGL16uNJtMYkk/img.png?width=2000&amp;amp;height=1451&amp;amp;face=0_0_2000_1451&quot;&gt;&lt;a href=&quot;https://alphahackerhan.tistory.com/66&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://alphahackerhan.tistory.com/66&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cUpv2a/hyWg46BwZy/gkitX6PWrA7Mir5H2P9DkK/img.png?width=800&amp;amp;height=580&amp;amp;face=0_0_800_580,https://scrap.kakaocdn.net/dn/b2m4jb/hyWhaZ35dT/o8XWsIOH96S3KZNQ9pcXAk/img.png?width=800&amp;amp;height=580&amp;amp;face=0_0_800_580,https://scrap.kakaocdn.net/dn/dhn3xY/hyWg3miFXi/HvKcPBzdzBGL16uNJtMYkk/img.png?width=2000&amp;amp;height=1451&amp;amp;face=0_0_2000_1451');&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;클린 아키텍쳐 vs 헥사고날 아키텍쳐 (2)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;2024.06.03 - [Server System/Software Architecture] - 클린 아키텍쳐 vs 헥사고날 아키텍쳐 (1)&amp;nbsp;클린 아키텍쳐 vs 헥사고날 아키텍쳐 (1)클린아키텍쳐를 처음 소개한 Bob Martin의 블로그(blog entry about Clean Architectur&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;alphahackerhan.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클린 아키텍쳐, 헥사고날 아키텍쳐의 공통의 목표와 의존성 방향에 대한 이해와 두 아키텍쳐의 개념적인 차이에 대해서 알아보고 싶으면 위 글을 참고하세요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 두 아키텍쳐를 파이썬으로 구현한다면 각 요소를 어떻게 구현할 수 있는지에 대해 실제 코드 예제를 통해 살펴보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코드예제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;헥사고날 아키텍쳐와 클린 아키텍쳐의 미묘한(?) 차이를 보여주기 위해, 도서관 애플리케이션을 만든다고 가정해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도서관 애플리케이션의 기능에는 책을 추가하는 기능(add book)과 책을 찾는 기능(get book) 두 가지가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) 헥사고날 아키텍쳐를 활용한 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도서관 애플리케이션에서 엔티티라 할 수 있는 것은 책(Book)이다. 도메인 영역에 다음과 같이 Book 클래스를 만들 수 있다.&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;lt;&amp;lt;도메인&amp;gt;&amp;gt;&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;# book.py
class Book:
    def __init__(self, book_id, title, author):
        self.book_id = book_id
        self.title = title
        self.author = author

&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;ldquo;포트&amp;rdquo;를 다음과 같이 만들 수 있다.&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;lt;&amp;lt;포트&amp;gt;&amp;gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;# book_repository_port.py
from abc import ABC, abstractmethod

class BookRepositoryPort(ABC):
    @abstractmethod
    def add_book(self, book):
        pass

    @abstractmethod
    def get_book(self, book_id):
        pass

&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;ldquo;어댑터&amp;rdquo;라는 개념으로 다음과 같이 구현할 수 있다.&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;lt;&amp;lt;어댑터&amp;gt;&amp;gt;&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;# in_memory_book_repository.py
from book_repository_port import BookRepositoryPort

class InMemoryBookRepository(BookRepositoryPort):
    def __init__(self):
        self.books = {}

    def add_book(self, book):
        self.books[book.book_id] = book

    def get_book(self, book_id):
        return self.books.get(book_id, None)

&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;다음으로 책과 관련한 기능들(add book, get book)을 Service로 만들어서, 사용자 인터페이스에서 해당 서비스를 통해 도서관 애플리케이션 기능을 이용할 수 있도록 만들 수 있다.&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;lt;&amp;lt;어플리케이션 서비스&amp;gt;&amp;gt;&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;# book_service.py
from book_repository_port import BookRepositoryPort

class BookService:
    def __init__(self, book_repository: BookRepositoryPort):
        self.book_repository = book_repository

    def add_book(self, book):
        self.book_repository.add_book(book)

    def get_book(self, book_id):
        return self.book_repository.get_book(book_id)

&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로, 사용자의 입력이 최초로 닿는 사용자 인터페이스를 다음과 같이 만들 수 있다. 이곳에서 사용자의 요청을 실제 도메인 영역으로 보내 처리될 수 있도록 한다. 또 외부 요소의 실제 구현체를 인스턴스화 해서, 인터페이스에 의존성 주입을 하는 곳도 이곳이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;&amp;lt;사용자 인터페이스&amp;gt;&amp;gt;&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;# main.py
from book import Book
from book_service import BookService
from in_memory_book_repository import InMemoryBookRepository

# Initialize repository and service
book_repository = InMemoryBookRepository()
book_service = BookService(book_repository)

# Add a book
book1 = Book(1, &quot;Clean Code&quot;, &quot;Robert C. Martin&quot;)
book_service.add_book(book1)

# Retrieve the book
retrieved_book = book_service.get_book(1)
print(f&quot;Retrieved Book: {retrieved_book.title}, Author: {retrieved_book.author}&quot;)

&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;헥사고날 아키텍쳐에서는 포트와 어댑터라는 개념을 이용해서 외부 요소와의 인터페이스와 외부 요소의 구현체를 표현할 수 있었다. 그리고 사용자 요청을 받아 비즈니스 로직을 실제로 수행하는 부분을 서비스라는 개념을 이용해서 구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 클린 아키텍쳐에서는 위 개념들을 어떻게 표현하는지 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 클린 아키텍쳐를 활용한 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;헥사고날 아키텍쳐에서와 마찬가지로 도서관 애플리케이션을 구성하는 가장 기본 단위는 Book이라고 할 수 있고, 그것이 엔티티가 될 것이다.&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;lt;&amp;lt;엔티티&amp;gt;&amp;gt;&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;# entities.py
class Book:
    def __init__(self, book_id, title, author):
        self.book_id = book_id
        self.title = title
        self.author = author

&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;헥사고날 아키텍쳐에서 BookService라는 서비스를 만들어서, 책과 관련한 기능들을 그곳에 다 정의한 것과는 다르게, 클린 아키텍쳐에서는 책 추가(add book), 책 찾기(get book)와 같은 사용자의 각 요청에 대응되는 유즈케이스 클래스(AddBook, GetBook)를 만들어 각 클래스에서 비즈니스 로직이 수행되도록 하는 것이 차이점이다.&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;lt;&amp;lt;유즈케이스&amp;gt;&amp;gt;&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;# use_cases.py
class AddBook:
    def __init__(self, book_repository):
        self.book_repository = book_repository

    def execute(self, book):
        self.book_repository.add(book)

class GetBook:
    def __init__(self, book_repository):
        self.book_repository = book_repository

    def execute(self, book_id):
        return self.book_repository.get(book_id)

&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;헥사고날 아키텍쳐에서 포트와 어댑터는 클린 아키텍쳐에서 인터페이스 어댑터(Interface adapter)라는 layer에서 표현되며, 인터페이스(BookRepository)와 그 인터페이스를 상속해 외부 요소의 구현체(InMemoryBookRepository)를 구현하는 것은 동일하다.&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;lt;&amp;lt;인터페이스 어댑터&amp;gt;&amp;gt;&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;# interface_adapters.py
from abc import ABC, abstractmethod

class BookRepository(ABC):
    @abstractmethod
    def add(self, book):
        pass

    @abstractmethod
    def get(self, book_id):
        pass

class InMemoryBookRepository(BookRepository):
    def __init__(self):
        self.books = {}

    def add(self, book):
        self.books[book.book_id] = book

    def get(self, book_id):
        return self.books.get(book_id, None)

&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 사용자의 요청을 받는 곳이 프레임워크와 드라이버 레이어에서 표현될 수 있다. 헥사고날에서와 마찬가지로 이 곳에서 사용자의 요청을 받아 도메인 영역에 해당하는 유즈케이스 레이어로 요청을 보내 비즈니스 로직이 수행되도록 한다. 또한 이곳에서 외부 요소의 구현체를 인스턴스화 해서 의존성 주입을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;&amp;lt;프레임워크와 드라이버&amp;gt;&amp;gt;&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;# main.py
from entities import Book
from use_cases import AddBook, GetBook
from interface_adapters import InMemoryBookRepository

# Initialize repository and use cases
book_repository = InMemoryBookRepository()
add_book_use_case = AddBook(book_repository)
get_book_use_case = GetBook(book_repository)

# Add a book
book1 = Book(1, &quot;Clean Code&quot;, &quot;Robert C. Martin&quot;)
add_book_use_case.execute(book1)

# Retrieve the book
retrieved_book = get_book_use_case.execute(1)
print(f&quot;Retrieved Book: {retrieved_book.title}, Author: {retrieved_book.author}&quot;)

&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 차이가 있다고 볼 수 있지만, 개인적으로 이런 차이 구분은 크게 의미를 가지지 않는다고 보는 편이다. 앞서 두 아키텍쳐가 공통적으로 가지는 주요한 목표에서 얘기했듯이 외부 요소와 도메인 로직을 구분하고, 의존성 관리를 함으로써 코드 변경과 테스트에 용이하도록 만드는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Server System/Software Architecture</category>
      <category>Clean Architecture</category>
      <category>hexagonal architecture</category>
      <category>Python</category>
      <category>Software Architecture</category>
      <category>소프트웨어 아키텍쳐</category>
      <category>클린 아키텍쳐</category>
      <category>파이썬</category>
      <category>헥사고날 아키텍쳐</category>
      <author>알파해커 테크노트</author>
      <guid isPermaLink="true">https://alphahackerhan.tistory.com/67</guid>
      <comments>https://alphahackerhan.tistory.com/67#entry67comment</comments>
      <pubDate>Sun, 9 Jun 2024 22:01:15 +0900</pubDate>
    </item>
    <item>
      <title>클린 아키텍쳐 vs 헥사고날 아키텍쳐 (2)</title>
      <link>https://alphahackerhan.tistory.com/66</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://alphahackerhan.tistory.com/65&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2024.06.03 - [Server System/Software Architecture] - 클린 아키텍쳐 vs 헥사고날 아키텍쳐 (1)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1717583071900&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;클린 아키텍쳐 vs 헥사고날 아키텍쳐 (1)&quot; data-og-description=&quot;클린아키텍쳐를 처음 소개한 Bob Martin의 블로그(blog entry about Clean Architecture)에 다음과 같은 말이 나온다(https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html).&amp;quot;The diagram at the top of this article [&quot; data-og-host=&quot;alphahackerhan.tistory.com&quot; data-og-source-url=&quot;https://alphahackerhan.tistory.com/65&quot; data-og-url=&quot;https://alphahackerhan.tistory.com/65&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dLKRto/hyWgY5hSGG/Rxs9PMxy6bNAM1UyWBxB5k/img.png?width=235&amp;amp;height=86&amp;amp;face=0_0_235_86,https://scrap.kakaocdn.net/dn/bsFU9s/hyWg0vgcxi/YWkckXfzHkozZkxK1YicUk/img.png?width=235&amp;amp;height=86&amp;amp;face=0_0_235_86,https://scrap.kakaocdn.net/dn/hEF92/hyWg3rZ5H6/v60PQeMzlztKFqzF1B13H0/img.png?width=330&amp;amp;height=263&amp;amp;face=0_0_330_263&quot;&gt;&lt;a href=&quot;https://alphahackerhan.tistory.com/65&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://alphahackerhan.tistory.com/65&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dLKRto/hyWgY5hSGG/Rxs9PMxy6bNAM1UyWBxB5k/img.png?width=235&amp;amp;height=86&amp;amp;face=0_0_235_86,https://scrap.kakaocdn.net/dn/bsFU9s/hyWg0vgcxi/YWkckXfzHkozZkxK1YicUk/img.png?width=235&amp;amp;height=86&amp;amp;face=0_0_235_86,https://scrap.kakaocdn.net/dn/hEF92/hyWg3rZ5H6/v60PQeMzlztKFqzF1B13H0/img.png?width=330&amp;amp;height=263&amp;amp;face=0_0_330_263');&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;클린 아키텍쳐 vs 헥사고날 아키텍쳐 (1)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;클린아키텍쳐를 처음 소개한 Bob Martin의 블로그(blog entry about Clean Architecture)에 다음과 같은 말이 나온다(https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html).&quot;The diagram at the top of this article [&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;alphahackerhan.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클린 아키텍쳐, 헥사고날 아키텍쳐의 공통의 목표와 의존성 방향에 대한 이해를 하고 싶다면, 위 포스팅 내용을 확인해주세요!&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 포스팅에서 두 아키텍쳐의 공통적인 목표가 무엇인지, 그 목표를 달성하기 위해 가장 핵심적인 요소가 무엇인지 살펴봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 그 공통의 목표를 달성하기 위해서 두 아키텍쳐가 어떤 이름으로 개념들을 설명하는지, 차이점은 무엇인지에 대해서 알아보자.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&amp;ldquo;헥사고날 아키텍처 Hexagonal Architecture는 클린 아키텍처를 구현하는 가장 대표적인 모델입니다.&amp;rdquo;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 의존성 방향에 대한 설명을 잘 이해했다면, 이제 클린 아키텍쳐 그림이나 헥사고날 아키텍쳐 그림에서 표현된 화살표 방향의 의미를 이해할 수 있을 것이다.&lt;/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;클린 아키텍쳐에서는 외부 요소 영역을 아래 이미지에서 파란색(Frameworks &amp;amp; Drivers)으로, 비즈니스 로직이 있는 도메인 영역을 빨간색(Application Business Rules)과 노란색(Enterprise Business Rules)로 표현했다. 그리고 외부 요소의 영역과 도메인 영역을 연결해주는 인터페이스를 초록색(Interface Adapters)으로 표현했다. (그리고 의존성 방향은 외부에서 도메인으로 향한다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1451&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2x77T/btsHPdcR7Hr/BF35o2SG4Tm7ukd3mtRywK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2x77T/btsHPdcR7Hr/BF35o2SG4Tm7ukd3mtRywK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2x77T/btsHPdcR7Hr/BF35o2SG4Tm7ukd3mtRywK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2x77T%2FbtsHPdcR7Hr%2FBF35o2SG4Tm7ukd3mtRywK%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;667&quot; height=&quot;484&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1451&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;헥사고날 아키텍쳐에서는 포트(Ports)와 어댑터(Adapters)라는 개념을 이용해서 외부 요소 영역과 도메인 영역을 연결해주는 인터페이스를 구현했다. 클린 아키텍쳐에서 Interface Adapters의 역할이라고 볼 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;포트&lt;/b&gt;: 내부 도메인 로직을 외부와 연결하는 추상적인 인터페이스.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;어댑터&lt;/b&gt;: 포트를 구현하여 실제 외부 시스템과 상호작용하는 구현체.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 클린아키텍쳐에서 Usecase와 Entity를 통해 표현된 도메인 영역을 Application Service와 Domain Model이라는 개념으로 표현했다. 아래 그림에서는 노란색 구름 모양으로 표현한 것이 외부 요소 영역이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTYD3u/btsHPb0qiSk/zHJoyjYoy9AH1w8WObrLAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTYD3u/btsHPb0qiSk/zHJoyjYoy9AH1w8WObrLAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTYD3u/btsHPb0qiSk/zHJoyjYoy9AH1w8WObrLAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTYD3u%2FbtsHPb0qiSk%2FzHJoyjYoy9AH1w8WObrLAk%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;675&quot; height=&quot;422&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1250&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Server System/Software Architecture</category>
      <category>Clean Architecture</category>
      <category>hexagonal architecture</category>
      <category>Software Architecture</category>
      <category>소프트웨어 아키텍쳐</category>
      <category>클린아키텍쳐</category>
      <category>헥사고날아키텍쳐</category>
      <author>알파해커 테크노트</author>
      <guid isPermaLink="true">https://alphahackerhan.tistory.com/66</guid>
      <comments>https://alphahackerhan.tistory.com/66#entry66comment</comments>
      <pubDate>Wed, 5 Jun 2024 19:33:55 +0900</pubDate>
    </item>
    <item>
      <title>클린 아키텍쳐 vs 헥사고날 아키텍쳐 (1)</title>
      <link>https://alphahackerhan.tistory.com/65</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;클린아키텍쳐를 처음 소개한 Bob Martin의 블로그(&lt;a href=&quot;https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html&quot;&gt;blog entry about Clean Architecture&lt;/a&gt;)에 다음과 같은 말이 나온다(&lt;a href=&quot;https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html&quot;&gt;https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html&lt;/a&gt;).&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;The diagram at the top of this article [Clean Architecture] is an attempt at integrating all these architectures [including Hexagonal Architecture] into a single actionable idea.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 헥사고날 아키텍쳐와 클린 아키텍쳐는 서로 다른 개념이 아니고, 헥사고날 아키텍쳐는 클린 아키텍쳐를 구체화한 모델이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;외부 요소와 내부 도메인 로직을 구분하고,&lt;/li&gt;
&lt;li&gt;외부 요소의 변화에 내부 도메인이 영향을 받지 않도록 하며,&lt;/li&gt;
&lt;li&gt;내부 도메인 로직의 테스트 용이성을 높이는 것이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 수행하기 위해, 다음 2가지를 고려해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) 비즈니스 로직과 외부 요소의 구분&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면, 우리가 만들고자 하는 서비스가 데이터베이스에서 a라는 값과 b라는 값을 가져와서 더하고 그 결과를 응답하는 것이라고 해보자. 여기서 비즈니스 로직은 a와 b를 합하고 응답을 주는 것이다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;return a + b
&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;이때 외부 요소는 데이터베이스이다. 외부 요소란 비즈니스 로직을 구현하기 위해 사용될 수 있는 서비스/프레임워크/도구를 의미한다고 볼 수 있다. 즉, 내가 어떠한 비즈니스 로직을 구현하기 위해 다른 누군가가 만들어놓은 서비스나 도구를 사용할 것이고, 그것이 대체 가능하다면 외부 요소라고 할 수 있다. (데이터베이스는 MySQL, DynamoDB, Redis 등 어떤 것이든 될 수 있다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 의존성 방향을 통한 분리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면, 외부 요소는 왜 비즈니스 로직과 분리해야 할까. 우리가 비즈니스 로직을 구현하면서 가져다 쓰는 툴은 언제든지 바뀔 수 있기 때문이다. 예를 들면, 성능이나 비용 등의 이유로 언제든지 데이터베이스로 MySQL을 사용하다가 DynamoDB로 변경할 수도 있고, 그 과정이 조금이라도 쉬우려면 외부 요소가 비즈니스 로직과 분리되어 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의존성 방향을 비즈니스 로직에서 외부 요소로 향하게 하지 않고, 반대로 외부 시스템이 내부 도메인 로직에 의존하도록 설계해야 한다. 그래야만 외부 요소와 비즈니스 로직을 분리하고, 외부 요소의 변경을 쉽게하며, 테스트 용이성을 높일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의존성 방향이란 누가, 누구를 사용하는지에 관련한 것이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 코드는 의존성의 방향이 비즈니스 로직에서 외부 요소(DB)로 향하는 것이다. 코드는 크게 BusinessLogic과 MySQL이라는 두 개의 클래스로 구성되어 있다. BusinessLogic 클래스는 MySQL로 부터 a, b 두 개의 값을 받은 후 더하는 역할을 하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, 외부요소가 변경되어도 바뀌지 않는 핵심 &lt;b&gt;비즈니스 로직은 &amp;ldquo;a+b&amp;rdquo;이고, MySQL은 외부요소&lt;/b&gt;이다. 그리고 작성된 코드를 보면 BusinessLogic이라는 클래스가 MySQL 객체를 생성하고, 해당 객체의 함수를 호출하여 &amp;ldquo;사용&amp;rdquo;하고 있다.&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class BusinessLogic:
	def __init__():
		self._mysql = MySQL()
		
	def do():
		a = self._mysql.get_data(&quot;a&quot;)
		b = self._mysql.get_data(&quot;b&quot;)
		return a + b

class MySQL():
	def __init__():
		...
	
	def get_data(key):
		query = ...
		result = connection.execute(query) 
		return result
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;(위 코드는 의존 관계를 표현하기 위한 것으로 일부 설명에 불필요한 부분은 생략되어 있습니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, &amp;ldquo;사용&amp;rdquo;한다는 것이 &amp;ldquo;의존&amp;rdquo;한다는 것과 같은 의미라고 볼 수 있다. 왜냐하면, 만약 MySQL 클래스의 코드가 변경이 되면, BusinessLogic 클래스 코드를 수정해야 할 수도 있기 때문이다. 반대로 위와 같은 의존 관계에서는 BusinessLogic 클래스를 수정한다고 해서 MySQL 클래스의 코드는 수정할 필요가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 그림으로 나타내면 다음과 같이 표현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;235&quot; data-origin-height=&quot;86&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/me2Bz/btsHMCchsKt/DvLG4AQBcrx1CjarNTBDvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/me2Bz/btsHMCchsKt/DvLG4AQBcrx1CjarNTBDvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/me2Bz/btsHMCchsKt/DvLG4AQBcrx1CjarNTBDvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fme2Bz%2FbtsHMCchsKt%2FDvLG4AQBcrx1CjarNTBDvk%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;235&quot; height=&quot;86&quot; data-origin-width=&quot;235&quot; data-origin-height=&quot;86&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;위와 같은 의존 관계에 있다면, 만약 MySQL을 DynamoDB와 같이 다른 것으로 바꾸게 되었을때 BusinessLogic 클래스의 코드를 필수적으로 고치게 되어 있다.&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;그렇다면 BusinessLogic 클래스가 외부 요소로 부터 데이터를 가지고 와야 한다는 기능을 가지고 있으면서도, 외부 요소의 변경에도 영향이 없게 하려면 어떻게 해야할까. 의존 방향을 외부 요소가 비즈니스 로직이 있는 방향으로 향하게 &amp;ldquo;역전&amp;rdquo;시키면 된다.&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;외부 요소가 비즈니스 로직을 향하게 하려면, 아래와 같이 변경하면 된다. 비즈니스 로직이 있는 영역에 저장된 값을 가져오는 인터페이스를 만들고, 그 인터페이스를 외부 요소가 상속하는 방식으로 하면, 외부 요소인 MySQL이 비즈니스 로직 방향으로 의존하는 형태가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상속을 하는 방향도 의존 방향이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;330&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Zf2SM/btsHNcEagXw/4CfFH69BA3iiAQ3SrqqOX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Zf2SM/btsHNcEagXw/4CfFH69BA3iiAQ3SrqqOX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Zf2SM/btsHNcEagXw/4CfFH69BA3iiAQ3SrqqOX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZf2SM%2FbtsHNcEagXw%2F4CfFH69BA3iiAQ3SrqqOX0%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;330&quot; height=&quot;263&quot; data-origin-width=&quot;330&quot; data-origin-height=&quot;263&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;위 그림에서 비즈니스 로직의 영역을 BusinessLogic 클래스 뿐만 아니라 인터페이스 영역까지(분홍색 영역)로 확대하고, 그 중 외부 요소와의 인터페이스의 역할을 하는 DB 인터페이스를 통해, 외부요소인 MySQL이 상속할 수 있도록 하면, 외부 요소가 비즈니스 로직 방향으로 의존하게 만들 수 있다.&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;ldquo;역전&amp;rdquo;이 만들어 진 것이고, MySQL이 아닌 DynamoDB와 같은 다른 외부 요소를 사용하고 싶다면, DB 인터페이스를 상속한 DynamoDB라는 새로운 클래스를 만들어 적용하면 된다. 그 과정에서 비즈니스 로직의 영역의 변경은 없다. 심지어 MySQL 클래스 코드 조차도.&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;이것이 DI(Dependency Injection)의 개념이고, 코드를 확장성에 열려있게 구현하는 방법이다.&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;위 의존성 관계를 코드로 표현하면 다음과 같다. BusinessLogic 코드 어디에도 MySQL과 같은 외부 요소에 대한 코드가 없다는 것을 알 수 있다. 다만, 인터페이스만이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;class BusinessLogic:
	def __init__(db: DB):
		self._db = db
		
	def do():
		a = self._db.get_data(&quot;a&quot;)
		b = self._db.get_data(&quot;b&quot;)
		return a + b

class DB(metaclass=ABCMeta):
	@abstractmethod
	def get_data(key):
		pass

class MySQL(DB):
	def __init__():
		...
	
	def get_data(key):
		query = ...
		result = connection.execute(query) 
		return result
&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;의존성 주입(DI, Dependency Injection)은 BusinessLogic 클래스를 생성하는 순간에 다음과 같이 외부 요소의 인스턴스를 전달함으로써 이루어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;business_logic = BusinessLogic(MySQL())
&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;위와 같이 의존성 역전을 구현하는 방법이 디자인 패턴 중 어댑터 패턴(Adapter pattern)이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어댑터 패턴은 SOLID의 OCP, DIP 원칙을 활용한 것이다. &lt;a href=&quot;https://guy-who-writes-sourcecode.tistory.com/31&quot;&gt;https://guy-who-writes-sourcecode.tistory.com/31&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Server System/Software Architecture</category>
      <category>Clean Architecture</category>
      <category>hexagonal architecture</category>
      <category>소프트웨어</category>
      <category>소프트웨어아키텍쳐</category>
      <category>클린아키텍쳐</category>
      <category>헥사고날아키텍쳐</category>
      <author>알파해커 테크노트</author>
      <guid isPermaLink="true">https://alphahackerhan.tistory.com/65</guid>
      <comments>https://alphahackerhan.tistory.com/65#entry65comment</comments>
      <pubDate>Mon, 3 Jun 2024 22:06:47 +0900</pubDate>
    </item>
    <item>
      <title>[패스트캠퍼스 + 온라인 강의 완강 후기] 클라우드를 활용한 데이터 파이프라인 구축</title>
      <link>https://alphahackerhan.tistory.com/64</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 엔지니어링 조직에 합류했기 때문에, 데이터 프로세싱에 대한 전반적인 지식과 방법 그리고 운영 노하우 같은 것들을 파악하는 것이 중요했다. 특히 AWS 환경에서 데이터를 운영하고 있는 만큼, AWS에서 구축하고 실습하는 예제를 볼 수 있으면 좋겠다고 생각했는데 마침 패캠에서 &quot;클라우드를 활용한 데이터 파이프라인 구축&quot;이라는 강의를 통해 그 내용을 제공하고 있었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RcixZ/btsBC3mK3Ad/Zo5Zu8Myimsbdsq93Kscm1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RcixZ/btsBC3mK3Ad/Zo5Zu8Myimsbdsq93Kscm1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RcixZ/btsBC3mK3Ad/Zo5Zu8Myimsbdsq93Kscm1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRcixZ%2FbtsBC3mK3Ad%2FZo5Zu8Myimsbdsq93Kscm1%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;536&quot; height=&quot;402&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강의라는 것이 모두 그렇듯이 우리가 실제 업무 환경에서 마주할 수 있는 디테일하고 어려운 상황에 대해 묘사하고, 해결 방법을 제공해주진 않는다. 그러나 데이터 파이프라인을 구축할 때 어떤 리소스를 사용하는지, 어떤 아키텍쳐로 만드는지에 대한 이해는 가능하다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;784&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dGDaTH/btsBDJ9p4oL/f65sg2P4uueOQ9g9jZ5mBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dGDaTH/btsBDJ9p4oL/f65sg2P4uueOQ9g9jZ5mBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dGDaTH/btsBDJ9p4oL/f65sg2P4uueOQ9g9jZ5mBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdGDaTH%2FbtsBDJ9p4oL%2Ff65sg2P4uueOQ9g9jZ5mBk%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;672&quot; height=&quot;430&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;784&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;사실 AWS 서비스는 엄청나게 많고, 데이터 관련 서비스만 해도 수십개는 될 것 같다. 이 모든 내용을 우리가 하나하나 찾아서 공부하고, 실습을 하기엔, 직장인 입장에선 쉽지 않은 것이 현실이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강의 하나로 임팩트하게 데이터 엔지니어링을 위한 서비스가 어떤 것이 있는지, 어떻게 구성하는지, 어떻게 설정하는지 빠르게 파악하고, 실무에 적용해보기에는 적절한 강의였다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;984&quot; data-origin-height=&quot;644&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YNr98/btsBFd3srsH/TYelkejgMCiKxAp9zaARM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YNr98/btsBFd3srsH/TYelkejgMCiKxAp9zaARM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YNr98/btsBFd3srsH/TYelkejgMCiKxAp9zaARM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYNr98%2FbtsBFd3srsH%2FTYelkejgMCiKxAp9zaARM0%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;451&quot; height=&quot;295&quot; data-origin-width=&quot;984&quot; data-origin-height=&quot;644&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;덤으로 완강 후 수료 증명서가 나오면, 올해도 스스로 발전하기 위해 노력했다는 뿌듯함까지 생긴다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124; text-align: start;&quot;&gt;본 게시물은 패스트캠퍼스 수강 후기 이벤트 참여를 위해 작성되었습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>etc</category>
      <category>데이터파이프라인 구축</category>
      <category>온라인 강의 후기</category>
      <category>패스트캠퍼스</category>
      <author>알파해커 테크노트</author>
      <guid isPermaLink="true">https://alphahackerhan.tistory.com/64</guid>
      <comments>https://alphahackerhan.tistory.com/64#entry64comment</comments>
      <pubDate>Fri, 8 Dec 2023 17:27:26 +0900</pubDate>
    </item>
    <item>
      <title>AWS Parameter Store (feat. KMS)</title>
      <link>https://alphahackerhan.tistory.com/63</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Parameter Store란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS Systems Manager 서비스의 기능이다.&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;특히, 애플리케이션에서 사용되는 값들 중, 코드로 노출되면 안되는 (좋지 않은) 값들이 있다. 데이터베이스 아이디/비번, 외부 서비스에 접근하기 위한 액세스 키 등이 그런 것이다. 파라미터 스토어는 코드로 노출되어선 안되는 각종 파라미터들을 안전하게 저장하고 관리할 수 있도록 도와주는 기능이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적인 특징으로는 다음과 같은 것들이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;무료&lt;/li&gt;
&lt;li&gt;Key-Value 형식&lt;/li&gt;
&lt;li&gt;KMS를 통해 파라미터에 암복호화 적용 가능&lt;/li&gt;
&lt;li&gt;IAM을 통해 접근 권한 제어 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Parameter 생성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS Systems Manager의 파라미터 스토어로 가서, 우측 상단에 있는 &amp;ldquo;파라미터 생성&amp;rdquo; 버튼을 클릭한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2790&quot; data-origin-height=&quot;458&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ujTLy/btrScbVW7Wq/mIRmAfBhxXf7q11Pqyldw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ujTLy/btrScbVW7Wq/mIRmAfBhxXf7q11Pqyldw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ujTLy/btrScbVW7Wq/mIRmAfBhxXf7q11Pqyldw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FujTLy%2FbtrScbVW7Wq%2FmIRmAfBhxXf7q11Pqyldw1%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;2790&quot; height=&quot;458&quot; data-origin-width=&quot;2790&quot; data-origin-height=&quot;458&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파라미터의 이름을 쓰고, 파라미터의 유형을 고른다. 예를 들어, 데이터베이스 패스워드와 같은 보안이 중요한 정보는 &amp;ldquo;보안 문자열&amp;rdquo; 유형을 선택하여, 암호화가 되도록 한다.&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;ldquo;보안 문자열&amp;rdquo;을 선택하게 되면, 기존에 생성해놓은 KMS Key를 선택할 수 있도록 되어있다. 그리고 저장하고자 하는 원본 파라미터 값을 &amp;ldquo;값&amp;rdquo;에 입력하고, &amp;ldquo;파라미터 생성&amp;rdquo;을 클릭한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;833&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PFuPW/btrR8JfMWeU/c4hl3mqWBa7jrHLQ4wRgok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PFuPW/btrR8JfMWeU/c4hl3mqWBa7jrHLQ4wRgok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PFuPW/btrR8JfMWeU/c4hl3mqWBa7jrHLQ4wRgok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPFuPW%2FbtrR8JfMWeU%2Fc4hl3mqWBa7jrHLQ4wRgok%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;704&quot; height=&quot;833&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;833&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;참고로, 이름을 지을때는 보통 Path 형태로 짓는다. 예를 들어, &amp;ldquo;/TEST/A&amp;rdquo;, &amp;ldquo;/TEST/B&amp;rdquo; 와 같은 방식이다. 왜냐하면, 한번에 동일한 Path에 있는 파라미터를 모두 불러올 수 있는 기능이 제공되기 때문이다. 즉, &amp;ldquo;/TEST&amp;rdquo;라는 Path에 있는 모든 파라미터를 달라고 명령어를 보내거나 SDK를 호출하면, &amp;ldquo;/TEST/A&amp;rdquo;, &amp;ldquo;/TEST/B&amp;rdquo; 모두 불어와진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. KMS를 이용한 Parameter 보호&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KMS를 활용하여, 생성한 Parameter에 대한 접근 제어를 통해 Parameter를 보호할 수 있다. KMS에서 Key를 생성하면 Key Policy를 확인할 수 있는데, 예를 들면 아래와 같이 설정할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
    &quot;Id&quot;: &quot;key-consolepolicy-3&quot;,
    &quot;Version&quot;: &quot;2012-10-17&quot;,
    &quot;Statement&quot;: [
        {
            &quot;Sid&quot;: &quot;Enable IAM User Permissions&quot;,
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Principal&quot;: {
                &quot;AWS&quot;: &quot;arn:aws:iam::ACCOUNT_ID:root&quot;
            },
            &quot;Action&quot;: &quot;kms:*&quot;,
            &quot;Resource&quot;: &quot;*&quot;
        },
        {
            &quot;Sid&quot;: &quot;Allow access for Key Administrators&quot;,
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Principal&quot;: {
                &quot;AWS&quot;: &quot;arn:aws:iam::ACCOUNT_ID:user/John&quot;
            },
            &quot;Action&quot;: [
                &quot;kms:Create*&quot;,
                &quot;kms:Describe*&quot;,
                &quot;kms:Enable*&quot;,
                &quot;kms:List*&quot;,
                &quot;kms:Put*&quot;,
                &quot;kms:Update*&quot;,
                &quot;kms:Revoke*&quot;,
                &quot;kms:Disable*&quot;,
                &quot;kms:Get*&quot;,
                &quot;kms:Delete*&quot;,
                &quot;kms:TagResource&quot;,
                &quot;kms:UntagResource&quot;,
                &quot;kms:ScheduleKeyDeletion&quot;,
                &quot;kms:CancelKeyDeletion&quot;
            ],
            &quot;Resource&quot;: &quot;*&quot;
        }
    ]
}
&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;위 Statement의 첫번째 블록은 Default로 생성되는 구문으로 접근 제어를 할 때, (Key Policy에 더해) IAM Policy도 함께 사용하겠다는 의미이다. 두번째 구문은 John이라는 IAM User에게 KMS 기능에 대한 권한을 부여한 내용이다. 자세히 보면, 실제로 해당 Key를 이용해서 암복호화 할때 사용되는 Encrypt, Decrypt관련 권한은 빠져있다.&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;그러나 해당 권한은 IAM Policy를 이용해 부여 가능하기도 하다. 즉, 특정 Key에 대한 접근 권한은 Key Policy와 IAM Policy를 모두 활용하여 섬세하게 컨트롤 할 수도 있다는 것이다. (예시에서 Encrypt, Decrypt 권한이 빠져있는 진짜(?) 이유는 보통의 경우 Key 관리하는 관리자와 사용하는 사용자를 구분하여 권한을 부여하고 관리하기 때문이다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Parameter 불러오기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 만들어진 Parameter는 boto3를 이용하여 불러올 수 있다(물론 CLI나 다른 방식으로도 가능하다).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, Parameter를 불러오기 위해서는 기본적으로 &amp;ldquo;ssm:GetParameter&amp;rdquo; 권한이 있어야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어, AWS Lambda에서 해당 코드가 동작한다면, Lambda에 적용되는 Role에 해당 권한이 적용되어 있어야 하며, 로컬에서 사용자가 로컬에 저장해놓은 프로파일(ACCESS ID/KEY)을 이용해 직접 실행시키는 거라면, 해당 사용자(IAM User)가 &amp;ldquo;ssm:GetParameter&amp;rdquo; 권한을 가지고 있어야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 해당 Parameter가 KMS Key에 의해 암호화되어 있다면, 해당 KMS Key에 대한 Decrypt 권한이 있어야만 복호화된 내용을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;boto3를 이용해 Parameter를 불러오는 코드는 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;ssm = boto3.client(&quot;ssm&quot;, &quot;ap-northeast-2&quot;)

response = ssm.get_parameters(
    Names=[&quot;parameter_name&quot;],
    WithDecryption=True
)

parameter = response['Parameters'][0]['Value']
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 레퍼런스&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/saltware/aws-systems-manager와-kms로-쉽고-안전하게-환경변수-관리하기-209047d5ab54&quot;&gt;https://medium.com/saltware/aws-systems-manager와-kms로-쉽고-안전하게-환경변수-관리하기-209047d5ab54&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@zzanzu/1-읽기-전에-312b3a87eea2&quot;&gt;https://medium.com/@zzanzu/1-읽기-전에-312b3a87eea2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.classmethod.jp/articles/lim-ssm-parameter-store/&quot;&gt;https://dev.classmethod.jp/articles/lim-ssm-parameter-store/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dublin-java.tistory.com/66&quot;&gt;https://dublin-java.tistory.com/66&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>AWS/Systems Manager</category>
      <author>알파해커 테크노트</author>
      <guid isPermaLink="true">https://alphahackerhan.tistory.com/63</guid>
      <comments>https://alphahackerhan.tistory.com/63#entry63comment</comments>
      <pubDate>Sun, 27 Nov 2022 01:25:00 +0900</pubDate>
    </item>
  </channel>
</rss>