<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>I move forward every day.</title>
    <link>https://doosicee.tistory.com/</link>
    <description>가만히 있는 것은 멈춘 것이 아닌 뒤처지는 것이다.</description>
    <language>ko</language>
    <pubDate>Thu, 8 Oct 2026 18:20:14 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>I move forward every day.</managingEditor>
    <image>
      <title>I move forward every day.</title>
      <url>https://tistory1.daumcdn.net/tistory/5314484/attach/e445b90f83f445c0a45849468e3fafde</url>
      <link>https://doosicee.tistory.com</link>
    </image>
    <item>
      <title>정보처리기사를 취득하다</title>
      <link>https://doosicee.tistory.com/entry/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC%EB%A5%BC-%EC%B7%A8%EB%93%9D%ED%95%98%EB%8B%A4</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;정보처리기사&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정보처리기사를 취득한 이유는 이전에 &lt;a title=&quot;한국사능력검정시험 &quot; href=&quot;https://doosicee.tistory.com/entry/%ED%95%9C%EA%B5%AD%EC%82%AC%EB%8A%A5%EB%A0%A5%EA%B2%80%EC%A0%95%EC%8B%9C%ED%97%98-1%EA%B8%89-%EC%B7%A8%EB%93%9D-%EA%B8%B0%EB%A1%9D&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;한국사능력검정시험&lt;/a&gt; 자격을 취득한 이유와 같다. 그리고 추가적으로 우리 회사는 주로 공공기관과 함께 사업한다. 사업에 참여할 개발자 중 정보처리기사 자격증 소지자가 참여하는 게 꽤나 도움이 되는 것 같다. 그래서 취득 조건이 되자마자 취득했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;준비과정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 시나공 정보처리기사 실기 책과 정처기 감자 사이트를 이용해서 자격증을 준비했다. 시험 준비 기간은 필기시험 5시간, 실기시험 1달을 준비했다. 지난 5년간 개발자로 일하며 틈틈이 강의도 보고, 실무에서 했던 일들 덕에 이론공부가 조금 필요했으나 코드 문제들이 쉽게 다가와서 조금은 수월하게 시험을 치렀던 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필기시험은 이전 몇개년도 기출들을 한번 살펴보고 치렀다. 대부분 익숙한 개념들이었고, 많은 사람들의 후기가 필기는 CBT 기출만 보고 가도 충분하다기에 그렇게 준비했다. 필기는 시험 가는 당일날 일찍 일어나 5시간 정도 공부했다. 짧은 시간 공부한 만큼 턱걸이로 합격하였으나 합격해서 다행이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실기시험은 성실히 준비하였다. 코드들은 현업에서 매일 사용하기에 익숙하였지만 이론들은 외워야 하기 때문이다. 실기책은 2번 정도 정독하였다. 중간중간 나오는 문제들도 성실히 풀어줬다. 책 2 회독을 마친 후에는 정처기 감자라는 사이트에서 문제를 성실히 풀었다. 시험이 다가오는 날까지 계속해서 풀어줬었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결과&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1267&quot; data-origin-height=&quot;297&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FID1w/dJMb99VtrFA/A9dg1pMPs15SoKb14BMFSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FID1w/dJMb99VtrFA/A9dg1pMPs15SoKb14BMFSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FID1w/dJMb99VtrFA/A9dg1pMPs15SoKb14BMFSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFID1w%2FdJMb99VtrFA%2FA9dg1pMPs15SoKb14BMFSk%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;1267&quot; height=&quot;297&quot; data-origin-width=&quot;1267&quot; data-origin-height=&quot;297&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히도 좋은 결과를 받게 되었다. 이번 정보처리기사 2회는 물시험이라는 말이 많았다. 그러나 물시험이든 불시험이든 자격증을 취득한 것은 변하지 않기에 뿌듯했다. 다음으로는 컴활 1급에 도전해 볼 예정이다. 한국사와 정보처리기사는 연에 3~5회만 시험을 치를 수 있기에 기간을 정해놓고 공부를했는데 컴활은 자주 치룰 수 있기에 퍼질까 봐 걱정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공부를 하고 자격증을 얻어가는 과정이 생각보다 재미있고 뿌듯하다. 회사 생활, 연애, 운동을 하며 공부하는 게 쉽진 않지만 내가 계속해서 앞으로 나아갈 수 있는 추진력을 주는 것 같다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;</description>
      <category>기록</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/76</guid>
      <comments>https://doosicee.tistory.com/entry/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC%EB%A5%BC-%EC%B7%A8%EB%93%9D%ED%95%98%EB%8B%A4#entry76comment</comments>
      <pubDate>Wed, 30 Sep 2026 21:06:56 +0900</pubDate>
    </item>
    <item>
      <title>한국사능력검정시험 1급 취득 기록</title>
      <link>https://doosicee.tistory.com/entry/%ED%95%9C%EA%B5%AD%EC%82%AC%EB%8A%A5%EB%A0%A5%EA%B2%80%EC%A0%95%EC%8B%9C%ED%97%98-1%EA%B8%89-%EC%B7%A8%EB%93%9D-%EA%B8%B0%EB%A1%9D</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;갑자기 왠 한국사?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&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&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;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;어떻게 준비했을까&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&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&gt;강의는 최태성 선생님의 40강 강의와 공부돼지님의 3시간 강의를 활용했다. 처음 한국사의 전체적인 흐름을 잡는 데에는 최태성 선생님의 40강 강의가 큰 도움이 되었다. 이후 세부적인 핵심 이론을 보완하는 과정에서는 공부돼지님의 무료 PDF 자료와 3시간 강의를 활용했다.&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&gt;강의를 모두 시청한 뒤에는 강의를 보며 직접 정리한 PDF와 &amp;lsquo;한국사 오답노트&amp;rsquo; 앱을 활용해 공부를 이어갔다. 먼저 오답노트 앱으로 여러 회차의 기출문제를 풀고, 문제를 풀면서 부족하다고 느낀 영역을 PDF를 다시 보며 부족한 부분을 보완하는 방식으로 공부를 반복했다.&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&gt;처음 이전 회차 기출문제들을 풀었을때는 정답률이 낮아서 심란했으나, 풀면 풀수록 반복되는 문제와 선지들이 많아서 금방 80점을 넘길 수 있게 되었다.&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;b&gt;&lt;span&gt;강의를 통해 전체적인 흐름을 잡고, 기출문제를 통해 부족한 부분을 찾아낸 뒤 다시 이론으로 돌아가 보완하는 방식​이&lt;/span&gt;&lt;/b&gt;&lt;span&gt; 내게 꽤나 잘 맞는 공부법이였고, 다행이도 좋은 결과를 받을 수 있게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;결과&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;744&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5gjFO/dJMcahlOSeU/DKPBDvZjKPSMHN5vkCXO71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5gjFO/dJMcahlOSeU/DKPBDvZjKPSMHN5vkCXO71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5gjFO/dJMcahlOSeU/DKPBDvZjKPSMHN5vkCXO71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5gjFO%2FdJMcahlOSeU%2FDKPBDvZjKPSMHN5vkCXO71%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;540&quot; height=&quot;744&quot; data-origin-width=&quot;540&quot; data-origin-height=&quot;744&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;ps. 최태성 강사님의 전야제는 꼭 시청하자.&lt;/p&gt;</description>
      <category>기록</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/74</guid>
      <comments>https://doosicee.tistory.com/entry/%ED%95%9C%EA%B5%AD%EC%82%AC%EB%8A%A5%EB%A0%A5%EA%B2%80%EC%A0%95%EC%8B%9C%ED%97%98-1%EA%B8%89-%EC%B7%A8%EB%93%9D-%EA%B8%B0%EB%A1%9D#entry74comment</comments>
      <pubDate>Sat, 26 Sep 2026 18:52:02 +0900</pubDate>
    </item>
    <item>
      <title>연애가 먼저인가 신앙이 먼저인가</title>
      <link>https://doosicee.tistory.com/entry/%EC%97%B0%EC%95%A0%EA%B0%80-%EB%A8%BC%EC%A0%80%EC%9D%B8%EA%B0%80-%EC%8B%A0%EC%95%99%EC%9D%B4-%EB%A8%BC%EC%A0%80%EC%9D%B8%EA%B0%80</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;연애가 먼저인가 신앙이 먼저인가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;교회를 다니다 보면 연애를 하는 많은 젊은 친구들을 보게 된다. 그중에서도 신앙생활을 열심히 하는 친구들은 연애를 하면서 이런 고민을 많이 하는 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&quot;내가 하나님보다 내 (남자/여자) 친구를 더 사랑하게 될까 봐 걱정돼.&quot;&lt;/span&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;&lt;span&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&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&gt;결국 &lt;/span&gt;&lt;b&gt;&lt;span&gt;하나님을 사랑하는 마음과 연애를 하며 상대방을 사랑하는 마음이 서로 충돌하는 것처럼 느껴지는 것이다.&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;그럼 나는?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&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&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&gt;다행히도 나는 대마법사가 되기 전 좋은 인연을 만나 연애를 시작하게 되었고 나도 남들이 했던 고민을 해볼 시기가 되었다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;여자친구는 하나님이 주신 선물이다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 연애 초기에 여자친구와 함께 읽고 나눴던 《연애신학》이라는 책에서 많은 도움을 받았다. 지금은 시간이 흘러 책의 내용이 정확히 기억나지는 않지만, 책을 읽으며 깨달았던 생각 하나는 지금까지도 내 안에 선명하게 남아있다.&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&quot;여자친구는 하나님이 주신 선물이다.&quot;&lt;br /&gt;&lt;/span&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;&lt;span&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;b&gt;&lt;span&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;&lt;span&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&gt;나는 조금 다르게 생각하게 되었다. &lt;/span&gt;&lt;span&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&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&gt;그래서 지금의 나는 &lt;/span&gt;&lt;b&gt;&lt;span&gt;하나님과 여자친구 중 한 사람을 선택해야 한다고 생각하지 않는다.&lt;/span&gt;&lt;/b&gt;&lt;span&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&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&gt;나는 그 과정에서 에로스뿐만 아니라 사랑의 또 다른 모습인 아가페도 조금씩 배워가는 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;에로스(Eros)와 아가페(Agape)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사랑에는 에로스와 아가페가 존재한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;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;어떤 이들은 에로스가 식어가면 상대방을 향한 마음도 식어간다고 느끼기도 한다. 하지만 나는 연애를 하면서 꼭 그렇지만은 않다는 것을 조금씩 알아가고 있다.&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;span&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&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;경치 좋은 카페에 갔다면 가장 먼저 생각나는 사람은 누구인가?&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;맛있는 음식을 먹을 때 함께 먹고 싶은 사람은 누구인가?&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;성과급을 받았다면 가장 먼저 선물해주고 싶은 사람은 누구인가?&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;내가 아플 때 가장 보고 싶은 사람은 누구인가?&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;만약 결혼했다면, 내가 죽었을 때 나의 재산과 자녀들을 맡기고 싶은 사람은 누구인가?&lt;/span&gt;&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 data-ke-size=&quot;size16&quot;&gt;&lt;span&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&gt;그렇다고 에로스를 중요하지 않게 생각하는 것은 아니다. &lt;/span&gt;&lt;span&gt;연애 초기에 느꼈던 서로에 대한 끌림과 설렘도 소중한 사랑의 한 모습이다. 시간이 지나면서 자연스럽게 그 모습이 달라진다고 해서 그것을 당연하게 여기고 방치해서도 안 된다고 생각한다. &lt;/span&gt;&lt;span&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&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&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;b&gt;&lt;span&gt;처음의 설렘도 소중하게 여기고, 시간이 지나며 깊어지는 사랑도 소중하게 여기자. 서로를 향한 에로스도 잘 지켜주자.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여자친구와 교제한 지 3년이 다 돼가는 지금은 결혼을 위한 준비를 하고 있다. 여자친구와의 교제를 통해 많은 사랑을 배우고 깨달아간다. 또 내가 사랑이 참 부족한 사람이었다는 것을 깨닫기도 한다. 하나님이 주신 관계 안에서 누리는 사랑은 참 기쁨인 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 이들이 하나님 안에서 참된 사랑의 행복을 누리길 소망한다.&lt;/p&gt;</description>
      <category>생각</category>
      <category>남자친구</category>
      <category>신앙</category>
      <category>여자친구</category>
      <category>연애</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/77</guid>
      <comments>https://doosicee.tistory.com/entry/%EC%97%B0%EC%95%A0%EA%B0%80-%EB%A8%BC%EC%A0%80%EC%9D%B8%EA%B0%80-%EC%8B%A0%EC%95%99%EC%9D%B4-%EB%A8%BC%EC%A0%80%EC%9D%B8%EA%B0%80#entry77comment</comments>
      <pubDate>Wed, 23 Sep 2026 10:31:37 +0900</pubDate>
    </item>
    <item>
      <title>처음 참가한 해커톤</title>
      <link>https://doosicee.tistory.com/entry/%EC%B2%98%EC%9D%8C-%EC%B0%B8%EA%B0%80%ED%95%9C-%ED%95%B4%EC%BB%A4%ED%86%A4</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;해커톤에 참가하게 된 계기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자로 일한 지 몇 년이 되었지만, 지금까지 해커톤에 참가해본 적은 없었다. 한 번쯤은 참가해보고 싶다는 생각은 했지만, 적절한 계기와 용기가 없었던 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러던 중 오랜 시간 알고 지낸 친구가 해커톤에 참여해보지 않겠냐고 제안했다. 평소라면 고민만 했을 것 같지만, 이번에는 용기를 내어 처음으로 해커톤에 참여해보게 되었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;처음 마주한 해커톤 현장&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c11D0N/dJMcafBpRFk/1uKpXlSJhATxuMKFrnqFJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c11D0N/dJMcafBpRFk/1uKpXlSJhATxuMKFrnqFJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c11D0N/dJMcafBpRFk/1uKpXlSJhATxuMKFrnqFJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc11D0N%2FdJMcafBpRFk%2F1uKpXlSJhATxuMKFrnqFJK%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;496&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;내가 참여한 해커톤은 &lt;/span&gt;&lt;b&gt;&lt;span&gt;코드게이트 2026 AI 스타트업 해커톤&lt;/span&gt;&lt;/b&gt;&lt;span&gt;이었다. 회사 프로젝트 일정 때문에 모든 일정에 참여하지는 못했고, 첫째 날 오후부터 둘째 날 아침까지 참여했다. &lt;/span&gt;&lt;span&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&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&gt;처음에는 여러 팀과 경쟁한다는 것이 조금 두렵기도 했다. 하지만 그 두려움은 오래가지 않았다. 팀원들을 만나 우리가 해야 할 작업을 정리하고 하나씩 개발을 진행하다 보니, 어느 순간부터 두려움보다는 재미가 더 커졌다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;짧은 시간안에 아이디어를 다시 정하다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번 해커톤은 미리 준비하고 기획한 아이디어로 참가하는 방식이 아니라, 현장에서 즉석으로 주어진 주제를 가지고 개발하는 방식이었다. &lt;/span&gt;&lt;span&gt;우리 팀에게 주어진 주제는 &lt;/span&gt;&lt;b&gt;&lt;span&gt;&quot;커머스/물류&quot;​&lt;/span&gt;&lt;/b&gt;&lt;span&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&gt;즉석에서 아이디어를 만들고 팀원들과 하나씩 구체화해가는 과정이 꽤 재미있었다. &lt;/span&gt;&lt;span&gt;나는 평소 내 아이디어를 적극적으로 말하는 것을 어려워하는 편이다. 하지만 함께한 팀원들과 친밀감이 있었기 때문인지 평소보다 훨씬 편하게 생각을 이야기할 수 있었고, 서로의 아이디어를 합쳐가며 개발 방향을 정할 수 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;우리가 만든 것&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현장에서 기획한 서비스는 &lt;/span&gt;&lt;b&gt;&lt;span&gt;쇼핑을 도와주는 AI 서비스&lt;/span&gt;&lt;/b&gt;&lt;span&gt;였다. &lt;/span&gt;&lt;span&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&gt;내가 팀에서 주로 맡은 역할은 &lt;/span&gt;&lt;b&gt;&lt;span&gt;인프라 구성과 프론트엔드&amp;middot;백엔드 개발 환경 구성&lt;/span&gt;&lt;/b&gt;&lt;span&gt;이었다. &lt;/span&gt;&lt;span&gt;개인적으로 사용하고 있는 서버에 SSL 인증서와 도메인을 적용하고, 우리가 개발한 프로젝트를 배포하여 외부에서도 접근할 수 있도록 구성했다.&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&gt;요즘은 AI를 활용해 개발하는 경우가 많지만, 사람이 코드를 이해하고 디버깅할 수 있도록 초기 코드 구조와 스타일을 잡아주는 작업은 여전히 필요하다고 생각했다. 그래서 예상하지 못한 오류가 발생했을 때 팀원들이 직접 코드를 확인하고 수정할 수 있도록 초기 개발 환경과 배포 설정을 구성했다.&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&gt;개발과 배포 환경을 구성하는 일은 회사에서도 자주 해왔던 일이었기 때문에 기술적인 부분에서는 큰 어려움이 없었다. &lt;/span&gt;&lt;span&gt;오히려 가장 어려웠던 것은 &lt;/span&gt;&lt;b&gt;&lt;span&gt;팀원들의 여러 아이디어를 하나로 합쳐가는 과정과, 제한된 시간 안에서 어떤 기능을 중심으로 구현해서 보여줄 것인가를 결정하는 일이었다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;처음 해커톤을 마치고&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;처음 참가한 해커톤은 생각보다 꽤 재미있었다. 무엇보다 식어가던 개발에 대한 흥미를 다시 살려주는 시간이었다. &lt;/span&gt;&lt;span&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&gt;그런 점에서 해커톤은 조금 달랐다. &lt;/span&gt;&lt;span&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&gt;무엇보다 아이디어를 내는 일이 재미있었다. &lt;/span&gt;&lt;span&gt;나는 스스로 생각보다 많은 아이디어를 가지고 있는 사람이라고 생각한다. 그러나 늘&amp;nbsp; 상상으로만 끝내고, 실현해내는 추진력이 부족했었다. &lt;/span&gt;&lt;span&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&gt;이번 경험을 통해 &lt;/span&gt;&lt;b&gt;&lt;span&gt;'내가 생각보다 아이디어를 잘 내는 사람이구나'​&lt;/span&gt;&lt;/b&gt;&lt;span&gt;라는 것을 다시 한번 깨달았다. &lt;/span&gt;&lt;span&gt;그리고 그동안 조금 부족하다고 생각했던 자신감이 채워져가는 것 같았다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3213&quot; data-origin-height=&quot;5712&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCcQSM/dJMcacxUwwV/j5mk1QeZ6opfY24VdbWV21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCcQSM/dJMcacxUwwV/j5mk1QeZ6opfY24VdbWV21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCcQSM/dJMcacxUwwV/j5mk1QeZ6opfY24VdbWV21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCcQSM%2FdJMcacxUwwV%2Fj5mk1QeZ6opfY24VdbWV21%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;290&quot; height=&quot;516&quot; data-origin-width=&quot;3213&quot; data-origin-height=&quot;5712&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 이날 진행된 해커톤의 만족도가 높았던 데에는 잘 준비된 간식과 맛있는 식사도 한몫했다. &lt;/span&gt;&lt;span&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&gt;다음에 기회가 된다면 다른 해커톤에도 한번 참가해보고 싶다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>기록</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/73</guid>
      <comments>https://doosicee.tistory.com/entry/%EC%B2%98%EC%9D%8C-%EC%B0%B8%EA%B0%80%ED%95%9C-%ED%95%B4%EC%BB%A4%ED%86%A4#entry73comment</comments>
      <pubDate>Mon, 21 Sep 2026 17:57:17 +0900</pubDate>
    </item>
    <item>
      <title>Spring AOP, Custom Annotation을 이용한 권한 검사</title>
      <link>https://doosicee.tistory.com/entry/Spring-AOP-Custom-Annotation%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EA%B6%8C%ED%95%9C-%EA%B2%80%EC%82%AC</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I2wS1/btsHfDDfvN3/fEIHiYL5btbr8oi6SQF1kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I2wS1/btsHfDDfvN3/fEIHiYL5btbr8oi6SQF1kK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I2wS1/btsHfDDfvN3/fEIHiYL5btbr8oi6SQF1kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI2wS1%2FbtsHfDDfvN3%2FfEIHiYL5btbr8oi6SQF1kK%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;225&quot; height=&quot;225&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;스프링을 이용해 개발하며 언제든지 사용할 수 있는 나만의 레거시 코드를 작성해 두어야겠다는 생각이 들어 개발하던 도중 적용했던 권한검사에 관련된 부분을 적어두고자 한다. 다른 많은 방법들이 있겠지만 AOP와 Annotation을 이용한 방법이 개발 도중 만났던 문제점과 현재 회사에서 제시했던 AOP에 대한 문제점을 커버하는 해결책이라 생각하여 적용해 보았다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;AOP 사용 시 문제점&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;현재 근무하고 있는 회사에서는 AOP를 사용하지 않는다. 한눈에 코드의 흐름이 들어오지 않기 때문이다. 또한 나만의 레거시 코드를 위해 만들던 프로젝트에서는 일부 메서드에만 권한을 적용하고 싶었으나 순수 AOP만으로는 메서드 별로 적용할 수 없었다.&lt;/span&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: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;정리하자면 다음과 같다.&lt;/span&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;복잡성: 코드의 모듈화가 향상되지만, 여러 곳에서 적용되는 규칙 때문에 코드의 복잡성이 증가한다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;숨겨진 동작: AOP는 코드의 흐름을 바꿀 수 있기 때문에 코드의 동작을 이해하기 힘들다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;디버깅의 어려움: 코드의 실행 경로가 예상치 못하게 변경될 수 있기 때문에 디버깅이 힘들다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문제 추적의 어려움: 코드의 흐름이 여러 곳으로 분산되므로 문제가 발생했을 때 문제 추적이 힘들다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;일부 메서드 적용 불가능: 메서드 별로 적용하고 싶었으나 AOP만을 이용했을 때는 어려움이 있다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;AOP 사용 시 장점&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;단점들이 분명 있지만 AOP 사용시 장점들도 존재한다. 그렇기에 AOP를 공부하고 적용해보고 싶었다. &lt;/span&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: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;장점들을 살펴보자.&lt;/span&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;관점 지향 프로그래밍: 애플리케이션을 특정 관점(보안, 로깅, 트랜잭션)으로 바라보고, 이러한 관점을 모듈화 하여 적용할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;중복 코드 제거: AOP를 사용하면 여러 곳에서 반복되는 코드를 한 곳에 모아서 관리할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;모듈화 및 재사용성: AOP는 비즈니스 로직과는 독립적으로 동작하기 때문에 모듈화와 재사용성을 높일 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;가독성 향상: AOP를 사용하면 핵심 비즈니스 로직과 별개로 발생하는 횡단 관심사(로깅, 트랜잭션, 보안 등...)를 분리할 수 있어 가독성이 향상된다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;AOP에는 포기하고 싶지 않은 장점들이 존재한다. 필자는 AOP를 한번쯤 사용해보고 싶었고 단점을 어느 정도 상쇄할 수 있는 방법을 찾아 적용해 보았다. 한번 살펴보자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Custom Annotation과 함께 AOP 적용하기&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;AOP만을 사용한다면 특정 메서드에만 권한검사 로직을 적용하기 힘든 문제점이 존재하였다. 이를 해결하기 위해 Custom Annotation을 함께 사용하였고, Annotation이 존재한다면 무언가가 적용되어 동작하고 있다는 것을 알릴 수 있어 숨겨진 동작에 대한 단점을 어느 정도 상쇄할 수 있다고 판단하였다.&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Custom Annotation 적용하기&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1715158238064&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * 권한 확인 관련 ANNOTATION 구성
 * AOP 적용 AuthAspect.java 클래스 파일 확인
 * */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BeforeRequiresAuthorization {
  String value();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;255&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvCop6/btsHgh05hPY/j2sGippztWYKfkH1KI0IUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvCop6/btsHgh05hPY/j2sGippztWYKfkH1KI0IUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvCop6/btsHgh05hPY/j2sGippztWYKfkH1KI0IUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvCop6%2FbtsHgh05hPY%2Fj2sGippztWYKfkH1KI0IUK%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;450&quot; height=&quot;206&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;255&quot;/&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;먼저 위와 같이 어노테이션을 직접 만들어준다. value()를 선언한 이유는 각 메서드 별로 검사해야 하는 권한명을 받기 위해서다.&lt;/span&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: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이후 컨트롤러에 직접 만든 어노테이션을 적용해 준다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1715158376360&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  @PostMapping(&quot;/bs/admin&quot;)
  @BeforeRequiresAuthorization(&quot;admin-create&quot;)
  public APIDataResponse&amp;lt;AdminResponseDto&amp;gt; createAdmin(
      @Validated @RequestBody AdminCreateRequestDto adminCreateRequestDto
  ) {
    AdminResponseDto adminResponseDto = adminService.createAdmin(adminCreateRequestDto);

    return APIDataResponse.of(adminResponseDto);
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;718&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bE7SOh/btsHfZfjZr7/1QR9b0SEqHsbWPOsWdpE9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bE7SOh/btsHfZfjZr7/1QR9b0SEqHsbWPOsWdpE9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bE7SOh/btsHfZfjZr7/1QR9b0SEqHsbWPOsWdpE9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbE7SOh%2FbtsHfZfjZr7%2F1QR9b0SEqHsbWPOsWdpE9k%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;718&quot; height=&quot;222&quot; data-origin-width=&quot;718&quot; data-origin-height=&quot;222&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;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;마지막으로 어노테이션이 적용된 메서드마다 AOP가 적용되도록 AOP클래스를 만들어 적용해 준다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1715158540051&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Aspect
@Component
public class AuthAspect extends BaseController{

  private final AuthFuncRepository authFuncRepository;

  @Autowired
  public AuthAspect(AuthFuncRepository authFuncRepository){
    this.authFuncRepository = authFuncRepository;
  }

  @Before(&quot;@annotation(requiresAuthorization)&quot;)
  public void checkAuthorization(BeforeRequiresAuthorization requiresAuthorization) {
    String authorization = requiresAuthorization.value();
    AuthFuncEntity auth = authFuncRepository.findByFuncNameAndAuthId(this.getSessionInfo().getFuncId(), authorization);

    if(auth == null){
      throw new APIException(ErrorCode.UNAUTHORIZED_FAIL);
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;966&quot; data-origin-height=&quot;528&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XlDZ5/btsHjcw7f9r/O2W19rFBKyIsF6fHpBXBpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XlDZ5/btsHjcw7f9r/O2W19rFBKyIsF6fHpBXBpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XlDZ5/btsHjcw7f9r/O2W19rFBKyIsF6fHpBXBpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXlDZ5%2FbtsHjcw7f9r%2FO2W19rFBKyIsF6fHpBXBpK%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;750&quot; height=&quot;410&quot; data-origin-width=&quot;966&quot; data-origin-height=&quot;528&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;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;필자가 메서드를 따로 적용하고 싶었던 이유는 해당 프로젝트에서 read에 관한 영역은 권한검사를 하지 않아도 된다고 생각했기 때문이다. 메뉴권한을 따로 관리하기 때문에 메뉴 접근권한 자체가 read 권한검사에 대한 역할을 수행하고 있다고 생각했기 때문이다.&lt;/span&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: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그래서 AOP를 이용해서 read를 제외한 다른 기능에 대해서만 권한검사를 적용하고 싶었고 이에 대한 방법을 찾던 도중 어노테이션을 이용하여 적용할 수 있다는 방법을 알게 되어 적용하게 되었다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;정리&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;커스텀 어노테이션을 달아주어 무언가 동작하고 있다는 것을 알려주었고, 어노테이션의 이름을 통해 메서드가 실행되기 전에 실행된다는 것을 알려주었다. 단점들을 어느 정도 상쇄한 것처럼 보인다(필자의 주관적인 생각). 하지만 무분별하게 많이 사용했다가는 숨겨진 동작들이 많아 디버깅이 어렵고 복잡해질 것이라는 생각이 든다. AOP는 팀원들과 미리 약속된 영역들만 사용하는 게 좋을 것 같다. 권한검사, 로깅 등.... 어느 프로젝트를 유지보수하게 되어도 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;우리 팀에서 이 영역들은 AOP가 적용되어 있다!라는&lt;/span&gt; 걸 인지할 수 있도록 말이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;참조&lt;/span&gt;&lt;/b&gt;&lt;/h2&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;a title=&quot;스프링 로그인 권한 검사에 대한 설계 방법&quot; href=&quot;https://stir.tistory.com/317&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stir.tistory.com/317&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;깃허브 소스&lt;/span&gt;&lt;/b&gt;&lt;/h2&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;a href=&quot;https://github.com/Doosic/backoffice-backend&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/Doosic/backoffice-backend&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1715215915874&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - Doosic/backoffice-backend&quot; data-og-description=&quot;Contribute to Doosic/backoffice-backend development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/Doosic/backoffice-backend&quot; data-og-url=&quot;https://github.com/Doosic/backoffice-backend&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/kcE2s/hyVZiqTwY2/SfEwJf7dPrJJitClWiYuHK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/Doosic/backoffice-backend&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/Doosic/backoffice-backend&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/kcE2s/hyVZiqTwY2/SfEwJf7dPrJJitClWiYuHK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - Doosic/backoffice-backend&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to Doosic/backoffice-backend development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Doosic/backoffice-front&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/Doosic/backoffice-front&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1715215926756&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - Doosic/backoffice-front: 백오피스 vue.js 로 간단구성&quot; data-og-description=&quot;백오피스 vue.js 로 간단구성. Contribute to Doosic/backoffice-front development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/Doosic/backoffice-front&quot; data-og-url=&quot;https://github.com/Doosic/backoffice-front&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/nBxFE/hyVZhyLHV2/haiklKL1ra9BMDW9HFmGpk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/Doosic/backoffice-front&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/Doosic/backoffice-front&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/nBxFE/hyVZhyLHV2/haiklKL1ra9BMDW9HFmGpk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - Doosic/backoffice-front: 백오피스 vue.js 로 간단구성&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;백오피스 vue.js 로 간단구성. Contribute to Doosic/backoffice-front development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Tech Notes</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/69</guid>
      <comments>https://doosicee.tistory.com/entry/Spring-AOP-Custom-Annotation%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EA%B6%8C%ED%95%9C-%EA%B2%80%EC%82%AC#entry69comment</comments>
      <pubDate>Wed, 8 May 2024 20:18:51 +0900</pubDate>
    </item>
    <item>
      <title>MCMS 웹 고도화 프로젝트 후기</title>
      <link>https://doosicee.tistory.com/entry/MCMS-%EC%9B%B9-%EA%B3%A0%EB%8F%84%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9B%84%EA%B8%B0</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;848&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dKjiwR/btsDQ5QT0rj/Isel43V58Tqg9c0FZI5mVK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dKjiwR/btsDQ5QT0rj/Isel43V58Tqg9c0FZI5mVK/img.jpg&quot; data-alt=&quot;출처: pixabay&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dKjiwR/btsDQ5QT0rj/Isel43V58Tqg9c0FZI5mVK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdKjiwR%2FbtsDQ5QT0rj%2FIsel43V58Tqg9c0FZI5mVK%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;450&quot; height=&quot;298&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;848&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: pixabay&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;목적: mcms 사용자 및 관리자 사이트 고도화&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;수행 기간: 2023년 6월 17일 ~ 2023년 12월 14일&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;수행 인원: 풀스택 2&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;기술 스택: vue.js, jsp, javascript, springframework, java, mybatis, mariaDB&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;협업 툴: svn&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;CI/CD: jenkins&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt; &lt;b&gt;기존 운영 중이던 mcms 프로젝트를 고도화하는 작업을 담당하게 되었고 사수로써 참여하게 되었다. 사수로 참여하기에는 부족한 점이 많았지만 팀장님께서 맡겨주셨고, 부사수 때와는 다르게 일에 대한 책임감과 부담감을 알게 되며 인간적으로 한층 더 성장할 수 있는 감사한 시간이었다.&lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;MCMS%20%EB%9E%80%3F-1&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;MCMS란?&lt;/h2&gt;
&lt;hr data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;mcms는 Media Contents Management System의 약자로 미디어 콘텐츠(기록물)를 관리하는 아카이브다. 좀 더 풀어서 설명하자면 &lt;b&gt;&lt;b&gt;여러 가지 콘텐츠들을 기준별로 분류하여 관리하는&amp;nbsp;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;사진, 영상&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&amp;nbsp;콘텐츠/시청각기록물 관리&lt;/span&gt;&amp;nbsp;솔루션이다.&lt;/b&gt;&lt;/b&gt; 기록물을 콘텐츠별로 볼 수 있는 사용자 사이트와 기록물을 등록하고 관리하는 관리자 사이트로 구성된다&lt;/span&gt;.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MCMS 고도화 프로젝트 담당업무&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt; 기획&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;고도화 기능 중 일부인 통계페이지에 대한 기획 및 스토리보드 작성&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;서버이관&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;온프레미스 서버에서 KT클라우드 서버로 서비스 및 데이터 이관&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;외부 업체와 API에 대한 요구사항 정의 및 협의&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;API에 대한 요구사항을 정의, 협의, API 명세서 작성, 인터페이스 설계&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;데이터 마이그레이션&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Excel -&amp;gt; mariaDB&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;페이지 구현 및 기능개발&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;페이지 퍼블리싱 및 요구 기능 구현&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;DB 백업 스크립트 적용&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;DB 데이터 백업을 위한 백업 스크립트 작성 및 적용&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;통합 테스트&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;통합 테스트 진행&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;산출물 일부 준비&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;테이블 목록 및 정의서, ERD, 테스트 케이스, 매뉴얼 작성&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;이번 프로젝트는 사수로 참여했던 만큼 책임질 일들과 해야 했던 일들이 많았다. 부사수 때는 페이지 구현과 기능개발에만 집중했었는데 그간 사수로써의 업무를 진행했던 선임이 얼마나 많은 일들을 책임지고 부담감을 느끼며 해왔는지 알게 됐다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;일정 및 이슈 관리&lt;/h2&gt;
&lt;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;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;프로젝트 일정 및 이슈들은 모두 스프레드시트를 통해 관리했다. 퍼블리싱, API, 테스트, 에러사항들을 모두 스프레드 시트의 탭을 나누어 관리했으며 프론트는 주소를 기준으로, 백엔드는 엔드포인트를 기준으로 모든 사항들을 관리하였다. 노션으로 관리하는 방법을 생각해 보았으나 현재 팀에서는 스프레드시트를 통해 모든 프로젝트를 공유하고 있으므로 모두가 알기 편한 방법인 회사 기준에 맞춰 진행하였다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;기획&lt;/h2&gt;
&lt;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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;해당 프로젝트의 전체적인 기획은 아니지만 관리자 사이트 통계 페이지에 대한 기획을 개발자 둘이서 진행하였다. 클라이언트가 필요로 하는 게 뭔지 생각해 보고 성장하길 원하시는 마음에 이사님께서 맡겨주셨었다. 누군가가 정해준 대로만 만들다가 화면이 어떻게 구성돼야 사용자가 편하게 볼 수 있을지, 어떤 데이터를 보여주어야 사용자가 필요로 하는 통계 데이터를 만들 수 있을지 많은 고민을 해볼 수 있는 시간이었다. 기획하는 시간과 결과 자체가 순조롭지는 않았으나 이사님과 차장님의 조언을 통해 잘 마무리할 수 있었다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기획을 할 때는 &quot;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;누가 어떤 이유로 필요로 하는가?&lt;/span&gt;&quot; 에서부터 시작을 했어야 했다. 처음에는 기록물관리 사이트에 통계 페이지이기에 콘텐츠를 기준으로 기간별 등록, 보유, 조회수에 대한 통계를 보여주려고 했었다. 그러나 클라이언트는 &quot;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;부서별로 성과를 나타낼 수 있는 통계 데이터&lt;/span&gt;&quot;를 필요로 했었다. 모든 기준이 부서별 성과를 나타낼 수 있는 지표가 되어야 했던 것이다. 이후 클라이언트의 필요사항에 따라 수정을 하였고 기획한 페이지를 통과받을 수 있었다. 처음부터 알고 진행했으면 좋았겠지만 그래도 이번 경험을 통해서 이러한 배움을 얻을 수 있었음에 감사한 시간이었다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;서버 이관&lt;/h2&gt;
&lt;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;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;서버 이관 작업은 &lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;CentOS 7.9 운영체제에 &lt;/span&gt;직접 apach, tomcat, mariaDB를 설치하며 서비스 운영환경을 구축해 볼 수 있는 기회였다. 종종 vm에 테스트 환경을 구성하는 연습을 했었는데 실제 적용할 기회가 다가와 감사했다. &lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;설치는 기존 온프레미스 서버에서 동작하던 것과 같이 이상 없이 작동하기 위해 기존에 설치하였던 컴파일 소스를 사용하여 클라우드 서버에 컴파일 설치 방식으로 설치하였다.&lt;/b&gt;&lt;/span&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;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;서버이관 작업을 해본 적이 없었기에 잘할 수 있을까?라는 막연한 두려움이 있었으나 큰 어려움 없이 잘 끝났다. 계정에 루트 권한을 부여받기도 했었고, 기존 온프레미스 서버와 경로를 똑같이 구성하기도 했었다. 가장 큰 요소는 vm에 같은 환경을 구성해 보며 연습하고 스크립트를 미리 정리를 해뒀던 게 큰 도움이 되었다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;외부 업체와 API에 대한 요구사항 정의 및 협의&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이번에 진행한 mcms 프로젝트는 메인이 되는 사이트가 따로 있었다. 적절한 예시가 생각나지 않지만 굳이 뽑아보자면 네이버와 네이버 웹툰과 같은 관계라고 볼 수 있는 것 같다. 우리가 네이버 웹툰 측인 셈인데 로그인 기능과 콘텐츠 자동연계 기능을 구현하기 위해 우리에게 필요한 요구사항을 정리하고 협의하는 과정을 거쳤다. 협의 과정은 굉장히 순조로웠고, 해줄 수 있다는 몇 마디의 말이 오고 간 게 전부였다. &lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;API 문서를 작성하며 배운 점은 세세하고 명확히 작성해줘야 한다는 것이었다. 테스트 URL, 상용 URL, 파라미터(타입, 필수여부, 대소문자), &lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;암호화 방법&lt;/span&gt;&lt;/b&gt;, 데이터 목록, 포맷형식, Http Method까지 예시와 함께 틈틈이 작성해서 전달하였다. 우리가 API를 제공받는 입장이기 때문에 필요한 데이터 목록만 전달하고 나머지는 협업사 측에 맡기는 게 맞는 것 같았지만 우리가 원하는 대로 맞춰주겠다고 하셔서 그렇게 진행했다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;API 문서를 보고 작업을 하기만 해 봤지 직접 다른 업체와 협의하는 과정을 거친 건 처음이었기에 좋은 경험이 되었다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;데이터 마이그레이션&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Excel에 담긴 자료들을 데이터베이스에 이관하는 작업들을 하였다. 어려울 것은 없었으나 클라이언트 측에서 전달해 준 양식대로 작성해주지 않았다는 문제였다. 부서가 제각각이라 그런지 잘 작성해 주신 부서도 있는 반면 전달된 양식에 마음대로 작성해서 주는 일이 있었다(결국은 필자가 양식대로 다시 맞춰야 하는 일이 있었다). 이미지, 영상, pdf 등.... 파일 같은 경우에는 경로가 틀리면 상당히 곤란했었다. 번거롭지만 파일을 찾지 못한 것들은 디비에 기록해 뒀다가 다시 경로를 잡고 변환해 주어야 했다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;또 특수한 상황이었기에 주말에만 작업을 진행할 수 있는 상황이었다.... 클라우드 서버로 이관하였는데 대용량의 파일들과 데이터들을 넣을 때 비용이 발생하기 때문이었다. 번거롭지만 주말에 서버를 내린 후에 파일 변환 및 데이터를 넣는 작업을 진행하였었다. 어려운 일은 없었으나 계속 신경이 쓰이는 작업이었었다.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;페이지 개발 및 기능 개발&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이번 프로젝트의 주된 작업은 통계 페이지와 API 연계 관련 기능 작업이었다. API 연계 작업은 걱정했던 것과 달리 협업체와의 소통과 API 문서가 잘 작성되니 무난하게 작업이 끝났다. 오히려 처음 구현해 보는 통계 기능에 대해서 많은 생각을 해보게 되었고, 많은 배움을 얻을 수 있는 시간이 되었다. 통계 페이지를 만들 때 생각해야 할 것들을 조금 정리해 본다.&lt;/span&gt;&lt;/b&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;통계 페이지란?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;통계 페이지란 과거의 데이터를 집계하여, 저장 후 화면에 표출하는 페이지다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;데이터의 정합성이 요구되며, 오차가 있어서는 안 된다.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;데이터 정합성 &lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;(data consistency)&lt;/span&gt;&lt;/b&gt; &lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;데이터 정합성이란?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; ※ 어떤 데이터들의 값이 서로 일치하는 상태를 의미한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;통계 페이지는 데이터의 정합성이 가장 중요하다. 데이터 정합성을 위해서 살펴봐야 할 것들을 정리해 보았다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이력 (history data)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이력 데이터를 만드는 이유&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;1. 문제 발생 시 과거의 데이터를 통해 원인을 발견하고 해결하기 위해서&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2. 데이터를 쌓아 유의미한 통계 데이터를 만들기 위해서&lt;/span&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이력 테이블을 설계할 때는 꼭 이력만으로 집계 데이터를 만들 수 있도록 설계해야 한다. 즉, 집계 데이터를 만들기 위해 필요한 모든 데이터를 가지고 있는 게 있어야 한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 데이터는 발생되는 이벤트(사원이라면 부서 이동, 입사, 퇴사 등&amp;hellip;)에 따라 얼마든지 변경될 수 있다. 과거의 이력을 보기 위해 만든 통계 데이터에 이벤트에 따라 실시간으로 변경될 수 있는 데이터가 끼어든다면 추후 데이터의 정합성이 깨질 가능성이 매우 크다. 그렇기에 자세한 이력을 쌓아 이력만으로 집계 데이터를 만들 수 있어야 한다. (자세한 이력의 기준은&lt;/span&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;별다른 DB Join 없이 이력 데이터만을 가지고 집계 데이터를 만들 수 있어야 한다&lt;/span&gt;.) &lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt; 이력 데이터만을 가지고 집계 데이터를 만들 수 있다면 이력 데이터는 집계 데이터에 대한 검증 데이터가 될 수 있으며, 문제가 생겨 다시 집계를 해야 할 시 과거에 쌓아둔 이력 데이터만을 가지고 다시 집계 데이터를 만들 수 있다. &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;집계 (total data)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; 집계 데이터를 만드는 이유 &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;※ 집계 데이터 없이 이력 데이터만을 쿼리 하여 페이지에 표출할 때에는 데이터의 양에 따라 속도 이슈를 야기할 수 있기 때문이다.&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; 집계 테이블을 설계할 때는 페이지에 표출할 데이터를 집계 테이블 내의 데이터 만으로 표출할 수 있도록 설계하고, 데이터를 쌓아야 한다. 하나 더 생각할 것은 집계 테이블이 정말 필요한지 생각해 보아야 한다. 이력만을 쌓고 그때그때 집계해도 충분할 수 있다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;DB 데이터 백업&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;최근 프로젝트를 유지보수 하며 DB의 테이블이 사라지는 일이 있었다. 후임에게 운영 DB와 테스트 DB의 정보를 알려줬었는데 마우스 클릭미스로 운영 DB의 테이블을 드롭하는 일이 발생했었다. 다행히도 매일 백업을 해두고 있었고, 밤 사이에 추가된 변경된 데이터가 없어 큰 문제없이 복구하였는데 땀이 삐질삐질 나고 식겁했던 순간이었다.&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;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;OS 환경이 centos 인 만큼 DB 데이터 백업은 crontab을 이용하여 작업했다. DB 백업 명령어를 작성하여 crontab에 등록하여 간단하게 백업할 수 있도록 만들었다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7; font-family: 'Noto Sans Light';&quot;&gt;크론탭(crontab)이란?&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;크론탭은 리눅스 운영체제에서 배치 작업을 스케줄링하기 위한 프로그램이다. 크론탭을 이용하면 특정 시간에 정기적인 작업이 가능하다.&amp;nbsp;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;통합 테스트 &lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;(Integration Testing)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt; &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h3&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이번 프로젝트는 테스트 코드를 따로 작성하지 않았다. 작성할 여유도 부족하였지만, 고도화 이전에 작성된 테스트 코드가 없었기 때문이다. 그래서 모든 개발이 완료된 후 &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;통합 테스트(Integration Testing)를 진행하였다. 진행 방식은 스프레드시트에 시나리오를 작성하고 &lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;페이지의 UI들이 사전 정의된 기능대로 동작하는지&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&amp;nbsp;1차, 2차 검증을 통한 방식으로 진행하였다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;통합 테스트(Integration Testing)란?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;시스템의 여러 구성요소들이 함께 작동하여 예상대로 상호작용하는지 확인하는 테스트 과정이다.&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;산출물 준비&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; &lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;산출물은 테이블 목록 및 정의서, ERD, 테스트 케이스, 사용자 매뉴얼, 관리자 매뉴얼을 작성하였다. &lt;/span&gt; &lt;/span&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;테이블 목록&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;물리적 테이블명, 논리적 테이블명을 excel 파일에 리스트화한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;테이블 정의서&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;테이블명, 칼럼의 물리적, 논리적 명칭, 타입, 길이, pk, fk, notnull 등을 excel 파일에 명시한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;ERD&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;ERD는 eclipse의 ermaster를 이용하여 작성하였다. 회사에서 공통적으로 사용하고 있기 때문이다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;사용자 매뉴얼&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;사용자 매뉴얼은 처음 사이트를 접하는 사용자가 수월하게 기능을 이용할 수 있도록 작성해 두었다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;관리자 매뉴얼&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;관리자 매뉴얼은 시스템이 꺼지거나 Error 발생 시 어떻게 대처해야 하는지 상세히 적어두었다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;처음 작성해 보는 것들이었지만 경험이 되었다. 생각보다 프로젝트를 마칠 때에는 이렇게 많은 파일들을 제공해 줘야 하는구나라는 것을 알게 되었다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;마무리&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;사수로써 프로젝트를 진행한 경험은 처음이고, 업체와 먼저 나서서 연락한 경험도 처음이기에 쉽지 않은 시간이었다. 책임감과 부담감에 야근하는 일도 많았지만 개발자로써 그리고 인간적으로 한층 성장하는 계기가 되어준 프로젝트였다. 경험이 늘어난다는 것에 대한 감사로 해당 프로젝트를 잘 마무리하였다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/Projects Reviews</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/65</guid>
      <comments>https://doosicee.tistory.com/entry/MCMS-%EC%9B%B9-%EA%B3%A0%EB%8F%84%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9B%84%EA%B8%B0#entry65comment</comments>
      <pubDate>Thu, 25 Jan 2024 11:44:48 +0900</pubDate>
    </item>
    <item>
      <title>Director Builder Pattern (디렉터 빌더 패턴)</title>
      <link>https://doosicee.tistory.com/entry/Builder-Pattern-%EB%B9%8C%EB%8D%94-%ED%8C%A8%ED%84%B4</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;642&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ULaDS/btss3DPySQS/8Jp1aoUsmzWs17bdBtXQHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ULaDS/btss3DPySQS/8Jp1aoUsmzWs17bdBtXQHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ULaDS/btss3DPySQS/8Jp1aoUsmzWs17bdBtXQHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FULaDS%2Fbtss3DPySQS%2F8Jp1aoUsmzWs17bdBtXQHk%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;550&quot; height=&quot;276&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;642&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;이 글에 주된 주제는 GoF의 디자인 패턴에서 정의하고 있는 디렉터 빌더 패턴입니다.&lt;/span&gt; 그러나 이펙티브 자바의 Simple Builder Pattern도 존재하기에 공부를 위해 일부를 다루고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;Director Builder Pattern (디렉터 빌더 패턴) 이란?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&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-origin-width=&quot;705&quot; data-origin-height=&quot;401&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dEfxUF/btssVK9yqn1/0UStFxFLQ4gAqnpr2uQZNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dEfxUF/btssVK9yqn1/0UStFxFLQ4gAqnpr2uQZNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dEfxUF/btssVK9yqn1/0UStFxFLQ4gAqnpr2uQZNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdEfxUF%2FbtssVK9yqn1%2F0UStFxFLQ4gAqnpr2uQZNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;684&quot; height=&quot;389&quot; data-origin-width=&quot;705&quot; data-origin-height=&quot;401&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;Builder: 빌더 인터페이스는 제품 즉, 인스턴스를 생성할 때 필요한 단계들을 선언한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;ConcreateBuilderA: 빌더 인터페이스의 구현체다. 제품(Product) 생성에 필요한 단계들을 구현하며, 인터페이스를 따르지 않는 제품을 생산할 수도 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;Product: ConcreateBuilder를 통해 생성된 제품이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;Director: 자주 사용되는 제품들을 정의해 두고 재사용할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;Client: 디렉터를 호출하여 제품들을 사용한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;빌더 패턴은 인스턴스를 만드는 방법들을 단계별로 정의하여 인스턴스를 만들어내는 패턴이라고 볼 수 있다. 아래 예제를 통해 빌더 패턴으로 어떠한 문제들을 해결할 수 있는지 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;Builder Pattern 사용 전 문제점&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;House(집) 객체를 만든다고 가정해 보자. 기본적으로 집을 지으려면 벽을 만들고, 문을 달고, 창문을 달아준 후, 지붕을 얹어줘야 한다. 하지만 이때 기본적인 집이 아닌 필요에 따라 옵션으로 난방 시스템, 수영장, 정원 등... 이 추가된 더 좋은 집을 원한다면 확장에 따라 클래스가 복잡해지거나, 생성자가 더러워지고 뚱뚱해지는 문제가 생긴다. Builder 패턴 등장 이전에 문제 해결을 위해 사용했던 방법을 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;점층적 생성자 패턴&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;점층적 생성자 패턴(Telescoping Constructor Pattern)은 생성자 오버로딩을 이용한 패턴이다. 필수 매개변수와 선택 매개변수들을 포함한 인스턴스를 생성할 때에 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1694146879999&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Home {
    private int walls;
    private int windows;
    private int doors;
    private int rooms;
    private boolean hasHeating;
    private boolean hasGarage;
    private boolean hasSwimPool;
    private boolean hasGarden;

    // 생성할 인스턴스들에 필요한 선택적 매개변수 조합에 따라 생성자 메서드를 계속 만들어야 한다.
    public Home(int walls, int windows, int doors, int rooms, boolean hasHeating, boolean hasGarage, boolean hasSwimPool, boolean hasGarden) {
        this.walls = walls;
        this.windows = windows;
        this.doors = doors;
        this.rooms = rooms;
        this.hasHeating = hasHeating;
        this.hasGarage = hasGarage;
        this.hasSwimPool = hasSwimPool;
        this.hasGarden = hasGarden;
    }

    public Home(int walls, int windows, int doors, int rooms, boolean hasHeating, boolean hasSwimPool) {
        this.walls = walls;
        this.windows = windows;
        this.doors = doors;
        this.rooms = rooms;
        this.hasHeating = hasHeating;
        this.hasSwimPool = hasSwimPool;
    }

    public Home(int walls, int windows, int doors, int rooms) {
        this.walls = walls;
        this.windows = windows;
        this.doors = doors;
        this.rooms = rooms;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1694148161497&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    // 전달해야 하는 인자값의 순서를 정확히 알기 힘들다.
    Home home = new Home(4, 4, 1, 2, true, true, false, true);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;그러나 점층적 생성자 패턴은 만들어야 하는 인스턴스에 조합이 다양해질수록 그에 대응하는 생성자 메서드를 만들어줘야 하며, 전달해야 하는 인자값이 많아질수록 인자값의 순서를 알기가 힘들어 가독성이 떨어진다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;자바 빈즈 패턴&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;자바 빈 패턴은 setter 메서드를 이용해 객체를 생성하는 패턴이다. 매개변수가 없는 생성자로 객체를 생성 후 setter 메서드를 이용해 클래스의 필드값을 설정하는 방식이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1694147996133&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Home {
    private int walls;
    private int windows;
    private int doors;
    private int rooms;
    private boolean hasHeating;
    private boolean hasGarage;
    private boolean hasSwimPool;
    private boolean hasGarden;

    public void setWalls(int walls) {
        this.walls = walls;
    }

    public void setWindows(int windows) {
        this.windows = windows;
    }

    public void setDoors(int doors) {
        this.doors = doors;
    }

    public void setRooms(int rooms) {
        this.rooms = rooms;
    }

    public void setHasHeating(boolean hasHeating) {
        this.hasHeating = hasHeating;
    }

    public void setHasGarage(boolean hasGarage) {
        this.hasGarage = hasGarage;
    }

    public void setHasSwimPool(boolean hasSwimPool) {
        this.hasSwimPool = hasSwimPool;
    }

    public void setHasGarden(boolean hasGarden) {
        this.hasGarden = hasGarden;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1694148113880&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    public static void main(String[] args) {
        // 기본 집
        Home defaultHome = new Home();
        defaultHome.setDoors(2);
        defaultHome.setWindows(2);
        defaultHome.setWalls(2);
        defaultHome.setRooms(3);

        // 정원이 있는 집
        Home hasGardenHome = new Home();
        hasGardenHome.setHasGarage(true);
        hasGardenHome.setDoors(2);
        hasGardenHome.setWindows(2);
        hasGardenHome.setWalls(2);
        hasGardenHome.setRooms(3);

        // 수영장이 있는 집
        Home hasSwinPoolHome = new Home();
        hasSwinPoolHome.setHasSwimPool(true);
        hasSwinPoolHome.setDoors(2);
        hasSwinPoolHome.setWindows(2);
        hasSwinPoolHome.setWalls(2);
        hasSwinPoolHome.setRooms(3);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;자바 빈 패턴은 생성자 오버로딩을 사용했을 때 나타났던 가독성 문제와 많은 생성자를 만들어야 했던 문제가 사라진다. 그러나 이 방식은 객체 하나를 만들기 위해 여러 메서드를 호출해야 하며, 객체 생성 시점에 모든 값들을 주입하지 않아 일관성(consistency) 문제와 불변성(immutable) 문제가 나타나게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;일관성&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;일관성이란 인스턴스를 생성할 때 필요한 필수 필드값들 반드시 설정되어 있어야 하며, 몇 번을 찍어내도 필수 값들이 존재하는 상태를 말한다. 그러나 자바 빈즈 패턴은 개발자가 실수로 setter 메서드를 호출하지 않는다면 해당 인스턴스는 일관성이 무너진 상태가 된다. 즉, 런타임 예외를 발생시킬 수도 있다. 해당 문제점은 생성자와 결합하여 해소할 수 있으나 불변성의 문제 때문에 자바 빈즈 패턴은 지양한다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;불변성&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;setter 메서드는 객체를 처음 생성할 때 필드값을 설정하기 위해 존재하는 메서드다. 그러나 setter 메서드는 외부에 노출되어 있는 메서드이다. 협업 과정 중 누군가 setter 메서드를 호출하여 객체를 조작할 수 있게 된다. 그렇기에 불변성을 보장할 수 없게 된다. (창문이 3개만 달린 Home 객체를 만들고 싶었으나 누군가가 창문을 10개로 늘릴 수도 있는 것이다.)&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;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;위와 같은 문제점들을 해결하기 위해 나온 것이 빌더 패턴(Builder Pattern)이다. 빌더 패턴은 객체 생성에 필요한 값들을 단계별로 채워갈 수 있으며, 최종적으로는 build 메서드로 인스턴스를 생성한다. 또한 모든 단계를 호출할 필요가 없어 객체의 특정 설정을 제작하는 데 필요한 단계들만을 호출하여 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;Builder Pattern 구현 예제&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;Builder Pattern은 구현 방법이 2가지로 나뉜다. 패턴이 등장한 시기와 해당 문제를 바라보고 해결하는 관점이 달랐기 때문이라고 생각한다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;GoF Builder Pattern: 객체의 생성을 단계별로 구현하고 싶을 때 사용한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;Simple Builder Pattern: 생성 시 지정해야 할 인자가 많을 때 사용. 객체의 일관성 불변성이 목적이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;GoF Builder Pattern&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1804&quot; data-origin-height=&quot;1822&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bs80BG/btstzormevp/lVGeIPQFYVu6CvD7WotuoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bs80BG/btstzormevp/lVGeIPQFYVu6CvD7WotuoK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bs80BG/btstzormevp/lVGeIPQFYVu6CvD7WotuoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbs80BG%2Fbtstzormevp%2FlVGeIPQFYVu6CvD7WotuoK%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;550&quot; height=&quot;555&quot; data-origin-width=&quot;1804&quot; data-origin-height=&quot;1822&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1694130510525&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface HomeBuilder {
  HomeBuilder walls(int walls);
  HomeBuilder windows(int windows);
  HomeBuilder doors(int doors);
  HomeBuilder rooms(int rooms);
  HomeBuilder hasHeating(boolean hasHeating);
  HomeBuilder hasGarage(boolean hasGarage);
  HomeBuilder hasSwimPool(boolean hasSwimPool);
  HomeBuilder hasGarden(boolean hasGarden);
  Home build();
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1694137848577&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Home {
    private String name;
    private int walls;
    private int windows;
    private int doors;
    private int rooms;
    private boolean hasHeating;
    private boolean hasGarage;
    private boolean hasSwimPool;
    private boolean hasGarden;

	// getter, setter 코드 생략

    @Override
    public String toString() {
        return &quot;Home{&quot; +
            &quot;name='&quot; + name + '\'' +
            &quot;, walls=&quot; + walls +
            &quot;, windows=&quot; + windows +
            &quot;, doors=&quot; + doors +
            &quot;, rooms=&quot; + rooms +
            &quot;, hasHeating=&quot; + hasHeating +
            &quot;, hasGarage=&quot; + hasGarage +
            &quot;, hasSwimPool=&quot; + hasSwimPool +
            &quot;, hasGarden=&quot; + hasGarden +
            '}';
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1694162393147&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class DefaultHomeBuilder implements HomeBuilder{

  private String name;
  private int walls;
  private int windows;
  private int doors;
  private int rooms;
  private boolean hasHeating;
  private boolean hasGarage;
  private boolean hasSwimPool;
  private boolean hasGarden;

  @Override
  public HomeBuilder name(String name) {
    this.name = name + &quot;(기본)&quot;;
    return this;
  }

  @Override
  public HomeBuilder walls(int walls) {
    this.walls = walls;
    return this;
  }

  @Override
  public HomeBuilder windows(int windows) {
    this.windows = windows;
    return this;
  }

  @Override
  public HomeBuilder doors(int doors) {
    this.doors = doors;
    return this;
  }

  @Override
  public HomeBuilder rooms(int rooms) {
    this.rooms = rooms;
    return this;
  }

  @Override
  public HomeBuilder hasHeating(boolean hasHeating) {
    this.hasHeating = hasHeating;
    return this;
  }

  @Override
  public HomeBuilder hasGarage(boolean hasGarage) {
    this.hasGarage = hasGarage;
    return this;
  }

  @Override
  public HomeBuilder hasSwimPool(boolean hasSwimPool) {
    this.hasSwimPool = hasSwimPool;
    return this;
  }

  @Override
  public HomeBuilder hasGarden(boolean hasGarden) {
    this.hasGarden = hasGarden;
    return this;
  }

  @Override
  public Home build() {
    Home home = new Home();
    home.setName(this.name);
    home.setWalls(this.walls);
    home.setRooms(this.rooms);
    home.setWindows(this.windows);
    home.setDoors(this.doors);
    home.setHasGarden(this.hasGarden);
    home.setHasGarage(this.hasGarage);
    home.setHasSwimPool(this.hasSwimPool);
    home.setHasHeating(this.hasHeating);
    return home;
  }
}

public class ModernHomeBuilder implements HomeBuilder{
  // 필드값 선언문 코드 생략
  // 메서드 오버라이딩 코드 생략
}

public class VintageHomeBuilder implements HomeBuilder{
  // 필드값 선언문 코드 생략
  // 메서드 오버라이딩 코드 생략
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1694162421340&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class HomeDirector {

  private HomeBuilder homeBuilder;

  public HomeDirector(HomeBuilder homeBuilder){
    this.homeBuilder = homeBuilder;
  }


  public Home hasGardenHome(){
    return homeBuilder
        .hasGarden(true)
        .name(&quot;정원이 있는 집&quot;)
        .doors(5)
        .rooms(3)
        .windows(8)
        .walls(4)
        .build();
  }


  public Home hasHeatingHome(){
    return homeBuilder
        .hasHeating(true)
        .name(&quot;난방기가 있는 따뜻한 집&quot;)
        .doors(3)
        .rooms(3)
        .windows(12)
        .walls(4)
        .build();
  }

  public Home hasSwimPoolHome(){
    return homeBuilder
        .hasSwimPool(true)
        .name(&quot;수영장이 있는 집&quot;)
        .doors(3)
        .rooms(3)
        .windows(12)
        .walls(4)
        .build();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1694162440122&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Client {
    public static void main(String[] args) {
        HomeDirector defaultHomeDirector = new HomeDirector(new DefaultHomeBuilder());
        System.out.println(defaultHomeDirector.hasGardenHome());

        HomeDirector modernHomeDirector = new HomeDirector(new ModernHomeBuilder());
        System.out.println(modernHomeDirector.hasHeatingHome());

        HomeDirector vintageHomeDirector = new HomeDirector(new VintageHomeBuilder());
        System.out.println(vintageHomeDirector.hasSwimPoolHome());
    }
}

// console 결과
Home{name='정원이 있는 집(기본 스타일)', walls=4, windows=8, doors=5, rooms=3, hasHeating=false, hasGarage=false, hasSwimPool=false, hasGarden=true}
Home{name='난방기가 있는 따뜻한 집(모던 스타일)', walls=4, windows=12, doors=3, rooms=3, hasHeating=true, hasGarage=false, hasSwimPool=false, hasGarden=false}
Home{name='수영장이 있는 집(빈티지 스타일)', walls=4, windows=12, doors=3, rooms=3, hasHeating=false, hasGarage=false, hasSwimPool=true, hasGarden=false}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;GoF Builder Pattern을 구현하는 순서를 살펴보자.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;빌더 인터페이스를 통해 제품을 생성할 때 필요한 단계들을 정의한다. 이때 리턴값은 자기 자신으로 하는데 그 이유는 자기 자신을 리턴함으로써 메서드 체이닝을 하기 위함이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;만들어질 객체(Home)의 클래스를 작성한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;각 제품을 표현하고 싶은 대로 빌더 인터페이스의 구현 클래스를 만들고 생성 단계들을 구현한다.(기본 집, 모던한 집, 빈티지한 집 등....)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;디렉터 클래스를 만들어 준다. 자주 만들어질 인스턴스를 탬플릿화 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;클라이언트는 빌더 객체와 디렉터 객체를 모두 생성하여 디렉터에 빌더를 전달한다. 디렉터를 통해서 미리 탬플릿화 되어있는 객체를 제공받아 사용한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;GoF의 Builder Pattern는 Simple Builder Pattern과 다르게 Director를 이용하여 자주 사용되는 제품을 템플릿화 하여 제공한다. Director 클래스는 같은 빌더 객체를 사용하여 제품을 제작하는 다양한 방법들을 캡슐화할 수 있다. 또한 Client는 미리 정의된 인스턴스를 호출함으로써 코드를 재사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;Simple Builder Pattern&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;834&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lXJX4/btstpCRTptY/GY9RNJkcFffYaDf01Bibr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lXJX4/btstpCRTptY/GY9RNJkcFffYaDf01Bibr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lXJX4/btstpCRTptY/GY9RNJkcFffYaDf01Bibr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlXJX4%2FbtstpCRTptY%2FGY9RNJkcFffYaDf01Bibr1%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;650&quot; height=&quot;456&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;834&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1694402536852&quot; class=&quot;arduino&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Home {
    private int walls;
    private int windows;
    private int doors;
    private int rooms;
    private boolean hasHeating;
    private boolean hasGarage;
    private boolean hasSwimPool;
    private boolean hasGarden;

    // 빌더 객체로만 초기화 될수 있도록 생성자는 private 로 한다.
    private Home(){}

    public static class Builder {
        // 필수 필드값
        private int walls;
        private int windows;
        private int doors;
        private int rooms;

        // 선택 필드값
        private boolean hasHeating;
        private boolean hasGarage;
        private boolean hasSwimPool;
        private boolean hasGarden;

        // 필수 필드값(매개변수)들은 빌더 생성자를 통해 받게 한다.
        public Builder(int walls, int windows, int doors, int rooms){
            this.walls = walls;
            this.windows = windows;
            this.doors = doors;
            this.rooms = rooms;
        }

        public Builder hasHeating(boolean hasHeating) {
            this.hasHeating = hasHeating;
            return this;
        }

        public Builder hasGarage(boolean hasGarage) {
            this.hasGarage = hasGarage;
            return this;
        }

        public Builder hasSwimPool(boolean hasSwimPool) {
            this.hasSwimPool = hasSwimPool;
            return this;
        }

        public Builder hasGarden(boolean hasGarden) {
            this.hasGarden = hasGarden;
            return this;
        }

        public Home build() {
            Home home = new Home();
            home.walls = this.walls;
            home.windows = this.windows;
            home.doors = this.doors;
            home.rooms = this.rooms;
            home.hasHeating = this.hasHeating;
            home.hasGarage = this.hasGarage;
            home.hasSwimPool = this.hasSwimPool;
            home.hasGarden = this.hasGarden;
            return home;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;simple builder pattern을 구현하는 순서를 살펴보자.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;먼저 대상 객체인 Home의 인스턴스는 빌더를 통해서만 생성해야 하기 때문에 private로 정의한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;빌더 클래스는 static inner class로 구현한다(그 이유는 조금 더 아래서 살펴보자.)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;빌더 클래스의 생성자는 public으로 하여 필수 필드값에 대해 생성자 매개변수로 받을 수 있게 하고, 선택적 매개변수는 메서드를 제공한다. 이때 메서드의 리턴값은 builder객체 자신이어야 하는데 이는 메서드 체이닝을 하기 위함이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;마지막으로는 최종적으로 객체를 생성하는 build() 메서드를 제공하여 최종적으로 인스턴스를 생성하여 전달한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;이때 주의할 점은&amp;nbsp;&lt;span style=&quot;text-align: start;&quot;&gt;빌더 클래스를 이용해 인스턴스를 생성할 때&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;그&amp;nbsp;대상이 되는 객체는 오로지 빌더 클래스에 의해 객체가 생성돼야 한다&lt;/span&gt;. 그렇기에 생성 대상인 외부 클래스의 생성자는 private로 정의하고, 내부 빌더 클래스에서 private 생성자를 호출함으로써 빌더 객체에 의해 초기화될 수 있도록 한다. 또한 빌더 클래스는 static inner class로 구현되야 한다. 그 이유를 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;Inner static class를 사용하는 이유&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;첫 번째, 하나의 빌더 클래스는 하나의 대상 객체 생성만을 생성한다. 그렇기에 두 클래스 간의 관계를 쉽게 파악할 수 있도록 물리적으로 같은 클래스에 위치한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;두 번째, static으로 선언하는 이유는&amp;nbsp;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;일반 내부 클래스는 외부 클래스를 먼저 인스턴스화하지 않으면 사용할 수 없다&lt;/span&gt;. 외부 클래스에 인스턴스를 만들기 위한 빌더 객체가 외부 클래스의 인스턴스 없이는 만들 수 없는 모순적인 일이 생기게 된다. 그렇기에 정적 내부 클래스를 사용하여 외부 클래스의 인스턴스 없이도 빌더 객체를 생성할 수 있도록 하는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1694402536857&quot; class=&quot;arduino&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    public static void main(String[] args) {
        // 외부 클래스를 먼저 생성해야만 builder 객체를 생성할 수 있다.
        Home home = new Home();
        Home.Builder builder = home.new Builder(1,2,3,4);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;세 번째, 메모리 누수 문제가 있다고 한다. (이는 추후 자세히 알아보자.)&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;사용시기&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;점층적 생성자 패턴(생성자 오버로딩)을 제거하고 싶을 때&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;점층적 생성자 패턴은 필요한 매개변수가 많아지고 조합이 복잡해질수록 많은 생성자를 만들어야 한다. 이를 제거하고 실제로 필요한 필드값들만을 단계별로 생성하고 싶을 때 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;일관성과 불변성을 지키고 싶을때&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;인스턴스를 생성할 때 필요한 필수 필드값들 반드시 설정되어 있어야 하며, 값이 누군가에 의해 조작되지 않길 원할 때에 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;제품(객체)을 다양하게 표현하고 싶을 때&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;예제에 나온 DefaultHomeBuilder, ModernHomeBuilder, VintageHomeBuilder 빌더들은 Home을 다양하게 표현한다. 이처럼 빌더 인터페이스로 모든 단계를 구현하고 제품을 여러 표현대로 생성하고 싶을 때 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;마무리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;빌더 패턴을 사용하면 객체를 구현할 때 단계적으로 필요한 필드값들만을 초기화할 수 있다. 객체(제품)를 다양하게 표현하고 싶을 때 같은 생성 코드를 재사용할 수 있다. 비즈니스 로직에서 복잡한 생성 코드를 고립시킬 수 있다&amp;nbsp; 그러나 패턴이 여러 개의 새 클래스를 생성해야 하므로 복잡성이 증가한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;참조&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;background-color: #e6f5ff; color: #0070d1;&quot; href=&quot;https://www.inflearn.com/course/%EA%B0%9C%EB%B0%9C%EC%9E%90-%EB%A9%B4%EC%A0%91-cs-%ED%8A%B9%EA%B0%95&quot;&gt;CS 지식의 정석 | 디자인패턴 네트워크 운영체제 데이터베이스 자료구조&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4&quot;&gt;백기선 - 코딩으로 학습하는 GoF의 디자인 패턴&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://refactoring.guru/ko/design-patterns/abstract-factory&quot;&gt;디자인 패턴에 뛰어들기 - 알렉산더 슈베츠&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.yes24.com/Product/Goods/115576266&quot;&gt;https://www.yes24.com/Product/Goods/115576266&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://inpa.tistory.com/entry/GOF-%F0%9F%92%A0-%EB%B9%8C%EB%8D%94Builder-%ED%8C%A8%ED%84%B4-%EB%81%9D%ED%8C%90%EC%99%95-%EC%A0%95%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;빌더패턴&amp;nbsp;-&amp;nbsp;완벽&amp;nbsp;마스터(Inpa&amp;nbsp;dev님)&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Tech Notes</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/64</guid>
      <comments>https://doosicee.tistory.com/entry/Builder-Pattern-%EB%B9%8C%EB%8D%94-%ED%8C%A8%ED%84%B4#entry64comment</comments>
      <pubDate>Mon, 4 Sep 2023 08:58:42 +0900</pubDate>
    </item>
    <item>
      <title>Abstract Factory Pattern (추상 팩토리 패턴)</title>
      <link>https://doosicee.tistory.com/entry/Abstract-Factory-Pattern-%EC%B6%94%EC%83%81-%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;642&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xvwrd/btsrYMAAMX3/e097yHmaCkyYnJ9Bk4uRX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xvwrd/btsrYMAAMX3/e097yHmaCkyYnJ9Bk4uRX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xvwrd/btsrYMAAMX3/e097yHmaCkyYnJ9Bk4uRX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxvwrd%2FbtsrYMAAMX3%2Fe097yHmaCkyYnJ9Bk4uRX1%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;1280&quot; height=&quot;642&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;642&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;Abstract Factory Pattern (추상 팩토리 패턴) 이란?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;관련 있는 여러 인스턴스를 만들어주는 팩토리를 구체적인 클래스에 의존하지 않고 만들 수 있게 해주는 생성패턴이다. 즉, 구체적인 구현에는 의존하지 않고 인터페이스에 주목하여, &lt;span style=&quot;background-color: #dddddd;&quot;&gt;인터페이스만을 사용해서 부품을 조립하고 제품으로 완성하는 패턴&lt;/span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dDMqED/btsrTOzC6g6/O8neZ5xketGtcp74leohKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dDMqED/btsrTOzC6g6/O8neZ5xketGtcp74leohKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dDMqED/btsrTOzC6g6/O8neZ5xketGtcp74leohKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdDMqED%2FbtsrTOzC6g6%2FO8neZ5xketGtcp74leohKK%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;800&quot; height=&quot;300&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;364&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;AbstractFactory: 추상적인 공장이다. 추상적인 공장에서는 추상적인 제품을 생산한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;ProductA, ProductB: 추상적인 제품이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;ConcreateFactory: 추상적인 공장의 구현체다. 즉, 구체적인 공장이다. 구체적인 제품을 생산한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;ConcreateProductA, ConcreateProductB: 추상적인 제품의 구현체이다. 즉, 구체적인 제품이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;Client: 의뢰자다. 구체적인 공장이나 제품에 대해서는 알지 못하며, 추상적인 공장을 사용하여 제품을 만들어낸다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;추상 팩토리 패턴은 인터페이스만을 사용해서 부품을 조립하고 제품으로 완성하는 패턴이다. 팩토리 패턴과 굉장히 비슷하다고 느껴진다. 그러나 이것은 디자인 패턴의 특징이다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;어떠한 문제를 바라볼때 생각하는 관점에 따라서 해결할 수 있는 방법이 다른 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 140px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;추상 팩토리(Abstract factory) 패턴&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;팩토리 메서드(Factory method) 패턴&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;공통점&lt;/td&gt;
&lt;td style=&quot;width: 66.6666%; height: 20px;&quot; colspan=&quot;2&quot;&gt;둘다 구체적인 객체 생성 과정을 추상화한 인터페이스를 제공한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 40px;&quot;&gt;관점&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 40px;&quot;&gt;팩토리를 사용하는 방법 (composition)에 초점을 둔다.&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 40px;&quot;&gt;팩토리를 구현하는 방법 (ingeritance)에 초점을 둔다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 60px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 60px;&quot;&gt;목적&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 60px;&quot;&gt;관련있는 여러 객체를 구체적인 클래스에 의존하지 않고 만들 수 있게 해주는 것.&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 60px;&quot;&gt;구체적인 객체 생성 과정을 하위 또는 구체적인 클래스로 옮기는 것.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;Abstract Factory Pattern 사용 전 문제점&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1692787875466&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class WhiteshipFactory extends DefaultShipFactory{
  
  @Override
  public Ship createShip() {
    Ship ship = new Whiteship();
    ship.setAnchor(new WhiteAnchor());
    ship.setWheel(new WhiteWheel());
    return ship;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;공장에서 배를 생산할 때에 anchor(닻)와 wheel(조종키)을 만들어줘야 한다. 위의 코드는 WhiteAnchor(닻)과 WhiteWheel(조종키)의 구체적인 코드를 알고 있다. 이때 기존에 생산하던 제품이 아니라 변형이 필요한 경우 위의 코드를 계속 변경해줘야 하는 문제점이 생긴다. 이러한 문제점을 해결하기 위한 패턴이 Abstract Factory Pattern이다. 계속 코드가 변경돼야 하는 문제점을 해결하며, 제품군을 계속 바꿔나갈 수 있게 한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;Abstract Factory Pattern 구현 예제&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2288&quot; data-origin-height=&quot;1462&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCvGBh/btsrUtCjMLp/PCkYpKISRIWc2m9O5wnACk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCvGBh/btsrUtCjMLp/PCkYpKISRIWc2m9O5wnACk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCvGBh/btsrUtCjMLp/PCkYpKISRIWc2m9O5wnACk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCvGBh%2FbtsrUtCjMLp%2FPCkYpKISRIWc2m9O5wnACk%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;700&quot; height=&quot;447&quot; data-origin-width=&quot;2288&quot; data-origin-height=&quot;1462&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1692839303469&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface ShipFactory {

  // java8에 추가된 디폴트 메서드
  // 객체 생성 전처리/ 후처리 메서드
  default Ship orderShip(String name, String email){
    validate(email);

    prepareFor(name);

    // 선박 객체 생성
    Ship ship = createShip();

    sendEmailTo(email, ship);
    return ship;
  }
  
  // 팩토리 추상 메서드
  Ship createShip();

  // Java9에 추가된 private 메서드
  private void sendEmailTo(String email, Ship ship){
    System.out.println(ship.getName() + &quot; 다 만들었습니다.&quot;);
  };

  private void validate(String email){
    if (email == null || email.isBlank()) {
      throw new IllegalArgumentException(&quot;연락처를 남겨주세요.&quot;);
    }
  }

  private static void prepareFor(String name){
    System.out.println(name + &quot; 만들 준비중&quot;);
  }
}

public abstract class DefaultShipFactory implements ShipFactory {
    @Override
    public void sendEmailTo(String email, Ship ship) {
        System.out.println(ship.getName() + &quot; 다 만들었습니다.&quot;);
    }
}

public class WhiteshipFactory extends DefaultShipFactory{

  private ShipPartsFactory shipPartsFactory;

  public WhiteshipFactory(ShipPartsFactory shipPartsFactory){
    this.shipPartsFactory = shipPartsFactory;
  }

  @Override
  public Ship createShip() {
    Ship ship = new Whiteship();
    ship.setAnchor(shipPartsFactory.createAnchor());
    ship.setWheel(shipPartsFactory.createWheel());
    return ship;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692839687919&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Data
public class Ship {
    private String name;
    private String color;
    private String logo;
    private Wheel wheel;
    private Anchor anchor;
}

public class Whiteship extends Ship {
    public Whiteship() {
        setName(&quot;whiteship&quot;);
        setLogo(&quot;\uD83D\uDEE5️&quot;);
        setColor(&quot;white&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1692840640534&quot; class=&quot;java&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface ShipPartsFactory {
  Anchor createAnchor();
  Wheel createWheel();
}

public class WhiteshipPartsFactory implements ShipPartsFactory{
  @Override
  public Anchor createAnchor() {
    return new WhiteAnchor();
  }
  @Override
  public Wheel createWheel() {
    return new WhiteWheel();
  }
}

public class WhiteshipPartsProFactory implements ShipPartsFactory{
  @Override
  public Anchor createAnchor() {
    return new WhiteAnchorPro();
  }
  @Override
  public Wheel createWheel() {
    return new WhiteWheelPro();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;먼저&lt;span style=&quot;font-family: 'Noto Sans Light'; text-align: left;&quot;&gt; Client 역할을 맡고있는 WhiteshipFactory를 생성한다.&lt;/span&gt; 눈여겨 봐야할 곳은 WhiteshipFactory 클래스에 createShip() 메서드다.&amp;nbsp; &lt;span style=&quot;font-family: 'Noto Sans Light'; text-align: start;&quot;&gt;&amp;nbsp;Abstract Factory Pattern 사용 전 문제점에서는 어떠한 anchor, wheel을 만들어야 하는지 구체적으로 알고있기에 변경이 필요할 경우 계속 코드가 변경돼야 하는 문제점이 있었다.&lt;/span&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;font-family: 'Noto Sans Light'; background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; text-align: start;&quot;&gt;그러나 추상 팩토리 패턴에서는 anchor, wheel이 생성되는 부분을 ShipPartsFactory 인터페이스 즉, 추상적인 공장을 주입받아 구체적인 클래스에 의존하지 않고 만들수 있게 되었다. &lt;span style=&quot;font-family: 'Noto Sans Light'; text-align: left;&quot;&gt;구체적인 공장이나 제품에 대해서는 알지 못하지만, 추상적인 공장을 사용하여 제품을 만들어낼 수 있게 되었다.&lt;/span&gt;&lt;/span&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;font-family: 'Noto Sans Light'; background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; text-align: start;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; text-align: left;&quot;&gt;사용할때는 아래 코드와 같이 사용할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1692840659825&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ShipInventory {

  public static void main(String[] args) {
    ShipFactory shipFactory = new WhiteshipFactory(new WhiteshipPartsFactory());
    Ship ship = shipFactory.createShip();

    ShipFactory shipProFactory = new WhiteshipFactory(new WhiteshipPartsProFactory());
    Ship shipPro = shipProFactory.createShip();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;사용시기&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;다양한 제품을 찍어내야 하지만 해당 제품들에 구체적인 클래스에 의존하지 않고싶을때&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;위의 예제코드에서 wheel(조종키) 제품을 만들었다. 이때 하나의 제품군이 아니라 빈티지, 현대식 등... 다른 형태의 제품이 필요한 경우 추상 팩토리 패턴을 사용함으로써 기존 코드를 변경하지 않으면서도 제품군을 확장할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;여러 제품군을 찍어내야 할때&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;잘 설계된 프로그램은 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;각 클래스는 하나의 책임만을 가지도록 한다&lt;/span&gt;. 만약 하나의 클래스가 여러 제품유형을 제조할 경우 추상 팩토리 패턴을 사용해 볼 가능성을 생각해 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;마무리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;추상 팩토리 패턴을 사용시 개방/폐쇄 원칙을 준수할 수 있으며, 제품마다의 생성 코드를 한곳으로 추출하여 단일 책임 원칙 또한 준수할 수 있다. 또한 구성 제품들과 클라이언트 코드 사이에 단단한 결합을 피할 수 있다는 장점이 있다. 그러나 너무 많은 클래스들이 생긴다. 추상 팩토리 패턴을 학습하며 필요 이상으로 코드가 복잡해진다는 생각이 들었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;패턴들을 적용하기 전에는 정말 패턴이 필요한게 맞는지 많은 고민을하고 사용해야 겠다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;background-color: #e6f5ff; color: #0070d1;&quot; href=&quot;https://www.inflearn.com/course/%EA%B0%9C%EB%B0%9C%EC%9E%90-%EB%A9%B4%EC%A0%91-cs-%ED%8A%B9%EA%B0%95&quot;&gt;CS 지식의 정석 | 디자인패턴 네트워크 운영체제 데이터베이스 자료구조&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4&quot;&gt;백기선 - 코딩으로 학습하는 GoF의 디자인 패턴&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://refactoring.guru/ko/design-patterns/abstract-factory&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;디자인 패턴에 뛰어들기 - 알렉산더 슈베츠&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;JAVA 언어로 배우는 디자인 패턴 입문&quot; href=&quot;https://www.yes24.com/Product/Goods/115576266&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.yes24.com/Product/Goods/115576266&lt;/a&gt;&lt;/p&gt;</description>
      <category>개발/Tech Notes</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/63</guid>
      <comments>https://doosicee.tistory.com/entry/Abstract-Factory-Pattern-%EC%B6%94%EC%83%81-%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4#entry63comment</comments>
      <pubDate>Thu, 24 Aug 2023 20:20:47 +0900</pubDate>
    </item>
    <item>
      <title>Factory Method Pattern (팩토리 메서드 패턴)</title>
      <link>https://doosicee.tistory.com/entry/Factory-Pattern-%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;642&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dCS2kg/btsrYN7kapG/aJbhm9vX7LpAkHVKNTbNc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dCS2kg/btsrYN7kapG/aJbhm9vX7LpAkHVKNTbNc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dCS2kg/btsrYN7kapG/aJbhm9vX7LpAkHVKNTbNc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdCS2kg%2FbtsrYN7kapG%2FaJbhm9vX7LpAkHVKNTbNc1%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;1280&quot; height=&quot;642&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;642&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;해당 글은 Java 8에 default 메서드가 추가된 이후 interface를 사용해 팩토리 메서드를 구현하는 것을 기준으로 작성된 글입니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Factory Method Pattern(팩토리 메서드 패턴) 이란?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;팩토리 패턴은 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;구체적인 인스턴스에 대한 구현을 서브 클래스가 정하는 패턴&lt;/span&gt;이다. 즉, 부모클래스에서 객체들을 생성할 수 있는 뼈대(interface)를 제공하고, 자식 클래스들이 생성될 객체의 유형을 결정할 수 있도록 하는 생성 패턴이다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5oCCO/btsqD6sUZGg/GWoM247FPzSzFe1LvbkHl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5oCCO/btsqD6sUZGg/GWoM247FPzSzFe1LvbkHl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5oCCO/btsqD6sUZGg/GWoM247FPzSzFe1LvbkHl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5oCCO%2FbtsqD6sUZGg%2FGWoM247FPzSzFe1LvbkHl0%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;550&quot; height=&quot;318&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;430&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;Creator: 뼈대 즉, interface를 제공하는 최상위 팩토리 인터페이스다. 서브 클래스들에게 구현을 위임한다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;templateMethod(): 객체 생성에 관한 전처리, 후처리를 템플릿화 한 메서드(공통 작업 처리)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;createProduct(): 서브 클래스에서 구현해야 할 객체 생성 추상 메서드&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;ConcreteCreator: 서브 클래스로써 구현해야 할 제품에 맞는 제품 객체를 반환하도록 추상 메서드를 구현한다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;Product: 제품 구현체를 추상화&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;ConcreteProduct: 제품 구현체&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000; text-align: start;&quot;&gt;팩토리 메서드 패턴은 객체(제품)를 만들어내는 공장을 만드는 패턴이라고 볼 수 있다. 어떤 제품이 생성될지에 관한 자세한 내용은 서브 클래스에서 결정한다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000; text-align: start;&quot;&gt;만드는 방법이 번거로움에도 불구하고 사용하는 이유는 상위 클래스는 객체 생성방식에 대 해 알 필요가 없기에 유연성을 갖게 되고, 객체의 구체적인 구현은 하위 클래스에서 구현하기 때문에 유지보수성이 증가하기 때문이다. 아래의 예제를 통해 사용하는 이유에 대해 조금 더 자세히 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Factory Method Pattern 사용 전 문제점&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1690936815302&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Data
public class Ship {
  private String name;
  private String email;
  private String logo;
  private String color;
}

public class ShipFactory {

  public static Ship orderShip(String name, String email){
    if (name == null || name.isBlank()) {
      throw new IllegalArgumentException(&quot;배 이름을 지어주세요.&quot;);
    }
    if (email == null || email.isBlank()) {
      throw new IllegalArgumentException(&quot;이메일을 남겨주세요.&quot;);
    }

    Ship ship = new Ship();
    ship.setName(name);

    if (name.equalsIgnoreCase(&quot;whiteship&quot;)) {
    	ship.setLogo(&quot;\uD83D\uDEE5&quot;);
    } else if(name.equalsIgnoreCase(&quot;blackship&quot;)) {
    	ship.setLogo(&quot;⚓&quot;);
    }
    
    .............
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;위의 코드는 배를 찍어내는 공장이다. 공장에서 흰색 배와 검정색 배 두가지 종류만을 제조한다면 무척이나 간단할 것이다. 그러나 공장이 잘되서 배의 종류가 늘어나고 하늘을 나는 배, 잠수함 등... 많은 것들을 제조하기 시작 한다면 조건이 많아져 구현하는 방법이 매우 복잡해질 것이다. 또한 배에 추가적인 특성이 생길 때 마다 기존 Ship 클래스의 내용이 계속 바뀌어야 한다.&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;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;이는 객체지향 원칙중 open closed principle(개방, 폐쇄) 원칙을 어기게 된다. 요구 사항이 생길 때마다 기존 코드 즉, Ship 클래스가 변해야 되기 때문이다. 이런 때에 팩토리 패턴을 사용하여, 확장에는 열려있고 변경에는 닫혀있는 코드를 작성할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;Factory Method Pattern 구현 예제&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1889&quot; data-origin-height=&quot;859&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beH9X8/btsqERjTvM4/NrKrLDBMe4XdSBeleKQse1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beH9X8/btsqERjTvM4/NrKrLDBMe4XdSBeleKQse1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beH9X8/btsqERjTvM4/NrKrLDBMe4XdSBeleKQse1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeH9X8%2FbtsqERjTvM4%2FNrKrLDBMe4XdSBeleKQse1%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;760&quot; height=&quot;346&quot; data-origin-width=&quot;1889&quot; data-origin-height=&quot;859&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1691567085841&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface ShipFactory {

  // java8에 추가된 디폴트 메서드
  // 객체 생성 전처리/ 후처리 메서드
  default Ship orderShip(String name, String email){
    validate(email);

    prepareFor(name);

    // 선박 객체 생성
    Ship ship = createShip();

    sendEmailTo(email, ship);
    return ship;
  }
  
  // 팩토리 추상 메서드
  Ship createShip();

  // Java9에 추가된 private 메서드
  private void sendEmailTo(String email, Ship ship){
    System.out.println(ship.getName() + &quot; 다 만들었습니다.&quot;);
  };

  private void validate(String email){
    if (email == null || email.isBlank()) {
      throw new IllegalArgumentException(&quot;연락처를 남겨주세요.&quot;);
    }
  }

  private static void prepareFor(String name){
    System.out.println(name + &quot; 만들 준비중&quot;);
  }
}

public class WhiteShipFactory implements ShipFactory{
  @Override
  public Ship createShip() {
    return new Whipteship();
  }
}

public class BlackShipFactory implements ShipFactory{
  @Override
  public Ship createShip() {
    return new BlackShip();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1691569120316&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Data
public class Ship {
  private String name;
  private String email;
  private String logo;
  private String color;
}

public class Whipteship extends Ship{
  public Whipteship() {
    setName(&quot;whiteship&quot;);
    setLogo(&quot;\uD83D\uDEE5&quot;);
    setColor(&quot;white&quot;);
  }
}

public class BlackShip extends Ship{
  public BlackShip(){
    setName(&quot;blackship&quot;);
    setLogo(&quot;⚓&quot;);
    setColor(&quot;black&quot;);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1691570115167&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Client {

  public static void main(String[] args) {
    Client client = new Client();
    client.print(new WhiteShipFactory(), &quot;whiteship&quot;, &quot;white@naver.com&quot;);
    client.print(new BlackShipFactory(), &quot;blackship&quot;, &quot;black@naver.com&quot;);
  }

  private void print(ShipFactory shipFactory, String name, String email) {
    System.out.println(shipFactory.orderShip(name, email));
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;먼저 Creator 즉, 뼈대를 담당할 최상위 팩토리 인터페이스 ShipFactory 를 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;Java 8 버전 이후 추가된 인터페이스의 디폴트 메서드와 Java 9 버전 이후 추가된 private 메서드를 통해 인터페이스로 구성할 수 있게 되었다고 한다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;ShipFactory 인터페이스에서는 서브 클래스에서 구현해야 할 객체 생성 추상 메서드 createShip()을 추상화 한다. 이후 각 선박의 종류에 맞게 ShipFactory 인터페이스를 구현하는 서브 팩토리 클래스를 만들어 createShip() 추상 메서드를 각 객체의 특성에 맞게 구현한다.&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: #000000; font-family: 'Noto Sans Light';&quot;&gt;ShipFactory 인터페이스의 orderShip() 기본 메서드를 보면 팩토리에서 진행되야 할 공통 작업 코드들을 수행하면서 특징에 따라 구현할 Ship 인스턴스를 만드는 작업만을 서브 클래스가 구현하도록 하는 모습을 볼 수 있다.&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: #000000; font-family: 'Noto Sans Light';&quot;&gt;팩토리 메서드 패턴을 적용하기 전 코드는 whiteShip, blackShip에 이어 &lt;span style=&quot;text-align: left;&quot;&gt;merchantShip을 추가한다면 기존 코드에 분기문을 추가하여 코드가 복잡해지고 기존 코드를 계속 수정해야 하는 문제점이 발생했을 것이다. 그러나 팩토리 메서드 패턴을 적용한다면 간단하게 서브 클래스를 구현하고 제품 객체를 정의하여&lt;/span&gt; 확장이 가능하다. 예제를 통해 merchantShip을 추가해보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691570769850&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class MerchantShipFactory implements ShipFactory{
  @Override
  public Ship createShip() {
    return new MerchantShip();
  }
}

public class MerchantShip extends Ship{
  public MerchantShip(){
    setName(&quot;merchantShip&quot;);
    setLogo(&quot; &quot;);
    setColor(&quot;blue&quot;);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1691570830549&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Client {

  public static void main(String[] args) {
    Client client = new Client();
    client.print(new WhiteShipFactory(), &quot;whiteship&quot;, &quot;grande@naver.com&quot;);
    client.print(new BlackShipFactory(), &quot;blackship&quot;, &quot;ariana@naver.com&quot;);
    client.print(new MerchantShipFactory(), &quot;merchantship&quot;, &quot;merchant@naver.com&quot;);
  }

  private void print(ShipFactory shipFactory, String name, String email) {
    System.out.println(shipFactory.orderShip(name, email));
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;위 코드와 같이 기존 소스코드에 아무런 변경없이 확장하였다. 그저 Client 에서 주문하기 위한 코드가 한 줄 추가되었을 뿐이다.&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: #000000; font-family: 'Noto Sans Light';&quot;&gt;확장에는 열려있으며, 변경에는 닫혀있는 구조를 팩토리 메서드 패턴을 이용하여 구현할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;사용시기&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;결합도를 낮추고자 할 때&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;팩토리 메서드 사용 전에는 인스턴스를 생성하고 제품에 따라 분기처리하는 로직이 한곳에 몰려있었다. 그러나 팩토리 메서드 이후에는 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;각각의 제품에 따라 인스턴스를 생성하는 공장이 나뉘고 공장에서 생성하는 제품에 로직에만 신경을 쓰게된다.&lt;/span&gt; 이러한 방식으로 인스턴스 생성부와 제품 처리 로직의 결합도를 낮추고 제품을 추가할때에 기존의 코드를 건드리지 않고 손쉽게 새로운 제품을 추가하고 싶을때 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;라이브러리 또는 프레임워크 사용자에게 컴포넌트를 확장하는 방법을 제공 할 때&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;ShipFactory라는 선박을 만들수 있는 라이브러리를 사용자에게 제공했다고 가정해보자. 해당 라이브러리는 화물용 선박, 전투용 선박 만을 제공한다. 그러나 사용자는 물고기를 잡는 어선이 필요하다. 이때 사용자에게 해당 ShipFactory를 구현할 수 있도록 제공한다면 사용자는 서브 클래스를 만들어 쉽게 어선을 구현 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;기존 객체를 재구성 하기보다 재사용 하려는 경우&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;팩토리 메서드 사용전 문제점 코드를 볼 때 생성로직과 분기처리 로직이 한곳에 모여있다. 대부분의 처리 로직이 중복되지만 제품이 새로 추가되거나, 생성해야 하는 제품에 따라 많은 부분이 변경되어야 하는 경우가 발생할 수 있다. 이때 팩토리 메서드 패턴을 사용한다면 새로 추가되는 제품에 들어가는 특수한 로직은 서브 클래스에서 구현할때 즉, 해당 제품을 만들때에 따로 처리할 수 있게된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;기존 객체를 재구성하지 않고 재사용할 부분들은 재사용하며, 새로 추가되는 제품 처리에 필요한 로직은 해당 제품을 생산하는 서브 클래스에서 별도로 처리할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마무리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;팩토리 메서드 패턴을 사용시 개방, 폐쇄 원칙을 준수할 수 있으며, 서브 클래스를 통해 객체를 구현하기에 수정사항 발생시 해당 서브 클래스만을 수정해도 된다는 유지보수의 편리성이 있다. 또한 제품을 따로따로 구현해도 되기에 여러 개발자가 협업을 통해 개발할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다만 각 제품마다 서브 클래스와 제품 구현체를 구현해주어야 하기 때문에, 작성해주어야 하는 구현체가 늘어날수록 클래스의 수가 많이 증가한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;background-color: #e6f5ff; color: #0070d1;&quot; href=&quot;https://www.inflearn.com/course/%EA%B0%9C%EB%B0%9C%EC%9E%90-%EB%A9%B4%EC%A0%91-cs-%ED%8A%B9%EA%B0%95&quot;&gt;CS 지식의 정석 | 디자인패턴 네트워크 운영체제 데이터베이스 자료구조&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4&quot;&gt;백기선 - 코딩으로 학습하는 GoF의 디자인 패턴&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://inpa.tistory.com/entry/GOF-%F0%9F%92%A0-%ED%8C%A9%ED%86%A0%EB%A6%AC-%EB%A9%94%EC%84%9C%EB%93%9CFactory-Method-%ED%8C%A8%ED%84%B4-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EB%B0%B0%EC%9B%8C%EB%B3%B4%EC%9E%90&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;인파 - 팩토리 패턴&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;팩토리 메서드 패턴&quot; href=&quot;https://refactoring.guru/ko/design-patterns/factory-method&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://refactoring.guru/ko/design-patterns/factory-method&lt;/a&gt;&lt;/p&gt;</description>
      <category>개발/Tech Notes</category>
      <category>백기선</category>
      <category>코딩으로 학습하는 GoF의 디자인 패턴</category>
      <category>팩토리 메서드 패턴</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/62</guid>
      <comments>https://doosicee.tistory.com/entry/Factory-Pattern-%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4#entry62comment</comments>
      <pubDate>Wed, 9 Aug 2023 20:12:30 +0900</pubDate>
    </item>
    <item>
      <title>Instagram Api Refresh Token batch 리펙토링</title>
      <link>https://doosicee.tistory.com/entry/Instagram-Api-Refresh-Token-batch-%EB%A6%AC%ED%8E%99%ED%86%A0%EB%A7%81</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;515&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VGRBg/btsjQgxtaun/RHNY6E27Pyu5bMACJxW0IK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VGRBg/btsjQgxtaun/RHNY6E27Pyu5bMACJxW0IK/img.jpg&quot; data-alt=&quot;출처 : https://nesoy.github.io/articles/2018-05/Refactoring&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VGRBg/btsjQgxtaun/RHNY6E27Pyu5bMACJxW0IK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVGRBg%2FbtsjQgxtaun%2FRHNY6E27Pyu5bMACJxW0IK%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;450&quot; height=&quot;290&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;515&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://nesoy.github.io/articles/2018-05/Refactoring&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;개발도중 Instagram API를 사용해야 할 일이 있었다. 해당 API를 사용하기 위해서는 Token을 발급받아 사용해야 하는데 토큰에 기한이 60일이라 주기적으로 새 토큰을 발급받아야 했다. 그래서 해당 기능을 하는 batch 서비스를 하나 만들게 되었고, 정말 짧은 코드지만 해당 코드를 리펙토링 하는 과정을 메모해 둔다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;초기 작성 코드&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Service
public class TokenService {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 선언부 생략...

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void callInstaRefreshTokenApi(){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TokenVO.Request tokenRequestData = this.getAccessToken();

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;webClientUtil.getBaseUrl(properties.getInstagramApiOptions().getRefreshTokenUrl())
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.get()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.uri(uriBuilder -&amp;gt; uriBuilder
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.queryParam(&quot;grant_type&quot;, properties.getInstagramApiOptions().getGrantType())
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.queryParam(&quot;access_token&quot;, tokenRequestData.getToken())
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.build())
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.accept(MediaType.APPLICATION_JSON)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.retrieve()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.bodyToMono(TokenVO.Response.class)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.doOnSuccess(refresh -&amp;gt; this.saveInstaApiToken(refresh))
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.block();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private TokenVO.Request getAccessToken(){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return tokenRepository.findFirstByOrderByTokenIdDesc().toApiTokenVO();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private void saveInstaApiToken(TokenVO.Response refreshToken){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TokenEntity entity = new TokenEntity();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;entity.setToken(refreshToken.getAccess_token());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;entity.setTokenType(refreshToken.getToken_type());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;entity.setExpiresIn(refreshToken.getExpires_in());

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tokenRepository.save(entity);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;초기에 작성한 코드는 위와 같았다. 서비스레이어에 모든걸 몰아넣었고, 위와 같이 작성한 코드에는 4가지 문제점이 있었다.&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;첫 번째: 코드만 보고 흐름이 한눈에 읽히지 않는다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;두 번째: 테스트 코드를 작성하기에 적합하지 않다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;세 번째: 서비스 레이어가 복잡하다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;callInstaRefreshTokenApi 메서드는 세 가지의 일을 처리하고 있다. 그러나 세 가지의 일을 처리하고 있다는 것이 한눈에 들어오지 않으며,&amp;nbsp; 각각의 작업 단위로 테스트 해볼수가 없다. 또한 서비스 레이어가 상당히 복잡하다. 이것외에도 더 문제가 있을수 있지만 일단 필자의 짧은 지식으로는 총 3개의 문제점을 발견할 수 있었다. 문제를 해결해보자.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;리팩토링&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;callInstaRefreshTokenApi 는 3가지 일을 한다고했다. 그 일은 아래와 같다.&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;토큰 재발급을 위해 DB에 저장되어있는 기존의 Token을 조회해온다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Instagram API에 토큰 재발급을 요청한다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;새로 발급받은 토큰을 저장한다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;위에서 말했던 모든 문제들은 메소드가 적절히 분리되지 않아서 발생되는 문제라고 생각된다. 첫 번째 리펙토링때에는 작업들을 메소드별로 한 가지의 작업 단위로 분리하여 메소드들이 무엇을 하는지 표현하는 것을 목표로하였다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;1차 리팩토링 코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;@Service
public class TokenService {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 선언부 생략...

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void refreshInstaApiToken(){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String accessToken = this.getAccessToken().getToken();

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TokenVO.Response resultApiData = this.callInstaRefrashTokenApi(accessToken);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.saveInstaApiToken(resultApiData);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private TokenVO.Request getAccessToken(){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return tokenRepository.findFirstByOrderByTokenIdDesc().toApiTokenVO();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private TokenVO.Response callInstaRefrashTokenApi(String accessToken){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TokenVO.Response apiResponse = new TokenVO.Response();

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;webClientUtil.getBaseUrl(cProperties.getInstagramApiOptions().getRefreshTokenUrl())
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.get()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.uri(uriBuilder -&amp;gt; uriBuilder
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.queryParam(&quot;grant_type&quot;, cProperties.getInstagramApiOptions().getGrantType())
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.queryParam(&quot;access_token&quot;, accessToken)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.build())
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.accept(MediaType.APPLICATION_JSON)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.retrieve()
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.bodyToMono(TokenVO.Response.class)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.doOnSuccess(refresh -&amp;gt; {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;apiResponse.setAccess_token(refresh.getAccess_token());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;apiResponse.setToken_type(refresh.getToken_type());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;apiResponse.setExpires_in(refresh.getExpires_in());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;})
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.block();

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return apiResponse;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private boolean saveInstaApiToken(TokenVO.Response resultApiData){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TokenEntity entity = new TokenEntity();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;entity.setToken(resultApiData.getAccess_token());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;entity.setTokenType(resultApiData.getToken_type());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;entity.setExpiresIn(resultApiData.getExpires_in());

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;entity = tokenRepository.save(entity);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return entity.getTokenId() != null ? true : false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Slf4j
@SpringBootTest
public class TokenServiceTest {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 선언부 생략....

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Test
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@DisplayName(&quot;인스타그램 Refresh Token API 호출 및 데이터저장&quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void refreshInstaApiToken(){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// given
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TokenVO.Request tokenRequestData = tokenDomain.getAccessToken();

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// when
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TokenVO.Response resultApiResponseData = tokenDomain.callInstaRefreshTokenApi(tokenRequestData.getToken());

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;boolean result = tokenDomain.saveInstaApiToken(resultApiResponseData);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertThat(result).isEqualTo(true);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;세 가지의 작업을 각각의 메소드로 분리하였다. 메인 서비스 로직인 callInstaRefreshTokenApi 에서 세 가지 일을 처리한다는 흐름이 보이기 시작한다. 테스트 코드도 더 명확히 작성할 수 있게 되었다. 이전에는 작업이 제대로 분리되어있지 않아 각각의 기능들을 테스트할수가 없었다. 그러나 위의 코드는 작업 단위로 메소드를 작성하였기에 작업 단위로 테스트가 가능해졌다. 또한 작업의 단위로 분리함으로 인해 메소드의 이름을 통해 해당 메소드가 무슨 작업을 하는지 표현할 수 있게 되었다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;1차 리펙토링 이후 아쉬운것은 서비스 레이어에 메소드가 많아 복잡하고 작업의 흐름에만 집중하기 힘들다. 그래서 위의 코드를 한번 더 개선하였다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;2차 리팩토링 코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Service
public class TokenService {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Autowired
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private TokenDomain tokenDomain;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void refreshInstaApiToken(){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TokenVO.Request tokenRequestData = tokenDomain.getAccessToken();

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TokenVO.Response resultApiResponseData = tokenDomain.callInstaRefreshTokenApi(tokenRequestData.getToken());

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tokenDomain.saveInstaApiToken(resultApiResponseData);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;2차 개선때는 token 관련으로 일을하는 메소드들을 tokenDomain이라는 클래스를 만들어 서비스 레이어와 분리하였다. 서비스 레이어에서는 서비스의 흐름에만 집중할 수 있도록 상세한 로직들은 tokenDomain 클래스에 작성하였다. 테스트코드는 1차 리펙토링때와 같다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;리펙토링을 통하여 위에서 말했던 세 가지의 문제들이 많이 개선되었다고 생각한다.&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;첫 번째: 코드만 보고 흐름이 한눈에 읽히지 않는다.&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;각각의 작업 단위, 즉 한가지의 일만 하도록 메소드를 분리하였고, 메소드의 이름으로 무슨 작업을 하는지 명확히 표현할 수 있게 되었다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;두 번째: 테스트 코드를 작성하기에 적합하지 않다.&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;작업 단위로 메소드를 분리하였기에 각 기능별로 테스트를 할 수 있게 되었다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;세 번째: 서비스 레이어가 복잡하다.&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;상세 로직들을 구현해놓은 domain클래스를 만들어 서비스레이어와 분리함으로써 서비스 레이어는 서비스 로직의 흐름에만 집중할 수 있게 되었다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;주니어 개발자인 필자가 작성한 코드는 많은 선배 개발자들에게 보이기에 너무나도 부끄러운 코드임이 분명하다. 그러나 이 글을 읽고 누군가 조언을 해준다면 좋겠다. 메소드명, 변수명도 많은 고민을 하였지만 더 생각이 나질않고 개선점도 지금에 얕은 지식으로는 더 보이지 않는다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;긴 글 읽어주셔서 감사드립니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/Tech Notes</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/54</guid>
      <comments>https://doosicee.tistory.com/entry/Instagram-Api-Refresh-Token-batch-%EB%A6%AC%ED%8E%99%ED%86%A0%EB%A7%81#entry54comment</comments>
      <pubDate>Sat, 24 Jun 2023 07:00:34 +0900</pubDate>
    </item>
    <item>
      <title>JRebel이 안될때 확인해 볼 사항들</title>
      <link>https://doosicee.tistory.com/entry/JRebel%EC%9D%B4-%EC%95%88%EB%90%A0%EB%95%8C-%ED%99%95%EC%9D%B8%ED%95%B4-%EB%B3%BC-%EC%82%AC%ED%95%AD%EB%93%A4</link>
      <description>&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Euh06/btsjJUTSVie/VxIr1hv548SDgcyLJ2GBlK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Euh06/btsjJUTSVie/VxIr1hv548SDgcyLJ2GBlK/img.jpg&quot; data-alt=&quot;출처: https://twitter.com/JRebel_Java&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Euh06/btsjJUTSVie/VxIr1hv548SDgcyLJ2GBlK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEuh06%2FbtsjJUTSVie%2FVxIr1hv548SDgcyLJ2GBlK%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;400&quot; height=&quot;400&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: https://twitter.com/JRebel_Java&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;JRebel을 잘 사용하던 도중 가끔 안될때가 있다. 여러가지 원인들이 있는데 하나씩 문제가 생길때마다 정리해놓고 기억하기위해 글을 작성한다.&lt;/span&gt;&lt;/b&gt;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;rebel.xml 파일 생성확인&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot;&gt;&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;JRebel 사용시 rebel.xml 파일이 생성되어있어야 한다. rebel.xml은 어느 파일을 핫스왑 해줄지 설정 정보가 적혀있는 파일이다. 아래의 이미지처럼 왼쪽의 체크박스를 클릭시 자동으로 rebel.xml 파일이 생성된다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;360&quot; data-origin-height=&quot;179&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6Ud23/btsjImDiZWb/jom9jw9QWf8mIeEQGvfWtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6Ud23/btsjImDiZWb/jom9jw9QWf8mIeEQGvfWtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6Ud23/btsjImDiZWb/jom9jw9QWf8mIeEQGvfWtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6Ud23%2FbtsjImDiZWb%2Fjom9jw9QWf8mIeEQGvfWtK%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;360&quot; height=&quot;179&quot; data-origin-width=&quot;360&quot; data-origin-height=&quot;179&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: left;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다만 가끔 생성이 안될때가 있는것 같다. 그럴때는 체크박스를 해체했다가 다시 체크해주도록 하자. 이렇게 해도 생성이 안된다면 다른 문제가 있거나 직접 작성해서 사용해보자.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;</description>
      <category>개발/Troubleshooting</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/49</guid>
      <comments>https://doosicee.tistory.com/entry/JRebel%EC%9D%B4-%EC%95%88%EB%90%A0%EB%95%8C-%ED%99%95%EC%9D%B8%ED%95%B4-%EB%B3%BC-%EC%82%AC%ED%95%AD%EB%93%A4#entry49comment</comments>
      <pubDate>Wed, 21 Jun 2023 12:19:38 +0900</pubDate>
    </item>
    <item>
      <title>Window11 Hyper-V 활성화 방법</title>
      <link>https://doosicee.tistory.com/entry/Window11-Hyper-V-%ED%99%9C%EC%84%B1%ED%99%94-%EB%B0%A9%EB%B2%95</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;717&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blTZay/btsjjyetfVQ/GJTKiJ6AWGjKO8KlxuSd6k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blTZay/btsjjyetfVQ/GJTKiJ6AWGjKO8KlxuSd6k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blTZay/btsjjyetfVQ/GJTKiJ6AWGjKO8KlxuSd6k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblTZay%2FbtsjjyetfVQ%2FGJTKiJ6AWGjKO8KlxuSd6k%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;400&quot; height=&quot;224&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;717&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서론&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h2&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;쿠버네티스 강의를 따라가던 도중 Hyper-V를 설치해야 했는데 Windows 11에는 Hyper-V가 기본으로 제공되지 않아 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;오류명: 0x800f080c &quot;microsoft-hyper-v은(는) 알 수 없는 기능 이름입니다.&quot;&lt;/span&gt; 라는 오류가났다. Windows 기능 켜기/끄기 라는 곳에 들어가보면 내 컴퓨터에 Hyper-V가 설치되어있는기 알 수 있다. 나는 없었기에 이를 설치하는 방법을 찾았고 이렇게 설치하는 방법이 좋은 방법인지는 알 수 없으나 설치하는 방법을 공유한다. 더 좋은 방법이 있다면 혹시나 이 방법이 컴퓨터에 악영향을 끼치는 방법이라면 댓글로 알려주시면 좋겠습니다.&lt;/span&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;설치방법&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h2&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;설치 방법은 아주 간단하다. 아래의 순서를 따라서 하나하나 실행해주면 된다.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;메모장을 켜고 아래의 Hyper-V 설치 명령어들을 붙여넣어준다.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;저장시 .txt가 아닌 .bat으로 저장해준다. 저장위치는 자기가 저장하고 싶은곳에 둔다.(필자는 실행파일을 쉽게 찾을수 있도록 바탕화면에 두었다)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;.bat 실행파일을 실행한다.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;재부팅한다.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Hyper-V 설치명령어(메모장에 붙여넣고 .bat 파일로 저장한다)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1686380286024&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pushd &quot;%~dp0&quot;
dir /b %SystemRoot%\servicing\Packages\*Hyper-V*.mum &amp;gt;hyper-v.txt
for /f %%i in ('findstr /i . hyper-v.txt 2^&amp;gt;nul') do dism /online /norestart /add-package:&quot;%SystemRoot%\servicing\Packages\%%i&quot;
del hyper-v.txt
Dism /online /enable-feature /featurename:Microsoft-Hyper-V -All /LimitAccess /ALL
pause&lt;/code&gt;&lt;/pre&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;설치완료 및 마무리&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;415&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/djCVUu/btsjm941Cla/vzJeajQqbDXqDHeIA5IbNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/djCVUu/btsjm941Cla/vzJeajQqbDXqDHeIA5IbNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/djCVUu/btsjm941Cla/vzJeajQqbDXqDHeIA5IbNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdjCVUu%2Fbtsjm941Cla%2FvzJeajQqbDXqDHeIA5IbNK%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;415&quot; height=&quot;366&quot; data-origin-width=&quot;415&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;설치 완료후 Windows 기능 켜기/끄기에 들어가서 Hyper-V가 잘 체크되어있는지 확인한다.&lt;/span&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;참조&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #222222;&quot; href=&quot;https://yscho03.tistory.com/130&quot;&gt;[Docker] Window 10 Home Hyper-V 활성화 방법&lt;/a&gt;&lt;/p&gt;</description>
      <category>개발/Troubleshooting</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/46</guid>
      <comments>https://doosicee.tistory.com/entry/Window11-Hyper-V-%ED%99%9C%EC%84%B1%ED%99%94-%EB%B0%A9%EB%B2%95#entry46comment</comments>
      <pubDate>Wed, 14 Jun 2023 09:00:04 +0900</pubDate>
    </item>
    <item>
      <title>특수 사례 패턴 (외부 API를 대하는 방법)</title>
      <link>https://doosicee.tistory.com/entry/%EA%B2%BD%EA%B3%84-%EC%99%B8%EB%B6%80-API%EB%A5%BC-%EB%8C%80%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-%EC%8B%A4%EC%A0%84%ED%8E%B8</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;books-1281581_1920.jpg&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;729&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HyYu8/btrSqtPxBL8/h8DqCz851biarnOqtwoHBK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HyYu8/btrSqtPxBL8/h8DqCz851biarnOqtwoHBK/img.jpg&quot; data-alt=&quot;출처: Pixabay로부터 입수된 Pexels님의 이미지 입니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HyYu8/btrSqtPxBL8/h8DqCz851biarnOqtwoHBK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHyYu8%2FbtrSqtPxBL8%2Fh8DqCz851biarnOqtwoHBK%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;550&quot; height=&quot;209&quot; data-filename=&quot;books-1281581_1920.jpg&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;729&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: Pixabay로부터 입수된 Pexels님의 이미지 입니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;클린코드라는 책에서 외부 라이브러리를 대하는 방법에 대해 알려주었다. 마침 진행하는 프로젝트에서 검색엔진이라는 외부 API를 사용하였고 해당 API를 사용할 때 특수 사례 패턴을 사용하여 코드를 작성하였다. 분명 부족한 점들이 많겠지만 &lt;/b&gt;&lt;b&gt;이번 글을 통해 어떤 방식으로 적용하였고 어떤 이점들을 얻었는지 정리해보려 한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;특수 사례 패턴 간단 설명 &lt;span style=&quot;color: #ee2323;&quot;&gt;✔&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;클래스를 만들거나 객체를 조작해 특수 사례를 처리하는 방식이다. 클래스나 객체가 예외적인 상황을 캡슐화해서 처리하므로 클라이언트 코드가 예외적인 상황을 처리할 필요가 없어진다.&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;특수 사례 패턴 적용 전 문제점들&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;pre id=&quot;code_1669765931316&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@GetMapping(&quot;/list&quot;)
public ModelAndView ExampleController(
    HttpServletRequest request,
    SearchVO searchVo
){
        SearchEnginRequestDto searchEnginRequestDto = new SearchEnginRequestDto();
        searchEnginRequestDto.setSearchSort(searchVo.getSearchSort());
        searchEnginRequestDto.setPage(searchVo.getPageNum());
        searchEnginRequestDto.setNget(searchVo.getNget());
        
        // 검색엔진 호출의 결과값을 받는다.
        // 호출하는 곳에서 매번 예외처리를 해줘야한다.
        Map&amp;lt;String, Object&amp;gt; map = new HashMap&amp;lt;&amp;gt;();
        try{
            map = new SearchEngin().sendRequest(searchEnginRequestDto);
        }catch(IRException e){
        // Exception 처리
            ........
        }
        
        // 받은 결과값들을 꺼내준다. 
        // 매번 타입캐스팅을 해야한다.
        HashMap resultSet = (HashMap) map.get(&quot;resultSet&quot;);
        HashMap result = new HashMap();
        List&amp;lt;Map&amp;gt; resultList = new ArrayList&amp;lt;&amp;gt;();

        if(!((ArrayList) resultSet.get(&quot;result&quot;)).isEmpty()){
            result = (HashMap) ((ArrayList) resultSet.get(&quot;result&quot;)).get(0);
        }
        if(result.get(&quot;resultDocuments&quot;) != null){
        	resultList  = (List)result.get(&quot;resultDocuments&quot;);
        }
        
        // 결과물을 model에 담아 프론트로 보내준다.
        ModelAndView model = new ModelAndView();
        // .............. 생략
        return model;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Exception 처리를 호출하는 곳에서 항상 처리해 줘야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;사용자가 올바른 유형으로 타입 캐스팅 할 책임을 져야 한다&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;호출하는 곳에서 책임지고 매번 null값을 체크하고 처리해야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;위의 모든 문제들은 호출하는 곳에서 매번 반복되는 문제를 해결해야 한다. 또한 예외처리, 키값 입력, 타입 케스팅, null값 체크는 코드의 길이는 늘리고 가독성은 낮춰 한번에 읽어 내려가기 어렵게 한다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;분명 생각지 못한 많은 문제들이 더 존재하리라 생각된다. 발견된 &lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;문제점들을 특수사례 패턴 및 리펙토링을 통해 하나씩 해결해 나가 보자.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;문제 해결 과정&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;첫 번째: 예외처리를 한 클래스에 모아서 처리할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1669968414219&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 감싸기 클래스 내부 코드의 일부(api 호출 메서드 생략)
@Slf4j
public class SearchEngin{

    public SearchEngin(){};
    
    // Exception을 한곳에서 공통적으로 처리
    public SearchResponseDto sendRequest(searchEnginRequestDto searchEnginRequestDto){
        try{
            return this.callSearchEngin(searchEnginRequestDto);
        }catch(IRException e){
            log.info(&quot;SearchEnginException: &quot; + e);
            return new SearchResponseDto();
        }catch(.... e){
            ................
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;특수 사례 패턴 이전에는 검색엔진을 호출하는 곳마다 예외처리를 위해 try, catch 문을 반복 작성해야 했다. 그러나 패턴 적용 이후에는 모든 예외처리를 한 곳에서 처리할 수 있게 되었으며 오류 발생시 한곳에서 처리할 수 있게 되었다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;예외 발생 시에 new SearchResponseDto() 객체를 리턴해준 이유는 SerchResponseDto에 getter(조회함수)를 구현해 두었고 null값을 처리할 수 있도록&amp;nbsp; 해두었기 때문이다.&lt;/span&gt;&lt;/blockquote&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;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;두 번째: 타입 캐스팅 DTO를 이용해 처리한다.&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1670196251929&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// DTO 적용 전
Map&amp;lt;String, Object&amp;gt; map = new SearchEngin().sendRequest(searchEnginRequestDto);
HashMap resultSet = (HashMap) map.get(&quot;resultSet&quot;);

HashMap result = new HashMap();
List&amp;lt;Map&amp;gt; resultList = new ArrayList&amp;lt;&amp;gt;();

if(!((ArrayList) resultSet.get(&quot;result&quot;)).isEmpty()){
    result = (HashMap) ((ArrayList) resultSet.get(&quot;result&quot;)).get(0);
    resultList  = (List)result.get(&quot;resultDocuments&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1706077998481&quot; class=&quot;java&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// DTO 적용 후
SearchResultResponseDto item = new SearchEngin()
            .sendRequest(searchEnginRequestDto)
            .getFirstResult();
List&amp;lt;HashMap&amp;gt; itemList = item.getResultDocuments();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;검색엔진을 통해 가져온 데이터를 HashMap이 아닌 직접 만든 DTO에 초기화하여 사용 시 클라이언트가 호출한 데이터를 매번 올바른 유형으로 타입 캐스팅 할 책임을 지지 않아도 된다.&lt;/b&gt;&lt;/span&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;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;세 번째: 호출하는 곳에서 null 값을 체크해야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1670282763621&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SearchEnginResponse 적용 전
Map&amp;lt;String, Object&amp;gt; map = new SearchEngin().sendRequest(searchEnginRequestDto);
HashMap resultSet = (HashMap) map.get(&quot;resultSet&quot;);

HashMap result = new HashMap();
List&amp;lt;Map&amp;gt; resultList = new ArrayList&amp;lt;&amp;gt;();

if(!((ArrayList) resultSet.get(&quot;result&quot;)).isEmpty()){
    result = (HashMap) ((ArrayList) resultSet.get(&quot;result&quot;)).get(0);
    resultList  = (List)result.get(&quot;resultDocuments&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1706078102719&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SearchEnginResponse 적용 후
SearchResultResponseDto item = new SearchEngin()
            .sendRequest(searchEnginRequestDto)
            .getFirstResult();
List&amp;lt;HashMap&amp;gt; itemList = item.getResultDocuments();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;검색엔진은 외부 API다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;API 명세서대로 값이 날아오지 않을 가능성, 아무런 값이 들어있지 않을 가능성, 예외를 발생시킬 가능성이 존재&lt;/span&gt;한다. 그렇기에 API를 호출해 사용하는 곳에서는 매번 발생될 수 있는 예외에 대한 대비책을 마련해두어야 한다.&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;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;프로젝트에서 사용한 검색엔진은 데이터가 5 depth까지 들어간다. 그렇기에 응답값으로 받은 데이터중 어느 곳에 무슨 데이터가 없을지 전혀 예측할 수 없다. 위에서 말했듯이 API 명세서대로 값이 날아오지 않을 가능성이 있기 때문이다. 그래서 해당 데이터들을 안전하게 꺼내 사용할 수 있게 몇 가지 조회 함수들을 만들어 해당 함수들로만 리턴 받은 데이터를 조회할 수 있게 만들었고, 만약 값이 존재하지 않을 경우 null값이 아닌 default값을 만들어 리턴해주도록 만들었다.&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;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;덕분에 호출하는 곳에서 반복적으로 null 값을 체크하지 않아도 된다.&lt;/b&gt;&lt;/span&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;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;네 번째: 특수 사례 처리를 위해 만든 클래스를 사용해 테스트를 편리하게 한다.&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;API가 개발 또는 수정단계에 있어 사용할 수 없거나 API 명세서대로 응답값을 내려주기 전이라면 해당 API를 이용해 테스트를 하기가 곤란할 것이다. 이때에는 특수 사례 처리를 위해 만든 클래스에 가짜 데이터를 주입하여 API가 개발단계인 실제 API를 호출하는 것처럼 우리 프로그램을 개발하고 테스트할 수 있다.&lt;/b&gt;&lt;/span&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;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;다섯 번째: 중복 제거 및 유지보수력 향상&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;위의 모든 작업들이 특수 사례 패턴 적용 전에는 일일이 호출하는 곳에서 처리해야 하는 작업들이었다. 그러나 특수 사례 패턴 이용 시 한 두 곳에서 모든 과정을 처리할 수 있기 때문에 중복되는 작업들이 줄어들었다.&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;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;또한 한 두곳에서 모든 일을 처리할 수 있기에 수정사항 또는 에러 발생 시 쉽게 처리할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;특수 사례 패턴을 통해 얻은 이점들&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;예외(Exception) 처리를 한 클래스에 모아서 처리할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;타입 캐스팅이 필요할 시 DTO를 만들어 사용하는 방식으로 dto 클래스에서 처리할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;호출하는 곳에서 매번 null값을 체크하지 않아도 된다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;특수 사례를 처리하기 위해 만들어둔 클래스에 가짜 데이터를 주입하여 실제 API를 호출한 것처럼 테스트를 할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;위의 작업들이 패턴을 적용하기 전에는 호출하는 곳에서 모두 처리해야 하는 반복작업이었지만 호출하는 곳에서 한 번에 처리할 수 있다. 코드량을 낮추고 가독성을 향상시킨다.&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;특수 사례 패턴을 활용함과 약간의 리펙토링을 적용해 보며 배운 것을 적용할 수 있어 기뻤다. 그리고 동시에 스스로 많은 부족함을 느꼈다. 뭐가 더 좋은 구조인지, 현재 짠 코드가 잘 만든 것이 맞는지 의문이다. 그러나 지금의 지식으로는 해결되지 않음을 알기에 기본 지식을 깊이 갈고닦아야겠다는 생각을 했다. 기본기가 많이 부족하여 더 좋은 방법과 무슨 문제가 더 있는지 알지 못하고 있다는 생각이 든다.&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: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;기본을 아주 깊게 공부해야 할 필요성을 알게 만들어준 고마운 경험이었다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/Tech Notes</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/39</guid>
      <comments>https://doosicee.tistory.com/entry/%EA%B2%BD%EA%B3%84-%EC%99%B8%EB%B6%80-API%EB%A5%BC-%EB%8C%80%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-%EC%8B%A4%EC%A0%84%ED%8E%B8#entry39comment</comments>
      <pubDate>Mon, 19 Dec 2022 08:21:46 +0900</pubDate>
    </item>
    <item>
      <title>MCMS 웹 프로젝트 후기</title>
      <link>https://doosicee.tistory.com/entry/MCMS-%EC%9B%B9-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9B%84%EA%B8%B0</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1272&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cRdRd9/btrRXu9rS2m/ziK0WrSQAQ7m6qAAWcEsQK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cRdRd9/btrRXu9rS2m/ziK0WrSQAQ7m6qAAWcEsQK/img.jpg&quot; data-alt=&quot;출처: pixabay&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cRdRd9/btrRXu9rS2m/ziK0WrSQAQ7m6qAAWcEsQK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcRdRd9%2FbtrRXu9rS2m%2FziK0WrSQAQ7m6qAAWcEsQK%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; alt=&quot;도서이미지&quot; loading=&quot;lazy&quot; width=&quot;450&quot; height=&quot;298&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1272&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: pixabay&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;개요&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;목적: mcms 사용자 사이트 구축&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;수행 기간: 2022년 11월 1일 ~ 2022년 12월 3일&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;수행 인원: 디자이너 1,&amp;nbsp; 풀스택3&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기술 스택: jsp, javascript, springframework, java, mybatis, mariaDB&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;협업 툴: svn&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt; 본래 해당 프로젝트는 후기를 작성하지 않으려 하였다. mcms는 관리자 사이트가 거의 모든 기능을 담당하고 사용자 페이지는 대부분 저장된 데이터들을 카테고리별로 분류하여 화면에 뿌려주기만 하면 되는 프로젝트였기 때문이다. 또한 대부분의 시간을 테이블 간의 관계 분석과 쿼리문을 짜는데 보내기도 했다. 그러나 해당 프로젝트에서&amp;nbsp;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;테스트 코드를 작성하며 느낀 테스트 코드의 중요성과 검색엔진을 도입하며 공부했던 것을 적용시켜보는 경험&lt;/span&gt;이 기억에 남아 후기를 통해 기록을 남기기로 하였다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;MCMS 란?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;mcms는 Media Contents Management System의 약자로 미디어 컨텐츠(기록물)를 관리하는 아카이브다. 좀 더 풀어서 설명하자면 &lt;b&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여러 가지 콘텐츠들을 기준별로 분류하여 관리하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;사진, 영상&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;콘텐츠/시청각기록물 관리&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;솔루션이다.&lt;/span&gt;&lt;/b&gt;&lt;/b&gt; 기록물을 컨텐츠별로 볼 수 있는 사용자 사이트와 기록물을 등록하고 관리하는 관리자 사이트로 구성된다.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;MCMS 프로젝트 담당 페이지&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;마이페이지&lt;/span&gt; &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;대표 이미지 변경, 프로필 수정, 비밀번호 변경&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;작품 관리 페이지&lt;/span&gt; &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;작품에 대한 기본적인 CRUD , 대표 이미지 자동 등록 및 수정, 콘텐츠(사진, 영상)에 대한 CRUD&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;통합 검색 페이지&lt;/span&gt;&lt;/b&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;검색엔진을 통해 데이터를 조회하고 화면에 바인딩&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3명의 인원이 분담하여 작업했기에 생각보다 필자가 담당한 페이지가 많지 않았다. 그렇다고 프로젝트 기간이 여유로운 것은 아니었다. 관리할 수 있는 기록물과 분류가 다양한 덕에 테이블 관계가 꽤나 복잡했기 때문이다. 때문에 기존 mcms 프로젝트 소스 분석과 테이블 간의 관계 분석에 시간을 많이 할당하였다. 또한 필요한 쿼리문을 만드는데도 시간을 많이 썼다. 아이템을 CRUD 할 때마다 연계된 테이블이 많아 생각보다 많은 테이블에 작업을 해야 했었다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;프로젝트 일정 관리&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1427&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3fR6E/btrUngnM2YY/Vg2FLiyacAyQZGJ0eUS00K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3fR6E/btrUngnM2YY/Vg2FLiyacAyQZGJ0eUS00K/img.png&quot; data-alt=&quot;일정 및 완료사항 공유&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3fR6E/btrUngnM2YY/Vg2FLiyacAyQZGJ0eUS00K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3fR6E%2FbtrUngnM2YY%2FVg2FLiyacAyQZGJ0eUS00K%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;450&quot; height=&quot;227&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1427&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;일정 및 완료사항 공유&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1681&quot; data-origin-height=&quot;697&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwrPNx/btrUmCSh20t/TulHDjM2s9KGLSbUx3mtA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwrPNx/btrUmCSh20t/TulHDjM2s9KGLSbUx3mtA0/img.png&quot; data-alt=&quot;이슈사항 공유&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwrPNx/btrUmCSh20t/TulHDjM2s9KGLSbUx3mtA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwrPNx%2FbtrUmCSh20t%2FTulHDjM2s9KGLSbUx3mtA0%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;450&quot; height=&quot;187&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1681&quot; data-origin-height=&quot;697&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이슈사항 공유&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;프로젝트의 일정관리 및 이슈사항 공유는 구글 스프레드 시트를 사용하여 진행했었다. 서로의 개발 일정을 공유하고 개발이 먼저 끝난 팀원이 아직 일정을 완료하지 못한 팀원의 개발을 돕거나 개발이 완료된 페이지들을 미리 테스트하여 수정이 필요한 곳을 적어줬다. 오류 수정은 본인이 개발한 곳은 본인이 직접 하는 방식으로 진행했다. 본인이 작성한 코드를 본인이 가장 잘 알기에 다른 팀원들이 디버깅 및 수정하는 것보다 효율적이기 때문이었다. 물론 프로젝트 기간이 상당히 여유 있었던 것도 있었다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;테스트 코드&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;기존 mcms 프로젝트들은 작성된 테스트 코드가 없다. 때문에 기존 mcms 시스템을 분석할 때 어려움이 있었다. 눈으로 보며 분석할 수 있으나 작성된 코드를 실행해보며 검증하는 과정의 필요성을 느꼈다. 때문에 이번 mcms 프로젝트는 테스트 코드를 작성하였고 작성함으로 얻은 이점들과 느낀 점을 적어봤다. &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아래 코드는 memberDAO 레이어의 비밀번호 변경 테스트 코드다. 특별한 내용은 없지만 회사 프로젝트에 사용한 코드를 그대로 올리는 것은 옳은 행동이 아니라 생각되어 몇몇 부분을 제거하고 변수 명도 다 변경한 상태다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// @Transactional을 사용하여 실행된 결과를 롤백해준다.
@DisplayName(&quot;memberPasswordUpdate&quot;)
@Transactional
@Test
public void memberPasswordUpdate(){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Given
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;long id = 0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String password = &quot;secret&quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;passwd = encryption(passwd, &quot;secret&quot;);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// When
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Integer resultRow = memberDAO.memberPasswordUpdate(id, password);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertThat(resultRow).isEqualTo(1);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;필자는 테스트 코드를 현업 프로젝트에서 작성하는 것은 이번이 처음이었다. 현업에 종사하는 수많은 선배 개발자들이 테스트 코드 작성을 중요시하고 강의와 블로그에서 필요성을 강조하기에 공부하고 토이 프로젝트에 적용해왔으나 중요성을 크게 느끼지는 못했었다. 그러나 이번 프로젝트를 통해 왜 필요한지 깨닫게 되었고 테스트 코드가 가져다준 이점들을 몇 가지 정리해봤다.&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;웹 퍼블리싱 작업이 끝나지 않아도 기능 구현 후 검증이 가능하다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;개발 종료 후 프로젝트 테스트 시 발생하는 오류를 좀 더 쉽게 찾고, 수정하고, 검증할 수 있다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;테스트 코드를 통해 실패부터 성공까지 검증한 로직은 추후 에러가 발생할 확률이 크게 낮아진다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다른 동료가 작성한 로직에 문제가 생겼을 때 분석하고 수정 후 검증하기가 매우 편하다. 그 반대도 마찬가지다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이번 mcms 프로젝트를 진행할 때 회사에 웹 퍼블리싱을 진행할 퍼블리셔의 숫자가 부족하여 퍼블리싱이 늦어졌다. 그러나 개발자가 프로젝트 마감시간이 다가오는데 가만히 있을수도 없었다. 그래서 테스트 코드를 작성함으로 문제를 해결했다. 작성한 서비스 로직과 쿼리문을 테스트 코드를 통해 미리 검증하였고 덕분에 수월하게 프로젝트를 진행할 수 있었다. 추후 테스트를 진행하며 생기는 오류들도 빠르게 수정할 수 있었고 웬만해서 테스트 코드를 통해 검증된 로직들은 문제가 발생하지 않았었다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이미지 압축 및 리사이징&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;프로젝트 진행도중 메인 페이지에 올라가는 이미지를 원본 이미지로 잘못 뿌리는 일이 생겼고 메인 페이지 로딩 속도가 너무 느려 확인해봤더니 이미지가 원본 그대로 올라갔고 용량이 너무 커 화면을 그리는 시간이 오래 걸렸던 것이었다. 필자는 이미지 크기에 대한 중요성을 이번 프로젝트를 진행하며 알게 되었다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;필자가 회사에 처음 와서 진행했던 프로젝트는 iot프로젝트였다. iot 프로젝트는 장비에서 보내주는 데이터를 수집하고 실시간성으로 제어하는 것이 주된 목표인 프로젝트였다. 그렇기에 빠른 속도로 데이터를 수집하는 것, 실시간성, 정확성이 정말 중요했던 프로젝트였다. 그렇다 보니 이미지와 영상을 다뤄볼일이 거의 없었다. 가끔 사용하는 이미지도 이미 압축된 이미지를 제공받았기 때문이었다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;반면 mcms 프로젝트는 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;사진, 영상 콘텐츠/시청각기록물&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt; 관리&lt;/span&gt; 솔루션이기 때문에 많은 영상과 이미지를 저장하고 분류해야 했고 화면상에 많은 이미지와 영상을 띄워줘야 했다. 때문에 이미지 하나를 저장해도 원본, 관리자 페이지, 사용자 페이지, 썸네일 용으로 각 용도에 맞게 압축 및 리사이징을 하여 저장했다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이미지를 압축하면 화질이 저하되지만 눈으로 보기에는 큰 차이를 느끼지 못한다. 아래는 비교 사진을 통해 비교해보자.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;974&quot; data-origin-height=&quot;354&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFeox1/btrSm0fDWSp/Qg9iJvKFnUX5nsNCkkfKM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFeox1/btrSm0fDWSp/Qg9iJvKFnUX5nsNCkkfKM0/img.png&quot; data-alt=&quot;이미지 출처 : Pixabay&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFeox1/btrSm0fDWSp/Qg9iJvKFnUX5nsNCkkfKM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFeox1%2FbtrSm0fDWSp%2FQg9iJvKFnUX5nsNCkkfKM0%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; alt=&quot;이미지 크기에 따른 화질비교 img&quot; loading=&quot;lazy&quot; width=&quot;850&quot; height=&quot;316&quot; data-origin-width=&quot;974&quot; data-origin-height=&quot;354&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이미지 출처 : Pixabay&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;두 이미지의 크기 차이는 10배가 넘지만 눈으로 봤을때 화질 차이가 나는걸 필자는 느끼지 못했다. 이번에는 크기 차이가 가져다주는 속도의 영향력이 얼마나 큰지 확인해보자.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;421&quot; data-origin-height=&quot;301&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1UVc9/btrSlFpLziL/3JYeJKcdZ15y4VCz2c6Oik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1UVc9/btrSlFpLziL/3JYeJKcdZ15y4VCz2c6Oik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1UVc9/btrSlFpLziL/3JYeJKcdZ15y4VCz2c6Oik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1UVc9%2FbtrSlFpLziL%2F3JYeJKcdZ15y4VCz2c6Oik%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; alt=&quot;이미지 크기에 따른 속도차이 img&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;357&quot; data-origin-width=&quot;421&quot; data-origin-height=&quot;301&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이미지에 표기되는 숫자도작고 화질이 좋지 않아 잘 보이지 않지만 &lt;span style=&quot;color: #000000;&quot;&gt;이미지 압축 전에는 약 2500ms 라는 시간이 걸렸고 압축 후에는 약 250ms라는 시간이 걸리는걸 볼수있다.&lt;/span&gt; 둘의 테스트 환경은 동일하다. 메인 페이지에 5장의 이미지를 뿌려주면되는 상황이였다. 위에 보듯이 용량에 따른 화질에 차이는 거의 느끼지 못하지만 속도차이는 약10배 정도로 이 차이는 실제 웹페이지에서 크게 체감된다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이번 프로젝트를 통해 이미지 사이즈에 대한 중요성을 알게 되었는데 이미지 압축과 리사이징이 언제 이루어지는 게 가장 좋은 걸까 라는 의문이 남았다. 게시물을 작성하며 텍스트 에디터에 이미지를 등록할 때, 게시물을 저장할 때 어느 순간 이루어져야 할까? 현재 회사에서는 게시물을 등록할 때에 이루어진다. 로딩 바가 있어서 변환 진행 현황을 확인할 수 있으나 느리다는 생각을 하였다. 사용자 입장에서 볼 때에 가장 자연스럽고 속도가 지연되지 않는다고 느끼려면 필자 생각에는 텍스트 에디터에 이미지를 올릴 때에 압축 작업이 이루어져 올라가는 방법이 괜찮은 것 같다. 압축이 되며 로딩 시간이 있겠지만 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;하나하나의 로딩 시간을 잠깐 기다리는 것과 여러 개가 로딩되는걸 한 번에 기다리는 건 다를 것 같다는 생각&lt;/span&gt;이 든다. 물론 해당 이미지를 사용하지 않고 다시 취소할 수도 있지만 말이다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;특수 사례 패턴 (외부 API를 대하는 방법)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;a style=&quot;background-color: #e6f5ff; color: #0070d1; text-align: start;&quot; href=&quot;https://doosicee.tistory.com/entry/%EA%B2%BD%EA%B3%84-%EC%99%B8%EB%B6%80-API%EB%A5%BC-%EB%8C%80%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-%EC%8B%A4%EC%A0%84%ED%8E%B8&quot;&gt;2022.12.19 - [Apply/BACKEND] - 특수 사례 패턴 (외부 API를 대하는 방법)&lt;/a&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;마무리&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아무런 기대가 없었던 mcms 프로젝트를 진행하며 많은 경험을 하게 되었다. 이미지 크기의 문제, 이론적으로만 필요성을 알고 있었던 테스트 코드의 중요성, 클린 코드를 읽으며 배웠던 외부 api를 대하는 방법 정말 많은 걸 배웠다. 또한 텍스트 에디터를 통해 이미지를 업로드할 때에 어느 순간에 이미지 압축작업이 이루어져야 하는지에 대한 생각을 해볼 수 있어서 좋았다. 이 부분에 대한 건 토이 프로젝트에 적용하며 테스트를 해봐야겠다. 개발자에 입장으로써는 한 번에 처리하는 것이 편하다고 느껴지나 사용자의 경험 측면에서 볼 때에 저장시간이 오래 걸리는 건 쾌적하지 못하겠다는 걸 느꼈다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;클린 코드를 읽고 언제 외부 api를 대하는 방법에 대하여 배운 것을 현업 프로젝트에 언제쯤 써먹어볼 수 있을까 고민했는데 이렇게 기회가 빨리 찾아올 줄은 몰랐다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;필자 개인적 소감으로 이번 프로젝트를 통해 배우고 공부했던걸 토대로 한층 더 성장했다고 생각되며, 다음번에 특수처리 클래스를 만들 때에는 지금은 알지 못하는 더 좋은 방법을 통해 훨씬 더 잘 만들 수 있지 않을까? 라는 기대감을 스스로에게 가져보며 마무리한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;긴 글을 읽어주셔서 감사합니다ㅎㅎ.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/Projects Reviews</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/38</guid>
      <comments>https://doosicee.tistory.com/entry/MCMS-%EC%9B%B9-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9B%84%EA%B8%B0#entry38comment</comments>
      <pubDate>Sun, 4 Dec 2022 08:35:06 +0900</pubDate>
    </item>
    <item>
      <title>CleanCode 9장 단위 테스트</title>
      <link>https://doosicee.tistory.com/entry/CleanCode-9%EC%9E%A5-%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EZgXR/btrRlHOtX15/09gae2SyCwNm0G1SbyUvZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EZgXR/btrRlHOtX15/09gae2SyCwNm0G1SbyUvZk/img.png&quot; data-alt=&quot;출처: 인사이트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EZgXR/btrRlHOtX15/09gae2SyCwNm0G1SbyUvZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEZgXR%2FbtrRlHOtX15%2F09gae2SyCwNm0G1SbyUvZk%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; alt=&quot;클린코드 이미지&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;467&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;과거 대다수의 프로그래머들은 TDD(Test Driven Development)라는 개념을 몰랐으며 단위 테스트란 자기 프로그램이 '돌아간다'는 사실만을 확인하는 일회성 코드에 불과했다. 지금에 와서는 애자일과 TDD 덕택에 단위 테스트를 자동화하는 프로그래머들이 많이 늘어났고 계속해서 늘어나는 추세다. 이번 장을 통해 테스트 케이스를 잘 작성하는 방법에 대해 알아보자.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;TDD 법칙 세 가지&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;TDD는 실제 코드를 짜기 전에 단위 테스트를 작성하라고 요구할것이다. 다음 세 가지 법칙을 살펴보자.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위 세 가지 규칙을 따른다면 실제 코드와 테스트 코드가 함께 묶여서 나올것이다. 몇 초 주기라고 말하기 애매하지만 테스트 코드가 잘 작성되었다는 가정하에 실제 코드는 금방 작성된다. 이렇게 일한다면 매일 수십 개, 매달 수백 개, 매년 수천 개에 달하는 테스트 케이스가 나온다. 모든 실제 코드를 사실상 전부 테스트하는 테스트 케이스가 나오는 것이다. 그러나 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;실제 코드와 맞먹을 정도로 방대한 테스트 코드는 관리 문제를 유발한다.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;깨끗한 테스트 코드 유지하기&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;과거 책의 글쓴이는 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;실제 코드와 동일한 품질 기준을 적용하지 않아야 한다&lt;/span&gt;고 명시적으로 결정된 팀을 코치하였었다고 한다. 팀원들에게 단위 테스트의 규칙을 깨도 좋다는 허가를 내렸고 지저분해도 빨리 개발하자는 것이 주제였다고 한다. 변수이름, 간결성, 잘 설계하는것 모두를 버리고 그저 돌아가기만 하면 되는 테스트 코드를 작성하면 되는 것이었다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;잘 작성하지 않은 테스트코드는 당장은 편할지 모르나 추후 많은 문제가 드러난다. 실제 코드가 발전하면 테스트 코드도 변해야 한다. 그러나 테스트 코드가 지저분하면 변경하기 힘들고 실제 코드를 짜는 시간보다 테스트 케이스를 작성하는 시간이 더 오래 걸리는 순간들이 많아진다. 기존 테스트 케이스가 실패하기 시작하면, 그동안 지저분하게 짜왔던 코드로 인해 실패하는 테스트 케이스들이 점점 늘어나고 어느 순간 테스트 케이스는 부담이 되어버린다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;새 버전을 출시할 때마다 테스트 케이스를 유지하고 보수하는 비용이 점점 커지며 큰 불만사항으로 자리 잡게 된다. 결국 테스트 코드를 폐기해야 하는 상황에 처하게 된다. 그러나 적절한 테스트 케이스가 없다면 개발자는 자신이 수정한 코드가 제대로 도는지 확인할 방법이 없다. 마땅히 검증할 방법이 없는 것이다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;결국에는 실패하는 테스트 케이스 때문에 검증하기를 포기하고 시스템의 결함률은 높아지는 악순환이 벌어진다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;테스트 케이스가 제공하는 장점들(유연성, 유지보수성, 재사용성)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;테스트 코드를 깨끗하게 유지해야 하는 이유들을 더 살펴보자. 테스트케이스는 코드에 유연성, 유지보수성, 재사용성을 제공하는 버팀목이 되어준다. 수정 요청사항이 들어왔을 때 또는 개선해야 할 부분들에 있어 기존에 잘 돌아가고 있는 프로그램을 수정하기란 만만치 않다. 수정 시 어느 곳에서 예상치 못한 버그가 발생할지 알 수 없기 때문이다. 그러나 테스트 케이스가 존재한다면 수정 후 테스트가 간단해지며, 미리 만들어둔 예외 사항들을 모두 통과한다면 이 코드가 안전하게 돌아간다는 확신을 얻을 수 있을 것이다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;따라서 테스트 케이스를 작성하는 것을 권장하며, 작성한다면 실제코드와 같이 작성하고 깨끗하게 유지하여야 한다. 테스트 코드가 실제 코드와 다르고 지저분하다면 결국에는 테스트 코드를 잃어버리고 실제 코드도 망가지게 된다.&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;깨끗한 테스트 코드&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;깨끗한 테스트 코드를 위해서는 가독성이 가장 중요하다. 명료성, 단순성, 풍부한 표현력이 필요하다. 테스트 코드는 최소의 표현으로 많은 것을 나타내야 한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;도메인에 특화된 테스트 언어&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;도메인에 특화된 언어(DSL)로 테스트 코드를 구현하는 기법이다. 시스템 조작 API를 사용할 때에 무슨 역할을 하는지 쉽게 알기 어려울 때가 있다. 이때에 API를 직접 호출해 사용하는 대신 API위에다 필요한 대로 함수와 유틸리티를 구현한 후 그 함수와 유틸리티를 사용하므로 테스트 코드에서 사용하는 특수 API가 된다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;DSL 이란?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;도메인 특화 언어는 관련 특정 분야에 최적화된 프로그래밍 언어입니다.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;필자가 이해하기로는 이 책에서 말하는 도메인 언어로 테스트 코드를 구현한다는 것은 테스트를 구현하는 당사자와 나중에 테스트 코드를 읽게 될 독자를 도울 수 있도록 &quot;API의 코드를 감싸 테스트 코드로 이름을 이해하기 쉽게 최적화하는 방법&quot;을 말하는 것 같다.(필자가 이해한 것이므로 틀릴 가능성이 있다.)&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;이중 표준&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;테스트 API에서 적용하는 표준은 실제 코드에 적용하는 표준과는 확실히 다르다. 단순하고, 간결하고, 표현력이 풍부해야 하지만 실제 코드만큼 효율적일 필요는 없다.&amp;nbsp; 예를 들어 여러 기능을 테스트해야 할 때 하나의 메서드 넣어 해결할 수 있지만 테스트 코드인 만큼 모두 분리하여 더 보기 쉽게 만들어도 괜찮다는 이야기이다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;또한 문자열을 출력할 때에도 String을 사용하여 출력하는 것보다 효율만 따지자면 StringBuffer를 사용하는 것이 더 효율적이지만 테스트 환경에서는 크게 무리가 아니라면 String을 사용해도 좋다. StringBuffer 사용 시 코드가 보기 흉해지기 때문이다. 실제 환경에서도 StringBuffer를 쓰지 않아서 치르는 대가가 미미한 경우가 대부분이므로 크게 무리가 아니라면 String을 사용해도 괜찮다.&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;테스트 당 assert 하나&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Junit으로 테스트 코드를 짤 때는 함수마다 assert 문을 단 하나만 사용해야 한다고 주장하는 이들이 있다. 꽤나 귀찮은 규칙이라 여겨질 수 있으나 assert문이 하나인 함수는 결론이 하나라서 코드를 이해하기가 쉽고 빠르다. 물론 이것이 강제되는 규칙은 아니다. 그러나 단일 assert문이라는 규칙은 꽤나 훌륭한 규칙이라고 생각된다.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;테스트 당 개념 하나&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;테스트 함수마다 한 개념만 테스트하기를 권장한다. 만약 개념이 세 개가 존재한다면 세 개의 테스트로 쪼개는 것이 마땅하다. 세 개념을 한 함수로 몰아넣는다면 독자는 각 절이 거기에 존재하는 모든 이유를 이해해야 한다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;예를 들어보자&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;에어컨은 status 값이 true 일시 전원이 켜진다. 날씨가 겨울일 때에는 온풍기로 가동된다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;에어컨은 status 값이 true 일시 전원이 켜진다. 날씨가 여름일 때에는 냉풍기로 가동된다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;에어컨은 각 계절에 따라 해당 공간이 적정 온도를 유지하고 있다면 가동되지 않는다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;위와 같은 경우는 코드를 이해하는데 시간이 더 걸릴 것이다. 테스트 함수 하나는 개념 하나만 테스트하는 것이 가장 바람직하다.&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;F.I.R.S.T&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;깨끗한 테스트는 다섯 가지의 규칙을 따르는데, 각 규칙을 살펴보자&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;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;빠르게(Fast)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;테스트는 빨라야 한다. 테스트가 빨리 돌지 않는다면 자주 돌릴 엄두를 내지 못한다. 자주 돌리지 않으면 초반에 문제를 잡아내지 못한다. 코드를 마음껏 정리하지도 못하고 결국 코드의 품질이 나빠질 것이다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;독립적으로(Independent)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;각 테스트는 서로 의존하면 안 된다. 한 테스트가 다음 테스트의 실행 환경을 준비해서는 안된다. 각 테스트는 독립적이어야 하고 어떠한 순서도 실행돼도 문제가 없어야 한다. 테스트가 서로에게 의존할 경우 하나의 테스트 실패 시 모든 테스트가 실패하므로 원인을 진단하기가 어려워지며 후반 테스트가 찾아내야 할 결함을 놓칠 가능성이 생긴다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;반복가능하게(Repeatable)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;테스트는 어떤 호나경에서도 반복 가능해야 한다. 실제 환경, QA 환경, 버스를 타고 집으로 가는 길에 사용하는 노트북에서도 실행할 수 있어야 한다. 테스트가 돌아가지 않는 환경이 있다면 환경이 지원되지 않기에 수행하지 못했다는 실패를 둘러댈 이유가 생기며 테스트를 수행하지 못할 상황이 생긴다.(데이터 베이스가 없이 실행될 수 없는 테스트 환경을 예로 들 수 있을 것이다. 이때에는 인메모리 디비를 사용할 수 있어야 할 것)&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;자가검증하는(Self-Validating)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;테스트는 bool 값으로 결과를 내야 한다. 성공 아니면 실패다. 통과 여부를 알기 위해서 로그파일을 읽게 해서는 안된다. 테스트가 스스로 성공과 실패를 가늠하지 않는다면 판단은 주관적이 되며 지루한 수작업 평가가 필요해진다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;적시에(Timely)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;테스트는 적시에 작성해야 한다. 단위 테스트는 테스트하려는 실제 코드를 구현하기 직전에 구현한다. 실제 코드를 구현한 다음에 테스트 코드를 만들면 실제 코드가 테스트하기 어렵다는 사실을 발견할지도 모른다. 또한 테스트가 불가능하도록 실제 코드를 설계할지도 모른다.&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;테스트 코드는 실제 코드만큼이나 프로젝트 건강에 중요하다. 필자도 실제로 현업에서 프로젝트의 유지보수를 진행하며 느꼈다. 유지보수를 위해 에러를 찾고 코드를 변경해야 하는데 테스트 코드가 없다면 검증하기가 굉장히 번거로워져 유연하게 변경할 수 없기 때문이다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;테스트 코드는 실제 코드의 유연성, 유지보수성, 재사용성을 보존하고 강화하는 효과가 있다. 그러므로 테스트 코드는 지속적으로 깨끗하게 관리하자. 표현력을 높이고 간결하게 정리하자.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/Read Book</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/36</guid>
      <comments>https://doosicee.tistory.com/entry/CleanCode-9%EC%9E%A5-%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8#entry36comment</comments>
      <pubDate>Wed, 16 Nov 2022 08:28:10 +0900</pubDate>
    </item>
    <item>
      <title>CleanCode 8장 경계</title>
      <link>https://doosicee.tistory.com/entry/CleanCode-8%EC%9E%A5-%EA%B2%BD%EA%B3%84</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnVCke/btrQQjUYlGS/xEfPAxkUJdY2KaJXvHurYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnVCke/btrQQjUYlGS/xEfPAxkUJdY2KaJXvHurYk/img.png&quot; data-alt=&quot;출처: 인사이트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnVCke/btrQQjUYlGS/xEfPAxkUJdY2KaJXvHurYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnVCke%2FbtrQQjUYlGS%2FxEfPAxkUJdY2KaJXvHurYk%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;350&quot; height=&quot;467&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우리가 프로그램을 만들 때에 모든 라이브러리들을 직접 개발해 사용하는 경우는 드물다. 때로는 오픈소스를 이용하고 , 때로는 외부에 솔루션 패키지들을 사고, 때로는 사내 다른 팀이 제공하는 컴포넌트를 사용한다. 우리는 이 외부 코드를 어떤 식으로든 우리 코드에 깔끔하게 녹여내야 한다. 해당 장에서는 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;소프트웨어 간의 경계를 깔끔하게 처리하는 기법과 기교&lt;/span&gt;를 알려준다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;경계란?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우리가 만든 코드와 외부 패키지의 코드가 만나는 지점&lt;br /&gt;ex) 외부 API를 호출한다면 해당 API를 호출하여 셋팅하고 사용하는 지점&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;외부 코드 사용하기&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;인터페이스 제공자와 사용자는 원하는 바가 다르다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;제공자는 최대한 많은 곳에 적용할 수 있기를 바라고 사용자는 자신이 원하는 요구대로 인터페이스가 집중되길 원한다.&lt;/span&gt; 서로 원하는 바가 다르기에 시스템 경계에서 문제가 생길 소지가 있다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;예로 java.util.Map을 살펴보자. 아래 코드와 같이 Map은 아주 다양한 인터페이스로 수많은 기능을 제공한다. Map이 제공하는 기능성과 유연성은 유용하지만 다음과 같은 위험성이 있다.&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Map은 객체 유형을 제한하지 않기에 어떠한 객체의 유형도 추가할 수 있다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Map을 여기저기 제공한다 가정했을 때 인터페이스가 변한다면 수정할 코드의 양이 많아진다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1668035285252&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Map의 다양한 인터페이스들
- clear() void - Map
- containsKey(Object Key) boolean - Map
- containsValue(Object key) boolean - Map
- entrySet() Set - Map
- get(Object key) Object - Map
- isEmpty() boolean - Map

// 그 외 다양한 인터페이스들 .................&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;위에 나온 위험성들을 하나씩 해결하는 방법에 대해 알아보자.&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 style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #006dd7;&quot;&gt;&lt;b&gt;첫 번째 어떠한 객체 유형도 추가할 수 있다.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1668217575878&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Sensor 객체를 담는 Map을 생성
Map sensors = new hashMap();

// Sensor 객체가 필요할 때 가져온다.
Sensor s = (Sensor) sensors.get(sensorId);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;위와 같은 코드가 여러번 반복된다 생각해보자. Sensor객체를 올바른 유형으로 변환하는 책임은 클라이언트 즉, 사용자가 책임을 져야 한다. 또한 위 코드는 동작하는데 문제는 없지만 가독성이 낮아 사용 의도가 한눈에 드러나지 않는다. 위와 같은 코드 대신 제네릭스(Generics)를 사용하면 코드 가독성이 올라간다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1668219018345&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Map&amp;lt;String, Sensor&amp;gt; sensors = new HashMap&amp;lt;Sensor&amp;gt;();
...
Sensor s = sensor.get(sensorId);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;제네릭을 사용함으로써 사용자가 변환을 책임지지 않아도 되게 되었으며, 코드의 가독성이 크게 높아졌다.&lt;/span&gt;&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 style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;두 번째 Map은 너무나도 다양한 인터페이스를 제공한다.&lt;/span&gt;&lt;/b&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;제네릭을 사용하여 변환의 책임문제와 가독성 문제를 해결했지만 Map &amp;lt;String, Sensor&amp;gt;가 사용자에게 필요하지 않은 기능까지 제공한다는 문제는 해결하지 못했다. 여러 기능을 이용할 수 있다면 좋은 게 아닐까 생각할 수도 있다. 그러나 Map인터페이스가 변할 경우, 수정할 코드가 상당히 많아진다. 인터페이스가 변할 가능성이 거의 없다고 생각할 수 있지만 자바 5가 제네릭스를 지원하며 Map 인터페이스는 변했다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;한 예시로 데이터베이스에서 주민번호, 핸드폰번호 등을 PrimaryKey로 사용하지 않는다. 현실의 것은 얼마든지 변경의 가능성이 있기 때문이다. 예로 들어 주민번호를 PrimaryKey로 사용하고 있었는데 어떠한 정책으로 인해 주민번호를 수집하지 못하게 되었다고 한다면 눈앞이 깜깜 해지는 상황이 벌어질 것이다. 즉, &lt;span style=&quot;background-color: #dddddd;&quot;&gt;변경될 가능성이 있는것은 늘 대비해둬야 한다는 것&lt;/span&gt;이다. Map 인스턴스를 여기저기 제공하지 않아야 하는 이유도 동일하다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그렇다면 이 문제를 어떤 방법으로 처리할지 알아보자.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1668314955639&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Sensors {
    private Map sensors = new HashMap();
    
    public Sensor getById(String id) {
        return (Sensor) sensors.get(id);
    }
    
    .....
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;경계 인터페이스인 Map을 Sensors 클래스 안으로 숨기는 방법이다. 따라서 Map 인터페이스가 변하더라도 나머지 프로그램에는 영향을 끼치지 않는다. Sensors 클래스 안에서 객체 유형을 관리하고 변환하기 때문이다. 또한 getById()처럼 프로그램에 필요한 인터페이스만 제공하도록 제한할 수 있다. 덕분에 코드는 이해하기 쉽지만 오용하기 어렵게 됐다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;항상 Map 클래스를 사용할때마다 캡슐화를 하라는 말은 아니다. Map(혹은 유사한 경계 인터페이스를)을 여기저기 넘기지 말라는 것이다. Map 인스턴스를 공개 API의 인수로 넘기거나 반환 값으로 사용하지 말자.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;경계 살피고 익히기&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;우리는 외부에서 만들어진 패키지(API)를 사용한다면 더 많은 기능을 출시하기가 쉬워진다. 외부 패키지를 사용하고 싶다면 어디서부터 어떻게 사용하기 시작해야할까? 외부 패키지의 기능이 원하는 대로 작동하는지 테스트하는 것은 우리 책임이 아니다. 그러나 우리가 만드는 프로그램에 사용하기 위한 것이기 때문에 사용할 코드를 테스트하는 것이 바람직하다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;타사의 라이브러리를 가져왔으나 사용법이 분명하지 않다고 가정한다면, 보통은 어느정도의 기간 동안 문서를 읽으면서 사용법을 결정한다. 그리고 우리 쪽의 코드를 작성해 라이브러리가 예상대로 동작하는지 확인할 것이다. 만약 이때에 오류가 난다면 우리 쪽 코드의 오류인지 라이브러리의 버그인지 찾아내느라 골치 아플 것이다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;다들 알겠지만 외부 코드를 사용하기는 어렵다. 이럴 때에 행해야 하는 일이 바로 학습 테스트다. 우리 쪽 코드를 작성해 외부 코드를 바로 호출하기보다는 간단한 테스트 케이스를 작성해 외부 API를 호출할 환경과 동일하게 구성하고 외부 API를 호출하여 통제된 환경에서 라이브러리가 이해한 대로 동작하는지 확인 및 학습하는 것이다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;이 학습 테스트라는 것은 API를 사용하려는 목적에 초점을 맞춘다.&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;log4 j 익히기&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;log4j 익히기는 간단하게 요약하면 학습 테스트를 어떻게 진행하는지를 코드 예시와 함께 알려준다. 아래 코드를 살펴보자&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1668339743476&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class LogTest{
    private Logger logger;
    
    @Before
    public void initialize(){
        logger = Logger.getLogger(&quot;logger&quot;);
        logger.removeAllAppenders();
        logger.getRootLogger().removeAllAppenders();
    }
    
    @Test
    public void basicLogger() {
        BasicConfigurator.configure();
        logger.info(&quot;basicLogger&quot;);
    }
    
    // 그외 필요한 기능에 대한 테스트들....
}&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;학습 테스트는 통제된 환경에서 내가 API를 제대로 이해하고 있는지를 확인할 수 있는 방법이다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;테스트 케이스를 통해 패키지의 기능들을 내가 사용할 기능들을 사용 환경에 맞춰 세팅하고 하나하나 테스트한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;테스트가 끝난 모든 기능들을 독자적인 클래스로 캡슐화하여 사용한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;테스트가 끝난 API를 독자적인 클래스로 캡슐화하는 순간 해당 &lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;패키지&lt;/span&gt;&lt;/b&gt;를 사용하는 나머지 프로그램들은 log4 j 경계 인터페이스를 몰라도 된다. log4j에 문제가 생긴다면 독자적인 클래스로 추출해둔 곳을 찾아가 디버깅하고 만들어둔 학습 테스트를 돌려보면 된다.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;학습 테스트는 공짜 이상이다&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;학습 테스트에 드는 비용은 없다. 있다면 개발자의 시간일 것이다. 그러나 어찌 됐든 간에 패키지를 사용하려면 패키지의 문서를 읽어봐야 하고 학습하는 시간이 필요하다. 패키지의 이해도를 높여주면 높여줬지 절대 손해가 되는 시간이 아니다. 오히려 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;필요한 기능의 지식만을 확보하는 손쉬운 방법&lt;/span&gt;이다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;학습 테스트는 패키지를 잘 사용할 수 있게 해 줄 뿐만 아니라 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;새 버전으로 변경될 때 학습 테스트를 통해 차이점이 있는지 손쉽게 확인할 수 있다.&lt;/span&gt; 우리는 새 버전이 출시될 때에 적용하기 망설여질 때가 많다. 기존에 잘 돌아가던 것을 새 버전으로 변경했을 때에 수정사항에 따라 버그가 발생할지도 모르기 때문이다. 이때에 앞서 작성해둔 학습 테스트를 통해 우리의 코드와 패키지의 새 버전이 호환되는지를 확인하고 호환되지 않는 곳이 있다면 독자적인 클래스로 추출해둔 곳을 찾아가 수정하여 새 버전으로 좀 더 쉽게 이전할 수 있다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;학습 테스트를 작성하지 않는다면 새 버전으로 이전하기가 망설여질 것이고, 필요 이상으로 낡은 버전을 오랫동안 사용하려는 유혹에 빠지기 쉽다.&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;아직 존재하지 않는 코드를 사용하기&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;경계와 관련해 또 다른 유형은 아는 코드와 모르는 코드를 분리하는 경계다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;우리가 알지 못하는 영역, 아직은 알 수 없는 영역과 부딪혔을 때에 대처하는 방법&lt;/span&gt;이다.&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;책에서 소개해준 일화&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;CleanCode 글의 저자는 무선통신 시스템에 들어갈 소프트웨어 개발을 시작했다. 해당 소프트웨어에는 '송신기&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(Transmitter)&lt;/span&gt;&lt;/b&gt;'라는 하위 시스템이 있는데 해당 시스템에 대한 지식이 전무하였고, '송신기&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(Transmitter)&lt;/span&gt;&lt;/b&gt;' 시스템을 책임진 사람들은 인터페이스도 정의하지 못한 상태였다. 그러나 프로젝트의 지연을 원치 않았기에 '송신기' 하위 시스템과 먼 부분부터 작업을 시작했다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;책의 저자는 위와 같은 상황에 부딪혔다. 먼 부분부터 작업을 시작했음에도 불구하고 경계 너머를 알 수 없어 한 치 앞도 내다볼 수 없는 상황이었지만 경계와 자꾸 부딪히며 우리에게 필요한 경계 인터페이스가 무엇인지 알게 되었다고 한다. 원하는 요구사항은 다음과 같다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&quot;지정한 주파수를 이용해 이 스트림에서 들어오는 자료를 아날로그 신호로 전송하라&quot;&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;'송신기(Transmitter)' 하위 시스템을 책임진 팀에서 API를 설계하기 전이므로 구체적인 방법은 모르나 우리 시스템에서 바라는 요구사항에 맞춰 자체적으로 인터페이스를 정의하는 방법이다. 아래 그림을 살펴보자&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1439&quot; data-origin-height=&quot;741&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bB0n5D/btrQ0vCMjvF/KXDhPudxryKwd25hdmuOy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bB0n5D/btrQ0vCMjvF/KXDhPudxryKwd25hdmuOy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bB0n5D/btrQ0vCMjvF/KXDhPudxryKwd25hdmuOy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbB0n5D%2FbtrQ0vCMjvF%2FKXDhPudxryKwd25hdmuOy0%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; alt=&quot;송신기 예측하기 이미지&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;257&quot; data-origin-width=&quot;1439&quot; data-origin-height=&quot;741&quot;/&gt;&lt;/span&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;송신기 API가 정의된 상태였다면 CommunicationsController에서 송신기 API를 호출하여 사용했을 가능성도 있었을 것이다. 그러나 아직 정의되지 않은 상태였기에 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;CommunicationsController와 아직 정의되지 않은 송신기 API를 독자적인 클래스인 TrasmitterClass를 만들어 필요한 인터페이스인 trasmit(frequency, stream) 메서드를 정의함으로써 분리했다.&lt;/span&gt; 위의 그림을 정리해보자면 아래와 같다.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;아직 정의되지 않은 송신기 API를 독자적인 클래스(Transmitter)로 추출해 우리 시스템에 필요한 인터페이스(trasmit(frequency, stream))를 정의한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;TransmitterAdapter를 구현해 Tranmitter API가 정의된 이후에 생길 수정사항들을 한 곳에서 처리해준다. (&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ADAPTER 패턴으로 API 사용을 캡슐화하여 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;우리가 원하는 인터페이스를 패키지가 제공하는 인터페이스로 변환해주는 곳&lt;/span&gt;이다.&lt;/span&gt;&lt;/b&gt;)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위와 같은 설계는 테스트도 간단하게 할 수 있다. 미리 필요한 인터페이스를 정의해뒀기 때문에 FakeTransmitter 클래스를 사용해 CommunicationsController 클래스를 테스트해줄 수 있고 또한 Transmitter API 인터페이스가 나온 다음 경계 테스트 즉, 학습 테스트를 작성하여 API를 올바르게 사용하는지 테스트하기도 좋다.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;깨끗한 경계&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;경계에서는 많은 일이 벌어지는대 변경이 대표적이다. 소프트웨어의 설계가 우수하다면 변경하는데 많은 투자와 재작업이 필요하지 않다. 통제하지 못하는 코드를 사용할때면 너무 많은 투자를 하여 향후 변경 비용이 지나치게 커지지않도록 주의해야 한다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;경계에 위치하는 코드는 깔끔히 분리하는게 좋다. Map의 예시에서 봤듯이, &lt;span style=&quot;background-color: #dddddd;&quot;&gt;독자적인 클래스로 경계를 감싸거나 ADAPTER 패턴을 사용해 우리가 원하는 인터페이스를 패키지가 제공하는 인터페이스로 변환해주는 방법을 이용하자.&lt;/span&gt; 어떠한 방법을 사용하던 학습 테스트를 작성하기 용이하고, 코드의 가독성이 높아지며, 경계 인터페이스를 다루는 일관성도 생긴다. 덤으로 외부 패키지가 변했을때에 변경해야 할 코드도 줄어든다.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;제 8장 경계를 통해 외부 패키지들을 어떻게 대해야하는지 알게되었다. 또한 외부 API가 아직 불분명한 상태일때에 ADAPTER 패턴을 이용하여 처리할 수 있다는 것도 알게되었다. 또한 새 버전으로 올리는 것은 언제나 쉽지않다고 느껴왔다. 변경 사항을 정확히 파악하지 못한다면 이곳저곳에서 버그가 생기기 마련이기 때문이다. 그러나 독자적인 클래스로 감싸서 그곳에서 모든 변경사항을 처리해준다면 새 버전으로 버전업을 하기가 수월하다는 것도 배우게되었다. 클린코드는 정말 읽으면 읽을수록 많은것을 배우게된다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;정리&lt;/span&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;경계 인터페이스를 사용할때에는 독자적인 클래스로 감싸 필요한 인터페이스만 사용하자. 테스트 하기도 좋다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;학습 테스트를 통해 외부 패키지를 학습하자(경계 테스트와 버전업에 큰 도움이 된다.)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;외부 API가 불분명 하다면 우리가 원하는 요구사항태로 인터페이스를 작성하고 테스트하고, 실제 API가 설계된 이후에는 ADAPTER 패턴을 사용하여 수정사항을 한곳에서 처리해주자&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>개발/Read Book</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/35</guid>
      <comments>https://doosicee.tistory.com/entry/CleanCode-8%EC%9E%A5-%EA%B2%BD%EA%B3%84#entry35comment</comments>
      <pubDate>Wed, 9 Nov 2022 22:45:40 +0900</pubDate>
    </item>
    <item>
      <title>CleanCode 7장 오류 처리</title>
      <link>https://doosicee.tistory.com/entry/CleanCode-7%EC%9E%A5-%EC%98%A4%EB%A5%98-%EC%B2%98%EB%A6%AC</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TQuoy/btrP0Hbmdr6/eFaaZxN7Nil6wo76kkpNb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TQuoy/btrP0Hbmdr6/eFaaZxN7Nil6wo76kkpNb0/img.png&quot; data-alt=&quot;출처: 인사이트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TQuoy/btrP0Hbmdr6/eFaaZxN7Nil6wo76kkpNb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTQuoy%2FbtrP0Hbmdr6%2FeFaaZxN7Nil6wo76kkpNb0%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; alt=&quot;클린코드 책 이미지&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;467&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;깨끗한 코드를 작성하는 방법을 다루는 책에서 오류 처리를 논하는 장이 있어 이상할 수도 있다. 그러나 오류처리는 깨끗한 코드를 작성하는 것과 연관성이 있다. 오류 처리는 프로그램에 반드시 필요한 요소중 하나이기 때문이다. 어떠한 변수로 인해 로직이 실패할지 모르기 때문이다. 무언가 잘못될 가능성은 언제나 존재한다. 잘못을 바로 잡을 책임은 프로그램을 구현한 우리 프로그래머에게 있다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;오류 처리는 모든 로직에 포함된다고 해도 과언이 아니다. 오류 처리 코드를 잘 작성하지 못해 여기저기 흩어진다면 실제 코드가 하는 일을 파악하기가 힘들어져 프로그램 논리를 이해하는데 방해된다. 이번 7장에서는 우아하고 고상하게 오류를 처리하는 기법과 고려 사항 몇 가지가 소개된다.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;오류 코드보다 예외를 사용하라&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;과거에는 예외를 지원하지 않는 프로그래밍 언어가 많았다고 한다. 때문에 오류를 처리하고 보고하는 방법이 상당히 제한적이었다. 직접 if문을 사용하여 오류 플래그를 만들고 오류코드를 직접 반환하는 방법이 전부였다. 코드를 통해 살펴보자&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1667395238410&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class DeviceController{
	...
    public void sendShutDown() {
    DeviceHandle handle = getHandle(DEV1);
    
    if (handle != DeviceHandle.INVALID){
        retrieveDeviceRecord(handle);
        
        if(record.getStatus() != DEVICE_SUSPENDED){
            pauseDevice(handle);
            clearDeviceWorkQueue(handle);
            clearDevice(handle);
    	} else {
        	logger.log(&quot;Device suspended .....&quot;);
        }
    } else {
    	logger.log(&quot;Invalid ........&quot;);
    }
    ....
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;위의 코드처럼 직접 오류 플래그를 만들고 직접 반환해주는 방법은 코드가 복잡해진다. 오류를 한 번에 처리하는 것이 아닌 함수를 호출한 즉시 오류를 확인해야 하기 때문이다. 또한 이렇게 반복되게 오류 처리를 하다 보면 잊어버리기도 쉽다. 그래서 예외가 발생하면 예외를 던져 예외처리를 한 번에 해주는 것이 가장 낫다. 아래는 예외를 던지는 코드이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1667395856391&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class DeviceController{
	...
    
    public void sendShutDown() {
    	try{
            tryToShutDown();
        } catch (DeviceShutDownError e){
            logger.log(e)
        }
    }
    
    private void tryToShutDown() throws DeviceShutDownError {
    	DeviceHandle handle = getHandle(DEV1);
        DeviceRecord record = retrieveDeviceRecord(handle);
        
        pauseDevice(handle);
        clearDeviceWorkQueue(handle);
        closeDevice(handle);
    }
    
    private DeviceHandle getHandle(DeviceId id){
    	....
        throw new DeviceShutDownError(&quot;Invalid ......&quot;);
        ....
    }
    
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;예외를 던지고 한 번에 처리해주는 것만으로도 코드가 많이 깨끗해졌다. 단순히 보기 좋아진 것뿐만 아니라 sendShutDown()에서 오류를 처리하고 tryToShutDown()에서 디바이스를 종료하여 뒤섞인 두 개념이 분리되어 코드의 품질도 더 나아졌다.&amp;nbsp;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;Try-Catch-Finally 문부터 작성하라&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;Try-catch-finlly 문에서 try블록에 들어가는 코드를 실행하면 어느 시점에서든지 실행이 중단된 후 catch문으로 넘어갈 수 있다. 어떤 면에서 try 블록은 트랜잭션과도 비슷하다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;try블록에서 어떤 일이 생겨도 catch 블록에서 대응하여 프로그램 상태를 일관성 있게 유지해야 한다.&lt;/span&gt; 그러므로 예외가 발생할 코드를 짤 때에는 try-catch-finally 문부터 작성하는 것이 좋다. try 블록에서 무슨 일이 생기던 호출자가 원하는 응답을 정의하기가 쉬워진다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;그렇다면 어떻게 해야 잘 사용할 수 있을지 &lt;b&gt;아래의 코드를 통해 더 자세히 알아보자&lt;/b&gt;.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1667689484453&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 파일이 없다면 예외를 던지는지 확인하는 단위 테스트케이스
@Test(expected = StorageException.class)
public void retrieveSectionShouldThrowOmInvalidFileName(){
	sectionStore.retrieveSection(&quot;invalid - file&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;첫 번째로 예외를 던지는지 확인하는 테스트 케이스를 작성하자. try 블록에서 코드가 실패한다면 catch 블록은 적절한 예외를 던져야 한다. 적절한 예외를 던지는지 알기 위해서는 강제로 예외를 던지는 테스트 케이스를 통과시키는 것이 가장 좋은 방법이기 때문이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1667690958807&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 파일이 없을시에 예외를 던지는 코드
public List&amp;lt;RecordedGrip&amp;gt; retrieveSection(String sectionName) {
    try{
    	fileInputStream stream = new FileInputStream(sectionName);
    } catch (Exception e){
    	throw new StorageException(&quot;retrieval error, e);
    }
    return new ArrayList&amp;lt;RecerdedGrip&amp;gt;();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;두 번째로 Exception 예외를 던져 테스트가 성공하는지 확인한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1667690965663&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 예외의 범위를 좁혀 적절한 예외를 던져주는 코드
public List&amp;lt;RecordedGrip&amp;gt; retrieveSection(String sectionName) {
    try{
    	fileInputStream stream = new FileInputStream(sectionName);
        stream.close();
    } catch (FileNotFoundException e){
    	throw new StorageException(&quot;retrieval error, e);
    }
    return new ArrayList&amp;lt;RecerdedGrip&amp;gt;();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;세 번째로 테스트가 &lt;b&gt;성공했다면 리펙토링을 통해 예외의 범위를 좁혀주자. 무슨 상황이던지 Exception 예외 하나만을 던진다면 무슨 에러가 발생했는지 자세히 알 수 없을 뿐 아니라 의미 &lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;b&gt;없는 예외 코드가 될 것이다. 범위를 좁혀 FileInputStream 생성자가 던지는 FileNotFoundException을 잡아준다.&lt;/b&gt;&lt;/b&gt;&lt;/span&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;위와 같이 예외를 일으키는 테스트 케이스를 작성한 후 통과하는 테스트 케이스를 작성하는 것을 권장한다. 그래야 자연스럽게 try블록의 트랜잭션 범위부터 구현하게 되기 때문이다.&lt;/b&gt;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;미확인 unchecked 예외를 사용하라&lt;/span&gt;&lt;/b&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;먼저 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;예외와 에러의 차이&lt;/span&gt; 그리고 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;확인된 예외와 미확인된 예외&lt;/span&gt;가 무엇인지 알아보자.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;예외와 에러 그리고 확인된 예외와 미확인 예외&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #ef6f53;&quot;&gt;&lt;b&gt;[예외 (Exception)]&lt;/b&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예외란 프로그램 내에서 발생하는 예외상황으로 프로그램 실행 중에 참조된 값이 잘못된 경우 등... 주로 배열의 크기에서 벗어난 인덱스에 접근하거나, 없는 파일을 열 때 발생한다. 자바에서 예외는 개발자가 직접 처리할 수 있기 때문에 예외 상황을 미리 예측하여 핸들링할 수 있다.&amp;nbsp;&lt;/span&gt;&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;size18&quot;&gt;&lt;span style=&quot;color: #ef6f53; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;[에러 (Error)]&lt;/b&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;에러란 시스템에서 발생하는 발생하는 에러 즉, JVM 내에서 발생하는 에러로 프로그램 내에서 개발자가 처리가 불가능하다. 예시로는 OutOfMemoryError, ThreadDeath 등이 있다.&lt;/span&gt;&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1785&quot; data-origin-height=&quot;1345&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQZqtg/btrQr3sQrq4/3mMKCZlZE2xdy8xtjvqBt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQZqtg/btrQr3sQrq4/3mMKCZlZE2xdy8xtjvqBt0/img.png&quot; data-alt=&quot;출처 :&amp;amp;amp;nbsp;https://madplay.github.io/post/java-checked-unchecked-exceptions&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQZqtg/btrQr3sQrq4/3mMKCZlZE2xdy8xtjvqBt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQZqtg%2FbtrQr3sQrq4%2F3mMKCZlZE2xdy8xtjvqBt0%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; alt=&quot;checked-unchecked img&quot; loading=&quot;lazy&quot; width=&quot;550&quot; height=&quot;414&quot; data-origin-width=&quot;1785&quot; data-origin-height=&quot;1345&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 :&amp;amp;nbsp;https://madplay.github.io/post/java-checked-unchecked-exceptions&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;예외는 &quot;확인된 예외(Checked Exception)&quot;와 &quot;미확인 예외(Unchecked Exception)&quot; 두 가지로 구분된다. 확인된 예외의 경우는 컴파일 단계에서 에러가 발생하기 때문에 무조건 처리해줘야 하지만, 미확인 예외는 개발자의 판단하에 처리하기 때문에 신경을 더 많이 써줘야 한다.&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;size18&quot;&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;[확인된 예외(Checked Exception)]&lt;/span&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;잘못된 코드가 아닌 잘못된 상황에서 발생하는 예외이다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;파일 열기와 같이 정확히 코드를 구현했음에도 불구하고 외부 환경(파일이 없는 상황 등)에 따라 발생이 가능하다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;명시적인 예외 처리를 강제하기 때문에 try~catch로 예외를 잡거나 throws로 호출한 메서드에게 예외를 던져 예외처리를 구현해줘야 한다. 구현하지 않을 시 컴파일 에러가 발생한다.(컴파일 시에 확인해서 확인된 예외이다.)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;RuntimeException 이외의 예외들이다.&lt;/b&gt;&lt;/span&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;size18&quot;&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;[미확인 예외(Unchecked Exception)]&lt;/span&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;런타임 시 잘못 구현된 코드로 인해 발생하는 예외이다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;컴파일 에러가 나지 않지만 적절한 예외처리가 없을 경우 프로그램이 강제 종료된다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;컴파일 시 확인하지 않고, 명시적인 예외처리를 강제하지 않기 때문에 Unchecked Exception이라 한다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;RuntimeException에 포함된 예외들이다.&lt;/b&gt;&lt;/span&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;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #ef6f53;&quot;&gt;&lt;b&gt;[왜 확인된 예외와 미확인 예외로 나뉘었을까?]&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;메서드를 호출하는 쪽은 그 메서드가 어떤 예외를 발생시킬지 알아야 한다. 따라서 자바는 checked Exception을 통해 해당 메서드가 발생시킬 예외를 강제로 처리하도록 하고 있다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;그렇다면 Runtime Exception 즉, 미확인 예외는 왜 강제로 처리하지 않을까? 미확인 예외는 잘못 구현된 코드로 인해 발생하는 예외이기 때문이다. 어디서나 빈번하게 발생할 수 있기 때문에 모든 Runtime Exception을 메서드에 명시하도록 강제하는 것은 코드를 지저분하게 만들 뿐만 아니라 프로그램의 명확성을 떨어트릴 수 있다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;슬슬 본론으로 들어가 보자.&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;미확인 예외를 사용하라!&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;자바 첫 버전이 확인된 예외를 선보였던 당시에는 확인된 예외를 모두 멋진 아이디어라고 여겼다. 메서드를 선언할 때는 메서드가 반환할 예외를 모두 열거했고, 예외는 메서드 유형의 일부였다. 또한 코드가 메서드를 사용하는 방식이 메서드 선언과 일치하지 않으면 컴파일을 하지 못했다고 한다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;확인된 예외는 실제로도 몇 가지 장점을 제공한다. 그러나 지금에 와서는 안정적인 소프트웨어를 제작하는 요소로 확인된 예외가 반드시 필요하지는 않다는 사실이 분명해졌다. 앞서 잘 사용되고 있는 c#, c++, 파이썬, 루비 언어들은 확인된 예외를 지원하지 않는다. 그럼에도 불구하고 안정적인 소프트웨어를 개발하는데 무리가 없다. 그러므로 우리는 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;확인된 오류가 치르는 비용에 상응하는 이익을 제공하는지&lt;/span&gt; 잘 따져봐야 한다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;우리가 확인된 예외를 사용함으로써 치르는 비용은 OCP(개방-폐쇄 원칙, Open Closed principle)를 위반하는 것이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84_%EC%9B%90%EC%B9%99&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;위키백과&lt;/a&gt;에 정의된 OCP에 대한 내용이다.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;소프트웨어 개발 작업에 이용된 많은 모듈 중에 &lt;/span&gt;&lt;span style=&quot;color: #ee2323; background-color: #dddddd;&quot;&gt;하나에 수정을 가할 때 그 모듈을 이용하는 다른 모듈을 줄줄이 고쳐야 한다면, 이와 같은 프로그램은 수정하기가 어렵다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt; 개방-폐쇄 원칙은 시스템의 구조를 올바르게 재조직(리팩터링) 하여 나중에&lt;/span&gt;&lt;span style=&quot;color: #ee2323; background-color: #dddddd;&quot;&gt; 이와 같은 유형의 변경이 더 이상의 수정을 유발하지 않도록 하는 것&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;이다. 개방-폐쇄 원칙이 잘 적용되면, 기능을 추가하거나 변경해야 할 때 이미 제대로 동작하고 있던 원래 코드를 변경하지 않아도, 기존의 코드에 새로운 코드를 추가함으로써 기능의 추가나 변경이 가능하다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;메서드에서 확인된 예외를 던졌는데 catch 블록이 몇 단계 위에 있다고 한다면 그 사이 메서드 모두가 선언부에 해당 예외를 정의해야 한다. 즉, &lt;span style=&quot;color: #000000; background-color: #dddddd;&quot;&gt;하나의 모듈에서 예외를 던질 때 해당 모듈을 이용하는 다른 모듈들에 줄줄이 예외를 정의해야 하는 것이다.&lt;/span&gt; 코드를 통해 살펴보자!&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1667736421914&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public FileManager getFile(FileRequestDto file) {
    try{
        example(file);
    }catch (FileNotFoundException e){
        logger.log(e);
    }
}

public static void example(FileRequestDto file) throws FileNotFoundException {
    fileExample(file.getFileName());
    ....
}

public static void fileExample(String fileName) throws FileNotFoundException {
    FileInputStream stream = new FileInputStream(fileName);
    ....
}&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;fileExample 메서드에서 던진 예외를 example 메서드에서 알고 있는 걸 볼 수 있다. getFile 즉, 해당 예외가 처리되기까지 중간과정에 속해있는 메서드들은 모두 예외를 알고 있어야 한다는 문제점을 확인할 수 있다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;작은 시스템에서는 괜찮다 생각할 수 있지만, 대규모 시스템에서 일어나는 호출 방식을 생각해보자. 최상위 함수가 아래 함수를 호출한다. 아래 함수는 그 아래 함수를 호출한다. 단계를 내려갈수록 호출하는 함수가 늘어난다. 만약 이때에 최하위 함수를 변경해 확인된 예외를 던진다면 함수는 선언부에 throws 절을 추가해야 한다. 이렇게 된다면 해당 함수를 호출하는 모든 함수가 throws 절을 추가해야 하고 최하위 함수부터 최상위 함수까지 연쇄적인 수정이 일어난다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;throws 경로에 위치하는 모든 함수가 최하위 함수에서 던지는 예외를 알아야 하므로 캡슐화가 깨진다.&lt;/span&gt;&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;물론 최하위 함수에서 바로 예외를 처리하는 방법도 있다. 그러나 우리는 &quot;오류코드보다 예외를 사용하라&quot;에서 &lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;예외를 던져 오류처리를&amp;nbsp;한 번에&amp;nbsp;해주는 것이&amp;nbsp;가장 낫다는 것과 무언가를 처리하는 메서드와 오류를 처리하는 메서드가 분리되는 것이 낫다는 것&lt;/span&gt;을 알게 되었다. 그렇기에 예외를 던져서 처리하는데 오류를 원거리에서 처리하기 위해 예외를 사용한다는 사실을 감안한다면 이처럼 확인된 예외가 캡슐화를 깨버리는 현상은 유감스럽다.&lt;/b&gt;&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;확인된 예외가 유용할 때도 있다. 중요한 라이브러리를 작성한다면 모든 예외를 잡아야 한다. 그러나 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;일반적인 애플리케이션은 의존성이라는 비용이 이익보다 크다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예외에 의미를 제공하라&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예외를 던질 때에는 해당 상황에 대해서 자세히 남겨주는 것이 좋다. 오류가 발생한 원인과 위치를 찾기 쉬워지기 때문이다. 자바는 모든 예외에 호출 스택을 제공하지만 호출 스택만으로는 원인을 찾아내기 힘들기에 오류 메시지에 자세한 정보를 담아 예외와 함께 던져주는 것이 좋다. 만약 애플리케이션이 로그를 남긴다면 catch 블록에서 오류를 파악하기 쉽도록 충분한 정보를 남겨주는 것이 좋다.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;호출자를 고려해 예외 클래스를 정의하라&lt;/span&gt;&lt;/b&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;오류를 분류하는 방법은 수없이 많다. 그러나 프로그래머에게 가장 중요한 관심사는 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;오류를 잡아내는 방법&lt;/span&gt;이 되어야 한다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;아래의 예제 코드는 오류를 형편없이 분류한 사례이다. 외부 라이브러리를 호출하는 try-catch-final 문을 포함한 코드로, 외부 라이브러리가 던질 예외를 모두 잡아내는 코드이다.&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1667739238344&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 라이브러리가 던질 예외를 모두 잡아낸다.
ACMEPort port = new ACMEPort(12);

try{
    port.open();
} catch (DeviceResponseException e){
    reportPortError(e);
    logger....
} catch (ATM1212UnlockedException e) {
    reportPortError(e);
    logger....
} catch (GMXError e){
    reportPortError(e);
    logger....
} finally{
	.....
}&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;위 코드의 경우에 예외를 대응하는 방식 즉, catch 블록의 로직이 예외 유형과는 다르게 동일하다. 그러므로 모든 예외를 잡아내는 것은 의미가 없다. 위와 같은 경우는 더욱 간결하게 고치기 쉽다. 호출하는 라이브러리 API를 감싸서 예외 유형을 하나만 반환해주면 된다. 아래 코드를 통해 살펴보자.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1667740098096&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;LocalPort port = new LocalPort(12);

try{
    port.open();
} catch (PortDeviceFilure e){
    reportError(e);
    logger....
} finally {
    ...
}

// ACMEPort 클래스가 던지는 예외를 잡아 변환하는 감싸기 클래스
public class LocalPort{
    private ACMEPort innerPort;
    
    public LocalPort(int portNumber){
        innerPort = new ACMEPort(portNumber);
    }
    
    public void open(){
        try{
            innerPort.open();
        } catch (DeviceResponseException e){
            throws new PortDeviceFailure(e);
        } catch (ATM1212UnlockedException e){
        	throws new PortDeviceFailure(e);
        } catch (GMXError e) {
            throws new PortDeviceFailure(e);
        }
      }
    ....
 }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;LocalPort 클래스처럼 ACMEPort를 감싸는 클래스는 매우 유용하다. 실제로 외부 API를 사용할 때는 감싸기 기법을 사용하면 많은 장점들을 가져다준다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;외부 API를 감싸면 외부 라이브러리와 프로그램 사이에 의존성이 크게 줄어든다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;나중에 다른 라이브러리로 갈아타더라도 비용이 적다. 하나의 예외만 반환하면 되기 때문이다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;감싸기 클래스에 외부 API를 호출하는 대신 테스트 코드를 넣어주는 방법으로 프로그램을 테스트하기 쉬워진다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;특정 업체가 API를 설계한 방식에 발목 잡히지 않는다. 프로그램이 사용하기 편리한 API를 정의하여 사용하면 그만이다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;감싸기 클래스를 하나 만들어 port 디바이스 실패를 표현하는 예외 유형 하나를 정의했을 뿐인데 코드가 깔끔해진 것과 동시에 많은 장점들을 얻었다.&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;정상 흐름을 정의하라&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;앞서 나온 모든 충고와 지침들을 충실히 따라간다면 비즈니스 논리와 오류 처리가 잘 분리된 코드가 나오게 된다. 그러나 외부 API를 감싸 독자적인 예외를 던져 중단한 뒤 호출한 코드에서 처리를 정의해 중단된 계산을 처리하는 것이 적합하지 않은 경우도 있다. 이러한 경우에는 특수 사례 패턴(SPECIAL CASE PATTERN)을 적용해 개선할 수 있다. &lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;코드를 통해 특수 사례 패턴을 알아보자.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;특수 사례 패턴(SPECIAL CASE PATTERN)&lt;br /&gt;&lt;br /&gt;반환할 값이 없을 때 예외를 던지는 것이 아니라 기본값을 반환하는 패턴&lt;/span&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;아래 코드는 비용을 청구하는 애플리케이션에서 총계를 계산하는 코드이다.&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1667742135657&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;try{
    MealExpenses expenses = expenseReportDAO.getMeals(employee.getID());
    mTotal += expenses.getTotal();
} catch (MealExpensesNotFound e){
    mTotal += getMealPerDiem();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;식비를 비용으로 청구했다면 직원이 청구한 식비를 총계에 더한다. 식비를 비용으로 청구하지 않았다면 catch 블록에서 일일 기본 식비를 총계에 더한다. 그런데 위와 같은 코드는 예외처리가 논리를 따라가기 어렵게 만든다. 이러한 특수 상황을 처리할 필요가 없어진다면 더 깔끔한 코드가 될 것이다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1667742420145&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;MealExpenses expenses = expenseReportDAO.getMeals(employee.getID());
mTotal += expenses.getTotal();


public class PerDiemMealExpenses implements MealExpenses {
	private static final int MEAL_EXPENSES_DEFAULT = 7000;
	public int getTotal() {
    	// 기본값으로 일일 기본 식비를 반환해준다.
        return MEAL_EXPENSES_DEFAULT;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ExpenseReportDAO를 고쳐 항상 MealExpense 객체를 반환하게 한다. 만약 청구한 식비가 없다면 일일 기본 식비를 반환하는 MealExpense 객체를 반환하는 방법이다. 위와 같은 방법을 특수 사례 패턴이라고 부른다. 클래스를 만들거나 객체를 조작해 특수 사례를 처리하는 방식이다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위와 같은 방법으로 처리한다면 클래스나 객체가 예외적인 상황을 캡슐화해서 처리하기 때문에 클라이언트 코드가 예외적인 상황을 처리할 필요가 없어진다.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;null을 반환하지 마라&lt;/span&gt;&lt;/b&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우리가 오류를 유발하는 습관 중 하나는 null을 반환하는 것이다. 평소 if문을 통해 null을 반환하는 코드를 봐왔다면 나쁘지 않다고 느낄 수도 있다. 그러나 어디선가 하나라도 null 확인을 빼먹는다면 NullPointerException이 발생하며 애플리케이션이 통제 불능에 빠질 가능성이 생긴다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그렇기에 메서드에서 null을 반환하고 싶은 유혹이 든다면 예외를 던지거나 특수 사례 패턴을 사용하는 것을 권장한다. 또한 사용하는 외부 API가 null을 반환할 때도 마찬가지다. 감싸기 클래스와 특수 사례 패턴으로 처리해주길 권장한다. 대부분에 경우에는 특수 사례 패턴을 사용하는 것이 손쉬운 해결책이라고 한다. 코드를 통해 살펴보자.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1667743654339&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;Employee&amp;gt; employees = getEmployees();
if (employees != null){
    for (Employee e : employees) {
        totalPay += e.getPay();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;위의 코드는 null을 반환한다. 하지만 반드시 null을 반환할 필요가 없다. getEmployees()를 변경해 빈 리스트를 반환한다면 코드가 훨씬 깔끔해질 것이다. 다행히도 자바에는 Collections.empltyList() 읽기 전용 빈 리스트를 반환해줄 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1667743744078&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;Employee&amp;gt; employees = getEmployees();
    for (Employee e : employees) {
        totalPay += e.getPay();
    }
    
// 직원이 없다면 빈 리스트를 반환
public List&amp;lt;Employee&amp;gt; getEmployees(){
	if (.. 직원이 없다면 ..) {
        return Collections.emptyList();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위와 같이 코드를 변경한다면 코드도 깔끔해질 뿐만 아니라 NullPointerException이 발생할 가능성도 줄어든다.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;null을 전달하지 마라&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;메서드에서 null을 반환하는 방식도 나쁘지만 메서드로 null을 전달하는 방식은 더 나쁘다. 보통 정상적인 인수로 null을 기대하는 API는 거의 없을 것이다. 정말 인수값으로 null을 기대하는 게 아니라면 메서드로 null을 전달하는 행동은 해서는 안된다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;만약 인자 값으로 null이 전달될 가능성이 있다면 인수로 들어오는 값들에 대해 항상 null 체크를 해줘야 할 것이다. 분명 코드가 아주 지저분해질 것이고 처리를 제대로 해주지 못한다면 NullPointerException이 발생할 것이다. 대안으로 assert 문을 사용하는 방법이 있지만 이것도 코드를 아주 잘 정리하는 방법일 뿐 문제를 해결하지는 못한다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;대다수에 프로그래밍 언어는 호출자가 실수로 넘기는 null을 적절히 처리하는 방법이 없다. 그렇기에 애초에 null을 넘기지 못하도록 금지하는 정책이 가장 합리적이다. 즉, null이 인수로 넘어오는 것부터 코드에 문제가 있다는 말이다. 이러한 정책을 확실히 하여 부주의한 실수를 저지를 확률을 낮추자!&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리&lt;/span&gt;&lt;/b&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;깨끗한 코드는 읽기도 좋아야 하지만 안정성도 높아야 한다. 오류 처리를 프로그램 논리와 분리해서 코드를 작성하면 오류 처리를 프로그램 논리와 분리하여 독립적인 추론이 가능해지고 코드 유지보수성도 크게 높아진다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;나는 이번 제7장 예외 처리를 읽으면서 많은 생각이 들었다. 내게 오류처리란 if문과 해당 메서드에서 바로 try-catch-finally문을 사용하는 것이 전부였기 때문이다. 예외를 던져 한 곳에서 처리하여 오류처리와 서비스 로직의 개념을 분리할 생각도 해보지 못했고, null 대신 빈 리스트를 반환할 생각도 못해봤다. if문으로 null을 처리하는 것을 당연하게 여기고 있었다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;인수로 null을 전달하는 것도 마찬가지다. 당연히 null을 전달하면 안 되겠지만 생각해보지는 못했던 문제이다. 내가 자연스럽게 넘기고 있던 인수들이 null을 반환할 가능성에 대해 생각하지 못했었다. 여러모로 많은 것을 배우게 됐다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;가장 기억해야 할 것이 무엇이냐 고르라 하면 하나를 딱 집어 고를 수 없을 정도로 많은 도움이 되었다. 아래는 내가 꼭 기억하며 적용해 나가야 할 내용들을 요약해두었다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;오류를 분류하는 방법은 많다 그러나 핵심은 오류를 잡아내는 방법이다. 외부 API에 대해서는 감싸기 클래스를 만들어 외부 API와의 의존성을 낮추고 예외 및 여러 상황들에 대응하자.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;특수 사례 패턴을 사용하여 null을 방지하고 프로그램의 논리를 간단하게 만들자.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;인수에 null이 전달되지 않도록 항상 주의하자.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예외 처리 시 호출 스택만을 남기기보다는 에러 로그를 통해 에러를 파악할만한 충분한 정보를 넘겨주자.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;오류 코드보다 예외를 사용하고 실패하는 테스트 케이스를 꼭 작성하자.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발/Read Book</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/34</guid>
      <comments>https://doosicee.tistory.com/entry/CleanCode-7%EC%9E%A5-%EC%98%A4%EB%A5%98-%EC%B2%98%EB%A6%AC#entry34comment</comments>
      <pubDate>Sun, 6 Nov 2022 23:41:55 +0900</pubDate>
    </item>
    <item>
      <title>CleanCode 6장 객체와 자료구조</title>
      <link>https://doosicee.tistory.com/entry/CleanCode-6%EC%9E%A5-%EA%B0%9D%EC%B2%B4%EC%99%80-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEcJzM/btrNPiE4mNM/0uE1f0bbPxsdVQYbbjVHA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEcJzM/btrNPiE4mNM/0uE1f0bbPxsdVQYbbjVHA1/img.png&quot; data-alt=&quot;출처: 인사이트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEcJzM/btrNPiE4mNM/0uE1f0bbPxsdVQYbbjVHA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEcJzM%2FbtrNPiE4mNM%2F0uE1f0bbPxsdVQYbbjVHA1%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;350&quot; height=&quot;467&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: 인사이트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;객체와 자료구조&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;자료 추상화&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;자료/객체 비대칭&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;디미터 법칙&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;자료 전달 객체&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;이 글을 읽기 전에 추상화의 개념을 간단하게 알아보자. 나무 위키에서는 추상화를 아래와 같이 정의했다.&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;컴퓨터과학에서 추상화는 어떤 종류의 대상들에 대해 그것이 가져야 할 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;핵심적인 특징들을 가지는 모델을&lt;/span&gt; 만드는 것이다.&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;예를 들어보자면 쇼핑몰에서는 회원에게 더 좋은 서비스를 제공하기 위해서는 고객의 정보가 필요하다. 회원의 정보는 이름, 주소, 휴대폰 번호, 성별 등... 이 있을 수 있다. 이때에 정보라는 범위가 모호하므로 위의 정보 외에도 직장, 취미, 특기, 음식, 이상형까지 포함할 수 있지만 회원 정보로는 필요하지 않다. 그렇기에 이러한 불필요한 정보들을 제거함으로써 중요한 공통점들만 남기는 것도 추상화라고 할 수 있다. (&lt;span style=&quot;background-color: #f8f9fa;&quot;&gt;reference&lt;/span&gt;: &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://steady-coding.tistory.com/453&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;추상화란?&lt;/a&gt;&lt;/span&gt;)&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;즉, 추상화는 어떠한 대상이 가져야 할 핵심적인 특징 중&amp;nbsp;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;불필요한 세부 사항은 버리고 공통적인 특징만을 가지는 것&lt;/span&gt;이다.&amp;nbsp;추상화의 이점은&amp;nbsp;모델링, 코드의 재사용성, 가독성, 일관된 방향성, 생산성, 에러 감소 여러 가지가 있다.&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;자료 추상화&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;pre id=&quot;code_1665195600664&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 첫 번째
public class Point{
  public double x;
  public double y;
}

// 두 번째
public interface Point{
  double getX();
  double getY();
  void setCartesian(double x, double y);
  double getR();
  double getTheta();
  void setPolar(double r, double theta);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;위의 두 클래스중 첫 번째는 구현을 외부로 노출하고 두 번째 클래스는 구현을 숨긴다. 두 번째는 점이 직교 좌표계를 사용하는지 극좌표계를 사용하는지 알 수 없다. 반면 첫 번째는 직교 좌표계를 사용하는 것이 분명하게 드러난다. 첫 번째 클래스의 변수들을 private로 바꾸고 조회 함수와 설정 함수를 제공한다고 해도 구현을 외부로 노출하는 것은 마찬가지다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;변수 사이에 함수라는 계층을 넣는다고 구현이 감춰지지는 않는다. 구현을 감추려면 &lt;span style=&quot;color: #ee2323;&quot;&gt;추상화&lt;/span&gt;가 필요하다. 형식적인 조회 함수(getter())와 설정 함수(setter())로 변수를 다룬다고 클래스가 되지는 않는다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;진정한 클래스는 추상 인터페이스를 제공해 사용자가 구현을 모른 채 자료의 핵심을 조작할 수 있어야 한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;자료 추상화 정리&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;나는&amp;nbsp;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;자료 추상화&lt;/span&gt;에서 구현이라는 단어에 집중했다. 구현을 외부로 노출하는 것과 노출하지 않는 것은 무엇일까?, 구현을 모른 채 자료의 핵심을 조작한다는 것은 무엇일까? 내 생각을 조금 정리해봤다.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;구현을 외부로 노출한다는 것&lt;/span&gt;은 추상화 인터페이스를 통해 노출된 객체의 행동을 사용하는것이 아닌 사용자가 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;직접적으로 객체의 상태를 조회하고 조작할 수 있는 상태&lt;/span&gt;이다. 코드를 통해 살펴보자&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1665617426108&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ExampleList {

    public Object[] elementData;
    
}


private ExampleList ExampleList(){

        ExampleList list = new ExampleList();
        list.elementData[0] = &quot;test&quot;;

        return list;
    }&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;평소 우리는 ArrayList를 사용할때에 add(), get() 등.. 의 메서드들을 이용하여 데이터 조회 및 조작을 했을 것이다. 그러나 위의 코드는 사용자가 직접적으로 객체의 상태를 조작하는 모습을 볼 수 있다. 여기에 public을 private로 바꿔주고 get(), set() 함수를 만들어줘도 같은 결과다. 그럼 어떻게 해야 할까? 구현을 외부로 노출하지 않는 것이 무엇인지 살펴보며 이해해보자.&lt;/span&gt;&lt;/b&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;구현을 외부로 노출하지 않는다는 것&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;은 추상화 인터페이스를 통해 노출된 행동을 사용하여 객체의 상태를 조회하고 조작할 수 있는 상태이다. 코드를 통해 살펴보자&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1665618583938&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ArrayList&amp;lt;E&amp;gt; extends AbstractList&amp;lt;E&amp;gt;
        implements List&amp;lt;E&amp;gt;, RandomAccess, Cloneable, java.io.Serializable{
        
    transient Object[] elementData;   
    
    ........
}

private ArrayList ExampleList(){

        ArrayList list = new ArrayList();
        list.add(&quot;test&quot;);

        return list;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;구현을 외부로 노출했을때 즉, ExampleList 클래스를 사용할 때는 elementData를 사용자가 직접 조작했었다. 반면 ArrayList는 add()라는 행동을 통해서 데이터를 조작하는 모습을 볼 수 있다. &lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ArrayList는 List 인터페이스의 구현 클래스이다. List 인터페이스에는 add(), get(), remove(), indexOf() 등... 객체의 상태를 조회, 조작할 수 있는 다양한 &lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;행동&lt;/span&gt;&lt;/b&gt;들이 정의되어있다. ArrayList 클래스를 통해 이 행위들을 구현하고, 구현된 &lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;행동&lt;/span&gt;&lt;/b&gt;들을 통해 데이터를 조회하고 조작하는 것이 바로 구현을 외부로 노출하지 않는다는 것이다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&quot;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;진정한 클래스는 추상 인터페이스를 제공해 사용자가 구현을 모른 채 자료의 핵심을 조작할 수 있어야 한다.&quot;라는&lt;/span&gt; 말에도 부합하다. &lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;행동&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;들로 데이터를 조작하기에 사용자는 구현을 모른 채 자료의 핵심을 조작할 수 있다. &lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;추가적으로 &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;span style=&quot;background-color: #dddddd; color: #000000;&quot;&gt;추상화를 할때에는 자료를 세세하게 공개하기보다는 추상적인 개념으로 표현하는 것이 좋다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;/b&gt;Vehicle이라는 인터페이스가 있고 연료상태를 나타내는 함수를 getGasollonsOfGasoline() 또는 getFuelTankCapacityInGallons()처럼 연료의 상세한 단위를 나타내기보다는 getPercentFuelRemaining()처럼 백분율이라는 추상적인 개념으로 알려주라는 것이다. 간단히 요약하면 상세한 단위로 알려주기보다는 상세한 것들을 통틀어 묶어줄 수 있는 더 상위의 개념을 사용하라는 이야기다.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;자료/객체 비대칭&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;자료 추상화에서 보인 List 예제는 객체와 자료 구조 사이에 벌어진 차이를 보여준다. 객체는 추상화 뒤로 자료를 숨긴 채 자료를 다루는 행동 즉, 함수만 공개한다. 반면 자료 구조는 자료를 그대로 공개하며 별다른 함수는 제공하지 않는다. 두 정의에 차이는 사소한 차이로 보일 수도 있지만, 그 차이가 미치는 영향은 크다. 코드를&amp;nbsp;통한&amp;nbsp;예시로&amp;nbsp;살펴보자.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;절차 지향적인 도형&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666310112765&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Square {
	public Point topLeft;
	public double side;
}

public class Rectangle{
	public Point topLeft;
	public double height;
	public double width;
}

public class Circle{
	public Point center;
	public double radius;
}

public class Geometry{
	public double area(Object shape) throws .....{
		if(shape instanceof Sqeare){
			return ....
		}else if(shape instanceof Rectangle){
			return ....
		}else if(shape instanceof Circle){
			return ....
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;Geometry는 세 가지의 도형 클래스를 다루고 있다. 각 도형 클래스들은 자료구조만을 제공할 뿐 어떠한 행동 즉, 메서드도 제공하지 않는다. 도형이 동작하는 방식은 Geometry클래스에서 구현된다. 절차적인 코드는 기존 자료구조를 변경하지 않으면서 새 함수를 추가하기가 쉽다.&amp;nbsp; 그러나&amp;nbsp;새로운&amp;nbsp;자료구조를&amp;nbsp;추가하려면&amp;nbsp;함수들을&amp;nbsp;고쳐야&amp;nbsp;하기&amp;nbsp;때문에&amp;nbsp;자료구조를&amp;nbsp;추가하기&amp;nbsp;어렵다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;객체지향적인 도형&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666310171506&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface Shape{
	double area();
}

public class Square implements Shape {
	private Point topLeft;
	private double side;

	public double area() {
		return side * side;
	}
}

public class Rectangle implements Shape {
	private Point topLeft;
	private double height;
	private double width;

	public double area() {
		return heigth * width;
	}
}

public class Circle implements Shape {
	private Point center;
	private double radius;
	private final double PI = 3.141592653589793;

	public double area() {
		return PI * radius * radius;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;객체 지향적 코드는 자료구조를 감추고 자료구조를 조작할 수 있는 행동 즉, 메서드를 제공한다. 객체 지향적인 코드는 기존 함수를 변경하지 않으면서 새 클래스를 추가하기가 쉽다. 그러나 새로운 함수를 추가하려면 추상 클래스의 구현 클래스들을 모두 고쳐야 한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;정리하자면 객체 지향 코드에서 어려운 변경은 절차 지향에서는 쉽고, 절차 지향에서 변경이 어려운것은 객체 지향에서 쉽다. 복잡한 시스템을 짜다 보면 새로운 함수가 아니라 새로운 자료 타입이 필요한 경우도 생길 수 있다. 이때는 클래스와 객체 지향 기법이 가장 적당하다. 반면,&amp;nbsp;새로운&amp;nbsp;자료 타입이&amp;nbsp;아닌&amp;nbsp;메서드가&amp;nbsp;필요한&amp;nbsp;경우도&amp;nbsp;생긴다.&amp;nbsp;이때는&amp;nbsp;절차적인&amp;nbsp;코드와&amp;nbsp;자료구조가&amp;nbsp;더&amp;nbsp;적합하다. &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모든 것이&amp;nbsp;객체임은&amp;nbsp;미신이다.&amp;nbsp;때로는&amp;nbsp;단순한&amp;nbsp;자료&amp;nbsp;구조와&amp;nbsp;절차적인&amp;nbsp;코드가&amp;nbsp;가장&amp;nbsp;적합한&amp;nbsp;상황도&amp;nbsp;있다.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;디미터&amp;nbsp;법칙&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;디미터의 법칙은 디미터라는 이름의 프로젝트를 진행하던 도중 객체가 다른 객체에 대해 지나치게 많이 알다 보니, 결합도가 높아져 좋지 못한 설계를 야기한다는 것을 발견하였다. 그래서 객체에게 자료를 숨기는 대신 함수 즉, 행동을 공개하기로 하였는데 이것이 디미터의 법칙이다. 즉,&amp;nbsp;디미터의&amp;nbsp;법칙은&amp;nbsp;다른&amp;nbsp;객체가&amp;nbsp;어떠한&amp;nbsp;자료를&amp;nbsp;갖고&amp;nbsp;있는지&amp;nbsp;속사정을&amp;nbsp;몰라야&amp;nbsp;한다는&amp;nbsp;법칙이다. &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 이유로 디미터의 법칙은 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;Don't Talk to Strangers(낯선 이에게 말하지 마라) 또는 Principle of least Knowledge(최소 지식 원칙)&lt;/span&gt;으로도 알려져 있다. 또는 직관적인 이해를 위해 여러개의&lt;span style=&quot;background-color: #dddddd;&quot;&gt; .(도트)를 사용하지 말라는 법칙&lt;/span&gt;으로도 많이 알려져 있다. 디미터의 법칙을 준수한다면 결합도를 낮추고 캡슐화를 높여 자율성과&amp;nbsp;응집도를&amp;nbsp;높일&amp;nbsp;수&amp;nbsp;있다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;낯선 이에게 말하지 마라,&amp;nbsp; 최소 지식 원칙&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;디미터의 법칙은 노출 범위를 제한하기 위해 객체의 모든 메서드는 다음과 같은 객체의 메서드만 호출해야 한다고 주장한다. &quot;클래스&amp;nbsp;C의&amp;nbsp;메서드&amp;nbsp;f는&amp;nbsp;다음과&amp;nbsp;같은&amp;nbsp;객체의&amp;nbsp;메서드만&amp;nbsp;호출해야 한다&quot;&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;클래스 C 객체의 메서드: 객체 자신의 메서드들&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;f가 생성한 객체: 메서드 내부에서 생성, 초기화된 객체의 메서드를 의미한다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;f 인수로 넘어온 객체: 메서드의 파라미터로 넘어온 객체들의 메서드들&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;C 인스턴스 변수에 저장된 객체: 인스턴스 변수로 가지고 있는 객체가 소유한 메서드&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;코드를 통해서 한번 살펴보자.(예제 참조:&lt;/span&gt; &lt;a href=&quot;https://tecoble.techcourse.co.kr/post/2020-06-02-law-of-demeter/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;디미터의 법칙&lt;/a&gt;&lt;span style=&quot;color: #000000;&quot;&gt;)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666312879039&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Demeter {
    private Member member;

    public void demeterMethod() {
        ....
    }

    public void testDemeter(Paramemter param) {
        demeterMethod();     	// 1.객체 자신의 메서드
        Local local = new Local();
        local.localMethod();    // 2. 메서드 내부에서 생성, 초기화된 객체의 메서드
        param.paramMethod();    // 3. 메서드의 파라미터로 넘어온 객체들의 메서드
        member.memberMethod();  // 4. 인스턴스 변수로 가지고 있는 객체가 소유한 메서드
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위 객체에서 허용된 메서드들이 있다. 그러나 해당 메서드가 반환하는 객체의 메서드를 다시 호출해서는 안된다. 간단히 예를 들자면 local.locaMethod(); 까지만 놀고 local.localMethod().unknownMethod(); 이런 식으로 호출해서는 안된다. 낯선 사람은 경계하고 주변 친구랑만 놀라는 의미다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;.(도트)를 사용하지 말라, 기차 충돌&lt;/span&gt;&lt;span style=&quot;color: #202124;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1666912686605&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;흔히 위와 같은 코드를 기차 충돌이라고 부른다고 한다. 여러 객차가 한 줄로 이어진 기차처럼 보이기 때문이다. 위와 같은 코드는 일반적으로 조잡하다 여겨지므로 피하는 것이 좋다. 사실 조잡하다는 이유보다 더 큰 이유가 있다. 위에서 말한 낯선 이에게 말하지 말라, 최소 지식 원칙을 어기고 있기 때문이다. getOption() 함수가 반환하는 객체의 getScratchDir() 함수를 호출하고, 그 반환 객체인 getAsolutePath() 함수를 호출하기 때문이다. 위의 코드는 아래와 같이 작성하는 게 더 좋다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666913055960&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDit();
final String outputDir = scratchDir.getAbsolutePath();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위에 나온 두 코드들은 확실히 함수 하나가 아는 지식이 많다. 즉, 함수 하나가 많은 객체를 탐색할 줄 안다는 말이다. 과연 이러한 함수들은 디미터의 법칙을 어긴 것일까...?&lt;span style=&quot;background-color: #dddddd;&quot;&gt; 위반에 대한 여부는 해당 함수가 객체인지 아니면 자료구조 인지에 달렸다.&lt;/span&gt;&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;객체라면 내부 구조를 숨겨야 하는 게 맞기 때문에 확실히 디미터의 법칙을 위반한다. 그러나 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;자료구조라면 당연히 내부 구조를 노출하므로 디미터의 법칙이 적용되지 않는다. 우리가 사용하는 Dto는 자료구조이다.&lt;/span&gt; 또한.(도트)를 사용하지 말라는 도트를 무조건 한 개만 찍으라는 말은 아니다 아래의 코드를 살펴보자.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666913546145&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public List&amp;lt;DetailMonsterDto&amp;gt; getAllDetailMonster() {
    return monsterRepository.findAll()
            .stream().map(DetailMonsterDto::fromEntity)
            .collect(Collectors.toList());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위의 코드가 디미터의 법칙을 어긴 것이라고 생각될 수 있다. 그러나 디미터의 법칙은 내부 결합도와 관련된 것이며, 문제가 되는 상황은 내부 구조가 외부에 유출되는 경우이다. 위의 코드는 Stream의 내부 구조가 노출되지 않았다. Stream을 다른 Stream으로 반환해줬을 뿐 캡슐화는 잘 유지되고 있다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;잡종 구조&lt;/span&gt;&lt;span style=&quot;color: #202124;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;잡종 구조란 절반은 객체, 절반은 자료 구조인 구조이다. 잡종 구조는 중요한 기능을 수행하는 함수도 있고, 공개 변수나 공개 조회/설정 함수도 있다. 공개/설정 함수는 비공개 변수를 그대로 노출한다. 이러한 구조는 새로운 함수를 추가하기도 힘들고 새로운 자료 구조를 추가하기도 어렵다. 잡종 구조는 객체와 자료구조의 단점만 모아놓은 구조이기 때문에 피하는 것이 좋다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;객체를 다룰 때에 내부 구조를 감추고 행동 즉, 메서드만을 공개해 조회/조작할 수 있어야 한다는 것을 생각하고 있다면 잡종 구조는 나오지 않으리라 생각된다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;구조체 감추기&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위의.(도트)에서 나왔던 ctxt, options, scratchDir들이 자료구조라면 문제가 되지 않는다. 다만 진짜 객체라면 어떨까? 앞서 나온 코드처럼 기차 충돌 형태 즉, 줄줄이 꽤어진 코드 형태를 취해서는 안된다. 객체라면 내부 구조를 감춰야 한다. 행동을 통해 뭔가를 명령해야 하지 속을 드러내라 해서는 안된다. 그렇다면 어떻게 감춰야 할까...?&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;먼저&lt;span style=&quot;background-color: #dddddd;&quot;&gt; 집중해야 할 것은 목적&lt;/span&gt;이다. 저렇게 경로들을 얻어내는 이유는 임시 디렉터리의 경로를 만들어 임시 파일을 생성하기 위해서라고 가정해보자. 그렇다면 직접 객체를 조회하여 임시 경로를 만들어 임시 파일을 생성하기보다는&lt;span style=&quot;background-color: #dddddd;&quot;&gt; 객체의 행동 즉, 메서드로 임시 파일을 생성하는 메서드를 만들어 두면 더 좋은 방법이 될 것이다.&lt;/span&gt;&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;경로를 만들기 위해 조회했던 객체들의 내부 구조를 드러내지 않으며 모듈에서 해당 함수는 자신이 몰라야 하는 여러 객체를 탐색할 필요가 없어진다. 디미터 법칙을 위반하지 않는다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;코드로 요약!&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1667141384397&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 임시 파일 생성 경로를 얻기 위해 객체를 조회
Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDit();
final String outputDir = scratchDir.getAbsolutePath();

// 파일 생성
String outFile = outputDir + &quot;/&quot; + className.replace('.', '/') + &quot;.class&quot;;
FileOutputStream fout = new FileOUtputStream(outFile);
BufferedOutputStream bos = new BufferedOutputStream(fout);


// 위와 같은 방법은 객체의 속을 드러내야하며, 여러 추상화 수준이 뒤섞여있다.
// 목적은 임시 디렉토리의 경로를 얻어 임시 파일을 생성하기 위함이다.
// 그렇다면 아래처럼 임시파일을 생성해주는 행동 즉, 메서드를 만드는건 어떨까?
BufferedOutputStream bos = ctxt.createScratchFileStream(classFileName);&lt;/code&gt;&lt;/pre&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;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;자료 전달 객체&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;자료 구조체의 전형적인 형태는 공개 변수만 있고 함수가 없는 클래스다. 이런 구조체를 때로는 자료 전달 객체 즉, Data Transfer Object, DTO라고 한다. 흔히 DTO는 데이터베이스에 저장된 가공되지 않은 정보를 애플리케이션 코드에서 사용할 객체로 변환하는 일련의 단계에서 가장 처음으로 사용하는 구조체이다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;좀 더 일반적인 형태는 '빈 Bean' 구조라고 한다. 빈은 비공개 private 변수를 조회/설정 함수로 조작한다. 우리가 흔히 사용하는 DTO가 빈 구조인 것이다&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1667142113087&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public Class Member{
    private name;
    private age;
    
    public Member(String name, Integer age){
    	this.name = name;
        this.age = age;
    }
    
    public String getName(){
    	return this.name;
    }
    
    public void setName(String name){
		this.name = name;
	}

	.......
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;활성 레코드(ActiveRecord)&lt;span style=&quot;color: #202124;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;활성 레코드는 DTO의 특수한 형태이다. 공개 변수가 있거나 비공개 변수에 조회/설정 함수가 있는 자료구조지만, 대개 save나 find와 같은 탐색 함수도 제공한다. 활성 레코드는 데이터베이스 테이블이나 다른 소스에서 자료를 직접 변환한 결과이다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;활성화 레코드에는 비즈니스 로직 메서드를 추가해서는 안된다. 활성화 레코드는 자료 구조체일 뿐 객체가 아니기 때문이다. 비즈니스 로직 메서드를 추가하는 순간 잡종 구조가 탄생한다. 그렇다면 어떻게 해결할까? 단순하다&lt;span style=&quot;background-color: #dddddd;&quot;&gt; 활성화 레코드는 그저 자료구조로 취급하면 된다.&lt;/span&gt; &lt;span style=&quot;background-color: #dddddd;&quot;&gt;비즈니스 로직이 필요하다면 해당 비즈니스 로직을 담은 객체를 만들면 된다. 자료 구조를 사용하고 싶다면 비즈니스 로직 객체의 행동을 통해 사용하거나, 자료구조의 인스턴스를 생성해 사용하면 된다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;객체는 동작을 공개하고 자료를 숨긴다. 그렇기에 기존 동작을 변경하지 않으면서 새 객체 타입을 추가하기는 쉬운 반면, 기존 객체에 새 동작을 추가하기는 어렵다. 추상화 클래스의 구현 클래스들에 추가된 동작을 모두 구현해줘야 하기 때문이다. &lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;반면 자료구조는 별다른 동작 없이 자료를 노출한다. 그래서 기존 자료구조에 새 동작을 추가하기는 쉬우나, 기존 함수에 새 자료 구조를 추가하기는 어렵다. 자료구조는 쉽게 생각하면 노출된 자료를 통해 메서드를 외부 클래스에서 구현한다고 생각하면 된다. 그렇기에 새 자료구조를 추가하면 이미 구현된 함수를 수정해야 한다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우리가 어떤 시스템을 구현할 때에 새로운 자료 타입을 추가하는 유연성이 필요하다면 객체가 더 적합하다. 동물이라는 추상 클래스를 통해 토끼, 호랑이, 곰 등... 여러 동물 타입을 쉽게 구현할 수 있다. 다른 경우로는 새로운 동작을 추가하는 유연성이 필요하다면 자료 구조와 절차적인 코드가 더 적합하다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;왜냐하면 이미 구현된 토끼, 호랑이, 곰에 새로운 동작을 추가하려면 동물 추상클래스를 구현한 모든 클래스에 동작을 구현해줘야 하기 때문이다.&lt;/span&gt;&lt;/span&gt;&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: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우수한 소프트웨어 개발자는 편견 없이 이 사실을 이해하고 직면한 문제에 대해서 최선의 해결책을 선택해야 한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/Read Book</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/30</guid>
      <comments>https://doosicee.tistory.com/entry/CleanCode-6%EC%9E%A5-%EA%B0%9D%EC%B2%B4%EC%99%80-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0#entry30comment</comments>
      <pubDate>Wed, 5 Oct 2022 09:10:31 +0900</pubDate>
    </item>
    <item>
      <title>CleanCode 5장 형식 맞추기</title>
      <link>https://doosicee.tistory.com/entry/CleanCode-5%EC%9E%A5-%ED%98%95%EC%8B%9D-%EB%A7%9E%EC%B6%94%EA%B8%B0</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YPSnJ/btrMXiS2vgj/fQDKjkmyXSoOL3eA9J9C50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YPSnJ/btrMXiS2vgj/fQDKjkmyXSoOL3eA9J9C50/img.png&quot; data-alt=&quot;출처: 인사이트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YPSnJ/btrMXiS2vgj/fQDKjkmyXSoOL3eA9J9C50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYPSnJ%2FbtrMXiS2vgj%2FfQDKjkmyXSoOL3eA9J9C50%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;350&quot; height=&quot;467&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: 인사이트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;형식 맞추기&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;형식을 맞추는 목적&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;적절한 행 길이를 유지하라&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;가로 형식 맞추기&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;팀 규칙&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;누군가 내 코드를 봤을 때 전문가라는 인상을 심어줄 수 있다면 얼마나 좋을까. 더 나은 코드를 작성하기 위해, 다른 프로그래머가 봤을 때 더 나은 가독성을 위해서는 끊임없는 고민과 노력이 필요한 것 같다. 회사에서 일한다면 회사에서 정한 규칙에 따라서, 개인이라면 개인이 정한 규칙에 따라서 일관성 있는 코드를 작성해야 한다. 그렇다면 일관성 있는 규칙을 세우기 위해서 무엇을 중요시해야 하는지 알아보자.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;형식을 맞추는 목적&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우리는 한가지를 분명히 짚고 넘어가야 한다. 우리 프로그래머들에게 코드란 의사소통의 일환이다. 그렇기에 코드 형식은 아주 중요하다는 것이다. 코드 형식을 맞추는 것이 개발자들의 일차적인 의무이다. 어쩌면 기능이 동작하는 코드가 개발자의 일차적인 업무라 생각할지도 모르겠다. 그러나 제4장 형식 맞추기에서는 그 생각이 바뀌게 되는 계기를 제공한다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예를 들어 우리가 IOT통합 관제, 제어 시스템 1차 버전을 만들었다 생각해보자. 다음 버전에서는 클라이언트의 요구사항들과 개선점을 반영하여 기능이 바뀌고 수정될 가능성이 아주 높다. 보통 우리는 다음 버전을 개발할 때 이전 버전에서 구현한 코드를 참고하여 다음 버전을 개발할 것이다. 오랜 시간이 지나 초기 버전에서 만든 코드의 흔적을 더 이상 찾아보기 힘들지라도 바뀌지 않는 것이 하나 있다. 바로 코드 형식이다. 개발자의 스타일과 규율은 사라지지 않는다. 그렇기에 맨 처음 잡아놓은 구현 스타일과 가독성 수준은 앞으로 바뀔 코드의 품질에 계속해서 큰 영향을 끼칠 것이다. 그렇다면 우리는 원활한 소통을 하기 위한 코드 형식을 알아야 한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;적절한 행 길이를 유지하라&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;코드의 세로 길이는 어느정도가 적당할까? 책에서는 자바 소스파일로 이루어진 유명 프로젝트 7개를 조사하였다. 수천 줄이 넘어가는 파일도 있지만 대부분의 프로젝트들은 파일당 500줄을 넘어가지 않으며 대다수가 200줄 미만의 코드로 작성되어있다. 우리가 이 조사 결과에서 알 수 있는 것은 대부분 200줄 미만인 파일로도 커다란 시스템을 구축할 수 있다는 것이다. 이미 다들 알고 있겠지만 일반적으로 큰 파일보다는 작은 파일이 이해하기가 쉽다. 반드시 지켜야 할 규칙은 아니지만 그렇게 하길 권장한다.&lt;/span&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #dddddd; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;신문 기사처럼 작성하라&lt;/span&gt;&lt;/b&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우리는 신문을 읽을때 위에서 아래로 읽는다. 내용을 몇 마디로 요약한 표제, 흥미를 끌 수 있는 첫 문단, 세세한 내용들이 고차원적인 순서부터 저차원 적인 순서로 작성된다. 소스 파일도 마찬가지다. 이름은 간단하면서도 설명이 가능하게 짓고, 그 아래로는 고차원적인 내용부터 저차원적인 순서로 세세한 사항들을 작성하는 것이 좋다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #dddddd; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;개념은 빈 행으로 분리하라&lt;/span&gt;&lt;/b&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우리가 보통 코드를 읽을때에는 위에서 아래로, 왼쪽에서 오른쪽으로 읽는다. 또한 일련의 행 묶음은 완결된 생각 하나를 표현한다. 그렇기에 생각 사이에는 빈 행을 넣어 분리해야 한다. 아래 코드를 살펴보자.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;빈 행이 있는 코드&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663995893657&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.fc_study.monsterGrowth.service;

import java.util.stream.Collectors;

import static com.fc_study.monsterGrowth.exception.MMakerErrorCode.NO_MONSTER;

@Service
public class MMakerService {

    private final MonsterRepository monsterRepository;
    private final DeadMonsterRepository deadMonsterRepository;

    public List&amp;lt;DetailMonsterDto&amp;gt; getAllDetailMonster() {
        return monsterRepository.findAll()
                .stream().map(DetailMonsterDto::fromEntity)
                .collect(Collectors.toList());
    }

    public CreateMonsterDto.Response createMonster(CreateMonsterDto.Request request) {
        validateCreateMonsterRequest(request);

        return CreateMonsterDto.Response.fromEntity(
                monsterRepository.save(createMonsterFromRequest(request)));
    }

    ......... 코드들
}&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;빈 행이 없는 코드&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663996401780&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.fc_study.monsterGrowth.service;
import java.util.stream.Collectors;
import static com.fc_study.monsterGrowth.exception.MMakerErrorCode.NO_MONSTER;
@Service
public class MMakerService {
    private final MonsterRepository monsterRepository;
    private final DeadMonsterRepository deadMonsterRepository;
    public List&amp;lt;DetailMonsterDto&amp;gt; getAllDetailMonster() {
        return monsterRepository.findAll()
                .stream().map(DetailMonsterDto::fromEntity)
                .collect(Collectors.toList());
    }
    public CreateMonsterDto.Response createMonster(CreateMonsterDto.Request request) {
        validateCreateMonsterRequest(request);
        return CreateMonsterDto.Response.fromEntity(
                monsterRepository.save(createMonsterFromRequest(request)));
    }
    ......... 코드들
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;첫 번째 코드는 패키지의 선언부, import문, 각 함수들의 사이에 빈 행이 들어간다. 두 번째 코드는 빈 행들을 모두 제거했다. &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;괄호 덕에 조금 환기가 되는 것 같지만 첫 번째에 비해 가독성이 크게 떨어진다. 두 코드가 다른 것은 줄 바꿈 뿐이다. &lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;별것 아닌 규칙이지만 이 빈행이 빠진다면 코드의 가독성이 현저하게 떨어지고 암호문처럼 보이게된다.&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; background-color: #dddddd; color: #000000;&quot;&gt;&lt;b&gt;세로 밀집도&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;줄 바꿈이 개념을 분리해준다면 세로 밀집도는 연관성을 의미한다. 서로 밀접한 코드는 세로로 가까이 놓아야 한다. package는 package끼리, import문은 import문끼리,&amp;nbsp; 변수는 변수끼리 모아두어야 코드가 '한눈'에 들어오는 효과를 볼 수 있다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; background-color: #dddddd; color: #000000;&quot;&gt;&lt;b&gt;수직 거리&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;함수 연관 관계들이 서로 흩어져 있다면 연관 관계와 동작 방식을 이해하기 위해서 소스파일들을 뒤지고 다녀야 할 것이다. 또한 연관된 함수들의 조각들이 어디 있는지 기억하기도 만만치 않다. 그렇기에 서로 밀접한 개념들은 세로로 가까이 둬야 한다. 한 파일에 속하는 것이 좋다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;1. 변수 선언&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;변수는 사용하는 위치에 최대한 가까이 선언하자. 우리가 앞으로 설계해야 할 함수는 매우 짧아야 한다. 분명 다들 긴 함수를 본 적이 있고 만들어본 적이 있을 것이라 생각한다. 다음 코드를 통해 살펴보자.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664235831859&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private static String itemProcessing(){
    String resultItem = &quot;&quot;;
    String item = &quot;&quot;;
    int itemNum = 5;
    
    for (){
    	if(){
        .......
        ....
        }
    }
    .......
    try{
    	.....
    	.........
    }catch{
    	...
    	......
    }
    // resultItem이 선언되어야할 이상적인 위치
    for (){
    	if(){
           resultItem = ....;
        }
    }
    return resultItem;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;resultItem은 가장 마지막에서 사용된다. 그러나 선언은 가장 맨 위에 되어있다. 다른 독자가 resultItem이 무슨 타입인지, &lt;b&gt;defalut값은 무엇이었는지 알기 위해서는 코드를 읽다가 변수의 선언부를 찾아가야 한다. 주석으로 표기해 둔 곳처럼 최대한 사용하는 곳에 가까이 위치하도록 해주자.&lt;/b&gt;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;2. 인스턴스 변수&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;방금 변수 선언에서는 변수는 사용하는 위치에 최대한 가까이 두자고 하였다. 반면 인스턴스 변수는 클래스의 가장 처음에 선언한다. 변수 간의 세로 거리 또한 두지 않는다.&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664236706105&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Example {
    private String fruit;
    private String basket;
    private String ......;
    private String ....;
    
    private String getFruit(){
    	.....
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;자바에서는 클래스의 선언부에 인스턴스 변수들을 모아 두고, C++에서는 가장 아래에다가 모아둔다고 한다. 어디에 모아두는가는 중요치 않다. 다만 변수 선언을 어디서 찾아야 할지 모두 알고 있어야 한다는 것이다.&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;b&gt;3. 종속 함수&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664322184293&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Example{

    public ResponseData exampleResponse(Request request){
        ResponseData response = new ResponseData();
        String examplePath = getExamplePath(request.exmaplePath);
        if(examplePath == null){
            response.setExamplePath(makeExmaplePath(request.menuId));     
        }else{
            response.setExamExamplePath(examplePath) 
        }
        return response;
    }
    
    private String getExamplePath(String path){
    	..................
        return examplePath;
    }
    
    private String makeExamplePath(String menuId){
    	.....................
        return examplePath;
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;한 함수가 다른 함수를 호출한다면 두 함수는 세로로 가까이 배치하는 것이 좋다. 호출하는 함수가 가장 위에 위치하고 그 아래로 호출되는 함수들이 배치되야한다. 코드를 읽는 사람은 당연히 해당 함수 후에 해당 함수가 호출하는 함수가 정의되어있으리라 생각한다. 해당 규칙을 지킨다면 전체적인 모듈 가독성도 높아진다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;4. 개념적 유사성&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개념적인 유사성 즉, 개념적인 친화도가 높을수록 코드를 가까이 배치하자. 한 함수가 다른 함수를 호출해 생기는 종속성이 한 예다. 변수와 그 변수를 사용하는 함수도 마찬가지다. 이외에도 개념적 유사성이 있는 예가 있는데 비슷한 동작을 수행하는 일군의 함수가 좋은 예다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664322839191&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@RestControllerAdvice(annotations = RestController.class)
public class APIExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler
    public ResponseEntity&amp;lt;Object&amp;gt; validation(ConstraintViolationException e, WebRequest request) {
        return handleExceptionInternal(e, ErrorCode.VALIDATION_ERROR, request);
    }

    @ExceptionHandler
    public ResponseEntity&amp;lt;Object&amp;gt; general(GeneralException e, WebRequest request) {
        return handleExceptionInternal(e, e.getErrorCode(), request);
    }

    @ExceptionHandler
    public ResponseEntity&amp;lt;Object&amp;gt; exception(Exception e, WebRequest request) {
        return handleExceptionInternal(e, ErrorCode.INTERNAL_ERROR, request);
    }

    .......................................
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위 함수들은 개념적인 친화도가 매우 높다. 기본 기능이 유사하고 간단하다. 종속적인 관계가 없더라도 가까이 배치할 함수들이다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;5. 세로 순서&lt;/span&gt;&lt;/b&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;호출되는 함수는 호출하는 함수 아래에 배치한다. 그러면 소스 코드 모듈이 고차원에서 저차원으로 자연스럽게 내려간다. &lt;/span&gt;&lt;/b&gt;이건 위에서도 알게 모르게 계속 강조되었던 내용이다.&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;가로 형식 맞추기&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;가로로 한 행은 얼마나 길어야 할까? 책에서 제공하는 통계에 따르면 대부분이 60자 미만으로 유지된다고 한다. 대부분의 프로그래머들은 긴 행보다 짧은 행을 좋아한다. 그렇다면 우리는 짧은 행을 만들기를 노력해야 한다. 사실 글쓴이는 어느 정도 기준을 정해뒀다. 아래 이미지를 살펴보자!&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1851&quot; data-origin-height=&quot;635&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctFsT9/btrNhN7rsKI/hH7ICkxjm4RnG33KM1jse1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctFsT9/btrNhN7rsKI/hH7ICkxjm4RnG33KM1jse1/img.png&quot; data-alt=&quot;내가 생각하는 적당한 가로행의 길이&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctFsT9/btrNhN7rsKI/hH7ICkxjm4RnG33KM1jse1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctFsT9%2FbtrNhN7rsKI%2FhH7ICkxjm4RnG33KM1jse1%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; alt=&quot;가로 행.img&quot; loading=&quot;lazy&quot; width=&quot;1851&quot; height=&quot;635&quot; data-origin-width=&quot;1851&quot; data-origin-height=&quot;635&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;개발할 때에 한쪽에 참고할 코드를 켜 두고 반대쪽에 코드를 작성할 때가 있다. 이때에 한쪽의 코드가 충분히 보일만한 크기가 적당한 가로 행의 길이라고 생각한다. 화면의 크기와 글씨 크기에 따라 좀 더 크게 볼 수 있겠지만 일정 기준을 팀원과 함께 정해놓고 사용한다면 될 것이라고 생각한다.&lt;/span&gt;&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;size18&quot;&gt;&lt;span style=&quot;color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;가로 공백과 밀집도&lt;/span&gt;&lt;/b&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;가로 공백으로는 밀접한 개념과 느슨한 개념을 표현할 수 있다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664366736350&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private void Example(ExamplePage example){
        int exampleTotalCount = example.getTotalCount();
        exampleTotalCount += testNumber;
        exampleTestPage(exampleTotalCount, example.getPageNum());
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;할당 연산자를 강조하기 위해 앞뒤로 공백을 넣어줬다. 할당 문은 왼쪽과 오른쪽에 요소가 분명히 나뉘는데 공백을 넣어줄 시 나뉜다는 사실을 더욱 강조해줄 수 있다. 반면, 함수는 이름과 이어지는 괄호 사이에 공백을 넣지 않았다. 서로 밀접한 개념임을 알려주기 위해서이다. 다만 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;인수는 쉼표 뒤에 공백을 사용하여 별개라는 사실을 강조&lt;/span&gt;해준다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;여기서 재미있는 것은 연산자들에 우선순위를 공백으로 표현해 줄 수도 있다는 것이다. 아래 코드를 살펴보자&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664367192727&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int num = a*b - c*b*7;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;사칙연산의 순위는 곱셈 == 나눗셈 이후 덧 샘 == 뺄셈이다.&amp;nbsp;공백을 이용해 사칙연산의 우선순위를 표현해주었다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;가로 정렬&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;가로 정렬은 변수들의 가로 행 거리를 일정간격으로 맞추는것이다. 글보다는 코드로 살펴보자.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664408114455&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private int      age;
private String   name;
private String   phoneNumber;
private char     gender;
private String[] groups;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;가로정렬은 언뜻 보면 유용한 것 같지만 코드가 엉뚱한 부분을 강조하는 문제가 있다. 변수의 유형보다는 변수명이 먼저 눈에 뜨인다. 결함이 있을 시 엉뚱한 곳이 강조되어 문제를 바로 발견하지 못할 수 있다. 아래와 같은 코드가 더 보기도 좋다. 익숙하지 않아서 그런지는 몰라도 위와 같은 코드는 어색하다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664408417702&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private int age;
private String name;
private String phoneNumber;
private char gender;
private String[] groups;&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;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;들여 쓰기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;들여 쓰기는 정보의 적용범위를 나타낸다.&lt;/span&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;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;들여 쓰기를 무시한 코드&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664409283552&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@ExceptionHandler
public ResponseEntity&amp;lt;Object&amp;gt; general(GeneralException e, WebRequest request) {return handleExceptionInternal(e, e.getErrorCode(), request);}
@ExceptionHandler
public ResponseEntity&amp;lt;Object&amp;gt; exception(Exception e, WebRequest request) {return handleExceptionInternal(e, ErrorCode.INTERNAL_ERROR, request);}
@Override protected ResponseEntity&amp;lt;Object&amp;gt; handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
    return handleExceptionInternal(ex, ErrorCode.valueOf(status), headers, status, request);}
private ResponseEntity&amp;lt;Object&amp;gt; handleExceptionInternal(Exception e, ErrorCode errorCode, WebRequest request) {return handleExceptionInternal(e, errorCode, HttpHeaders.EMPTY, errorCode.getHttpStatus(), request);}
private ResponseEntity&amp;lt;Object&amp;gt; handleExceptionInternal(Exception e, ErrorCode errorCode, HttpHeaders headers, HttpStatus status, WebRequest request) {return super.handleExceptionInternal(
            e, APIErrorResponse.of(false, errorCode.getCode(), errorCode.getMessage(e)), headers, status, request);}}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;들여쓰기 한 코드&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664409307485&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; @ExceptionHandler
    public ResponseEntity&amp;lt;Object&amp;gt; general(
    GeneralException e, WebRequest request
    ) {
        return handleExceptionInternal(e, e.getErrorCode(), request);
    }


    @ExceptionHandler
    public ResponseEntity&amp;lt;Object&amp;gt; exception(
    Exception e, WebRequest request
    ) {
        return handleExceptionInternal(e, ErrorCode.INTERNAL_ERROR, request);
    }

    @Override
    protected ResponseEntity&amp;lt;Object&amp;gt; handleExceptionInternal(
    Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request
    ) {
        return handleExceptionInternal(
        ex, ErrorCode.valueOf(status), headers, status, request
        );
    }

    private ResponseEntity&amp;lt;Object&amp;gt; handleExceptionInternal(
    Exception e, ErrorCode errorCode, WebRequest request
    ) {
        return handleExceptionInternal(
        e, errorCode, HttpHeaders.EMPTY, errorCode.getHttpStatus(), request
        );
    }

    private ResponseEntity&amp;lt;Object&amp;gt; handleExceptionInternal(
    Exception e, ErrorCode errorCode, HttpHeaders headers, HttpStatus status, WebRequest request
    ) {
        return super.handleExceptionInternal(
                e,
                APIErrorResponse.of(false, errorCode.getCode(), errorCode.getMessage(e)),
                headers,
                status,
                request
        );
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위, 아래 두 개의 코드다 같은 동일한 코드이다. 차이는 들여 쓰기의 유무이다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;가끔씩 if문 또는 while문에 들여 쓰기를 무시하고싶은 때가 있다. 한줄로 처리할 수 있기 때문이다. 그러나 이미 우리는 들여쓰기를 규칙으로 사용하고있기에 들여쓰기를 통해 해당 함수의 범위를 확실하게 표현해주자. 글쓴이만 그런지는 모르겠지만 가끔 들여 쓰기가 무시된 if, while문을 보면 눈에 잘 안 들어와 별생각 없이 지나치게 될 때가 있다. 아래처럼 괄호가 없는 것도 아주 드물게 보인다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1664409657342&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (isBooleanTestMethod()) test = true;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1664409683685&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (isBooleanTestMethod()){
	test = true;
}&lt;/code&gt;&lt;/pre&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;팀 규칙&lt;/span&gt;&lt;/b&gt;&lt;/h2&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;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;각자가 속한 팀마다 코드를 작성해 나가는 방법이 다를 것이다. 자신이 만약 팀에 속한다면 따라야 할 규칙은 팀 규칙이다. 모든 팀원들이 해당 팀의 규칙을 따라야 하고, 그래야만 소프트웨어가 일관적인 스타일을 보이게 된다. 좋은 소프트웨어 시스템은 읽기 쉬운 문서로 이뤄진다. 스타일은 일관적이고 매끄러워야 한다. 일관적임으로 독자에게 신뢰감을 줄 수 있는 코드를 작성하자.&lt;/b&gt;&lt;/span&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;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리&lt;/span&gt;&lt;/b&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;코드 스타일에 있어 팀 규칙이 가장 중요하다고 생각된다. 모두가 일관된 코드 스타일을 유지함으로써 코드를 좀 더 읽기 쉽게 해 준다. 상수나 변수 그리고 클래스 파일들이 당연히 있을 것이라고 여겨지는 위치에 항상 존재한다. 앞서 말했던 규칙들은 모두 좋은 형식을 맞출 수 있는 규칙들이지만 개인적으로는 팀 규칙이 가장 위에 있으리라고 생각된다. 로마에 가면 로마 법을 따르듯이 팀에 속한다면 팀의 규칙을 따르는 건 당연한 것이다. 팀의 규칙에 불만이 있을 수도 있다. 더 좋은 방법이 있을수도 있다. 그렇다면 팀원들과 적극적으로 소통해 자신의 의견을 나누고 의논해보자. 마무리가 길었지만 결론은 일관성 있고, 좋은 코드 스타일을 갖추도록 노력하자.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/Read Book</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/27</guid>
      <comments>https://doosicee.tistory.com/entry/CleanCode-5%EC%9E%A5-%ED%98%95%EC%8B%9D-%EB%A7%9E%EC%B6%94%EA%B8%B0#entry27comment</comments>
      <pubDate>Sat, 24 Sep 2022 11:18:01 +0900</pubDate>
    </item>
    <item>
      <title>CleanCode 4장 주석</title>
      <link>https://doosicee.tistory.com/entry/CleanCode-4%EC%9E%A5-%EC%A3%BC%EC%84%9D</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SPP7i/btrMxEiuJeY/tkbpXirWgF6lO1X44wD7ZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SPP7i/btrMxEiuJeY/tkbpXirWgF6lO1X44wD7ZK/img.png&quot; data-alt=&quot;출처: 인사이트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SPP7i/btrMxEiuJeY/tkbpXirWgF6lO1X44wD7ZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSPP7i%2FbtrMxEiuJeY%2FtkbpXirWgF6lO1X44wD7ZK%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;350&quot; height=&quot;467&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: 인사이트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;주석&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;주석은 나쁜 코드를 보완하지 못한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;코드로 의도를&amp;nbsp; 표현하라&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;좋은 주석&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;나쁜 주석&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&quot;나쁜 코드에 주석을 달지 마라. 새로 짜라.&quot;&amp;nbsp; -브라이언 w. 커니핸, P.J 플라우거&lt;br /&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;잘 달린 주석은 그 어떤 정보보다 유용하다. 그러나 우리에게 프로그래밍 언어를 치밀하게 사용해 의도를 표현할 능력이 있다면 주석은 필요 없다. 그러나 코드로 모든 의도를 표현하지 못해 때때로 주석을 사용하게 된다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;코드에 모든 생각을 담지 못한다면 그것은 자신에게 표현력이 부족하다는 것이다.&lt;/span&gt; 모든 진실은 코드에 담겨있다. 그렇기에 주석은 반가운 손님이 아니다.&lt;/span&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;주석은 나쁜 코드를 보완하지 못한다&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;코드에 주석을 추가하는 이유는 코드만으로 모든 것을 말하지 못하기 때문이다. 표현력이 풍부하고 깔끔하며 주석이 거의 없는 코드가, 주석이 많이 달린 어수선하고 복잡한 코드보다 훨씬 좋다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;더럽혀진 방이 왜 더럽혀져 있는지 설명할 시간에 깨끗이 치우는데 시간을 보내길 권장한다.&lt;/span&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;코드로 의도를 표현하라!&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;pre id=&quot;code_1663571510052&quot; class=&quot;erlang&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 직원에게 복지 혜택을 받을 자격이 있는지 검사한다.
if ((employee.flags &amp;amp; HOURLY_FLAG) &amp;amp;&amp;amp;
	(employee.age &amp;gt; 65))
    

if (employee.isEligibleForFullBenefits())&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;분명 코드만으로 의도를 설명하기 어려운 경우가 존재한다. 하지만 위의 코드처럼 대다수의 경우는 몇 초의 시간만 투자한다면 코드로 의도를 표현할 수 있다. 주석으로 달려는 설명을 함수로 만들어 표현해도 충분하다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;좋은 주석&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;주석이 분명 필요할 때가 있다. 글자 값을 한다고 생각하는 주석 몇 가지를 알아보자. 그러나 잊지 않길 바란다. 가장 좋은 주석은 주석을 달지 않을 방법을 찾아낸 주석이다.&lt;/span&gt;&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: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;법적인 주석&lt;/span&gt;&lt;/b&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;회사에서 정립한 구현 표준에 맞춰 법적인 이유로 특정 주석을 넣으라고 할 때.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&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: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;정보를 제공하는 주석&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663628606742&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 4~32자의 비밀번호는 4개 중 3개 이상 필요합니다(대문자
// 및 소문자, 숫자 및 특수 문자) 및 최대
// 2개의 동일한 연속 문자.
private static final String PASSWORD_REGEX = ^(?:(?=.*\d)(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[^A-Za-z0-9]) + 
    (?=.*[a-z])|(?=.*[^A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[A-Z]) + 
    (?=.*[^A-Za-z0-9]))(?!.*(.)\1{2,})[A-Za-z0-9!~&amp;lt;&amp;gt;,;:_=?*+#.&amp;rdquo;&amp;amp;&amp;sect;%&amp;deg;()\|\[\]\-\$\^\@\/] +
    {8,32}$

Pattern passwordRegex = Pattern.compike(PASSWORD_REGEX);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;비밀번호를 만들 때에 필요한 조건 정보가 담긴 주석이다. 정규식을 하나하나 직접 알아내려면 꽤나 복잡할 것이다. 이런 때에 주석은 유용하다.&lt;/span&gt;&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: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;의미를 명료하게 밝히는 주석&lt;/span&gt;&lt;/b&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;일반적으로 인수나 반환 값 자체를 명확하게 만들면 좋겠지만, 인수나 반환 값이 표준 라이브러리나 변경하지 못하는 코드라면 의미를 명료하게 밝히는 주석이 유용하다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663630078626&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void testCompareTo() throw Exception{
    ......
    
    assertTrue(a.compareTo(a) == 0); // a == a
    assertTrue(a.compareTo(b) != 0); // a != b
    assertTrue(aba.compareTo(ab) == 0); // ab == ab
    assertTrue(a.compareTo(b) == -1); // a &amp;lt; a
    assertTrue(aa.compareTo(ab) == -1); // aa &amp;lt; ab
    assertTrue(ba.compareTo(bb) == -1); // ba &amp;lt; bb
    assertTrue(b.compareTo(a) == 1); // b &amp;gt; a
    assertTrue(ab.compareTo(aa) == 1); // ab &amp;gt; aa
    assertTrue(bb.compareTo(ba) == 1); // bb &amp;gt; ba
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;compareTo()에서 문자열을 비교할 때 기준값과 비교대상이 동일한 경우(0), 기준값이 비교대상보다 작을 경우(-1), 기준값이 비교대상보다 클 경우(1)를 반환한다. 이 부분에 대해 명료하게 알 수 없기에 주석을 사용하여 의미를 명료하게 밝힐 수 있다. 그러나 가장 최선인 주석을 달지 않고 해결할 더 나은 방법이 있는지 생각해보고 주석을 달도록 주의하자.&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;background-color: #dddddd; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;결과를 경고하는 주석&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;때로는 다른 프로그래머에게 결과를 경고해야 할 때가 있다. 특정 테스트 케이스가 돌아가는데 시간이 오래 걸린다면 해당 테스트 케이스를 꺼야 할 것을 권장한다.&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: #000000; background-color: #dddddd; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;TODO주석&lt;/b&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; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;TODO주석은 '앞으로 할 일'을 의미한다. 필요하다고 여기지만 당장 구현하기 어려운 업무들을 적어둔다. 누군가에게 문제를 봐달라고 요청할 때, 당장 좋은 이름이 떠오르지 않아 더 좋은 이름을 떠올려 달라 할 때, 앞으로 발생할 수정사항에 맞춰 코드를 고치라는 주의 사항을 남길 때에 유용하다. 그렇다고 TODO코드를 떡칠해서는 안된다. 해결할 수 있는 건 당장 해결하고 주기적으로 TODO 주석을 점검하여 없애도 괜찮은 것은 없애는 것이 좋다.&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;background-color: #dddddd; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;중요성을 강조하는 주석&lt;/b&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; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;대수롭게 여길만한 코드에 중요성을 강조하기 위해서도 주석을 사용할 수 있다. 예를 들어 공백 제거에 대한 부분이다. 문자열의 시작 부분에 공백이 있으면 다른 문자열로 인식된다던지 하는 부분이다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;나쁜 주석&lt;/span&gt;&lt;/b&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대다수의 주석들은 나쁜 주석에 속할 가능성이 높다. 허술한 코드를 지탱하거나, 엉성한 코드를 변명하거나, 미숙한 결정에 대해 합리화하는 독백에서 크게 벗어나지 못한다.&lt;/span&gt;&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: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;주절거리는 주석&lt;/span&gt;&lt;/b&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;독자에게 정확한 정보전달을 하지 못하는 주석이다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;주석이 달려있음에도 불구하고 아무런 도움이 되지 못해 답을 알기 위해 다른 코드를 뒤져봐야 한다.&lt;/span&gt; 이런 주석은 바이트만 낭비하는 쓰레기일 뿐이다. 주석을 달기로 결정했다면 충분한 시간을 들여 최고의 주석을 달아줘야 한다.&amp;nbsp;&lt;/span&gt;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;같은 이야기를 중복하는 주석&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663660284678&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// orgName에 값이 비어있다면 전부 조회, 값이 있다면 orgName에 담긴 값을 포함한 orgName을 대소문자를 무시하고 조회해온다.
if(orgName.isEmpty()){
    resultList = cmsFileRepository.findAll(pageable);
}else{
    resultList = cmsFileRepository.findByOrgNameContainingIgnoreCase(orgName, pageable);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;주석에 달린 내용이 코드의 내용을 그대로 중복한다. 이러한 코드는 주석을 읽는 시간이 코드를 읽는 시간보다 더 오래 걸릴 수 있다. 위의 주석은 &lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;코드보다 읽기 쉽지도 않으며,&lt;/span&gt;&lt;/b&gt;&amp;nbsp;주석이 코드보다 더 많은 내용을 제공하지도 못하고 있다. 이러한 주석은 코드보다 부정확해 독자가 코드를 대충 이해하고 넘어가게 만들 수가 있다.&lt;/span&gt;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;의무적으로 다는 주석&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;함수를 만들 때에 Javadocs를 달거나 모든 변수에 주석을 의무적으로 달아야 한다는 규칙은 좋지 않다. 코드와 주석이 같은 이야기를 하는 괴물 같은 주석이 계속 탄생할지도 모른다. 이러한 주석은 코드만 헷갈리게 하고, 의무적으로 다는 주석에 잘못된 정보를 기술할 가능성만 생긴다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;이력을 기록하는 주석&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663663018944&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;20-05-26: ........를 추가..
20-07-07: ........를 변경...
20-09-03: ........를 수정..
20-12-25: ........를 추가...
21-03-14: ..........
21-11-26: ...........
22-03-25: ............
22-05-13: ...........&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예전에는 이러한 방식으로 모듈을 편집할 때마다 모듈 첫머리에 변경 이력을 기록하고 관리하는 관례가 바람직했다고 한다. 그러나 지금은 소스 관리 시스템이 아주 잘되어있으므로 이러한 이력들은 혼란만 가중시킬 뿐이다. 제거하는 것이 좋다.&lt;/span&gt;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;있으나 마나 한 주석&lt;/b&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;주절거리는 주석과 같은 말이다. 코드를 짜다가 뭔가가 잘 안 됐을 때에 주석으로 분풀이를 했다는 생각이 드는 주석들이다. 예를 들어 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;// 왜 이렇게 더러워!라는&lt;/span&gt; 식의 정말 쓸데없는 주석을 말한다. 그냥 대화할 사람이 없어서 주석이랑 대화라도 했다는 느낌이다.&lt;/span&gt;&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;background-color: #dddddd; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;함수나 변수로 표현할 수 있다면 주석을 달지 마라&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663714670344&quot; class=&quot;reasonml&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 전역 목록 &amp;lt;smodule&amp;gt;에 속하는 모듈이 우리가 속한 하위 시스템에 있는가?
if(smodule.getDependSubsystems().contains(subSysMod.getSubSystem()))


ArrayList moduleDependees = smodule.getDependSubsystems();
String ourSubSystem = subSysMod.getSubSystem();
if (moduleDependees.contains(ourSubSystem))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 부분은 글쓴이도 이제까지 실수하고 있었던 부분이다. 코드를 한 줄로 작성하기 위해 변수에 굳이 담지 않고 작성했었다. 그러나 CleanCode를 읽으며 변수에 담거나 함수로 작성함으로써 의미를 표현할 수 있고, 표현해주는 것이 중요하다는 것을 깨닫는다. 물론 변수에 담지 않아도, 함수로 만들지 않아도 충분히 의미가 표현된다면 굳이 담을 필요는 없다. 중요한 것은 전달력이라고 생각한다.&lt;/span&gt;&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: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위치를 표현하는 주석&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663715187104&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;============= Action =========================================
......
............
.............&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;아마 다들 한 번씩 작성해봤거나, 본적이 있을수도 있다고 생각된다. 글쓴이는 frontend작업을 할때에 드물지만 한번씩 썼던 것 같다. 배너 아래 특정 기능들을 모아 두는 것이다. 너무 자주 사용하지만 않는다면 이러한 배너는 눈에 띄며 주의를 환기해준다. 정말 주의할 것은 너무 무분별하게 너무 자주 사용하지 말라는 것이다. 코드를 읽는 사람이 익숙해진다면 흔한 잡음으로 여기게 될 수 있다.&lt;/span&gt;&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: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;닫는 괄호에 다는 주석&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663716715486&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;try {
	for (){
    	while() {
        
    	}// while
    } // for
} // try
catch (... e){

}// catch&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;예전에 학원에 다닐 때, 그리고 백준 코테를 풀 때에 이러한 주석을 많이 사용했었다. 닫는 괄호에 주석을 작성해 해당 반복문들이 어디서 닫히는지 확인하는 용도로 사용했었다. 이러한 닫는 괄호는 중첩이 심하고 장황한 함수라면 의미가 있겠지만 우리가 추구해야 하는 함수에게는 필요하지 않으므로 닫는 괄호에 주석을 달아야겠다는 생각이 드는 함수라면 함수를 줄이려 시도해보자.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;공로를 돌리거나 저자를 표시하는 주석&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663888069011&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* 글쓴이가 작업 */&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;누가 작업을 했는지 보고 찾아가서 물어보는 데에는 유용할 수 있다. 그러나 &lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;소스 관리 시스템이 누가 언제 무엇을 수정했는지 전부 기억하기 때문에 굳이 주석을 달아줄 필요가 없다.&amp;nbsp;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;주석으로 처리한 코드&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;글쓴이도 이 책을 읽기 전에는 자주 했던 행동이다. 뭔가 기능을 만들어놓고 요구사항이 바뀌었을 때 아직 커밋 전이라면 주석으로 기존에 코드를 남겨뒀었다. 그러나 이러한 코드는 시간이 지나면 쓰레기가 되고 다른 누군가는 중요하기에 남겨둔 코드라 생각해 계속 지우지 않고 남겨둘 가능성이 있다. 나중에 다시 쓸 것만 같은 코드라면 한번 커밋을 해둬 기록을 남기는 것도 좋은 방법인 것 같다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;HTML 주석&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;주석에 HTML 문법을 남겨두는 것인데 아직 한 번도 HTML 주석을 본적이 없다. 사용하지 않도록 주의하자. 혐오 그 자체라고 표현할 정도다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;전역 정보&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663890115025&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
* 적합성 테스트가 동작하는 포트: 기본값 8082
*/
public void set........&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;주석을 달아야 한다면 근처에 있는 코드에 대해서만 기술하는 게 좋다. 또한 시스템 전반적인 정보를 기술하는 건 좋지 않다. 예를 들어 함수가 동작하는 포트를 주석으로 달아 놓았을 때다. 해당 함수는 포트를 통제하지 못한다. &lt;b&gt;시스템 어딘가에 있는 포트를 제어하는 다른 함수를 설명하는 일이 될 뿐이다. 또한 포트 기본값을 설정하는 코드가 변하면 주석도 함께 변한다는 보장이 없다.&lt;/b&gt;&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;background-color: #dddddd; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;너무 많은 정보&lt;/span&gt;&lt;/b&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;주석에는 너무 많은 정보를 알려줄 필요는 없다. 해당 알고리즘이 시작된 역사부터 어떤 게 어떻게 더해지고, 변하고, 인코딩 되고, 정렬되는지 하나하나 전부 늘어놓는 정보는 불필요하다.&lt;/span&gt;&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;background-color: #dddddd; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모호한 관계&lt;/span&gt;&lt;/b&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;주석을 달았다면 독자가 주석과 코드를 보고 무엇을 말하는지 확실히 알 수 있어야 한다. 인수가 두 개라면 첫 번째로 무엇이 들어갈지, 두 번째에 무엇이 들어갈지 무언가를 더해야 한다면 그것이 첫 번째 인수인지, 두 번째 인수인지 설명을 정확히 해야 한다. 이러한 주석은 역시나 코드만으로 다 설명하는 능력이 부족해서다.&lt;/span&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리&lt;/span&gt;&lt;/b&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;제4장 주석을 읽으며 느낀 점은 주석을 달지 않아도 함수나 변수의 이름으로 생각보다 잘 설명할 수 있다는 것이었다. 그간 함수와 변수명을 짓는 내 노력이 부족했음을 깨닫는다. 주석은 나쁜 코드를 보완하지 못한다는 말이 와닿는다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;주석이 달려있어도 누군가가 수정하려면 코드를 읽어야 하는데 코드 자체가 나쁘다면 주석이 별 도움이 되지 않기 때문이다&lt;/span&gt;. 클린 코드를 읽다 보면 반성할 일과 깨닫는 것이 참 많은 것 같다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/Read Book</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/26</guid>
      <comments>https://doosicee.tistory.com/entry/CleanCode-4%EC%9E%A5-%EC%A3%BC%EC%84%9D#entry26comment</comments>
      <pubDate>Mon, 19 Sep 2022 16:13:32 +0900</pubDate>
    </item>
    <item>
      <title>CleanCode 3장 함수</title>
      <link>https://doosicee.tistory.com/entry/CleanCode-3%EC%9E%A5-%ED%95%A8%EC%88%98</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpjOn4/btrL5RPNmSO/CmlTipnWPng1loWOibMmC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpjOn4/btrL5RPNmSO/CmlTipnWPng1loWOibMmC0/img.png&quot; data-alt=&quot;출처: 인사이트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpjOn4/btrL5RPNmSO/CmlTipnWPng1loWOibMmC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpjOn4%2FbtrL5RPNmSO%2FCmlTipnWPng1loWOibMmC0%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; alt=&quot;클린코드.img&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;467&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: 인사이트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;함수&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;현재 프로그램의 가장 기본적인 단위는 함수이다. 함수를 잘 만드는 방법 몇가지에 대해서 정리해보자.&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;한 가지의 일만 해라&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;함수 당 추상화 수준은 하나로&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;함수 인수의 개수&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;부수효과를 일으키지 마라&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;반복하지 마라&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;명령과 조회를 분리하라&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;오류 코드보다 예외를 사용하라&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;반복하지 마라&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;함수는&amp;nbsp; 어떻게 짜야하는가 및 결론&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;들어가기 전 함수를 왜 사용하는지 알아보자.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;1.반복적인 프로그래밍을 피하기위해 즉, 코드의 재사용성을 높이기 위해서&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;2.큰 개념을(함수) 다음 추상화 수준에서 여러 단계로 나눠 수행하기 위해서 (by CleanCode)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;코드의 재사용성을 높이기 위해서라는건 모두 알고있는 사실일것이다. 그러나 '&lt;span style=&quot;background-color: #dddddd;&quot;&gt;큰 개념을 다음 추상화 수준에서 여러 단계로 나눠 수행하기 위해서&lt;/span&gt;' 라는 말은 처음들어보는 사람들도 있을것이라고 생각된다. 이 말이 무엇을 말하는 것인지는 아래의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;한 가지의 일만 해라&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;를 보면 알수있다.&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;한 가지의 일만 해라&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;함수는 한 가지를 해야 한다. 그 한가지를 잘 해야 한다. 그 한 가지만을 해야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;함수는 한 가지를 해야하며, 그 한가지를 잘 해야한다는데 여기서 '한 가지'란&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;하나의 개념(함수) 아래 같은 추상화 수준&lt;/span&gt;을 말하는 것이다. 아래 그림을 참고해보자.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1803&quot; data-origin-height=&quot;1031&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kHxRE/btrL4a3EEFH/liarPSpxjmd2ZV0D2tWaXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kHxRE/btrL4a3EEFH/liarPSpxjmd2ZV0D2tWaXk/img.png&quot; data-alt=&quot;추상화 수준&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kHxRE/btrL4a3EEFH/liarPSpxjmd2ZV0D2tWaXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkHxRE%2FbtrL4a3EEFH%2FliarPSpxjmd2ZV0D2tWaXk%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;450&quot; height=&quot;257&quot; data-origin-width=&quot;1803&quot; data-origin-height=&quot;1031&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;같은 추상화 수준이란 큰 개념(함수)을 분해하여 기능 A, B, C 를 만들고, 기능들이 단계별로 수행되는것을&amp;nbsp;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;하나의 개념&lt;b&gt;(함수)&amp;nbsp;&lt;/b&gt;아래 같은 추상화 수준&lt;/span&gt;&amp;nbsp;이라 한다. 코드를 통해 한번 더 살펴보자.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;HtmlUtil.java (출처:클린코드)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663118744248&quot; class=&quot;haxe&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static String renderPageWithSetupsAndTeardowns(
        PageData pageData, boolean isSuite
    )throws Exception{
        boolean isTestPage = pageData.hasAttribute(&quot;Test&quot;);
        if (isTestPage){
           WikiPage testPage = pageData.getWikiPage();
           StringBuffer newPageContent = new StringBuffer();
           includeSetupPages(testPage, newPageContent, isSuite);
           newPageContent.append(pageData.getContent());
           includeTeardownPages(testPage, newPageContent, isSuite);
           pageData.setContent(newPageContent.toString());
        }
        return pageData.getHtml();
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;renderPageWithSetupsAndTeardowns() 함수는 다음과 같은 일을하고있다. testPage인지 확인하고, WikiPage를 가져오고 버퍼를 생성하는 등... 여러 일들을 하는게 보인다.&amp;nbsp;&lt;b&gt;하나의 개념아래 같은 추상화 수준을 잘 지키고 있는것일까? 위의 코드는 두 개의 추상화 수준을 가지고 있기 때문에 아래와 같이 한번 더 코드를 줄일 수 있다.&lt;/b&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;HtmlUtil.java (출처:클린코드)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663118744248&quot; class=&quot;haxe&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static String renderPageWithSetupsAndTeardowns(
            PageData pageData, boolean isSuite
    )throws Exception{
        if (isTestPage(pageData)){
            pageData = includeSetupAndTeardownPages(pageData, isSuite);
            return pageData.getHtml();
        }
    }

    private static Boolean isTestPage(pageData){
        return pageData.hasAttribute(&quot;Test&quot;);
    }

    private static PageData includeSetupAndTeardownPages(PageData pageData, boolean isSuite){
        WikiPage testPage = pageData.getWikiPage();
        StringBuffer newPageContent = new StringBuffer();
        includeSetupPages(testPage, newPageContent, isSuite);
        newPageContent.append(pageData.getContent());
        includeTeardownPages(testPage, newPageContent, isSuite);
        pageData.setContent(newPageContent.toString());
        
        return pageData;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;이제 더 이상 의미를 유지하면서 renderPageWithSetupsAndTeardowns() 함수를 줄일수는 없다. isTestPage(), includeSetupAndTeardownPages() 두 함수를 묶어 하나의 함수를 더 만들수는 있지만 똑같은 내용을 다르게 표현할 뿐 추상화 수준은 바뀌지 않는다. 위의 코드를 그림으로 살펴본다면 다음과 같은 모습일 것이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;555&quot; data-origin-height=&quot;270&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oRkFU/btrL34bmHXw/KrArjInlakOedizlRRqsZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oRkFU/btrL34bmHXw/KrArjInlakOedizlRRqsZ0/img.png&quot; data-alt=&quot;추상화 수준&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oRkFU/btrL34bmHXw/KrArjInlakOedizlRRqsZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoRkFU%2FbtrL34bmHXw%2FKrArjInlakOedizlRRqsZ0%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;450&quot; height=&quot;219&quot; data-origin-width=&quot;555&quot; data-origin-height=&quot;270&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;함수가 '한 가지' 일만 하는지 판단하는 방법을 알아보자. 함수가 '한 가지'만 하는지 판단하는 방법은 두가지가 있다.&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;단순히 다른 표현이 아니라&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;의미 있는 이름으로 다른 함수를 추출할 수 있다면&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;더 이상 나누면 의미가 없을것 같다고 판단될때&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;함수 당 추상화 수준은 하나로!&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;함수가 '한 가지' 작업을 확실히 하려면 함수 내 모든 문장의 추상화 수준이 동일해야 한다. 추상화 수준이란&amp;nbsp;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;해당 코드를 읽으며 파악할 수 있는 정보의 수준&lt;/span&gt;을 말한다. 자세한 설명을 위해 코드를 살펴보자.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663118764272&quot; class=&quot;haxe&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static String renderPageWithSetupsAndTeardowns(
            PageData pageData, boolean isSuite
    )throws Exception{
        if (isTestPage(pageData)){
            pageData = includeSetupAndTeardownPages(pageData, isSuite);
            return pageData.getHtml();
        }
    }

    private static Boolean isTestPage(pageData){
        return pageData.hasAttribute(&quot;Test&quot;);
    }

    private static PageData includeSetupAndTeardownPages(PageData pageData, boolean isSuite){
        WikiPage testPage = pageData.getWikiPage();
        StringBuffer newPageContent = new StringBuffer();
        includeSetupPages(testPage, newPageContent, isSuite);
        newPageContent.append(pageData.getContent());
        includeTeardownPages(testPage, newPageContent, isSuite);
        pageData.setContent(newPageContent.toString());
        
        return pageData;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;높은 추상화 수준&lt;/span&gt;:&amp;nbsp; isTestPage(), includeSetupAndTeardownPages()는 추상화 수준이 높다. 이름을 통해 무슨 역할을 하는지는 알겠지만 내부에서 어떠한 코드를 통해 어떠한 일이 이루어지는지를 알 수 없기 때문이다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;중간 추상화 수준&lt;/span&gt;: isTestPage 내부의 pageData.hasAttribute(&quot;Test&quot;) 는 추상화 수준이 중간이다. pageData객체에 hasAttribute 함수를 통해 해당 &quot;Test&quot; Attribute 가 있는지 없는지 판단이 가능하기 때문이다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;낮은 추상화 수준&lt;/span&gt;: .append(pageData.getContent()) 는 추상화 수준이 낮다. 바로 어떤 의미인지 유추할 수 있기 때문이다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;함수 인수의 개수&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;함수에서 이상적인 인수 개수는 0개이다. 그다음으로는 1개(단항), 2개(이항), 3개(삼항) 이고, 4개(다항) 이상은 특별한 이유가 있더라도 사용하지 않아야한다. 코드를 읽는 사람은 어떠한 인수가 넘어가는지 전부 알아야 하기 때문에&amp;nbsp;&lt;b&gt;인수가 늘어날수록 함수를 이해하는것이 어렵기 때문이다.&lt;/b&gt;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;단항 형식&lt;/span&gt;&lt;b&gt;&lt;b&gt;:&amp;nbsp;단항 형식&lt;/b&gt;&lt;/b&gt;을 사용하는 이유는 보통 두 가지다. 인수에 질문을 던지는 경우 boolean fileExists(&quot;MyFile&quot;), 인수를 뭔가로 변환해 반환하는 경우 InputStream fileOpen(&quot;MyFile&quot;) 가 있다. 이 두가지의 경우는 코드를 읽는 사람이 당연하게 받아들인다. 가장 좋은 단항 형식의 사용법이다.&lt;/b&gt;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;이벤트 함수&lt;/span&gt;&lt;b&gt;&lt;b&gt;:&amp;nbsp;이벤트 함수&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;는 드물지만 아주 유용한 함수이다. 이벤트 함수는 입력 인수만 있고 출력 인수는 없다. 이벤트 함수를 호출하면 인수로 무언가의 상태가 바뀐다. 그렇기에 코드와 이름을 통해 이벤트라는 사실이 명확히 들어나야 한다.&lt;/b&gt;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;단항 함수를 가급적 피해야 하는 경우&lt;/span&gt;&lt;b&gt;&lt;b&gt;:&amp;nbsp;&lt;/b&gt;&lt;/b&gt; 바로 출력 인수(반환값이 없는 함수의 인수)이다. 함수는 인수를 입력받으면 조회와 변환 두가지 목적으로 처리된다. 함수의 통념상 x를 받았으면 y를 반환해야하는데 반환값이 없다면....? 인수는 받아놓고 이걸 어떻게 변환한다는건지 알 수 없기 때문이다. 출력 인수는 해당 객체안에 함수를 만들어 출력 인수를 만들지 않는 방식을 사용해야한다. (&lt;span style=&quot;background-color: #dddddd;&quot;&gt;출력인수에 대한 내용은 아래에 좀더 자세히 나온다.)&lt;/span&gt;&lt;/b&gt;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;플래그 인수&lt;/span&gt;: 플래그 인수란&amp;nbsp;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;호출되는 함수가 실행할 로직을 호출하는 쪽에서 선택하기 위해 전달하는 인수&lt;/span&gt;라고 한다. CleanCode 에서는 플래그 인수는 아주 끔찍한 인수라고 한다. boolean 값을 넘김으로써 true, false 일때에 따라 여러가지의 일을 처리한다는 것을 의미하기 때문이다. 다음 코드를 통해 살펴보자.&lt;/span&gt;&lt;/b&gt;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;이항 함수&lt;/span&gt;:&amp;nbsp;이항 함수는 인수가 2개인 함수로써 인수가 1개인 함수보다 이해하기 어렵다. Point p = new Point(0, 0) 이 가장 좋은 예이며, 다음과 같이 자연적인 순서로 표현되는 경우 외에는 사용을 지양하는것이 좋다.&lt;/span&gt;&lt;/b&gt;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;삼항 함수 및 다항 함수&lt;/span&gt;&lt;b&gt;&lt;b&gt;:&amp;nbsp;인수가 3개를 넘어간다면&lt;/b&gt;&lt;/b&gt;&amp;nbsp;왠만해서는 사용하지 말자. 정말 이해하기 어렵게 만들기 때문이다. 사용하게 된다면 정말 신중히 고려해서 사용하자. 삼항 함수를 대처할 방법은&amp;nbsp;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;인수 객체&lt;/span&gt;를 사용하는 방법이 있다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;인수 객체&lt;/span&gt;&lt;b&gt;&lt;b&gt;:&amp;nbsp;&lt;/b&gt;&lt;/b&gt;&amp;nbsp;2~3개 이상의 인수가 필요할때에 일부를 독자적인 클래스 변수로 선언하여야 할 가능성을 짚어보자. 예를들어 다음 코드를 살펴보자.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663118764275&quot; class=&quot;reasonml&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Circle makeCircle(double x, double y, double radius);
Circle makeCircle(Point center, double radius);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;첫 번째 makeCircle()은 x와y를 각각의 인수로 받지만, 두 번째 makeCircle()은 x와 y 속성을 가진 Point 객체로 인수를 받는다. 객체를 통해 인수를 줄이는 방법이 눈속임처럼 보일 수 있지만 변수를 묶어 넘기려면 이름을 붙여야 하므로 결국은 개념을 표현하게 된다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;인수 목록&lt;/span&gt;: 때로는 인수가 가변적인 함수도 필요하다. String.format 메서드와 같이 말이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663118764276&quot; class=&quot;lasso&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public String format(String format, Object... args)

String.format(&quot;%S worked %.2f hours.&quot;, name, hours);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;String.format의 선언부를 보면 알수있듯 String.format은 이항 함수이다. 여러개의 인수를 넣을수 있으나 가변인수를 전부 동등하게 취급하기에 List형 인수 하나로 취급할 수 있다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;동사와 키워드&lt;/span&gt;: 좋은 함수 이름을 만들때는 함수와 인수가 동사/명사 쌍을 이루는것이 좋다. 예를들어 write(name)같은 경우이다. name(이름)을 write(쓴다) 라고 명확히 드러난다. 더 좋은 방법은 wirteField(name)이다. 이렇게 쓴다면 name이 Field라는 사실이 분명하게 드러나기 때문이다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;부수효과를 일으키지 마라&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;부수효과란 함수의 이름에 명시된 '한 가지' 일 외에 다른 일을 하는것이다. 만약 부수효과가 필요하다면 함수 이름에 분명히 명시해야한다. 함수에 적힌 이름만을 믿고 사용했는데 알지못하는 부수효과가 일어난다면.... 꽤나 애먹을 것이다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;출력인수&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;출력인수란 함수에서 결과를 돌려받는 인수를 말한다. 아래 예제들을 통해 자세히 알아보자.&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: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;출력인수&amp;nbsp;&lt;b&gt;(함수에서 결과를 돌려받는 인수, 입력의 상태가 변경되는것)&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663118764276&quot; class=&quot;cpp&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    // x = 1
private void example(int x){
    // x + 1
    sumOne(x);
    
    // return 2
    return x; 
}

private void sumOne(int x){
	x = x + 1;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;입력인수 (일반적인 의미의 인수, 함수에게 전달해주는 인수)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663118764277&quot; class=&quot;cpp&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    // x = 1
private void example(int x){
    // x + 1
    int y = sumOne(x);
    
    // return 2
    return y; 
}

private int sumOne(int x){
    int y =  x + 1;
    return y;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;✔&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;출력인수(함수에서 결과를 돌려 받는 인수)&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;sumOne(x) 함수를 호출할때 1의 값을 가진 x라는 인자를 전달하였다. 함수 내부에서는 x + 1 이라는 작업이 이루어지고 결과값을 입력인수로 받은 x에게 다시 넣어주었다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;x -&amp;gt; f -&amp;gt; x&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라는 부자연스러운 함수처리 과정을 보여준다.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;✔&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;입력인수(일반적인 의미의 인수)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;sumOne(x) 함수를 호출할때 1의 값을 가진 x라는 인자를 전달하였다. 이때 x를 입력인수라 한다. 함수 내부에서는 x + 1 이라는 작업이 이루어지고 y라는 결과물을 반환해준다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;x -&amp;gt; f -&amp;gt; y&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;로 자연스러운 함수의 처리과정이다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;우리가 기대하는 일반적인 함수라면&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;x -&amp;gt; f -&amp;gt; y&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라는 결과를 기대한다. 그러나 출력인수는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;x-&amp;gt; f -&amp;gt; x&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라는 결과물을 도출한다.&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;일반적으로 우리는 인수를 함수 입력으로 해석하기에 출력인수에 혼란함을 느낄것이다. 출력인수임을 알기위해서는 해당 함수의 선언부를 찾아봐야하며, 이러한 행위는 인지적으로 거슬린다는 것이므로 지양하는것이 좋다.&lt;/b&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;명령과 조회를 분리하라!&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;함수는 뭔가를 수행하거나 답하거나 둘 중 하나의 일만 해야한다. 객체의 상태를 변경하거나 정보를 반환하거나. 만약 둘 다 한다면 혼란을 가져온다. 코드를 통해 살펴보자.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663307461035&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public boolean set(Stirng attribute, String value);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위의 함수는 attribute인수로 들어온 속성값을 찾아 값을 value로 설정 후 boolean 타입으로 반환해준다. 이 함수를 실재로 사용하면 혼돈을 초래한다. 다음 코드를 통해 어떤지 살펴보자&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663307654422&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (set(&quot;username&quot;, &quot;Alice&quot;))...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;위와같은 코드를 읽은 사람은 무슨생각을 할까? userName을 Alice로 설정하는 코드일까? 아니면 userName이 Alice인지 확인하는 코드일까? 함수를 호출하는 코드만으로는 혼란이 올것이다. 일반적으로 프로그래머들은 if문 안에 들어간 저 함수를 이렇게 해석할것이다. &quot;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;username이 Alice라면? true. 아니라면 false&lt;/span&gt;&quot; 라고. 함수의 이름을 바꾸면 해결될까? 함수의 이름을 set이 아닌setAndCheckIfExists라고 바꿔도 어색함이 느껴질것이다. 이럴때는 아래 코드와 같이 명령과 조회를 분리해서 사용해야한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663308138167&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (attributeExists(&quot;username&quot;)) {
	setAttribute(&quot;username&quot;, &quot;Alice&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;오류 코드보다 예외를 사용하라&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;pre id=&quot;code_1663316023804&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (deletePage(page) == E_OK) {
    if (registry.deleteReference(page.name) == E_OK) {
        if (configKeys.deleteKey(page.name.makeKey()) == E_OK){
            logger.log(&quot;....................&quot;);
        } else {
            logger.log(&quot;....................&quot;);
        }
    } else {
        logger.log(&quot;....................&quot;);
    }
} else {
    logger.log(&quot;....................&quot;);
    return E_ERROR;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;오류코드보다는 예외를 사용해야한다. 오류코드를 반환하면 호출자는 오류 코드를 바로 처리해야하고, 여러 단계로 중첩되는 코드를 야기하기 때문이다. 아래의 예외코드는 어떤지 살펴보자.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663316396216&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;try {
    deletePage(page);
    registry.deleteReference(page.name);
    configKeys.deleteKey(page.name.makeKey());
} catch (Exception e) {
    logger.log(e.getMessage());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예외를 사용하면 오류 처리 코드가 원래의 코드에서 분리되어 훨씬 깔끔하게 처리할 수 있다. 이렇게 깔끔해졌음에도 불구하고 책에서는 &lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Try/Catch 블록을 별도의 함수로 뽑아낼것을 권장한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663317232780&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void delete(Page page){
    try {
        deletePageAndAllReferences(page);
    } catch (Exception e) {
        logError(e);
    }
}

private void deletePageAndAllReferences(
        Page page
)throws Exception {
    deletePage(page);
    registry.deleteReference(mock);
    configKeys.deleteKey(mock);
}

private void logError(Exception e){
    logger.log(e.getMessage());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;deletePageAndAllReferences() 함수에서는 예외를 던지고 deletePageAndAllReferences()를 호출하는 delete() 함수에서 예외를 처리하는 방식이다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;반복하지 마라!&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;반복하지 마라!&lt;/span&gt;는 중복에 대한 이야기다. 우리가 함수를 만드는 이유중 하나는 중복을 제거하기 위함이다. 우리가 어떠한 문제를 해결하기 위한 알고리즘을 짰다고 해보자. 해당 알고리즘이 적용되야 하는곳은 총 4곳이다. 만약 알고리즘을 수정해야 할 일이 생긴다면 우리는 4곳을 전부 손봐야 한다. 수정하다보면 사람이기에 무언가 하나 빠트려 오류가 발생할 확률도 생긴다. 그러나 알고리즘을 함수로 만든다면 해당 함수만 수정하여 4곳 모두 간단하게 처리할 수 있다.&lt;/b&gt;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;중복은 소프트웨어에서 모든 악의 근원이다. 많은 원칙과 기법(AOP, COP...)은 중복을 없애거나 제거하기위해 나왔다.&lt;/b&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;함수는 어떻게 짜야하는가 및 결론&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;소프트웨어를 짜는것은 여느 글짓기와 비슷하다고 한다. 글짓기는 블로그에 리뷰를 작성하는 과정과 비슷하다. 책을 읽고 내 생각을 정리하고, 전달력을 높이기 위해 고민하고 다듬는다. 처음 작성한 글은 서투르고 전달력이 좋지않다. 그렇기에 몇번이고 수정할 때가 있다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;함수를 짤때도 마찬가지다. 처음에는 복잡하고, 이름에 제대로된 의미를 담지 못할때가 있다. 때로는 중복된 코드내용이 있고, 인수 목록이 길어질 때도 있다. 처음은 서툴지 모르나 함수를 짠후에는 다음 과정을들을 단위 테스트로 작성하고, 코드를 다듬고, 함수를 만들고, 이름을 바꾸고, 중복을 제거하여 보다 나은 함수로 만든다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;프로그래밍은 언어설계의 기술이다. 언어는 전달력이 중요하다. 프로그래밍에 대가들은 시스템을 구현할 프로그램이 아니라 풀어가야할 이야기로 여긴다. 함수는 결국 시스템 내에서 발생하는 모든 동작을 설명하는 언어이다. 우리가 함수를 작성하는 진짜 목표를 잊지말자 시스템이라는 이야기를 작성하고, 더 쉽게 풀어나가기 위해 변수명을 고민하고 함수만드는것을 고민하는것이다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;제 3장 함수를 읽으며 얻은 깨달음&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;글쓴이는 '한 가지의 일만 해라' 를 읽으며 반성하는 시간을 가졌다. 글쓴이는 항상 첫 번째 HtmlUtil.java 코드와 같이 짰다. 함수를 사용하는 이유는 코드의 재사용성을 높이기 위해서 라는 말에 얽매여 있었고, &quot;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;단 한곳에서만 사용될것이라면 굳이 함수로 만들 필요가 있을까?&lt;/span&gt;&quot; 라는 생각을 가졌기 때문이다. 그래서 재사용되지 못할 코드라면 함수로 만들지 않았었다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그러나 이 책을 읽으며 깨닫게 된것은 재사용되지 못할 코드라도 추상화 하여 &quot;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;하나의 함수로 만듬으로써 이름을 통해 무슨 역할을 하고 있는지 전달할 수 있다는 것&lt;/span&gt;&quot;이다.&amp;nbsp;includeSetupAndTeardownPages()를 함수로 만들지 않고 코드를 줄이기 전의&amp;nbsp;HtmlUtil.java처럼 코드를 짰다고 생각해보자. 무얼 하고있는지 빠르게 파악할수가 없다. 그러나 두 번째&amp;nbsp;HtmlUtil.java처럼 함수로 만든다면 이름을 통해 해당 함수가 무슨 역할을 하고 있는지 전달받을수 있다.&lt;/span&gt;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;깨달음을 얻긴했지만 이것이 정답인지는 확신하지 못한다. 더 생각하고 더 많은것들을 접하며 배워야 겠다는 생각이 든다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/Read Book</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/24</guid>
      <comments>https://doosicee.tistory.com/entry/CleanCode-3%EC%9E%A5-%ED%95%A8%EC%88%98#entry24comment</comments>
      <pubDate>Thu, 15 Sep 2022 18:26:33 +0900</pubDate>
    </item>
    <item>
      <title>CleanCode 2장 의미 있는 이름</title>
      <link>https://doosicee.tistory.com/entry/CleanCode-2%EC%9E%A5-%EC%9D%98%EB%AF%B8-%EC%9E%88%EB%8A%94-%EC%9D%B4%EB%A6%84</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oPUXM/btrL34iabQ9/27vJddpjgkFaDoRTxeCcnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oPUXM/btrL34iabQ9/27vJddpjgkFaDoRTxeCcnk/img.png&quot; data-alt=&quot;출처: 인사이트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oPUXM/btrL34iabQ9/27vJddpjgkFaDoRTxeCcnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoPUXM%2FbtrL34iabQ9%2F27vJddpjgkFaDoRTxeCcnk%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; alt=&quot;클린코드.img&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;467&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: 인사이트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;의미 있는 이름&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;책에서 말하는 의미 있는 이름을 작성하기 위해서는 너무나도 많은 사항들이 있지만 조금 간추려보았다.&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;의도를 분명히 밝혀라 (글쓴이 개인적으로는 가장 중요하다고 생각한다)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;그릇된 정보를 피하라&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;의미 있게 구분하라&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;발음하기 쉬운 이름을 사용하라&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;검색하기 쉬운 이름을 사용하라&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;한 개념에 한 단어를 사용하라&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;말장난을 하지 마라&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;의미 있는 맥락을 추가하라&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;불필요한 맥락을 없애라&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;의도를 분명히 밝혀라&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;의미있는 이름이란 &quot;의도가 분명히 드러나는 이름&quot;이다. 좋은 이름을 짓는 것은 쉽지 않다. 그러나 좋은 이름 덕에 미래의 나, 그리고 다른 동료들은 이름만으로도 무슨 기능을 하는지 파악할 수 있고, 많은 시간을 절약할 수 있을 것이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663118644305&quot; class=&quot;coffeescript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;getDataList(){
 this.$http.get(url).then((responseData) =&amp;gt; {
	this.dataList = responseData.body;
    }).catch() .....
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;위 코드의 메서드명과 변수의 이름을 보고 무엇을 추측할 수 있는가. 응답 값으로 무엇을 받고, 변수에 무엇은 담는다는 것인지 전혀 알 수 없다. &lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;위와 같이 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;변수 또는 함수의 존재 이유, 수행 기능, 사용 방법에&lt;/span&gt; 대해 의문이 들고 따로 주석이 필요하다면 의도를 분명히 드러내지 못했다는 것이다. &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;또한 검색으로 원하는 메서드명과 변수명을 검색할 때에 모두 getDataList(), dataList 라면..? 끔찍할 것이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663118652090&quot; class=&quot;coffeescript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;getUserList(){
 this.$http.get(url).then((responseData) =&amp;gt; {
	this.userList= responseData.body;
    }).catch() .....
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;하지만 위의 코드와 같이 의도가 드러난다면 무엇이 담기는지 명확하게 알 수 있다. &quot;유저의 정보를 가져오는 메서드와 유저의 정보를 담는 변수구나.&quot;라고. 또한 검색할 때에도 getUserList(), userList로 의미 있는 이름으로 구분된다면 내가 원하는 정보를 금방 찾을 수 있을 것이다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그릇된 정보를 피하라&lt;/span&gt;&lt;/b&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;우리는 &lt;b&gt;그릇된 정보는 코드 의미를 흐리기 때문&lt;/b&gt; 남겨서는 안 된다. 여러 사용자들을 그룹으로 묶을 때, 실제 List가 아니라면 userList를 사용하지 않는다. &lt;b&gt;프로그래머들에게 List라는 단어는 특수한 의미가 있다. 계정을 담는 변수가 실제 List 가 아니라면 프로그래머에게 그릇된 정보를 제공하는 것이다. 그러므로 userGroup, bunchOfUsers 또는 users라 하는 게 좋다.&lt;/b&gt;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;b&gt;서로 비슷한 이름을 사용하지 않도록 주의하자. 예를 들어 한 모듈에서 XYZControllerForEfficientHandlingOfStrings라는 이름을 사용하고, 또 다른 모듈에서 &lt;b&gt;&lt;b&gt;XYZControllerForEfficientStorageOfStrings라는 이름을 사용한다면 IDE에서 제공하는 검색 기능 및 자동완성 기능을 사용했을 때 바로 구분하기 힘들 것이다.&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;소문자 l 과 대문자 O를 변수로 사용하는 것을 피해라. 자칫하면 l은 1처럼 보이고, O는 0처럼 보일지도 모른다.&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;의미 있게 구분하라&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #f89009;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;연속적인 숫자를 덧붙인 의미 없는 이름은 사용해서는 안된다. 아무 의미가 없기 때문이다. 아래의 코드를 살펴보자.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663213697711&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static copyChars(char[] a1, char[] a2){
	for (int i = 0; i &amp;lt; a1.length; i++){
    	a2[i] = a[i];
    }
}

public static copyChars(char[] source, char[] destination){
	for (int i = 0; i &amp;lt; source.length; i++){
    	destination[i] = source[i];
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #f89009;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;첫 번째 copyChars()에 a1과 a2에는 무슨 의미가 있을까? 아무 의미도 없다. 두 번째처럼 source, destination을 사용한다면 코드를 읽기가 훨씬 쉬워진다.&lt;/span&gt;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #f89009;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;불용어(분석에 큰 의미가 없는 단어)를 사용한 이름 역시도 아무 정보도 제공하지 못한다. 다음과 같은 함수들이 있다고 생각해보자.&lt;/span&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;getActiveAccount();&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;getActiveAccounts();&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;getActiveAccountInfo();&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;계정 정보를 가져와야 할 때에 어떤 함수를 호출해야 할까? 무슨 차이가 있는지 전혀 구분이 되지 않는다. 읽는 사람이 차이를 확실히 알 수 있도록 작성해야 한다.&lt;/span&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #f89009;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;발음하기 쉬운 이름을 사용하라&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;프로그래밍은 사회활동이다. genymdhms(generate date, year, month, day, hour, minute, sec-ond)를 축약한 것이다. 잘못 발음하면 바보처럼 들릴 수도 있다. 우리는 토론을할 수도 있고, 발표를 할 수도 있고, 리뷰를 할수도 있다. 소통하기 쉬운 이름을 사용하자.&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;검색하기 쉬운 이름을 사용하라&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;387&quot; data-origin-height=&quot;241&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brfwIO/btrMcQ4lr6r/aaD3OAIyVTiZ2FHAGWTSk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brfwIO/btrMcQ4lr6r/aaD3OAIyVTiZ2FHAGWTSk1/img.png&quot; data-alt=&quot;intelliJ e문자 검색&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brfwIO/btrMcQ4lr6r/aaD3OAIyVTiZ2FHAGWTSk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrfwIO%2FbtrMcQ4lr6r%2FaaD3OAIyVTiZ2FHAGWTSk1%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;387&quot; height=&quot;241&quot; data-origin-width=&quot;387&quot; data-origin-height=&quot;241&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;intelliJ e문자 검색&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;문자 하나를 사용하는 이름과 상수는 텍스트 코드에서 쉽게 눈에 띄지도 않으며,&amp;nbsp; 특히 상수는 여러 곳에서 사용하기 마련이다. e라는 문자의 변수가 있다고 생각해보자. e는 영어에서 가장 많이 쓰이는 문자다. 검색해서 찾기 정말 힘들 것이다. &lt;b&gt;이름을 만들 때는 너무 짧지 않게 하여 검색하기 쉬운 이름을 만들자.&lt;/b&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;한 개념에 한 단어를 사용하라&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;추상적인 개념 하나에는 단어를 하나 선택하여 사용하자. 우리는 데이터를 찾아 가져올 때에 getUserId, findUserId라는 용어를 사용하는걸 흔히 볼 수 있다. 이 밖에도 fetch, retrieve 등... 이 있는데 모두 찾는다, 가져온다 라는 의미들을 가졌다. 우리는 무언가를 가져오는 메서드를 클래스마다 get, find, fetch, retrieve.. 제 각각의 이름으로 부른다면 혼란스러울 것이다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;좀 더&amp;nbsp; 예시를 들어보자면 우리는 보통 Controller는 UserController, BoardController 등...으로 클래스 이름을 만든다. 그런데 Controller의 개념은 같으나 단어를 다르게 사용해 어떤 곳은 UserController인 반면 어떤곳은 BoardManager라면 혼란스러울 것이다. 이것을 당장 개발한 나는 알 수도 있으나&amp;nbsp;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;미래의 나와 다른 개발자들은 혹시 다른 의미가 있는지 생각하게 될 것이다.&lt;/span&gt;&amp;nbsp;어떠한 단어를 사용하라는 정답은 없지만 같이 일하는 동료들과 맞추어 개발하길 권장한다.&amp;nbsp;&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;말장난을 하지 마라&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;말장난을 하지 마라. 이 말이 무슨 말일까? 바로 한 단어를 두 가지 목적으로 사용하지 말라는 것이다. 기존 add가 하나의 값에 값을 더한다는 의미로 사용되고 있다면 집합에 값을 추가하는 경우에는 insert나 append라는 이름이 적당하다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;프로그래머가 작성할 코드의 목표는 대충 훑어봐도 이해할 코드가 목표이다.&lt;/span&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;의미 있는 맥락을 추가하라&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;firstName, lastName, street, houseNumber, city, state라는 변수가 있다고 하자. 변수들을 다 훑어본다면 주소라는 것을 알 수 있다. 그러나 state라는 변수 하나만 사용한다면 주소의 일부라는 것을 알 수 있을까? 코드를 통해 보도록 하자!&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1663219823905&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private void example1(){
    String firstName;
    String lastName;
    String street;
    int houseNumber;
    String city;
    String state;
  }
  
  private void example2(){
    String state;
  }

  private void example3(){
    String addrState;
  }
  private void example4(){
    address.getState();
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;첫 번째 example1에 변수를 다 훑어본다면 state가 주소의 일부라는 것을 알 수 있다. 그러나 example2처럼 state는 변수 하나만 사용한다면 주소의 일부라는 사실을 알 수가 없다. 이럴 때에는 addr라는 접두어를 추가해 example3과 같이 addrState라 쓰면 맥락이 좀 더 분명해진다. 가장 좋은 것은 example4와 같이 클래스를 만들어 사용하는 것이다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;불필요한 맥락을 없애라&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;GasStationDelixe라는 애플리케이션을 만든다고 가정해보자. 이때 모든 클래스 이름을 GSD로 시작하는 것은 전혀 바람직하지 못하다. IDE에서 G를 입력하고 자동 완성 키를 누르면 IDE는 G가 들어가는 모든 클래스를 열거해준다. 이런 행위는 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;개발자를 도와주는 IDE를 방해하는 행위일 뿐&lt;/span&gt; 전혀 의미 없다. 또한 특정 클래스를 검색할 때에 GSD를 검색하면 GSD가 포함된 단어가 모두 나와서 검색마저도 효율적이지 못하게 한다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;2장 의미 있는 이름을 읽으며 느낀 점&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;책에서는 &quot;좋은 이름을 선택하려면 설명 능력이 뛰어나야 하고 문화적인 배경이 같아야 한다. 좋은 이름을 선택하는 능력은 기술, 비즈니스, 관리 문제가 아닌 교육 문제다.&quot;라고 말한다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;좋은 변수, 함수명을 만들기 위해 항상 고민해왔다고 생각했지만, 책에서 말하는 모든 사항을 고려하지는 못했었다. 좋은 이름을 짓는 것은 프로그래머의 역할이고 책임이다. 역할과 책임을 다하기 위해 노력해야겠다. 내가 선택하는 이름들이 최선이 될 것이라고 생각하지는 않는다. 그러나 최선에 것을 선택하려 노력한다면, 그것이 축적되어 더 좋은 개발자로 한 발짝, 한 발짝 나아갈 것이라고 생각한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/Read Book</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/23</guid>
      <comments>https://doosicee.tistory.com/entry/CleanCode-2%EC%9E%A5-%EC%9D%98%EB%AF%B8-%EC%9E%88%EB%8A%94-%EC%9D%B4%EB%A6%84#entry23comment</comments>
      <pubDate>Wed, 14 Sep 2022 10:24:51 +0900</pubDate>
    </item>
    <item>
      <title>CleanCode 1장 깨끗한 코드</title>
      <link>https://doosicee.tistory.com/entry/CleanCode-1%EC%9E%A5-%EA%B9%A8%EB%81%97%ED%95%9C-%EC%BD%94%EB%93%9C</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&quot;클린 코드&quot;라는 책을 통해 사내 스터디를 하였다. 클린 코드라는 책을 선택한 이유는 개발자가 꼭 읽어야 할 책들 중 하나였고, 더 좋은 코드를 작성하기 위해 읽게 되었다.&amp;nbsp;&lt;span style=&quot;background-color: #99cefa;&quot;&gt;출처: 인사이트, 글쓴이: 로버트 C. 마틴&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tCH7E/btrL6RhMsQk/ojgdUVu6lrkNPXMaknZsHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tCH7E/btrL6RhMsQk/ojgdUVu6lrkNPXMaknZsHk/img.png&quot; data-alt=&quot;출처: 인사이트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tCH7E/btrL6RhMsQk/ojgdUVu6lrkNPXMaknZsHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtCH7E%2FbtrL6RhMsQk%2FojgdUVu6lrkNPXMaknZsHk%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;350&quot; height=&quot;467&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: 인사이트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;깨끗한 코드가 왜 중요할까?&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 책에서 나온 내용의 일부이다. 80년대 후반 킬러 앱 하나를 구현한 회사가 있었고, 큰 인기를 끌었으나 새 버전에 대한 출시가 점점 늦어지고 이전에 발견됐던 버그가 그대로 남아있는 문제가 있었다고 한다. 그 회사는 얼마 못가 망했고 후일 책의 저자가 망한 회사의 초창기 직원을 만났을 때에 들은 이야기는 &quot;초기 코드를 마구 짰고 갈수록 엉망이 되어 감당이 안되었다&quot;라고 했다고 한다. 이 글을 읽으며 나는 깊이 공감하였고, 나 자신이 짰던 코드들을 돌아보게 되었다.&lt;/span&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;태도&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우리는 코드를 짤 때에 항상 코드에 전문가다운 태도를 취해야 한다. 코드가 잘못됐다면 모두 개발자의 잘못이기 때문이다. 때로는 &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;촉박한 개발 일정에 쫓길 수도 있다. 그러나 우리는 시간에 쫓기더라도 좋은 코드를 짜야한다. 좋은 코드를 사수하는 것이 프로그래머들의 책임이기 때문이다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;책에서는 이런 비유를 하나 들었다. 자신이 의사라고 가정해보자. 어느 환자가 수술 전에 손을 씻지 말라고 요구했다. 손 씻는데 시간이 걸리기 때문이다. 그렇지만 의사는 단호하게 거부한다. 왜? 당연하다 질병과 감염의 위험은 환자보다는 의사가 더 잘 알기 때문이다. 환자의 말을 그대로 따르는 행동은 전문가 답지 못하다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우리 프로그래머들은 코드의 전문가다. 좋은 코드를 짜고, 좋은 아키텍처를 설계하고, 더 좋은 성능을 위해 고민하는 것이 이 분야의 전문가인 우리 프로그래머들이 해야 할 일이다. 시간이 촉박한 것 이해한다. 그러나 우리는 전문가답게 좋은 코드를 짜기 위해서 항상 공부하기를 노력하고, 생각하기를 노력해야 한다.&lt;/span&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;깨끗한 코드&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&quot;깨끗한 코드를 어떻게 작성할 것인가?&quot; 이 책에서는 깨끗한 코드가 무엇인지 모르면 작성할 수 없다고 말한다. 또한 깨끗한 코드를 구분할 줄 안다고 해서 작성할 줄 아는 것은 아니라고 한다. 즉, 쉽게 말하자면 &quot;내 방의 디자인이 엉성하고 복잡한 것은 알겠으나 그걸 치우고 아름답게 꾸미는 것은 다른 문제다.&quot;라는 말이다. 그렇다면 깨끗한 코드란 무엇일까? 이 책에서는 여러 노련한 프로그래머들에 의견을 구했고 그들의 말 중 몇 가지를 정리해봤다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;비야네 스트롭스트룹&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;논리가 간단해야 버그가 숨어들지 못한다. 의존성을 줄여야 유지보수가 쉬워지며 오류는 명백한 전략에 의해 처리되어야 한다. 성능을 최적으로 유지해야 원칙 없는 최적화로 코드를 망치려는 유혹에 빠지지 않는다. 코드는 한 가지를 제대로 한다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;그래디 부치&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;깨끗한 코드는 단순하고 직접적이다. 아주 잘 쓴 문장처럼 읽힌다. 설계자의 의도를 숨기지 않는다. 오히려 명쾌한 추상화와 단순한 제어문으로 가득하다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;빅 데이브 토마스&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;깨끗한 코드는 작성자가 아닌 사람도 읽기 쉽고 고치기 쉽다. 단위 테스트와 인수 테스트 케이스가 존재한다. 깨끗한 코드에는 의미 있는 이름이 붙는다. 의존성은 최소이며 각 의존성을 명확히 한다. 특정 목적을 달성하기 위한 방법은 하나만 제공한다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;마이클 페더스&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;깨끗한 코드는 언제나 누군가 주의 깊게 짰다는 느낌을 주며 고치려 하면 언제나 제자리로 돌아온다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;론 제프리스&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;모든 테스트를 통과한다. 중복이 없다. 시스템 내 모든 설계 아이디어를 표현한다. 클래스, 메서드, 함수 등을 최대한 줄인다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;워드 커닝햄&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;코드를 읽으면서 짐작 했던 기능을 각 루틴이 그대로 수행한다면 깨끗한 코드이다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;노련한 프로그래머들이 했던 말들은 &lt;/b&gt;모두 피가 되고 살이 되는 말들을 요약해보면 아래와 같다.&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;깨끗한 코드는 단순해야 한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모든 테스트 케이스가 존재하고, 통과해야 한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;코드에 설계자의 의도가 드러나며, 짐작했던 기능을 수행한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;오류는 명백한 전략에 의해 처리가 되어야 한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;많은 조언들 중 &quot;깨끗한 코드는 단순해야 한다&quot;라는 말이 핵심이라고 생각한다. 단순하기에 읽기 쉽고, 기능을 짐작할 수 있고, 고치기 쉽고, 고치려 하면 제자리로 돌아오기 마련이다.&lt;/b&gt;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;최근 개인적으로 가장 공감되는 말은 &quot;모든 테스트 케이스가 존재하고 통과해야 한다&quot;이다. 회사에 있는 오래된 프로젝트들은 수정 요청사항이 들어올 때마다 골치 아프다. 테스트 케이스가 존재하지 않기에 메서드를 조금 수정하더라도 어디까지 영향을 미치는지 알 길이 없기 때문이다. 이럴 때는 차라리 영향력을 일일이 체크하기보다는 요청사항에 맞게 하나 만드는 것이 더 빠르다. 테스트 케이스가 있었다면 이런 걱정은 필요 없었을 것이다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;1장 깨끗한 코드를 읽고 난&amp;nbsp; 후 들었던 생각과 깨끗한 코드를 알아가는 방법&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;나는 회사에 입사 후 책과 강의를 이용해 공부를 했다. 간혹 책과 강의를 보다 보면 주변 사람들에게 이런 말을 듣는다. &quot;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;책하고 강의를 보는 건 소용없어 직접 해보는 게 최고야!&quot;라고.&lt;/span&gt; 일부분 공감은 하지만 온전히 공감하지는 못한다. 개발자라면 책과 강의 그리고 구글링을 통해 항상 새로운 것을 접해야 한다고 생각한다. 물론 예전 것도 중요하고 공부해야 한다. 그러나 글쓴이가 말하는 새로운 것이란 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;새로운 기술뿐만 아니라 다른 개발자들이 설계한 아키텍처 그리고 어떠한 방법을 통해 코드를 더 효율적으로 작성하는지 많이 접해야 한다는 말&lt;/span&gt;이다.&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;깨끗한 코드에서 이런 말이 나온다. '&lt;span style=&quot;background-color: #dddddd;&quot;&gt;깨끗한 코드가 무엇인지 모르면 깨끗한 코드를 만들려고 애써봤자 소용이 없다.'라고.&lt;/span&gt; 이 말에 깊이 공감한다. 나는 입사 후 첫 프로젝트를 진행하며 기능을 만들어갈 때마다 더 좋은 방법은 없는지 검토하고, 리펙토링 하기를 반복하여 스스로 만족스럽다 할만한 코드를 짜고 뿌듯해했었다. 그러나 여러 강의와 깃허브를 통해 코드들을 접하고, 책을 읽으며 스스로 만족하며 작성했던 코드들 속에서 풍겨오는 악취를 맡게 되었다.&lt;/b&gt;&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;깨끗한 코드가 무엇인지 알기 위해서는 깨끗한 코드가 무엇인지 알아야 된다. 스스로 생각을 통해 개선하며 알아갈 수도 있고, 책을 통해, 강의를 통해, 깃허브를 통하는 등... 여러 자료를 접하며 알아갈 수 있다 그러나 그중 가장 접근하기 쉬운 방법은 강의와 책이라고 생각한다. &lt;/b&gt;&lt;/span&gt;&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: #f89009;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;강의에 장점 2가지&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;첫 번째는&lt;/span&gt; &lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;네이버, 카카오, 당근, 구글, 마이크로 소프트 등.... 에서 근무했거나 근무하는 실력 있는 개발자들이 모여 강의한다는 것이다. 강사들이 각자가 속한 조직에서 배운 좋은 개발 방법들을 강의를 통해 보여주고, 나는 그 방법들을 좀 더 쉽게 접근하고 배울 수 있다. 또한 왜 이런 방식으로 개발했고, 이런 방법을 택했는지 개발자들의 생각을 들어볼 수 있다.&lt;/span&gt;&lt;/b&gt;&lt;/b&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;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;두 번째는&lt;/span&gt; 너무 많은 정보 덕에 선택의 폭이 넓어진다는 것이다. 가장 좋은 방법이라 생각되는 것을 택하고 분별해야 할 능력 또한 요구되지만, 좋은 것을 스스로 분별해내는 과정이 나의 생각의 영역을 넓혀주기 때문이다.&lt;/span&gt;&lt;/b&gt;&lt;/b&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;책을 읽는 것에 장점&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;강의만으로는 부족했던 상세한 내용들을 채워준다. 또한 책을 읽고 생각을 정리하며 잘못 이해했던 개념들은 바로잡고, 알았던 개념은 더 깊게, 몰랐던 개념은 새롭게 알게 된다.&lt;/span&gt;&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;우리가 작성하고 늘 접하고 있는 코드와 개발 방법이 가장 완벽한 것이라고 생각하는가? 나는 언제부턴가 더욱더 확신할 수 없게 되었다. 항상 더 좋은 방법이 있을 거라는 생각을 가지게 된다.&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/Read Book</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/22</guid>
      <comments>https://doosicee.tistory.com/entry/CleanCode-1%EC%9E%A5-%EA%B9%A8%EB%81%97%ED%95%9C-%EC%BD%94%EB%93%9C#entry22comment</comments>
      <pubDate>Wed, 14 Sep 2022 10:23:09 +0900</pubDate>
    </item>
    <item>
      <title>Cache 기본 개념 및 SpringBoot 예제</title>
      <link>https://doosicee.tistory.com/entry/Cache%EC%99%80-SpringBoot-Redis</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;강의를 듣던 도중 Redis를 접하게 되었고 캐시에 대한 내용과 Redis를 사용하는 방법에 대해서 정리해본다. 총 2번의 리뷰를 통해 진행한다. 이번 리뷰에서는 Cache의 기본 개념 및 SpringBoot를 통한 예제를 살펴보자&amp;nbsp;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;캐시란(Cache)?&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;캐시는 자주 사용하는 데이터나 값을 미리 복사해 놓는 임시 장소를 가리킨다. 동일한 요청이 들어오면 작업을 수행해서 결과를 만드는 대신 &lt;b&gt;이미 보관된 결과를 돌려주는 방식&lt;/b&gt;을 말한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boKWQf/btrHTqKjScz/A439RJAYmssEeOFbo9PV20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boKWQf/btrHTqKjScz/A439RJAYmssEeOFbo9PV20/img.png&quot; data-alt=&quot;출처 : https://mangkyu.tistory.com/69&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boKWQf/btrHTqKjScz/A439RJAYmssEeOFbo9PV20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboKWQf%2FbtrHTqKjScz%2FA439RJAYmssEeOFbo9PV20%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;450&quot; height=&quot;253&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://mangkyu.tistory.com/69&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;캐시는 저장공간이 작고 비용이 비싸지만 빠른 성능을 제공한다. 하지만 저장공간이 작고 비용이 비싼만큼 모든 상황에서 쓸 수 있는 것은 아니다. 아래와 같은 경우에 사용을 고려하면 좋다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;반복적으로 동일한 결과를 돌려주는 작업(이미지, 썸네일, 실시간 검색어 등...)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;잘 바뀌지 않는 정보를 외부에서 반복적으로 읽어올때 (DB 데이터 호출 및 api 호출)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;캐시는 Memory에 데이터를 저장하였다가 불러 사용한다. Enterprise급 Application에서 DBMS의 부하를 줄이고, 시간이 오래 걸리는 작업들에 대해 성능을 높일 수 있다. 캐시의 데이터가 변하는 시점(노출될 광고가 변하는 시점, 사람의 나이가 변하는 시점 등...)에 맞춰 전략적으로 캐시를 사용하면 된다.&amp;nbsp;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;Spring Cache Abstraction(캐시 추상화)&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;예제를 보기전에 먼저 Spring Cache Abstraction(캐시 추상화)을 먼저 간단하게 알아보고 넘어가자. 캐시 추상화는 &lt;b&gt;애플리케이션에 &quot;투명하게&quot; 캐시를 넣어주는 기능&lt;/b&gt;이다. 캐시가 시스템, 애플리케이션에 투명하게 자리잡는다는 말은 무엇일까?&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;데이터가 통신하는 시스템 쌍방이 캐시의 존재를 모른다는 의미&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;캐시가 있건 없건, 시스템의 기대 동작은 동일해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;캐시의 목표는 오로지 성능&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;캐시는 오로지 성능을 위해서 자리를 잡고있는 것이기 때문에 다른 것에 영향을 미쳐서는 안 된다&lt;/b&gt;. 다른 데이터가 바뀌어 버린다면 또 다른 비즈니스 로직이 되어버린다. 오로지 성능만을 위하기 때문에 다른 것에 영향을 미치지 않는다는 의미로 &quot;투명하다&quot;라는 말을 쓴다고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;예제&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;예제 환경&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;SpringBoot 2.7.2&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Gradle&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Java11&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;lombok&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;파일 구성&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Controller&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Service&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Entity&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Repository&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;RepositoryImpl&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;실제 DB와 연동은 하지않으며 Dto는 구현하지 않았습니다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;build.gradle&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;plugins {
    id 'org.springframework.boot' version '2.7.2'
    id 'io.spring.dependency-management' version '1.0.12.RELEASE'
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
}

tasks.named('test') {
    useJUnitPlatform()
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;캐시관련 설정을 편리하게 지원해주는 패키지 spring-boot-cache는 spring-boot-starter에 기본 내장되어있다고 한다. spring-boot-start를 사용한다면 spring-boot-cache는 내장되어있기에 패키지를 주입하지 않아도 된다. redis를 사용하기 전에 기본 내장되어있는 캐시를 사용해보자.&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;User.java&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;@AllArgsConstructor(staticName = &quot;of&quot;)
public class User {

    private Long id;

    private String name;

    private String email;

    private Integer age;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;staticName이라는 옵션을 사용하여 &amp;nbsp;static factory 메소드를 사용한 것 외에는 별 기능이 없는 Domain 클래스이다.&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;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;UserRepository.java&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;public interface UserRepository {

    User findByIdCache(Long id);
    User findByIdNoCache(Long id);
    void refresh(Long 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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;UserRepositoryImpl.java&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;@Slf4j
@RequiredArgsConstructor
@Repository
public class UserRepositoryImpl implements UserRepository {

    // DB를 연결하지 않았기에 예제의 DB 역할을 해줄 Map
    private final Map&amp;lt;Long, User&amp;gt; storage;

    @Override
    @Cacheable(&quot;User&quot;)
    public User findByIdCache(Long id) {
        slowQuery(3000);
        return storage.get(id);
    }

    @Override
    public User findByIdNoCache(Long id) {
        slowQuery(3000);
        return storage.get(id);
    }

    @Override
    @CacheEvict(value = &quot;User&quot;, key = &quot;#id&quot;)
    public void refresh(Long id){
        log.info(&quot;Cache Clear: &quot; + id);
    }


    // storage 에 유저정보를 넣어준다.
    public User enroll(Long id, String name, String email, Integer age){
        return storage.put(id, User.of(id, name, email, age));
    }

    // 빅 쿼리를 돌려 시간이 걸린다는 가정
    private void slowQuery(long seconds) {
        try{
            Thread.sleep(seconds);
        }catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
    }
}&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이번 예제의 핵심 코드이다. UserRepositoryImpl.java 를 살펴보자.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;@Cacheable 은 캐시를 저장/조회하기 위한 어노테이션이다.&lt;/b&gt; 캐시를 적용할 메서드에 @Cacheable 어노테이션을 붙여주면 &lt;b&gt;캐시에 데이터가 없을 경우에는 기존 로직을 실행하여 데이터를 캐시에 데이터를 넣어주고, 캐시에 데이터가 있을 시에는 캐시의 데이터를 반환해준다. &lt;/b&gt;캐시는 기본적으로 이름 하위에 key-value 형태로 데이터가 저장되는데, @Cacheable(&quot;User&quot;) 의 &quot;User&quot; 이 캐시의 이름이다. User(id=0, name=jack, email=jack@naver.com, age=30)&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;캐시에 데이터가 없을 경우 왜 기존로직을 실행하여 데이터를 캐시에 넣어줄까?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;간단한 이유이다. 캐시는 데이터를 잠깐 저장하는 곳이다. 그렇기에 조회할 데이터가 없다면 DB에서 데이터를 가져와 캐시에 데이터를 넣어 사용하는 것이다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;메서드 refresh는&lt;/b&gt; 저장된 캐시를 비워주기 위한 메서드이다. 이때에 @CacheEvict 어노테이션을 사용한다. @CacheEvict는 저장된 캐시를 비워주기 위한 어노테이션이다. 캐시에 저장된 정보가 업데이트되는 주기에 맞춰 캐시를 비우고 새로 데이터를 넣어줘야 한다. value로는 캐시의 이름을 전달하고 key로는 캐시에 저장되는 값의 key를 전달하여준다. 위의 예제 같은 경우에는 id 값을 전달하였다.&amp;nbsp;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;메서드 slowQuery는&lt;/b&gt; 아주 많은 양의 데이터가 존재하여 한번 조회할 때에 3초라는 시간이 걸린다 가정하기 위해 만들었다. 캐시를 사용했을 때와 하지 않았을 때의 속도 차이를 비교하기 위한 메서드이다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;메서드 enroll은&lt;/b&gt; 현재 예제에서는 데이터베이스와 연결하여 사용하고 있지 않기 때문에, 예제를 위해 애플리케이션 실행 시에 Map타입의 storege에 데이터를 넣어 데이터베이스의 역할을 만들어주기 위함이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;User.controller.java&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;@Slf4j
@EnableCaching // 어노테이션을 이용하여 해당 클래스에서 캐시기능을 사용하겠다는 선언
@RequiredArgsConstructor
@RestController
public class UserController {

    private final UserService userService;

    @GetMapping(&quot;/user/nocache/{id}&quot;)
    public User getNoCacheUser(
            @PathVariable Long id
    ){
        long start = System.currentTimeMillis();      // 시간측정
        User user = userService.printUserNoCache(id); // 데이터베이스 조회
        long end = System.currentTimeMillis();

        log.info(user.getName() + &quot;NoCache 수행시간 : &quot; + (end-start));
        return user;
    }

    @GetMapping(&quot;/user/cache/{id}&quot;)
    public User getCacheUser(
            @PathVariable Long id
    ){
        long start = System.currentTimeMillis();   // 시간측정
        User user = userService.printUser(id);     // 데이터베이스 조회
        long end = System.currentTimeMillis();

        log.info(user.getName() + &quot; Cache 수행시간 : &quot; + (end-start));
        return user;
    }

    // key 값을 이용하여 캐시삭제
    @GetMapping(&quot;/user/refresh/{id}&quot;)
    public void refreshCache(
            @PathVariable Long id
    ){
        userService.refresh(id);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Contoller는 만들어둔 로직을 url을 통해 호출할 수 있게 해 두었다. 캐시가 있을 때와 없을 때의 수행 시간을 측정해보며 비교해보자.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;Nocache&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1658709145708&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;http://localhost:8080/user/nocache/0&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1658709190072&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;http://localhost:8080/user/nocache/1&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1658709190740&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;http://localhost:8080/user/nocache/2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;먼저 캐시를 적용하지 않은 url을 호출해서 시간이 얼마나 걸리는지 확인해보자. 각 url을 2번씩 호출하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1056&quot; data-origin-height=&quot;137&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yE6VC/btrH5eI9Dl9/pNkZnLFuR2GzJbbIkK4wm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yE6VC/btrH5eI9Dl9/pNkZnLFuR2GzJbbIkK4wm0/img.png&quot; data-alt=&quot;캐시 미적용&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yE6VC/btrH5eI9Dl9/pNkZnLFuR2GzJbbIkK4wm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyE6VC%2FbtrH5eI9Dl9%2FpNkZnLFuR2GzJbbIkK4wm0%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; alt=&quot;NoCache img&quot; loading=&quot;lazy&quot; width=&quot;1056&quot; height=&quot;137&quot; data-origin-width=&quot;1056&quot; data-origin-height=&quot;137&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;IDE의 콘솔이다. 캐시를 적용하지 않을 시에는 각 url을 호출할 때마다 3초의 시간이 걸리는 걸 볼 수 있다. 그렇다면 캐시를 적용했을 때에는 어떻게 되는지 살펴보자.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;Cache&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1658709415375&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;http://localhost:8080/user/cache/0&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1658709425638&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;http://localhost:8080/user/cache/1&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1658709431477&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;http://localhost:8080/user/cache/2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;캐시를 적용한 url을 각 3번씩 호출하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1081&quot; data-origin-height=&quot;198&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZMvaA/btrH3QOBW58/AkMEt6BGodC6idGdORFUc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZMvaA/btrH3QOBW58/AkMEt6BGodC6idGdORFUc1/img.png&quot; data-alt=&quot;캐시 적용&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZMvaA/btrH3QOBW58/AkMEt6BGodC6idGdORFUc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZMvaA%2FbtrH3QOBW58%2FAkMEt6BGodC6idGdORFUc1%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; alt=&quot;cache img&quot; loading=&quot;lazy&quot; width=&quot;1081&quot; height=&quot;198&quot; data-origin-width=&quot;1081&quot; data-origin-height=&quot;198&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;첫 호출 시에는 캐시에 데이터가 없기 때문에 3초라는 시간이 걸리지만 그 이후부터는 캐시에 저장된 데이터를 사용하여 0초라는 시간이 걸리는 걸 확인할 수 있다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;만약 이때에 데이터베이스에 저장된 유저의 정보가 변경된다면 어떻게 해야 할까? 기존 캐시에 저장되어있던 변경된 유저의 데이터를 지우고 변경된 데이터를 다시 캐시 데이터에 넣어주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1658714189866&quot; class=&quot;pgsql&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;http://localhost:8080/user/cache/0&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1658714211066&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;http://localhost:8080/user/refresh/0&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1658714222060&quot; class=&quot;pgsql&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;http://localhost:8080/user/cache/0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1103&quot; data-origin-height=&quot;163&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ba3Q5o/btrH09IbqaA/FOuGeOrBiLc0QbkpnPTgaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ba3Q5o/btrH09IbqaA/FOuGeOrBiLc0QbkpnPTgaK/img.png&quot; data-alt=&quot;캐시 clear&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ba3Q5o/btrH09IbqaA/FOuGeOrBiLc0QbkpnPTgaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fba3Q5o%2FbtrH09IbqaA%2FFOuGeOrBiLc0QbkpnPTgaK%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; alt=&quot;refresh img&quot; loading=&quot;lazy&quot; width=&quot;1103&quot; height=&quot;163&quot; data-origin-width=&quot;1103&quot; data-origin-height=&quot;163&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;캐시 clear&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;id 값이 0번인 유저를 4번 호출했다. 유저의 정보가 변경됐다고 가정하고 id값이 0인 유저의 캐시를 refresh 한 후에 다시 호출했을 때의 모습이다. 캐시를 refresh 한 후에는 다시 3초라는 시간이 걸리고 그 뒤에는 캐시 데이터를 가져와 0초가 적용된 모습을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;마무리&lt;/span&gt;&lt;/b&gt;&lt;/h3&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;강의를 보던 도중 캐시에 대한 내용이 나와 공부하게 되었다. 처음에는 springframework에 내장되어있는 캐시를 사용하는 예제를 통하여 공부하였고, Redis 까지 적용시키는 공부를 하게되었다. 캐시에 대해 깊게 공부를 한 것은 아니지만 대략적으로 캐시란 무엇인지 알게 되었다. 다음 리뷰에는 현재 글의 예제에 Redis를 적용시키는 리뷰를 작성하고 Docker을 이용하여 테스트 컨테이너를 띄우는 방법에 대해 리뷰할 예정이다.&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: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://github.com/Doosic/cache-example&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예제 코드가 담긴 깃허브 링크&lt;/span&gt;&lt;/a&gt;&lt;/span&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Reference&lt;/span&gt;&lt;/b&gt;&lt;/h3&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;a href=&quot;https://jojoldu.tistory.com/57&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;기억보단&amp;nbsp;기록을&amp;nbsp;캐시&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://fastcampus.co.kr/dev_online_spring&quot;&gt;FastCampus 한 번에 끝내는 Spring 완전판 초격차 패키지&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mangkyu.tistory.com/179&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;캐시 추상화와 사용법&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@tyjk8997/%EC%BA%90%EC%8B%9C%EC%99%80-%EA%B6%81%EA%B8%88%ED%95%9C%EC%A0%90&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;캐시란 무엇인가?&lt;/a&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;관련 리뷰&lt;/b&gt;&lt;/h3&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;a href=&quot;https://doosicee.tistory.com/entry/Redis%EB%A5%BC-SpringBoot%EC%97%90-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Redis를 SpringBoot에 적용하기&lt;/a&gt;&lt;/p&gt;</description>
      <category>개발/Tech Notes</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/16</guid>
      <comments>https://doosicee.tistory.com/entry/Cache%EC%99%80-SpringBoot-Redis#entry16comment</comments>
      <pubDate>Fri, 22 Jul 2022 05:19:39 +0900</pubDate>
    </item>
    <item>
      <title>읽기 좋은 코드가 좋은 코드다</title>
      <link>https://doosicee.tistory.com/entry/%EC%9D%BD%EA%B8%B0-%EC%A2%8B%EC%9D%80-%EC%BD%94%EB%93%9C%EA%B0%80-%EC%A2%8B%EC%9D%80-%EC%BD%94%EB%93%9C%EB%8B%A4</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&quot;읽기 좋은 코드가 좋은 코드다&quot; 라는 책을 통해 사내 스터디를 진행하게 되었다. 원래는 클린코드를 진행 할 예정이였으나 클린코드를 읽기전 한번 이 책을 읽어보면 좋겠다는 차장님의 추천을 받아 읽게되었다. 이 책은 &quot;The Art Of Readable Code&quot;&amp;nbsp; 즉, 더 나은 코드를 작성하는 간단하고 실전적인 테크닉이라고 책을 소개한다. 모든 내용을 정리하고 리뷰할 수는 없으나 핵심적인 내용들만을 정리한다. 개발에 입문하였다면 이 책을 한번씩은 꼭 읽어보길 바란다(예제는 c언어와 자바스크립트로 구성되어있다) &lt;span style=&quot;background-color: #99cefa;&quot;&gt;출처: O'REILLY, 한빛미디어&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFA8uq/btrFGPS4GKu/jiwaj4QOF0GufofC9M5f01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFA8uq/btrFGPS4GKu/jiwaj4QOF0GufofC9M5f01/img.png&quot; data-alt=&quot;출처: O'REILLY, 한빛미디어&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFA8uq/btrFGPS4GKu/jiwaj4QOF0GufofC9M5f01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFA8uq%2FbtrFGPS4GKu%2Fjiwaj4QOF0GufofC9M5f01%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; alt=&quot;읽기 좋은 코드가 좋은 코드다.jpg&quot; loading=&quot;lazy&quot; width=&quot;450&quot; height=&quot;600&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: O'REILLY, 한빛미디어&lt;/figcaption&gt;
&lt;/figure&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;코드는 이해하기 쉬워야 한다&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&quot;코드는 이해하기 쉬워야 한다&quot; 라는 주제가 이 책의 첫번째 목차이다. 내가 짠 코드를 누군가 볼때에 이해하기 쉬워야 내 코드를 분석하는데 들이는 시간 낭비를 줄일 수 있고, 가장 중요한건 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;6개월 후의 내가 봤을때에 이 코드를 쉽게 알아볼 수 있는가?&lt;/span&gt; 라는것이 핵심적인 부분이다. 우리는 단순하게 한 줄, 두 줄의 코드가 더 좋다는 생각을 할 때가 있다. 길게 늘어질 코드를 줄일 수 있기 때문이다. 그러나 무분별 하게 코드를 줄인다면 가독성이 떨어지는 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;즉, 누군가 알아보기 힘들고 6개월 뒤의 내가 못알아볼 수 있는 문제가 생길수 있다.&lt;/span&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;간단한 예시&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;첫 번째 코드&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656291832999&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int minAge = 10;
int maxAge = 20;

int userAge = minAge &amp;lt; maxAge &amp;amp;&amp;amp; minNum != maxNum ? (minNum * 5) : (maxAge * 2)&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;두 번째 코드&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656292614472&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int minAge = 10;
int maxAge = 20;
int userAge;

if(minAge &amp;lt; maxAge &amp;amp;&amp;amp; minNum != maxNum){
	userAge = minAge * 5;
}else{
	userAge = maxAge * 2;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;위의 두 코드들은 같은 결과를 낸다. minAge가 maxAge 보다 작으면서 둘의 값이 같지 않다면 (minNum * 5)를 반환하고 그 반대라면 (maxAge * 2) 를 반환하는 것이다. 둘의 코드를 비교해봤을때 어떤것이 더 보기좋은 코드일까? 첫 번째 코드는 분명 간결하지만, 오히려 두 번째 코드가 더 친숙하게 느껴진다. 어떤 측면이 더 중요한 것일까...?&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;책에서는 이러한 코드에 대한 연구를 수행한 끝에, 가독성과 관련한 가장 중요한 통계적 사실이 있음을 알게 되었고 그것을 '가독성의 기본 정리' 라고 부른다고 한다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;핵심 포인트는 코드는 다른 사람이 이해하는 데 들이는 시간을 최소화하는 방식으로 작성되어야 한다.&lt;/span&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;내가 짠 코드를 평범한 동료가 읽고 이해하는데 걸리는 시간이 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;'이해를 위한 시간'&lt;/span&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;그래서 결론은 무엇일까? 적은 분량으로 코드를 작성하는 것이 좋은 목표이긴 하지만, &lt;span style=&quot;background-color: #dddddd;&quot;&gt;이해를 위한 시간을 최소화 하는게 더 좋은 목표라고 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;이름에 정보 담기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;특정한 단어 고르기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;보편적인 이름 피하기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;추상적인 이름 대신 구체적인 이름 사용하기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;접두사 혹은 접미사로 이름에 추가적인 정보 덧붙이기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이름이 얼마나 길어져도 좋은지 결정하기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;추가적인 정보를 담을 수 있게 이름 구성하기&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;변수의 이름은 작은 설명문이다. 모든걸 담을수는 없지만 좋은 변수명을 생각하고 담으려고 노력해야한다.&lt;/span&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;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;보편적인 이름 피하기✔&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;코드를 짜다보면 흔하게 사용하는 이름들이 있다. tmp, 루프반복자(for문)의 i, j 등... 흔하게 사용하는 이 이름들을 사용하는 것은&amp;nbsp; &quot;내 머리로는 이름을 생각해낼 수 없어요&quot; 라고 고백하면서 책임을 회피하는 증거에 불과하다. 이렇게 무의미한 이름이 아니라, 개체의 값이나 목적을 정확하게 설명하는 이름을 골라야 한다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;물론 이 이름들을 사용하지 말라는 것은 아니다. 사용할 곳에 알맞게 의미있게 사용되어야 한다는 것이다. 한번 예시를 통해 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;간단한 예시 (tmp: &lt;span style=&quot;background-color: #ffffff;&quot;&gt;Temporary(일시적인, 임시적인)&lt;/span&gt;)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;첫 번째 코드&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656302616076&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public User createUser(String name, int age){
	User tmp = new User();
	tmp.setName(name);
	tmp.setAge(age);

	return tmp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;첫 번째 코드를 살펴보면 간단하게 유저를 생성해주는 메소드이다. 이 과정이 짧긴 하지만 tmp 변수의 주된 목적은 임시적인 저장소 역할로 국한되지 않았다. 이럴때에는 userinfo 같은 이름이 더 적절할 것이다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;두 번째 코드&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656323510286&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if(right &amp;lt; left){
    tmp = right;
    right = left;
    left = tmp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;두 번째 코드의 경우 tmp 라는 이름이 완벽하게 작용한다. 이름 그대로 임시적인 저장소 역할고 제한되어있다. 이때 tmp 라는 이름은 코드를 읽는 사람에게 변수가 임시저장소 이외에 다른 용도가 없다는 사실을 잘 전달한다. tmp는 다른 함수로 전달되거나, 값이 다시 초기화되거나, 여러 차례 반복적으로 사용되는 변수가 아니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;간단한 예시 (for 문)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;첫 번째 코드&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656324281375&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for (int i = 0; i &amp;lt; clubs.size(); i++){
	for (int j = 0; j &amp;lt; clubs[i].members.size(); j++){
    		for (int k = 0; k &amp;lt; users.size(); k++){
        	if (clubs[i].members[k] == users[j]){
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;위의 코드를 보면 흔히들 사용하는 i, j, k 를 반복문의 인덱스로 사용하였다. 이러한 이름들은 보편적이지만 &quot;나는 반복자다&quot; 라는 의미를 충분히 전달한다. 그러나 위의 if 구문에는 오류가 있고 members[]와 users[] 는 잘못된 인덱스를 사용하고 있다. 바로 알 수 있겠는가...? 인덱스가 정확히 사용되었다면 if문은 아래의 코드와 같아야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656324705421&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (clubs[i].members[j] == users[k]){}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;위와같이 i, j, k 를 인덱스로 사용한다면 무엇이 잘못됬는지 한눈에 알아보기 힘들다는 문제가 있다. 물론 예시와 같이 3중 반복문을 사용하는 일은 흔하지 않을 것이다. 사용되었다면 데이터 저장 구조가 잘못되었는지, 또는 더 나은 방법이 있는지 찾아야 할것이다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;그렇다면 이럴때에는 또는 반복문을 사용할때에는 인덱스의 이름을 어떻게하는게 좋을까..? 이럴 때는 더 명확한 의미를 드러내는 이름을 사용하면 도움이 된다. club_i, members_i, users_i 와 같이 말이다. 혹은 더 간결하게 ci, mi, ui 같은 이름을 사용하는 편이 좋은 선택이다. 변경된 코드를 살펴보자&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656325099329&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for (int ci = 0; ci &amp;lt; clubs.size(); ci++){
	for (int mi = 0; mi &amp;lt; clubs[ci].members.size(); mi++){
    		for (int ui = 0; ui &amp;lt; users.size(); ui++){
        	if (clubs[ci].members[mi] == users[ui]){
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;훨씬 가독성이 높고 좋은 코드가 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;추가적인 정보를 이름에 추가하기&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;앞서 말했듯이 변수의 이름은 작은 설명문이다. 충분한 공간은 아니지만, 이름안에 끼워 넣은 추가 정보는 변수가 눈에 보일 때마다 전달된다. 단위를 포함하는 값들을 통해 어떤 방법으로 더 좋은 변수명을 만들 수 있는지 살펴보자&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;간단한 예시 (단위를 포함하는 값들)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;첫 번째 코드&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656325995575&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Long start = new Date().getTime();
Long elapsed = new Date().getTime() - start;
log.info(&quot;Load time was: &quot; + elapsed + &quot; seconds&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;첫 번째 코드는 사실 특별한 오류를 발생시키는 코드는 아니다. 그러나 getTime() 이 초(second) 단위가 아니라 밀리초(millisecond) 단위를 반환하기 때문에 잘못된 결과를 출력한다. 이럴때에는 변수에 _ms 를 추가하여 단위를 명시해주면 모든 문제가 명확해진다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;두 번째 코드&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656326139194&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Long start_ms = new Date().getTime();
Long elapsed_ms = new Date().getTime() - start_ms;
log.info(&quot;Load time was: &quot; + elapsed_ms / 1000 + &quot; seconds&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;프로그래밍에는 시간뿐만 아니라 다른 단위도 자주 사용된다. 확실하게 구별해주도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;이름은 얼마나 길어야 하는가?&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;우리는 코드를 짤때 이름에 많은 정보를 담으면 좋겠지만 이름이 지나치게 길면 안 된다는 제한이 암묵적으로 존재한다.&amp;nbsp; 그 누구도 다음과 같이 이름을 사용하지 않을것이다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;ThatConvertsImageFilesAndVideoFiles&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;ServiceClass&lt;/span&gt; 이름이 길면 길수록 기억하기도 어렵고, 다음 줄로 코드가 넘어갈 수 있을 정도로 화면을 차지한다. 반면 너무 길어서는 안된다는 조언을 맹목적으로 받아들인 나머지 오직 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;단어 하나 혹은 문자 하나로 된 이름&lt;/span&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;길어도 안되고, 짧아도 안되고 변수는 정확한 용도에 따라 그때그때 판단해야 한다. 다행히도 판단에 도움이 될 만한 조언이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;좁은 범위에서는 짧은 이름이 괜찮다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656327320648&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (true){
    HashMap&amp;lt;String, Integer&amp;gt; m = new HashMap&amp;lt;&amp;gt;();
    m.put(&quot;map&quot;, 5);
    log.info(&quot;keyMap: &quot;+m.get(&quot;map&quot;));
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;다음과 같은 좁은 범위에서만 사용되는 변수의 이름에 많은 정보를 담을 필요가 없다. 즉, 변수의 타입이 무엇인지, 초기값이 무엇인지, 그것이 어떻게 사라지는지 등과 같은 변수가 담고 있는 모든 정보가 쉽게 한눈에 보이므로 짧은 이름을 사용해도 상관없다. 그러나 m이 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;전역변수로 사용된다면 어떨까?&lt;/span&gt;&amp;nbsp; m의 타입이나 목적이 드러나지 않으므로 코드의 가독성이 떨어질것이다. 즉, 좁은 범위에서는 많은 정보를 담을 필요가 없으나 전역변수로 사용될때에는 확실하게 변수명에 의미를 담아주자.&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: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;약어와 축약형&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;때때로 우리는 짧은 이름을 사용하기 위해 약어나 축약형을 사용한다. 예를들어 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;BackEndDeveloper 대신 BEDeveloper&lt;/span&gt; 라는 이름을 사용할 수 있을것이다. 그러나 이러한 축약은 나중에 혼란을 가져올지 모른다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;책 저자의 경험에 의하면 프로젝트에 국한된 의미를 가진 약어 사용은 좋은 생각이 아니라고 한다고 한다&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;.&lt;/span&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;따라서 가장 좋은방법은 팀에 새로 합류한 사람이 이름이 의미하는 바를 이해할 수 있는것이다. 예를 들어 프로그래머들 사이에서 흔히 사용하는 String 을 대신하는 str 또는 document 를 대신하는 doc 는 FormatStr() 이라는 함수를 보면 바로 의미하는 바를 알 수 있을것이다. 그러나 BEDeveloper의 의미는 이해할 수 없다.&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: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;불필요한 단어 제거하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;예를 들면 ConvertToString() 이라는 이름대신 ToString() 이라고 짧게 써도 실질적인 정보는 사라지지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;오해할 수 없는 이름들&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이름을 지을때에는 &quot;본인이 지은 이름을 다른사람들이 다른 의미로 해석할 수 있을까?&quot; 라는 질문을 던져보며 철저하게 확인해보아야 한다.&amp;nbsp;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656328507206&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;results = filter(yearList, 2022);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;위의 코드를보자. filter 메소드를 통해 무엇을 하는지 한눈에 이해가 되는가? 2022년만을 고른다는 것인지, 제거한다는 것인지 알 수 없다. 이럴때에는 results 라는 이름보다는 고를때에는 selectYear, 제거할때에는 excludeYear 이 훨씬 더 나은 이름이 될것이다.&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;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;한계를 설정하는 이름에는 한계를 표기해라.&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656328982301&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ITEM_IN_CARTS = 10;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위의 상수명을 한번 살펴보자. 위의 ITEM_IN_CART 를 봤을때에 CART에 담을수 있는 ITEM의 갯수가 최소 10 이라는걸까, 최대 10이라는 걸까? 한눈에 알수가 없다. 이럴때에는 다음과 같이 이름에 한계를 드러나게 해주자&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656329122703&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;MAX_ITEMS_IN_CART = 10;&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;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;불리언 변수에 이름붙이기.&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656329722153&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Boolean readPassword = true;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위의 코드는 읽은 방법에 따라서 두 가지 상반된 해석이 가능하다.&lt;/span&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;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;패스워드를 읽을 필요가 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;패스워드가 이미 읽혔다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 경우에는 read 라는 단어를 사용하지 않는 것이 최선이다. 대신 userIsAuthenticated(사용자가 인증되었습니다) 라는 단어를 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;미학&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;왠 미학...? 나는 미학이라는 제목을 보고 미학이 무슨상관이지 라는 생각을 했었는데 뒷장의 내용들을 보자마다 아...~ 라는 생각을 했다. 보기좋은 코드가 곧 읽기좋은 코드이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;다음과 같은 코드를 보자. 자 어떤 생각이 드는가?&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656345295263&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HashMap&amp;lt;String, String&amp;gt; jsonAdams = new HashMap&amp;lt;&amp;gt;();
jsonAdams.put(&quot;name&quot;, &quot;Mr.jsonAdams paris G Middle Smooth Names&quot;);
jsonAdams.put(&quot;age&quot;, &quot;25&quot;);
jsonAdams.put(&quot;ssn&quot;, &quot;97012314231423&quot;)

HashMap&amp;lt;String, String&amp;gt; GDragon = new HashMap&amp;lt;&amp;gt;();
GDragon.put(&quot;name&quot;, &quot;Mr.GDragon Sun Static Void Main&quot;);
GDragon.put(&quot;age&quot;, &quot;27&quot;);
GDragon.put(&quot;ssn&quot;, &quot;87012314231423&quot;);

HashMap&amp;lt;String, String&amp;gt; parisMillie = new HashMap&amp;lt;&amp;gt;();
parisMillie.put(&quot;name&quot;, &quot;Mr.parisMillie HashMaps Cool Guys&quot;);
parisMillie.put(&quot;age&quot;, &quot;28&quot;);
parisMillie.put(&quot;ssn&quot;, &quot;77012314231423&quot;);

HashMap&amp;lt;String, String&amp;gt; testAdams = new HashMap&amp;lt;&amp;gt;();
testAdams.put(&quot;name&quot;, &quot;testAdams&quot;);
testAdams.put(&quot;age&quot;, &quot;30&quot;);
testAdams.put(&quot;ssn&quot;, &quot;67012314231423&quot;);

assertEquals(jsonAdams.get(&quot;name&quot;), &quot;Mr.jsonAdams paris G Middle Smooth Names&quot;);
assertEquals(GDragon.get(&quot;name&quot;), &quot;Mr.GDragon Sun Static Void Main&quot;);
assertEquals(parisMillie.get(&quot;name&quot;), &quot;Mr.parisMillie HashMaps Cool Guys&quot;);
assertEquals(testAdams.get(&quot;name&quot;), &quot;testAdams&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;아.... 정말 지저분한 코드이다. 누가보라고 짠 코드야? 라는 생각이 들것이다.(개선되는 모습을 보여주기 위해 더 지저분한 코드를 짜고싶었지만 어떻게해야 더 지저분해질지 감이안왔다) 위와같은 코드는 미학적으로 만족스럽지 못한 코드이다. 어떤줄은 이름에 따라 너무 길고 또한, 아름답지 않고 일관성 있는 패턴도 결여되어있다. 위의 코드를 총 2번에 걸쳐 개선할건데 첫번째로는 메소드를 사용하여 위의 코드를 한번 개선하여보자.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;메소드를 활용하여 불규칙성 및 중복코드 제거하기&lt;b&gt;&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656346166747&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private HashMap&amp;lt;String, String&amp;gt; createUser(String name, String age, String ssn){
        HashMap&amp;lt;String, String&amp;gt; userInfo = new HashMap&amp;lt;&amp;gt;();
        userInfo.put(&quot;name&quot;, name);
        userInfo.put(&quot;age&quot;, age);
        userInfo.put(&quot;ssn&quot;, ssn);

        return userInfo;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1656345986648&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HashMap&amp;lt;String, String&amp;gt; jsonAdams = 
        createUser(&quot;Mr.jsonAdams paris G Middle Smooth Names&quot;, &quot;35&quot;, &quot;957488371837283&quot;);
HashMap&amp;lt;String, String&amp;gt; GDragon = 
        createUser(&quot;Mr.GDragon Sun Static Void Main&quot;, &quot;&quot;, &quot;&quot;);
HashMap&amp;lt;String, String&amp;gt; parisMillie = 
        createUser(&quot;Mr.parisMillie HashMaps Cool Guys&quot;, &quot;&quot;, &quot;957488371837283&quot;);
HashMap&amp;lt;String, String&amp;gt; testAdams = 
        createUser(&quot;testAdams&quot;, &quot;35&quot;, &quot;&quot;);

assertEquals(jsonAdams.get(&quot;name&quot;), &quot;Mr.jsonAdams paris G Middle Smooth Names&quot;);
assertEquals(GDragon.get(&quot;name&quot;), &quot;Mr.GDragon Sun Static Void Main&quot;);
assertEquals(parisMillie.get(&quot;name&quot;), &quot;Mr.parisMillie HashMaps Cool Guys&quot;);
assertEquals(testAdams.get(&quot;name&quot;), &quot;testAdams&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;createUser 메소드를 만들어 한번 개선한 코드이다. 중복되는 코드를 없애서 코드를 더욱 간결하게 하였고, 해당 메소드를 사용하여 또 다른곳에서 createUser을 사용할 수 있기때문에 새로운 테스트도 쉬워졌다. 나는 사실 여기까지면 꽤나 만족하는 코드라고 생각한다. 하지만 책에서는 도움이 된다면 코드의 열을 맞추는것도 추천한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;도움이 된다면 코드의 열을 맞춰라&lt;b&gt;&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656346435234&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HashMap&amp;lt;String, String&amp;gt; jsonAdams = 
        createUser(&quot;Mr.jsonAdams paris G Middle Smooth Names&quot;, &quot;35 &quot;, &quot;957488371837283&quot;);
HashMap&amp;lt;String, String&amp;gt; GDragon = 
        createUser(&quot;Mr.GDragon Sun Static Void Main         &quot;, &quot;&quot;   , &quot;&quot;);
HashMap&amp;lt;String, String&amp;gt; parisMillie = 
        createUser(&quot;Mr.parisMillie HashMaps Cool Guys       &quot;, &quot;&quot;   , &quot;957488371837283&quot;);
HashMap&amp;lt;String, String&amp;gt; testAdams = 
        createUser(&quot;testAdams                               &quot;, &quot;35 &quot;, &quot;&quot;);

assertEquals(jsonAdams.get(&quot;name&quot;), &quot;Mr.jsonAdams paris G Middle Smooth Names&quot;);
assertEquals(GDragon.get(&quot;name&quot;), &quot;Mr.GDragon Sun Static Void Main&quot;);
assertEquals(parisMillie.get(&quot;name&quot;), &quot;Mr.parisMillie HashMaps Cool Guys&quot;);
assertEquals(testAdams.get(&quot;name&quot;), &quot;testAdams&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;다음과 같이 코드의 열을 맞춘다면 createUser() 메소드에 주어지는 파라미터가 무엇인지 더욱더 쉽게 구별할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;의미 있는 순서를 선택하고 일관성 있게 사용하라&lt;b&gt;&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우리가 코드를 나열할때 또는 변수를 선언할때에 순서에 아무런 의미를 두지 않고 선언할때가 많다. 그러나 변수에도 순서를 두는것이 중요하다. 가장 중요한것에서 가장 덜 중요한 순서로 변수를 나열하고, 알파벳 순서대로 나열하여 일관성있는 방식으로 나열해야한다고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;코드를 문단으로 쪼개라&lt;b&gt;&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656347307015&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private monsterFamily(){
    family = monster.family();
    familyNumber = family.getFamilyNumber();
    bigHeightMonster = family.getBigHeightMonster();
    smallHeightMonster = family.getsmallHeightMonster();
    nonMonster = family.getPerson();
    nonMonsterName = nonMonster.getPersonName();
    log.info(family);
    log.info(familyNumber);
    log.info(bigHeightMonster);
    log.info(smallHeightMonster);
    log.info(nonMonster);
    log.info(nonMonsterName);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위의 코드는 뚜렷하게 드러나지는 않지만 구별되는 여러 단계를 거치고있다. 이런 코드들을 여러 문단으로 쪼개고 각 문단별로 주석처리를 해주면 다른 누군가 또는 미래의 내가 알아보기 쉬울 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656347468347&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private monsterFamily(){
    // 몬스터 패밀리의 총 가족인원수를 가져온다.
    family = monster.family();
    familyNumber = family.getFamilyNumber();
    
    // 몬스터 패밀리중 키가 큰 몬스터와 작은 몬스터를 가져온다.
    bigHeightMonster = family.getBigHeightMonster();
    smallHeightMonster = family.getsmallHeightMonster();
    
    // 몬스터 패밀리중 사람을 대려와 이름을 확인한다.
    nonMonster = family.getPerson();
    nonMonsterName = nonMonster.getPersonName();
    
    //각 결과들을 출력한다.
    log.info(family);
    log.info(familyNumber);
    log.info(bigHeightMonster);
    log.info(smallHeightMonster);
    log.info(nonMonster);
    log.info(nonMonsterName);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;코드를 문단별로 정리하니 가독성이 훨씬 높아졌다. (예시를 위한 코드입니다)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;개인적인 스타일 대 일관성&lt;b&gt;&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;코드를 짜다보면 사람마다 스타일이 다르고 팀마다 스타일이 다르다. 여러 강의와 다른사람들이 짠 코드들을 보다보면 개개인의 코드 스타일이 다르다는걸 쉽게 알수있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656347701106&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Person{

};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;위의 코드와 같이 짜는 사람이 있는 반면 아래의 코드와 같이 짜는 사람이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656347729185&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Person
{

};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;누구의 코드 스타일이 옳다고는 하지 못한다. 다만 일관성이 가장 중요하다. 한 프로젝트 내에서 모두가 다른 스타일로 코드를 짠다면... 생각만 해도 끔찍하다. 적어도 같은 프로젝트 내에서는 그 프로젝트의 코드 스타일을 따르자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;주석에 담아야하는 대상&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;주석의 목적은 코드를 읽은 사람이 코드를 작성한 사람만큼 코드를 잘 이해하게 돕는 데 있다. 이때에 어떤 주석을 달아야 가치가 있을지 살펴보자&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;코드에서 빠르게 유추할 수 있는 내용은 주석으로 달지 말라.&lt;b&gt;&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656362629856&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//앞에오는 내용의 뒤에 공백을 기준으로 새로운 내용을 합쳐준다.
String name = &quot;name&quot;.join(&quot; &quot;,&quot;Json private&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;기술적으로 볼때 이 코드는 이미 코드가 무슨일을할지 다 설명하고 있다. 주석에 새로운 정보라고 할 것이 없는것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;나쁜 이름에 주석을 달지말고 이름을 고쳐라.&lt;b&gt;&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이름으로 메소드 혹은 변수의 의미를 모르겠을때에는 주석으로 때울 생각을 하지말고 먼저 이름을 고치고 이후에 주석으로 상세한 설명을 덧붙여 주자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;자신의 생각을 기록하라.&lt;b&gt;&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;자신이 코드를 짜며 생각했던 것들을, 또 시험했던 것들을 적어놓는 것이다. 예를들어 이런 방식으로 코드를 짰을때에 어떠한 방식보다 속도가 ??% 정도 빠르다. 이렇게 짰을때에 어떠한 더 나은 결과를 나타낸다 등... 자신이 경험했던것들을 적어놓아 다른사람이 코드를 최적화하느라 시간을 허비하지 않게 도와준다.''&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;코드에 있는 결함을 설명하라.&lt;b&gt;&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;코드를 짜다보면 프로젝트의 일정상 시간이 촉박할 때가 있고, 그 과정가운데 버그를 갖게 될 요소가 생길 수 밖에 없다. 이러한 문제들이 있을때에는 몇가지 주석으로 문제를 표시해둘 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 117px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;표시&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;보통의 의미&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;TODO:&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;아직 하지 않은 일&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;FIXME:&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;오동작을 일으킨다고 알려진 코드&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;HACK:&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;아름답지 않은 해결책&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;XXX:&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 20px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;위험! 여기 큰 문제가 있다&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;TextMate&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;ESC&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;팀마다 이러한 표시들을 사용하는지, 언제 사용하는지 다를 수 있으나 자신의 생각을 담은 이러한 주석을 남기는것을 당연하게 생각해야 한다는 것이다. 주석은 코드의 질이나 상태 그리고 추후 개선 방법들을 제시하는 길이될수 있기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;주석 남기기를 두려워 하지 마라&lt;b&gt;&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;많은 프로그래머들이 주석을 남기는 것을 달가워하지 않는다고 한다. 좋은 주석을 달기 위해서 고민하는 시간들을 아깝게 생각하기 때문이라고 한다. 그러나 주석을 자주 남길수록 자신의 생각의 질이 향상되어 궁극적으로는 주석을 달 일이 많아지지 않을것이며, 꾸준히 달아둬야 나중에 한꺼번에 많은 분량의 주석을 달아야하는 일을 피할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;명확하고 간결한 주석 달기&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;코드의 의도를 명시하라&lt;b&gt;&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;간혹 주석을 달다보면 코드가 수행하는 동작을 그대로 설명하는 데 그치는 경우가 있다. 예를들어&lt;span style=&quot;background-color: #dddddd;&quot;&gt; // 리스트를 역순으로 반복한다. &lt;/span&gt;라던지. 이러한 주석들도 괜찮긴하나 다음과 같이 달아주면 더욱더 좋을거라고 상각한다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;// 몬스터를 키가 큰 값에서 낮은값 순으로 나타내준다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;이름을 가진 함수 파라미터 주석&lt;b&gt;&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&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-origin-width=&quot;584&quot; data-origin-height=&quot;39&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvXnpk/btrFWyopvdg/PmWrQk3LJHg2QgXgjxd2a1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvXnpk/btrFWyopvdg/PmWrQk3LJHg2QgXgjxd2a1/img.png&quot; data-alt=&quot;파라미터 주석&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvXnpk/btrFWyopvdg/PmWrQk3LJHg2QgXgjxd2a1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvXnpk%2FbtrFWyopvdg%2FPmWrQk3LJHg2QgXgjxd2a1%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; alt=&quot;파라미터 주석.JPG&quot; loading=&quot;lazy&quot; width=&quot;584&quot; height=&quot;39&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;39&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;위의 사진과같이 파라미터에 들어갈 값들에 어떤값들이 들어가야 하는지 주석을 달아주는 것이다. 그러나 요즘은 친절하게도 IntelliJ의 기능인지 자바에서 제공해주는 기능인지는 모르겠으나 다음 사진과같이 알아서 표기해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;471&quot; data-origin-height=&quot;24&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OtXfY/btrFWznlloe/25IJjejZobCIlgHw0L7Mb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OtXfY/btrFWznlloe/25IJjejZobCIlgHw0L7Mb0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OtXfY/btrFWznlloe/25IJjejZobCIlgHw0L7Mb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOtXfY%2FbtrFWznlloe%2F25IJjejZobCIlgHw0L7Mb0%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;471&quot; height=&quot;24&quot; data-origin-width=&quot;471&quot; data-origin-height=&quot;24&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;읽기 쉽게 흐름제어 만들기&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우리가 코드를 짤때에 if 문, for문 등 조건,루프, 흐름을 통제하는 코드가 없다면 매우 읽기 편할것이다. 그러나 빠질수 없는 요소이기에 코드에 존재하는 흐름제어를 최대한 읽기 쉽게만드는 방법을 알아보자.&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: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;조건문 인수의 순서&lt;b&gt;&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656365259068&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (length &amp;gt;= 20){}

if (20 &amp;lt;= length){}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;위 코드중 어떤것이 더 읽기 쉬울까? 아마 대부분의 개발자들은 첫번째 코드가 읽기 쉽다고 느낄것이다. 이와 관련하여 발견된 유용한 규칙이 있다고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;왼쪽&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;오른쪽&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;값이 더 유동적인 질문을 받는 표현&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;더 고정적인 값으로. 비교대상으로 사용되는 표현&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이러한 규칙은 다음 한국말과도 일치한다. &quot;초록색입니다. 풋사과는&quot; 라고 말하는것은 뭔가 부자연스럽다. 하지만 &quot;풋사과는 초록색입니다.&quot; 라고 말하는것은 자연스럽다. 이것과 같은 맥락이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;if/else 블록의 순서&lt;b&gt;&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;if/else 문의 블록의 순서를 생각해본적이 있는가? 사실 나는 한번도 생각해본적이 없으나 두가지중 어느 한 쪽을 선택해야 하는 몇가지 규칙이 있다고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656365917613&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (apple == greenApple){
	
} else {

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위의 코드를 다음과 같이 바꿀 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656366000796&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (apple != greenApple){
	
} else {

}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;부정이 아닌 긍정을 다루어라. 즉 if(!apple) 이 아닌 if(apple) 을 선호하자. 생각해보면 if 문을 사용할때에 if(!apple) 과도 같은 방식으로 되어있다면 !에 대해서 무엇을 부정한건지 한번쯤 살펴보게 된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;간단한 것을 먼저 처리하라&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;더 흥미롭고, 확실한 것을 먼저 다루어라&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;라는 규칙이 있다. 자신이 짠 if/else 문이 올바른 순서대로 작성되었는지 잘 확인하고 중복된 검사나 잘못된 검사를 피하자. 다들 if/else 문을 사용하며 한번씩 경험했었을 것이다. 순서만 잘 배치해도 더 간결해질 수 있는 상황이 있음을&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;삼항 연산자를 이용하는 조건문 표현&lt;b&gt;&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656366620222&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int minAge = 10;
int maxAge = 20;

int userAge = minAge &amp;lt; maxAge &amp;amp;&amp;amp; minNum != maxNum ? (minNum * 5) : (maxAge * 2)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;글의 시작점에서 만났던 코드이다. 분명 한줄로 모든걸 끝낼수 있으나 이 삼항 연산자는 두개의 값을 선택하는것에서 끝나는 것이 아닌 결과값에 계산까지 들어간 복잡한 문제이다. 이러한 코드는 if/else 문을 사용하는 것이 더욱 보기 편하다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656366733305&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int minAge = 10;
int maxAge = 20;
int userAge;

if(minAge &amp;lt; maxAge &amp;amp;&amp;amp; minNum != maxNum){
	userAge = minAge * 5;
}else{
	userAge = maxAge * 2;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;기본적으로 if/else 를 이용하길 바란다. 삼항연산자는 매우 간단할때에만 사용하길 추천한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;중첩을 최소화 하라&lt;b&gt;&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우리는 코드를 작성하다보면 if 문안에 if문 그리고 그안에 if문을 한번더 작성하는 사태를 초보시절에 한번쯤은 경험하게 된다. 코드의 중첩이 심할수록 이해하기 어려워지는 문제가 있고 위에서 어떠한 조건들을 지나서 왔는지 파악하기 힘들어진다. 다음은 사과가 잘 익었다면&amp;nbsp; 잘 익은 맛있는 사과를 리턴해주는 메소드입니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656367097866&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; if (apple.getName() != &quot;apple&quot;){	
    if (apple.getSize() &amp;gt; greenApple.getSize()){
        if (apple.getAppleStatus() == &quot;ripeApples&quot;){
        	return apple;
        }
    }else{
		return apple.setSize(greenApple.getSize() + 1);
    }
}else{
	return &quot;사과가 아닙니다.&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;다음과 같은 중첩되는 코드가 있다. 한눈에 알아보기 힘든 아주 잘못된 코드이다.(중첩이라는 상황을 위해 일부러 더욱더 평소에는 볼수조차 없는 지저분한 코드를 만들었다) 이런 코드들은 함수의 중간에서 반환하여 중첩을 최소화 해주자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656367434827&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (apple.getName() != &quot;apple&quot;){
     return &quot;사과가 아닙니다.&quot;; 
}

if (apple.getSize() &amp;lt; greenApple.getSize()){
   	return apple.setSize(greenApple.getSize() + 1);
}

if (apple.getAppleStatus() == &quot;ripeApples&quot;)){
     return apple;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;실패에 대한 경우들을 먼저 처리하고 다음 상황들을 정리할 수 있다. 코드가 훨씬 보기 좋아졌다 별거 아닌 내용인데 코드를 중첩시킨다면 정말 알아보기 힘든 코드가 되는 문제를 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;변수와 가독성&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 책에서는 변수를 엉터리로 사용하면 코드를 이해하기 힘들고 어려워진다고 말하며, 특히 3가지 문제가 있다고 한다.&lt;/span&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;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;변수의 수가 많을수록 기억하고 다루기 더 어려워진다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;변수의 범위가 넓어질수록 기억하고 다루는 시간이 더 길어진다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;변수값이 자주 바뀔수록 현재값을 기억하고 다루기가 더 어려워진다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;변수 제거하기&lt;b&gt;&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656368535734&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String appleStatus = apple.getStatus();
fruitsStatus.setApple(appleStatus);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;다음 코드는 사과의 상태를 과일상태에 set 해주는 상황이다. 그런데 이때에 appleStatus 변수가 꼭 필요할까?&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656368601705&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fruitsStatus.setApple(apple.getStatus());&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;전혀 appleStatus&amp;nbsp;변수가 필요하지 않으며 다음과 같이 한줄로 끝날수 있다. 물론 한 메소드 안에서 여러곳에서 중복되어 사용된다면 어딘가에 담아두는것이 좋다 그러나 그럴필요가 없다면 굳이 변수로 선언하지 않아도 된다.&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: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;변수의 범위를 좁혀라&lt;b&gt;&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우리는 변수의 범위를 최대한 좁혀야 할 필요가 있다. 개발을 하다보면 전역변수를 자제하라는 말을 한번씩은 들어봤을 것이다. 전역변수는 어디에서 어떻게 사용되는지 일일이 확인하기 어렵고, 지역변수의 이름과 중복이 되어 nameSpace가 더러워질 수 있다. 또한 어떠한 코드를 실행하다 지역 변수를 변경할 때 실수로 전역 변수를 변경하여 문제가 발생할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;값을 한번만 할당하는 변수를 선호하라&lt;b&gt;&lt;b&gt;✔&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이게 무슨말일까...? 간단하게 상수를 선호하라 라는 말이다. 변수의 값이 변하는 곳이 많을 수록 현재값을 추측하기가 어려워지는 문제가 있다. 그러나 상수로 할당해준다면 값이 변할리 없기에 개발자에게 추가적인 생각을 요구하지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1656369007578&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@PostMapping(&quot;/create-monster&quot;)
    public CreateMonsterDto.Response createMonster(
            @Valid @RequestBody final CreateMonsterDto.Request request
    ){
        return mMakerService.createMonster(request);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;다음과 같은 방식으로 request 로 받은 몬스터의 생성 정보는 final 로 선언하여 변경될 수 없게 만들어준다. 이후에는 값이 변할 일이 없기에 개발자는 추가적인 생각없이 편하게 작업을 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;한번에 하나씩&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;한 번에 하나의 작업만 수행하게 코드를 구성해야 한다. 왜냐하면 한번에 여러가지 일을 수행하는 코드는 이해하기가 어렵고, 코드 블록 하나에서 객체를 초기화하고, 업데이트하는 등 여러가지 작업이 뒤섞이면 코드를 이해하기 힘들것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;자바언어를 기반으로 생각해보자 우리는 Controller, Service 등... 각 레이어 별로 역할을 구분한다. 그리고 메소드를 만들때에 getDetailMonster() 라는 몬스터의 상세정보를 가져오는 기능을 만들면 만들었지 MonsterCreateAndUpdate() 라는 한번에 여러가지 일을 하는 메소드를 만들지는 않는다. 메소드당 하나의 작업을 수행하게 함으로써 함수 하나에서 행하는 일들을 줄이고 기능을 나눠 재활용성을 높이는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;테스트 친화적 개발&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;우리는 테스트에 익숙해져야 할 필요가 있다. 먼저 테스트를 함으로써 우리에 코드를 한번 더 생각할 수 있고, 앞으로 일어날 혹시모를 에러들을 예방할 수 있다. 테스트코드는 추후 유지보수 하기 쉽게 만들어야하며 복잡하게 만든다면 기능이 변경되어 테스트가 필요할때에 코드를 보기 싫은 상황이 올수 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 책을 읽으며 주니어 개발자인 글쓴이는 많은 도움이 되었다. 항상 코드를 짜며 변수명을 어떻게 지어야 좋을지 고민했고, 길이를 길게 해도될지에 대한 고민을 했었는데 고민에 대한 가닥을 어느정도 잡을수 있었고, 앞으로 더욱더 생각하는 개발을 할 초석을 만들어주었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이 책을 읽기 전까지는 개발하며 코드를 줄이는게 무조건 좋다는 생각에 삼항문을 열심히 사용하고, 반복문에 i, j 를 아무런 생각없이 신나게 사용했었는데 반성하는 시간을 갖게되었다. 이래서 책을 읽고 공부를 꾸준히 해야하나보다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/Read Book</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/15</guid>
      <comments>https://doosicee.tistory.com/entry/%EC%9D%BD%EA%B8%B0-%EC%A2%8B%EC%9D%80-%EC%BD%94%EB%93%9C%EA%B0%80-%EC%A2%8B%EC%9D%80-%EC%BD%94%EB%93%9C%EB%8B%A4#entry15comment</comments>
      <pubDate>Mon, 27 Jun 2022 20:56:09 +0900</pubDate>
    </item>
    <item>
      <title>그림으로 공부하는 IT 인프라 구조(리뷰 및 주요 개념 정리)</title>
      <link>https://doosicee.tistory.com/entry/%EA%B7%B8%EB%A6%BC%EC%9C%BC%EB%A1%9C-%EA%B3%B5%EB%B6%80%ED%95%98%EB%8A%94-IT-%EC%9D%B8%ED%94%84%EB%9D%BC-%EA%B5%AC%EC%A1%B0%EC%A0%95%EB%A6%AC</link>
      <description>&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;첫 회사에서는 Node.js를 기반으로 자바스크립트 언어를 사용해 웹 서버를 구성하고 MongoDB, RabbitMQ, Nginx를 사용하여 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;IOT 관제 및 제어 웹 사이트&lt;/span&gt;를 솔루션 프로그램으로 개발하게 되었습니다. 개발 이후에는 윈도우, 리눅스(우분투) 서버에 직접 배포해야 했고, 배포를 하러 다녔었습니다(현재도 다니는 중). 그래서 IT 인프라에 대한 기본적인 지식이 있으면 좋겠다는 생각을 하였고 &lt;b&gt;'&lt;span style=&quot;background-color: #dddddd;&quot;&gt;그림으로 공부하는 개정판 IT인프로 구조'&lt;/span&gt;라는&lt;/b&gt; 책을 스터디하게 되었습니다. 이 책을 읽고 모든 내용을 정리하지는 않았으나 최소한 &lt;b&gt;응용 소프트웨어 개발자로서 알아두면 좋을 정보들을 정리한 글입니다. &lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCcUAH/btrFf3bvipV/mMJNgegZWuwVCv4oAW6B80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCcUAH/btrFf3bvipV/mMJNgegZWuwVCv4oAW6B80/img.png&quot; data-alt=&quot;출처: SHOEISHA, Jpub(제이펍) / 책 구매후 직접찍은 사진&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCcUAH/btrFf3bvipV/mMJNgegZWuwVCv4oAW6B80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCcUAH%2FbtrFf3bvipV%2FmMJNgegZWuwVCv4oAW6B80%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; alt=&quot;그림으로 공부하는 개정판 IT 인프라 구조 이미지&quot; loading=&quot;lazy&quot; width=&quot;450&quot; height=&quot;600&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: SHOEISHA, Jpub(제이펍) / 책 구매후 직접찍은 사진&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;아키텍처 구조&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;아키텍처 구조란?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;쉽게 말해서 데이터를 처리하는 구조이다.(서버의 분산 등..)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;궁극의 아키텍처 구조를 사용할 수는 없을까?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;각 아키텍처마다 장단점이 있으며 궁극의 아키텍처라는 것이 있다면 좋겠지만 각 아키텍처 그리고 설계 요소에는 반드시 장점과 단점이 존재한다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;집약형 아키텍처&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;대형 컴퓨터를 이용하여 모든 업무를 처리하는 형태이다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;한 대의 대형 컴퓨터만 있으면 되므로 구성이 간단하다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;대형 컴퓨터의 리소스 관리나 이중화에 의해 안정성이 높고 고성능이다&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;대형 컴퓨터의 도입 비용과 유지 비용이 비싸다&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;확장성에 한계가 있다&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;분할형 아키텍처&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;여러 대의 컴퓨터를 조합해서 하나의 시스템을 구축하는 구조다.(서로가 연결되어 데이터를 교환한다)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;낮은 비용으로 시스템을 구축할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;서버 대수를 늘릴 수 있어서 확장성이 높다&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;대수가 늘어나면 관리 구조가 복잡해진다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;한 대가 망가지면 영향 범위를 최소화하기 위한 구조를 검토해야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;물리 서버와 논리 서버의 차이&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;분할형 아키텍처에서 이용되는 컴퓨터를 '서버'라고 한다. 서버라는 용어는 컴퓨터 자체를 가리키는 경우도 있고, 컴퓨터에서 동작하고 있는 소프트웨어를 가리키는 경우도 있다. 서버라는 용어는 원래 '특정 역할에 특화된 것'을 의미한다. 레스토랑의 웨이터를 서버라고 부르는 경우도 있다고 한다.(주문 접수나 음식을 내오는 것에 특화되어있고 요리는 하지 않기 때문이다)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;클라이언트-서버형 아키텍처&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;업무 애플리케이션, 미들웨어, 데이터베이스 등의 소프트웨어를 '물리 서버' 상에서 운영하고 있다. 클라이언트-서버형의 특징은 클라이언트 측에 전용 소프트웨어를 설치해야 한다는 것이다. 예를 들어 주식 판매 시스템은 그래프 표시나 주가 흐름 분석은 PC에서 하고, 필요에 따라 서버에서 주가 데이터를 취득하는 방식이 많다고 한다. 이 방식에서 서버 측은 데이터 입출력만 하면 되기에 처리당 부하가 낮아서 많은 pc 가 동시에 요청을 보내도 문제가 없다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;하지만 버그가 있을 수도 있고 개선사항이 있을 때마다 정기적으로 업데이트가 필요하다는 단점이 있다. 흔히 우리가 사용하는 애플리케이션들이 그러하다. 업데이트 내용을 적용시켜야 할 때는 플레이스토어로 강제 이동시켜 업데이트를 해야 들어갈 수 있는 경우가 있을 것이다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;클라이언트 측에서 많은 처리를 실행할 수 있어서 소수의 서버로 다수의 클라이언트를 처리할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;클라이언트 측의 소프트웨어 정기 업데이트가 필요하다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;서버 확장성에 한계가 발생할 수 있다.(클라이언트 PC의 한계)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;3계 층형 아키텍처&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;프레젠테이션 계층, 애플리케이션 계층, 데이터 계층의 3층 구조로 분할되어 있는 것이 3계 층형 아키텍처이다. 내가 잘 아는 MVC 패턴과도 같은 구조인 것 같다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;프레젠테이션 계층&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;사용자의 입력을 받는다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;웹 브라우저 화면을 표시한다&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;애플리케이션 계층&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;사용자 요청(Request)에 따라 업무 처리를 한다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;데이터 계층&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;애플리케이션 계층의 요청에 따라 데이터를 입출력을 한다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;서버 부하 집중 개선&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;클라이언트 단말의 정기 업데이트가 불필요&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;'처리 반환'에 의한 서버 부하 저감&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;구조가 클라이언트-서버 구성보다 복잡하다&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;수평 분할형 아키텍처&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;'수평 분할형 아키텍처'란 용도가 같은 서버를 늘려나가는 방식이다. 참고로 수직 분할형과 수평 분할형은 배타적인 관계가 아니며, 대부분의 시스템이 이 두 가지 방식을 함께 채택하고 있다. 예를 들자면 프레젠테이션 계층, 애플리케이션 계층, 데이터 계층 수직분할형 아키텍처와 같은 형태이나 서울, 부산, 대전 등 각 지역별로 서버를 나누는 것이다. 다른 지역의 정보를 알고 싶다면 그 지역의 시스템에 접속하여 확인하면 된다.&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;서울 -&amp;gt; 프레젠테이션 계층 -&amp;gt; 애플리케이션 계층 -&amp;gt; 데이터 계층(서울의 정보뿐이다)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;부산-&amp;gt; 프레젠테이션 계층 -&amp;gt; 애플리케이션 계층 -&amp;gt; 데이터 계층(부산의 정보뿐이다)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;수평으로 서버를 늘리기 때문에 확장성이 향상된다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;분할한 시스템이 독립적으로 운영되므로 서로 영향을 주지 않는다.(서울 쪽의 서버가 다운되더라도 부산의 서버는 멀쩡히 돌아갈 수 있다)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;데이터를 일원화해서 볼 수 없다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;애플리케이션 업데이트는 양쪽을 동시에 해 주어야 한다&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;처리량이 균등하게 분할돼 있지 않으면 서버별 처리량에 치우침이 생긴다.(사용하는 클라이언트의 수는 다른데 둘 다 서버 크기가 같아 많이 이용하는 쪽은 서버에 부하가 걸리고 조금 이용하는 곳은 서버가 놀게 되는 것이다)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;공유형 아키텍처&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;일반 기업 시스템이라면 아주 사이가 나쁘지 않은 한 서울과 부산에서 다른 애플리케이션을 이용하는 경우는 드물다. 공유형에서는 단순 분할형과 달리 일부 계층에서 상호접속이 이루어진다.(데이터 계층에서 서울과 부산의 데이터를 동기 처리)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;수평으로 서버를 늘리기 때문에 확장성이 향상된다&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;분할한 시스템이 서로 다른 시스템의 데이터를 참조할 수 있다&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;단점 &lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;분할한 시스템 간 독립성이 낮아진다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;공유한 계층의 확장성이 낮아진다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;직렬/병렬&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;직렬/병렬이란?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;간단한 예시로 3차선 도로와 1차선 도로를 생각할 수 있다. 1차선 도로는 직렬, 2차선 이상의 도로는 병렬이라고 볼 수 있는데, 이때에 1차선 도로의 요금소를 통과한다면 차가 밀릴 때는 줄줄이 대기하는 현상이 벌어질 것이다. 이때 도로를 3차선으로 나누고 요금소를 3개를 배치해준다면 1차선으로 요금소에 일을 처리하는 것보다 훨씬 수월해질 것이다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;병목현상이란?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;3차선 도로에서 요금소 3개를 배치하여 수월하게 일을 처리하던 도중 도로가 1개로 합쳐지는 합류점이 있고, 합류점의 1차선 구간은 사고가 발생하기 쉽다. 3차선의 차들이 모두 1개의 차선으로 들어가야 하기 때문이다. 1차선 구간은 전체 흐름을 느리게 만드는 원인으로 '병목지점(Bottleneck)'이 된다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;그렇다면 전부다 병렬 처리하면 되는 게 아닐까?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;처리 특성에 따라서 병렬화할 수 있는 것과 없는 것이 있다. 따라서 직렬 처리가 분기해서 병렬로 되거나, 다시 합류에서 직렬로 되기도 한다. 이 합류점, 직렬화 위치, 분기점이 병목 현상이나 문제가 발생하기 쉬운 지점이 된다. 병렬 처리를 할 때에는 가능 한 병렬화해서 직렬 부분을 줄이고, 어쩔 수 없이 직렬 화해야 하는 경우네는 효율성을 높이는 것이 중요하다. 또한 병렬화에서는 분담해서 일을 진행한 것을 한 곳에 모으는 데 오버헤드가 걸린다고 한다. 그렇기에 무리해서 병렬화하면 직렬 처리에 의해 속도가 느려지는 경우가 있다. 잘 파악해서 어떤 부분을 병렬화할지 파악하는 것이 중요하다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;병목 현상은 어떻게 해결할까?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;1. 병목 현상이 발생하고 있는 위치를 정확히 파악한다. 이를 위해서는 각 서버의 처리량이나 응답 상황 로그를 취득해서 어느 서버가 병목지점이 되고 있는지를 파악해야 한다. (3 계층의 그림을 그려가며 파악하는 것이 다른 사람과의 정보 공유도 되고 쉽고 빠르게 파악할 수 있다.)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;2. 병목 위치를 파악했다면 튜닝을 하는 것이다. 병목 위치를 더 작은 단위로 '세분화'해서 병목 영역을 더 '집중적으로' 파헤치는 접근법이 유효하다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;3. 또 다른 방법으로는 시스템의 이용자 수를 제한하는 것이다. 그렇게 해도 될까?라고 생각할 수 도 있지만, 이것은 유량 제어라는 이름이 붙어 있을 정도로 매우 직관적인 방법이라고 한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;유량제어란?&lt;/b&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;적절한 계층에서 이용자 수를 제한하는 접근법이다. 예를 들어, 일반적인 웹 시스템 등에서도 '해당 사이트는 트랙픽 초과로 차단되었습니다' 또는 티켓팅 시 대기인원 500명 남았습니다. 등 서버에 부하가 걸리지 않게 웹 서버 계층에서 유량 제어를 하는 것이다.&lt;/b&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;다만 메시지가 아닌 실제 에러 코드가 표기되는 경우가 있는데, 이것은 유량 제어가 실패해서 AP 서버나 DB 서버 계층의 어딘가에서 리소스가 최대치를 넘었기 때문에 에러라는 형태로 제어 결과를 표시하는 것이다.&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;4. 유량 제어를 했음에도 에러를 뱉어줄 경우 '수평분할(Sharding)'을 통해서 서버를 증설함으로써 시스템 전체 허용량을 늘리는 접근법을 병용할 필요가 있다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;병목 현상의 숙명의 적, 데이터베이스&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;사용자 측에서 유량 제어를 하지 않고 웹 서버 및 AP 서버를 늘리면 최종적으로는 DB 서버가 병목 지점이 되는 경우가 대부분이다. '파라미터만 바꾸면 빨라지는 거 아니야?'라고 말할 수 있지만 그런 마법과 같은 파라미터는 존재하지 않고, 이미 설계 시점에 설정이 끝난 상태이다. 그래서 튜닝 시점에는 애플리케이션 개발자의 협조가 반드시 필요하다고 한다. 개발은 협업이다 소통하며 개발하자.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;폴링이란?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;폴링(Polling)은 정기적으로 질의하는 것을 가리킨다. 정기적으로 질의함으로써 상대가 어떤 상태인지, 어떤 요구를 가지고 있는지 등을 알 수 있다. 웹 앱 개발자가 가장 이해하기 쉬운 예로는 배치시스템이다. 스케쥴링에 따라 정기적으로 데이터를 조회하여 일을 처리한다. 예를 들어 정기적으로 이메일 발송을 하는 것도 이러할 것이다. 비밀번호를 3개월마다 변경해야 하고 그것을 알려줄 메일을 발송해야 한다. 이럴 때에 배치 시스템을 사용하여 3개월마다 주기적으로 비밀번호 변경한 지 3개월이 지난 유저들을 체크하여 발송해주는 것이다.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;폴링의 특징&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;질의 방향이 단방향이다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;질의는 일정 간격을 따라 정기적으로 발생한다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;폴링의 주요 장점&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;반복(루프)만 하면 되기에 프로그래밍이 쉽다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;상대가 응답하는지 확인할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;모아서 일괄적으로 처리할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;계층구조&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;컴퓨터 세계에서는 많은 부분에서 계층 구조를 적용하고 있다. 이것 또한 모델, 뷰, 컨트롤러는 생각하면 쉬울 것이다. 뷰에서는 특정 url로 요청을 보낸다. 이후에 컨트롤러에서 받은 것을 서비스 계층으로 전달한다. 서비스 계층은 데이터 계층과 연결되어 있으며 자신의 역할에 따라 비즈니스 로직을 처리한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;계층구조는 왜 사용할까?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;계층 구조에서는 데이터나 기능 호출 흐름에 따라 계층 간 역할이 나누어진다는 특징이 있다. 역할이 나누어져 있기 때문에 각 층은 자신이 담당하는 일만 책임을 지며, 다른 일은 다른 계층이 책임을 진다. 상호 연결돼 있는 계층들에서는 교환 방법, 즉 인터페이스만 정해 두면 된다. 이 또한 모델, 뷰, 컨트롤러로 생각하면 쉬울 것이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;프로토콜&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;네트워크에 대해 언급할 때 빠트릴 수 없는 것이 프로토콜이다. 프로토콜은 영어로는 사전에 정해 놓은 순서를 의미한다. 컴퓨터가 서로 소통하기 위해 정한 규약을 가리킨다. 미국인과 한국인이 있고 이 둘은 서로의 언어밖에 모르는 상황이다 이때에 둘이 대화를 한다면 소통이 되지 않고 이것은 프로그램도 마찬가지이다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;컴퓨터의 거의 모든 곳에 프로토콜이 사용된다. 떨어진 곳에 있는 두 개의 장비는 사전에 절차를 정해 두지 않으면 서로 통신할 수 없다. 그래서 네트워크와 프로토콜은 떼려야 땔 수 없는 관계다. 우리가 흔히 사용하는 마우스 usb 또한 프로토콜이 존재한다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;인터넷 프로토콜 스택의 4 계층&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;애플리케이션 계층 - HTTP, FTP&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;전송 계층 - TCP, UDP&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;인터넷 계층 - IP&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;네트워크 인터페이스 계층&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;IP 인터넷 프로토콜&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;지정한 IP 주소에 데이터를 전달.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;패킷(패키지로 이해하면 된다)이라는 통신 단위로 데이터를 전달.(IP 패킷: 내 IP, 상대방의 IP를 담아준다)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;인터넷 망에서는 서버들이 다 이 규약을 따르고 있기 때문에 출발지와 도착지를 알아서 던져준다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;상대방에서 메시지를 잘 받은 후 받았다는 응답을 다시 보내주면 상대방이 잘 받은 것을 알 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;비연결성&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;패킷을 받을 대상이 없거나 서비스 불능 상태여도 패킷 전송 (상대의 서버가 꺼져있어도 확인하지 않고 보낸다)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;비신뢰성&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;중간에 패킷이 사라질 수 있다.(중간중간 많은 노드(서버)들을 경유하여 상대 서버에 도착하는데 중간서버에 문제가 발생하여 패킷이 소실되어도 알 수 없다)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;패킷이 순서대로 도착하지 않을 수 있는 문제가 있다.(패킷의 용량이 클 때가 있고 작을 때가 있는데 패킷의 용량이 약 1500 바이트가 넘어간다면 그것을 적당한 크기로 분할하여 보낸다. 그러나 이것이 노드를 타고 상대 서버로 보내질 때에 다른 노드를 타고 갈 수 있는데 순서가 다르게 도착할 수 있는 문제가 있다. 메인 메뉴와 디저트를 함께 보냈는데 사이즈가 너무 커서 분할되었고 디저트가 먼저 도착하고 이후에 메인 메뉴가 도착하는 문제가 발생할 수 있다는 것이다.)&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;프로그램 구분&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;같은 ip를 사용하는 서버에서 통신하는 애플리케이션이 둘 이상이라면? &lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;TCP/IP 프로토콜 (전송 제어 프로토콜)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;IP 프로토콜에는 전송 순서, 상대방이 잘 받았는지에 대한 검증에 대한 문제 등... 이 있었다. 그러나 TCP에서는 이것들을 해결해 준다. TCP 세그먼트라는 것에 출발지 PORT와, 목적지 PORT, 전송 제어, 순서, 검증 정보 등을 담아서 보내준다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;TCP의 특징&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;연결 지향 - TCP 3 way handshake(가상 연결)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;데이터 전달 보증&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;순서 보장&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;3 way handhaske 란?&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;클라이언트 측에서 SYN이라는 메시지를 보낸다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;상대측에서 잘 받았다고 ACK라는 메시지와 함께 연결해줘 라는 SYN을 다시 보내고&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;클라이언트에서 상대측이 보낸 메시지를 잘 받았다고 ACK와 함께 데이터를 상대측에 다시 보내준다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;상대측에서는 데이터를 잘 받았다는 메시지를 전송해준다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;데이터 전달 보증&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;IP 로만 데이터를 보낸다면 같은 IP를 사용하는 서버에서 통신하는 애플리케이션이 둘 이상이라면 문제가 될 것이다. 그렇기에 PORT 번호를 담아 보내서 구분하도록 한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;b&gt;순서 보장&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;패킷의 용량이 커서 분할하여 보낼 때 문제점은 서로 다른 노드로 이동하게 된다면 어떠한 순서로 도착할지 모른다는 것이었다. 그러나 패킷마다 순서(시퀀스 번호)를 달아주어 순서대로 받을 수 있게 보장해주는 것이다. 패킷 1, 패킷 2, 패킷 3 이 있고 1보다 2가 먼저 들어온다면 받은 상대측에서는 1을 다시 보내줘라고 메시지를 보내는 방식으로 순서를 보장한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;흐름 제어와 폭주 제어&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;데이터 보증을 시퀀스 번호와 ACK를 통해 처리하면 정말 장점이 많으나 이렇게 된다면 데이터를 보내고 ACK를 받기를 계속 기다리는 작업을 반복 처리하다 보면 시간이 많이 걸린다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;동기로 통신을 하면 효율이 나쁘기 때문에 ACK를 기다리지 않고 전송하는 것이 좋은데 TCP는 어느 정도의 세그먼트 수라면 ACK를 기다리지 않고 전송하는 윈도우 개념을 가지고 있으며, ACK를 기다리지 않고 전송 가능한 데이터 크기를 윈도우 크기라고 한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;폭주 제어는 무엇일까?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;송신 측 윈도우를 폭주 제어라고 부른다. 이 송신 측 윈도우 크기는 네트워크 폭주 상태(혼잡 상태)에 맞추어 변경시키기 대문이다. 네트워크가 혼잡하면 폭주 윈도우 크기를 작게 해서 전송 데이터 양을 줄인다. 이것이 폭주 제어다. TCP는 주변에 영향을 주지 않도록 자중하는 프로토콜이다. 만약 전송 프로토콜을 만든다면 무조건 성능이 좋고 빠르다고 좋은 것은 아니다. 주변 네트워크에 민폐를 끼치지 않고 잘 전달해 줄 수 있어야 한다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;네트워크 계층의 프로토콜 IP&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;IP의 역할은 간단히 말하자면, '지정한 대상 서버까지 전달받은 데이터를 전해 주는 것'이라 할 수 있다. 간단하지만 TCP/IP 중에서도 가장 중요한 기능이다. 단 IP에서는 반드시 전달을 보장하지 않는 점 그리고 IP 담당하는 기능은 중요하지만 그리 많지 않다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;IP의 중요한 기능&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;IP주소를 이용해서 최종 목적지에 데이터 전송&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;라우팅&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;라우팅이란?&lt;/b&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;송신 및 수신 시에 서버 내에서만 처리되는 TCP와 달리 IP는 경로 도중에 다양한 처리가 이루어진다. 라우팅도 그중 하나다. 더욱 쉽게 이해한다면 데이터를 전송할 때에 여러 노드(서버)를 거쳐서 전송한다고 하였는데 그 과정을 라우팅이라 하는 것이다.&lt;/b&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;데이터 전송 시 어떻게 최종 목적지의 IP주소가 있는 서버를 아는가?&lt;/span&gt;&lt;br /&gt;외부와 접속하는 네트워크는 보통 기본 게이트웨이(Default Gateway)라는 라우터가 설치돼 있다. 라우터와 서버는 자신이 알고 있는 목적지 정보를 라우팅 테이블(경로표)이라 하는 형태로 목록화하여 가지고 있다. 출발 서버에서 어느 곳으로 도착할지 모르기에 기본 게이트웨이로 보내주고 외부 네트워크와 접속된 게이트웨이는 라우팅 테이블에 따라 아는 범위 내에서 데이터를 전송해준다.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;패킷의 좀비화 &lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;IP 헤더는 TTL(Time To Live)이라는 생존 시간 정보를 가지고 있다. 예를 들어 TTL = 64부터 시작한다고 할 때 라우터를 하나씩 경유할 때마다 라우터가 IP 헤더의 TTL을 1 씩 줄여서 전송해준다. 경유할 때마다 64,63,62,61.... 0 이 되는데 0이 되는 시점에는 라우터가 패킷을 파기한다. 정상적으로 전송된 경우에는 64개나 라우터를 경유할 이유가 없기 때문이다. 만약 정해진 TTL 값이 없다면 패킷이 좀비가 되어 배회하고 다닐 것이다.&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;패킷 하나의 데이터는 총 1500 바이트를 전송할 수 있는데 TCP 헤더가 20바이트, IP 헤더가 20바이트를 사용하기 때문에 (TCP20 + IP20 = 40) 정확히 데이터는 총 1460 바이트를 전송할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;고갈되는 IP주소(Ipv4, Ipv6)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;IP 주소가 고갈된다는 이야기를 들어본 적은 없지만 어디선가 들린다고 한다. 2010년 이후부터 그 심각성이 부각되면서 다양한 대책이 논의됐다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;현재 사용되고 있는 IP는 Ipv4인데, 주소를 32비트로 표현하고 있다. 이 경우 약 43억 개의 IP 주소를 만들 수 있지만, 인터넷의 폭발적인 보급과 함께 43억 개의 주소가 거의 고갈돼 가고 있다. 이것을 보완하기 위한 간단한 방법은 IP 주소를 늘리는 것이다. IP 주소를 32비트에서 128비트로 늘리는 방법으로 문제를 해결하였다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;IPV6의 문제점&lt;/b&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;Ipv6는 Ipv4와 호환성을 가지고 있지 않다. Ipv4를 전제로 한 네트워크 장비나 애플리케이션은 Ipv6를 사용할 수 없다. 또한, 상호 통신을 하기 위해서는 기본적으로 웹 서비스 제공 측과 이용 측 쌍방이 Ipv6에 대응하는 네트워크 장비와 애플리케이션을 사용해야 한다. 그러나 2000년 전후로 사양 및 구현 방법이 소개된 Ipv6는 조금씩 Ipv6 대응 환경으로 바뀌어서 이제는 Ipv6를 사용할 준비가 거의 끝났다고 할 수 있다.&lt;/b&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;참고로 , Ipv4와 Ipv6가 호환성이 없다고 말했는데, TCP 및 그 윗단계의 HTTP는 양쪽 버전을 모두 지원하기 때문에 사용자는 Ipv4로 통신을 하고 있는지 Ipv6로 통신을 하고 있는지 의식할 필요가 없다.&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;참조 및 책 후기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;이 글은&lt;/b&gt; &lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;span style=&quot;background-color: #006dd7;&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;'&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;그림으로 공부하는 개정판 IT 인프라 구조' &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;를 읽고 응용 소프트웨어 개발자로서 알아두면 좋다고 생각되는 정보들을 정리한 글입니다. &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;이 책을 읽으며 몰랐던 개념들에 대해 많이 알게 되었다. 병목현상, 폴링, IPV4와 IPV6의 차이, TCP/IP 가 어떻게 동작하는지, 직렬/병렬 처리 등... 많은 내용을 더 자세히 알게 되어 좋았다. 이 책에는 이 외에도 더 많은 것을 담고 있고, 책에 나온 모든 내용을 이곳에 정리한 것은 아니다 프로세스, 스레드, 메모리, 캐시 등... 책에는 더 많은 내용들이 담겨있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; 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: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;서버직뿐만 아니라 웹 개발에 종사한다면 이 책을 한번 읽어보는 것을 추천한다. 그림으로 많은 내용들이 설명되어있어 글로만 보는 것보다 이해하기 쉽고 다가가기 쉽다고 느꼈다.&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;&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;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;스터디&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;이 책은 회사에서 사내 스터디를 하며 읽은 책이기에 아직은 둘 뿐이지만 정리한 내용을 스터디 멤버들에게 리뷰해주었다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t6GYK/btrFbNBx3Xe/niA1FYtzBfqAcCkoVTETW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t6GYK/btrFbNBx3Xe/niA1FYtzBfqAcCkoVTETW1/img.png&quot; data-alt=&quot;리뷰를 하고있는 글쓴이의 모습이다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t6GYK/btrFbNBx3Xe/niA1FYtzBfqAcCkoVTETW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft6GYK%2FbtrFbNBx3Xe%2FniA1FYtzBfqAcCkoVTETW1%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; alt=&quot;리뷰하는 글쓴이의 모습&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;533&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;회사에 갓 입사했을 때에 2달간의 공부 기간을 받았었다. 매주 배운 것을 발표하는 시간을 갖었었는데 실전 프로젝트에 투입되며 발표할 일이 없었는데, 아직은 둘 뿐이지만 사내 스터디로 진행하며 발표하니 목소리가 떨렸다. 실제로는 그림으로 설명하기 위해 칠판에 그려가며 설명했는데 사진은 한컷 뽑으려고 어정쩡한 자세와 함께 프로젝트 빔과 함께 찍었다ㅎㅎ.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/Read Book</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/14</guid>
      <comments>https://doosicee.tistory.com/entry/%EA%B7%B8%EB%A6%BC%EC%9C%BC%EB%A1%9C-%EA%B3%B5%EB%B6%80%ED%95%98%EB%8A%94-IT-%EC%9D%B8%ED%94%84%EB%9D%BC-%EA%B5%AC%EC%A1%B0%EC%A0%95%EB%A6%AC#entry14comment</comments>
      <pubDate>Mon, 20 Jun 2022 08:03:24 +0900</pubDate>
    </item>
    <item>
      <title>Required request body is missing, Argument(s) are different! Wanted</title>
      <link>https://doosicee.tistory.com/entry/SpringBoot-TestCode-Error-%EC%A0%95%EB%A6%AC</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;TDD, BDD에 대해 공부하면서 Error를 만나게 되었고 열심히 구글링을 하여 해결법은 찾았으나 그 원인까지는 설명해주지 않았기에 분석 후 정리를 한다. (오류의 정리이기 때문에 이 글에서는 TDD와 BDD에 대한 설명은 없습니다.)&lt;/b&gt;&lt;/span&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;오류 내용&lt;/b&gt;&lt;/h3&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;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. url: /create-monster, message: Required request body is missing&lt;/span&gt;&lt;/b&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. Argument(s) are different! Wanted, Actual&amp;nbsp;invocations&amp;nbsp;have&amp;nbsp;different&amp;nbsp;arguments&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;864&quot; data-origin-height=&quot;65&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8rkkx/btrEznotlfX/JhoZcrDEUTdSc8f54t3mpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8rkkx/btrEznotlfX/JhoZcrDEUTdSc8f54t3mpk/img.png&quot; data-alt=&quot;1. url: /create-monster, message: Required request body is missing&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8rkkx/btrEznotlfX/JhoZcrDEUTdSc8f54t3mpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8rkkx%2FbtrEznotlfX%2FJhoZcrDEUTdSc8f54t3mpk%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; alt=&quot;Required request body is missing&quot; loading=&quot;lazy&quot; width=&quot;864&quot; height=&quot;65&quot; data-origin-width=&quot;864&quot; data-origin-height=&quot;65&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1. url: /create-monster, message: Required request body is missing&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;885&quot; data-origin-height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bl8MGY/btrEvMwcVA8/hH47kwrrBujBdkPs9LGJR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bl8MGY/btrEvMwcVA8/hH47kwrrBujBdkPs9LGJR1/img.png&quot; data-alt=&quot;2. Argument(s) are different! Wanted, Actual&amp;amp;amp;nbsp;invocations&amp;amp;amp;nbsp;have&amp;amp;amp;nbsp;different&amp;amp;amp;nbsp;arguments&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bl8MGY/btrEvMwcVA8/hH47kwrrBujBdkPs9LGJR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbl8MGY%2FbtrEvMwcVA8%2FhH47kwrrBujBdkPs9LGJR1%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; alt=&quot;2. Argument(s) are different! Wanted&amp;amp;#44; Actual invocations have different arguments&quot; loading=&quot;lazy&quot; width=&quot;885&quot; height=&quot;196&quot; data-origin-width=&quot;885&quot; data-origin-height=&quot;196&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2. Argument(s) are different! Wanted, Actual&amp;amp;nbsp;invocations&amp;amp;nbsp;have&amp;amp;nbsp;different&amp;amp;nbsp;arguments&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1번 오류에 대한 정리(&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;url: /create-monster, message: Required request body is missing)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h4&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;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; background-color: #dddddd; color: #000000;&quot;&gt;&lt;b&gt;오류의 시작&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;- response 객체와 request 객체 (테스트에 공통으로 사용할 수 있게 인스턴스 변수로 선언)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1654903193243&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    private MonsterEntity responseMonster = MonsterEntity.builder()
            .id(1L)
            .monsterLevel(BABY)
            .monsterType(FLY)
            .statusCode(StatusCode.HEALTHY)
            .ssn(&quot;12345612345123&quot;)
            .name(&quot;BabyMonster&quot;)
            .age(3)
            .height(170)
            .weight(73)
            .build();

    private CreateMonsterDto.Request getCreateRequest(){
                return CreateMonsterDto.Request.builder()
                        .id(1L)
                        .monsterLevel(BABY)
                        .monsterType(FLY)
                        .statusCode(StatusCode.HEALTHY)
                        .ssn(&quot;12345612345123&quot;)
                        .name(&quot;BabyMonster&quot;)
                        .age(3)
                        .height(170)
                        .weight(73)
                        .build();
    }&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- 실행 코드(Controller)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1654903073533&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Test
    @DisplayName(&quot;Monster Created Test&quot;)
    void createMonster() throws Exception{
        // given
        given(mMakerService.createMonster(getCreateRequest()))
                .willReturn(CreateMonsterDto.TestResponse.fromEntity(responseMonster));

        // when
        CreateMonsterDto.Response result = mMakerService.createMonster(getCreateRequest());

        // then
        mockMvc.perform(
                        post(&quot;/create-monster&quot;)
                                .contentType(contentType)
                                .content(new ObjectMapper().writeValueAsString(result)))
                .andExpect(status().isOk())
                .andDo(print())
                .andReturn();
    }&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;- MMakerService.createMonster (Service)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;vbscript&quot;&gt;&lt;code&gt;public CreateMonsterDto.Response createMonster(
        CreateMonsterDto.Request request
){
    validateCreateMonsterRequest(request);

    return CreateMonsterDto.Response.fromEntity(
            monsterRepository.save(
                    createMonsterFromRequest(request)
            )
    );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;위의 코드들은 몬스터를 생성하는 테스트 코드이다. 내가 원했던 결과는 Request로 보낸 데이터를 Response로 잘 응답받는 것이었다.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1654903612456&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    요청)
    MockHttpServletRequest:
                  Body = null&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1654903654894&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  응답)
        MockHttpServletResponse:
                   Status = 200
            Error message = null
                  Headers = []
             Content type = null
                     Body =
            Forwarded URL = null
           Redirected URL = null
                  Cookies = []&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그런데&amp;nbsp; 저 코드를 실행하니 Request, Response의 body에는 아무런 데이터가 실려있지 않았다. ExceptionHandler는 message: Required request body is missing 다음과 같은 메시지를 뱉어주고 있었다. 나는 분명 데이터를 넣어서 보내줬는데 뭐가 문제인 걸까...?&lt;/span&gt;&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;&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;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;원인 파악&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;잠깐! 원인 파악 과정 도중 알게 된 내용&lt;br /&gt;&lt;br /&gt;어떠한 함수가 실행 됐을 때에 어떤 데이터를 응답해줄지 가정해둔 given의 createMonster 메서드에서 받는 매개변수와&lt;br /&gt;실행 함수가 정의된 when에서 createMonster 메서드의&lt;span style=&quot;background-color: #dddddd;&quot;&gt; &quot;매개변수의 내용물이 같아야 한다.&quot;&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;엥?&lt;span style=&quot;background-color: #dddddd;&quot;&gt; &quot;매개변수의 내용물이 같아야 한다.&quot;&lt;/span&gt; 이 말은 무슨 말일까? &lt;span style=&quot;background-color: #dddddd;&quot;&gt;given의 getCreateRequest(). name = '괴물감자'&lt;/span&gt; 가 들어있는데, &lt;span style=&quot;background-color: #dddddd;&quot;&gt;when 의 getCreateRequest().name = '괴물 고구마'&lt;/span&gt;가 들어있어서는 안 된다는 말이다. 내용물(값)이 같아야 한다.&lt;br /&gt;- given: given(mMakerService.createMonster(getPotato())) 의 getPotato().name = '괴물감자 &lt;br /&gt;- when: mMakerService.createMonster(getPotato()) 의 getPotato().name = '괴물감자'&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사실 생각해보면 당연한 내용이다.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;어떠한 함수가 매개변수를 받아 어떤 행위를 할지 정의하였고(given)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;given(mMakerService.createMonster(obj.name = 괴물고구마))
                     .willReturn(CreateMonsterDto.TestResponse.fromEntity(responseMonster));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;어떠한 함수를 실행시킨다(when)&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;mMakerService.createMonster(obj.name = 괴물감자);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;-&amp;nbsp;given&amp;nbsp;:&amp;nbsp;어떠한&amp;nbsp;데이터가&amp;nbsp;준비되었을때.&amp;nbsp;즉,&amp;nbsp;Mock객체가&amp;nbsp;특정&amp;nbsp;상황에서&amp;nbsp;어떤&amp;nbsp;행위를&amp;nbsp;해야할지&lt;br /&gt;-&amp;nbsp;when:&amp;nbsp;어떤&amp;nbsp;함수를&amp;nbsp;실행할지&lt;br /&gt;-&amp;nbsp;then:&amp;nbsp;어떤&amp;nbsp;결과를&amp;nbsp;내놓는다&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;어떤 함수를 실행시킬 때 매개변수 Obj.name 값으로 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;괴물 감자를&lt;/span&gt; 넣어줬으면서&amp;nbsp; 그 함수가 해야 할 행위에는 매개변수 &lt;b&gt;Obj.name &lt;/b&gt;값으로 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;괴물 고구마를&lt;/span&gt; 넣어주는 것은 말이 안 되는 것이다.&lt;/b&gt; &lt;br /&gt;&lt;b&gt;(&lt;span style=&quot;background-color: #dddddd;&quot;&gt;obj.name = 괴물감자&lt;/span&gt; 는 매개변수로 넘어간 obj 안에 값이 저렇게 들어있다고 쉽게 설명하기 위해 저렇게 표기해둔 것이다.)&lt;br /&gt;&lt;br /&gt;또한 리턴 값도 마찬가지다. willReturn()에 리턴되는 값으로는 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;&quot;현재 테스트 코드 상에서는&quot;&lt;/span&gt; Request로 넘겨준 값들을 반환해줘야 한다. Request로 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;괴물 감자를&lt;/span&gt; 보내주었고, &lt;span style=&quot;background-color: #dddddd;&quot;&gt;괴물 감자를&lt;/span&gt; save&amp;nbsp; 하였다.&amp;nbsp; save 이후 저장한 객체를 다시 return 하여 되돌려 받았을 때 응답 즉, Response에서 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;괴물 호박&lt;/span&gt; 이 나오는 건 말이 안 된다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;감자를 저장했는데 호박이 나온 것&lt;/span&gt;이다...&lt;br /&gt;&lt;br /&gt;(주니어 개발자가(6개월 차) 구글링을 통해, 그리고 테스트를 하며 깨달은 것이므로 분석이 정확하지 않을수도 있다.)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;위의 원인 파악 과정 도중 알게 된 내용을 다 읽어봤다면 아래의 내용을 보자마자 바로 원인을 알 수 있을 것이다.&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: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;@ToString 을 사용했을때 &lt;/span&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;CreateMonsterDto.Request(id=1, monsterLevel=BABY, monsterType=FLY, statusCode=HEALTHY, ssn=96050311082045, name=애기몬스터, age=3, height=170, weight=73) &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;@ToString 을 사용하지 않았을때&lt;/span&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;com.fc_study.monsterGrowth.dto.CreateMonsterDto$Request@61911947 &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;new ObjectMapper().writeValueAsString(getCreateRequest()) 를 사용했을때 (Json 타입으로의 변환)&lt;/span&gt;&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp;:&amp;nbsp;{&quot;id&quot;:1,&quot;monsterLevel&quot;:&quot;BABY&quot;,&quot;monsterType&quot;:&quot;FLY&quot;,&quot;statusCode&quot;:&quot;HEALTHY&quot;,&quot;ssn&quot;:&quot;96050311082045&quot;,&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&quot;name&quot;:&quot;애기몬스터&quot;,&quot;age&quot;:3,&quot;height&quot;:170,&quot;weight&quot;:73}&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;@ToString을 사용하지 않았을 때의 결괏값을 본다면 객체의 주소 값(CreateMonsterDto$Request@61911947)을 반환해 주는 것을 볼 수 있다.&amp;nbsp; 즉, 객체의 내용물을 비교해야 하는데 주소 값을 비교하기 때문에 문제가 되고 있다고 생각해볼 수 있었고. 위의 원인 파악 과정 도중 알게 된 내용인 &lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&quot;매개변수의 내용물이 같아야 한다.&quot;가&lt;/span&gt; 성립되지 않는 것이다. 물론 매개변수로 넘겨진 객체 안의 내용물들은 똑같다 그러나 매개변수로 보내진 객체의 주소가 다르고, 객체의 주소로 비교했기 때문에 null을 반환한 것이다.&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;/b&gt;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;b&gt;값을 꺼내서 비교하지않고 객체끼리 비교했을때 어떤결과가 나오는지 살펴보자.&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1152&quot; data-origin-height=&quot;231&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZYXil/btrEwjURqet/ktdHeQ9IDBSUoNv1Nycpk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZYXil/btrEwjURqet/ktdHeQ9IDBSUoNv1Nycpk1/img.png&quot; data-alt=&quot;getCreateRequest() 객체의 내용물 비교&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZYXil/btrEwjURqet/ktdHeQ9IDBSUoNv1Nycpk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZYXil%2FbtrEwjURqet%2FktdHeQ9IDBSUoNv1Nycpk1%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; alt=&quot;getCreateRequest 내용물 비교&quot; loading=&quot;lazy&quot; width=&quot;1152&quot; height=&quot;231&quot; data-origin-width=&quot;1152&quot; data-origin-height=&quot;231&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;getCreateRequest() 객체의 내용물 비교&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1457&quot; data-origin-height=&quot;43&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SsP7A/btrEwjUQ6Nk/wOije3XZNoJTKQcBTXAeR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SsP7A/btrEwjUQ6Nk/wOije3XZNoJTKQcBTXAeR1/img.png&quot; data-alt=&quot;log.info(&amp;quot;compare1 : &amp;quot;+ (getCreateRequest().equals(getCreateRequest())));&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SsP7A/btrEwjUQ6Nk/wOije3XZNoJTKQcBTXAeR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSsP7A%2FbtrEwjUQ6Nk%2FwOije3XZNoJTKQcBTXAeR1%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;1457&quot; height=&quot;43&quot; data-origin-width=&quot;1457&quot; data-origin-height=&quot;43&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;log.info(&quot;compare1 : &quot;+ (getCreateRequest().equals(getCreateRequest())));&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;getCreateRequest().equals(getCreateRequest())&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;코드는 다음과 같이 비교하였고, 분명 내용물이 같은 객체인데 false가 나온다... 근데 잘 살펴보면 그냥 getCreateRequst()를 비교했을때에는 객체의 주소가 나온다.&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;First:&amp;nbsp;com.fc_study.monsterGrowth.dto.CreateMonsterDto$Request@221ca495&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Second:&amp;nbsp;com.fc_study.monsterGrowth.dto.CreateMonsterDto$Request@119d4443&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;그렇다면 안의 값을 꺼내서 한번 비교를 해보자.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;41&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xcbf3/btrEvMCY9e7/7hW6yH5p6c7j2fn4kYMWK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xcbf3/btrEvMCY9e7/7hW6yH5p6c7j2fn4kYMWK1/img.png&quot; data-alt=&quot;log.info(&amp;quot;compare2 : &amp;quot;+ (getCreateRequest().getId().equals(getCreateRequest().getId())));&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xcbf3/btrEvMCY9e7/7hW6yH5p6c7j2fn4kYMWK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxcbf3%2FbtrEvMCY9e7%2F7hW6yH5p6c7j2fn4kYMWK1%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;948&quot; height=&quot;41&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;41&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;log.info(&quot;compare2 : &quot;+ (getCreateRequest().getId().equals(getCreateRequest().getId())));&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&gt;getCreateRequest().getId().equals(getCreateRequest().getId())&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;코드는 다음과 같이 비교하였고, 값을 꺼내서 비교해주니 true 가 나온다. 당연한 결과이다 1 == 1 같냐고 묻는것이다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;해결방법&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;해결방법은 2가지가 있었다.&lt;/span&gt;&lt;/b&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. &lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;@EqualsAndHashCode&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. org.mockito.ArgumentMatchers.any();&lt;/span&gt;&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;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;해결방법 1: 첫 번째 방법으로는 @EqualsAndHashCode 어노테이션을 사용하는 것이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;u&gt;&lt;b&gt;매개변수로 넘어가는 CreateMonsterDto.Request의 어노테이션으로 달아주면 된다.&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;@EqualsAndHashCode Annotation 이란?&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;@EqualsAndHashCode 어노테이션은 equals 와 hashcode 를 자동으로 생성해주는 어노테이션 입니다. @ToString 어노테이션과 마찬가지로 exclude 파라미터로 필드를 제외하거나 callSuper 파라미터로 부모 객체를 생략하거나 포함할 수 있습니다.&lt;br /&gt;&lt;br /&gt;- equals : 두 객체의 내용이 같은지, 동등성(equality)를 비교하는 연산자입니다.&amp;nbsp;&lt;br /&gt;동등성 : 객체의 값이같다. 동등성은 변수가 참조하고 있는 객체의 주소가 서로 다르더라도 내용만 같으면 두 변수는 동등하다고 이야기 할 수 있다.(equals 연산자로 파악가능)&lt;br /&gt;&lt;br /&gt;- hashcode : 두 객체가 같은 객체인지, 동일성(identity)를 비교하는 연산자입니다. &lt;br /&gt;동일성 : 객체의 주소가 같다. 주소값이 같기 때문에 두 변수가 있다면 같은 객체를 바라본다.(== 연산자)&lt;/b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;equals와 hashcode를 자동으로 생성해준다고 한다. 현재 문제가 되는 것은 주소 값을 비교하기 때문에 문제가 되는것인데 동등성(equals)를 보면 이렇게 적혀있다. &quot;동등성은 변수가 참조하고 있는 객체의 주소가 서로 다르더라도 내용만 같으면 두 변수는 동등하다고 이야기 할 수있다.&quot; 라고. 주소값을 비교하기 때문에 문제가 되었는데 @EqualsAndHashCode를 사용하여 객체 안의 내용물을 비교하여 문제가 해결되었다.(RequestDto 에 붙여주면 된다)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;@EqualsAndHashCode를 그냥 사용하게 되면 서로 다른 연관관계를 순환 참조하느라 무한루프가 발생하게 되고, 결국 스택 오버 플로우가 발생하기 때문에 id 값만 주로 사용한다. @EqualsAndHashCode(of = &quot;id&quot;)&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;exclude : 제외시킬 변수명&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;of : 포함시킬 변수명&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;callSuper : 상위 클래스 호출 여부 물음&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;doNotUseGetters : getter 사용 여부&lt;/b&gt;&lt;/span&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;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;해결방법 2: 두 번째 방법으로는 &lt;b&gt;org.mockito.ArgumentMatchers.any(); 메서드를 사용하는 것이다.&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;any() 란?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;any() : 모든 매개 변수에 대하여 같은 행동을 하는 Mock 객체를 만들 수 있다.&lt;br /&gt;&lt;br /&gt;Mock 이란?&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;실제 객체를 다양한 조건으로 인해 제대로 구현하기 어려울 경우 가짜 객체를 만들어 사용하는데, 이를 Mock 객체라 한다.&lt;br /&gt;&lt;br /&gt;MockObject (Mock 객체)란?&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;- 행위를 검증하기 위해 사용되는 객체를 지칭하며 수동으로 만들 수도 있고 프레임워크를 통해 만들 수 있다. &lt;/b&gt;&lt;br /&gt;&lt;b&gt;- 행위 기반 테스트는 복잡도나 정확성 등 작성하기 어려운 부분이 많기 때문에 상태 기반 테스트가 가능하다면 만들지 않는다. &lt;/b&gt;&lt;br /&gt;&lt;b&gt;- Mock 객체는 테스트 더블 하위 객체로 써의 좁은 의미와 테스트 더블을 포함한 넓은 의미 2가지로 사용될 수 있다.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;언제 사용해야 할까?&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;- 테스트 작성을 위한 환경 구축이 어려운 경우&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;- 테스트가 특정 경우나 순간에 의존적인 경우&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;- 시간이 걸리는 경우&lt;br /&gt;&lt;br /&gt;유의사항&lt;br /&gt;1. Mock 프레임워크가 정말 필요한지 확인한다. Mock을 사용하는 경우 테스트 케이스 유지에 복잡성이 더해지기 때문에 Mock이 없는 의존성 적은 구조로 프로그래밍한다. &lt;br /&gt;2. 어떤 Mock 프레임워크를 사용하느냐는 핵심 문제가 아니다. 어떤 프레임워크를 사용하느냐에 따라 테스트 케이스 작성에 커다란 영향이 미치지 않는다. 단지 익숙해지기까지 시간이 필요할 뿐이다.&lt;br /&gt;3. Mock 객체는 Mock 일 뿐이다. 실제 객체로 작동을 해보았을 때 잘 작동하지 않을 수도 있다. Mock 객체는 흉내를 내는 객체이기 때문이다.&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;실행할 함수(when)와 함수의 실행행위를 정의(given)할 때 넘겨주는 매개변수의 내용물이 아닌 주소 값으로 비교하여 문제가 되었었는데 가짜 객체를 만들어 사용함으로써 문제가 해결되었다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;밑의 코드는 현재 글의 시작 부분에 있는 테스트 코드에 매개변수를 Mock 객체로 대체한 모습이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;    @Test
    @DisplayName(&quot;Monster Created Test&quot;)
    void createMonster() throws Exception{
        // given
        given(mMakerService.createMonster(any()))
                .willReturn(CreateMonsterDto.TestResponse.fromEntity(responseMonster));

        // when
        CreateMonsterDto.Response result = mMakerService.createMonster(any());

        // then
        mockMvc.perform(
                        post(&quot;/create-monster&quot;)
                                .contentType(contentType)
                                .content(new ObjectMapper().writeValueAsString(result)))
                .andExpect(status().isOk())
                .andDo(print())
                .andReturn();
    }&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2번 오류에 대한 정리(&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Argument(s) are different! Wanted,&amp;nbsp; Actual&amp;nbsp;invocations&amp;nbsp;have&amp;nbsp;different&amp;nbsp;arguments&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; background-color: #dddddd;&quot;&gt;&lt;b&gt;오류의 시작&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; background-color: #dddddd;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;일단 코드부터 확인해보자&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;@Test
@DisplayName(&quot;Monster Created Test&quot;)
void createMonster() throws Exception{
    // given
    given(mMakerService.createMonster(any()))
            .willReturn(CreateMonsterDto.TestResponse.fromEntity(responseMonster));

    // when
    CreateMonsterDto.Response result = mMakerService.createMonster(any());

    // then.
    mockMvc.perform(
                    post(&quot;/create-monster&quot;)
                            .contentType(contentType)
                            .content(new ObjectMapper().writeValueAsString(result)))
            .andExpect(status().isOk())
            .andDo(print())
            .andReturn();
            
    then(mMakerService).should(times(2)).createMonster(getCreateMonster());
}&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;1번 에러의 테스트 코드에서 한 줄이 추가되었다. then(mMakerService). should(times(2)). createMonster(getCreateMonster()); 해당 메서드가 몇 번 실행되었는지 검증하는 코드이다. 2번 에러는 해당 코드에서 발생하였고 간단한 문제였다.&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;Argument(s) are different! Wanted&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;주장이 다릅니다!&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;Actual invocations have different arguments&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;실제 호출에는 다른 인수가 있습니다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;given과 when에서는 any()(Mock 객체)를 사용해놓고 then 검증과정에서는 getCreateMonster()을 사용했으니 문제가 됐었던 것이다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000; background-color: #dddddd;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;해결방법&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;given(mMakerService.createMonster(any()))
        .willReturn(CreateMonsterDto.TestResponse.fromEntity(responseMonster));

// when: 어떠한 함수를 실행하면
CreateMonsterDto.Response result = mMakerService.createMonster(any());

// then: 어떠한 결과가 나와야 한다.
mockMvc.perform(
                post(&quot;/create-monster&quot;)
                        .contentType(contentType)
                        .content(new ObjectMapper().writeValueAsString(result)))
        .andExpect(status().isOk())
        .andDo(print())
        .andReturn();
then(mMakerService).should(times(2)).createMonster(any());&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;다음과 같이 테스트 코드에서 사용하는 매개변수들을 any()로 같이 사용하거나 아래와 같이 getCreateRequest(); 로 사용하면 된다. getCreateRequest(); 를 사용할 때는 @EqualsAndHashCode를 사용해야 함을 잊지 말자&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;given(mMakerService.createMonster(getCreateRequest()))
        .willReturn(CreateMonsterDto.TestResponse.fromEntity(responseMonster));

// when: 어떠한 함수를 실행하면
CreateMonsterDto.Response result = mMakerService.createMonster(getCreateRequest());

// then: 어떠한 결과가 나와야 한다.
mockMvc.perform(
                post(&quot;/create-monster&quot;)
                        .contentType(contentType)
                        .content(new ObjectMapper().writeValueAsString(result)))
        .andExpect(status().isOk())
        .andDo(print())
        .andReturn();
then(mMakerService).should(times(2)).createMonster(getCreateRequest());&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;문제는 해결되었으나 아직은 어떤 방법을 사용하는 게 더 나은 방법인지 모르겠다. Mock객체로 해결하는 방법이 좋은지 @EqualsHashCode로 해결하는 게 좋은지...&amp;nbsp; 내가 모르는 또 다른 해결 방법도 분명 있을 것이다. 앞으로도 테스트 코드를 계속 짜고 많은 글과 강의, 다른 사람들의 코드를 보며 꾸준히 성장해서 알게 되길 바란다.&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: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;이 글은 주니어 개발자(6개월 차)가 강의를 보고 복습하며 발생된 에러를 구글링과 디버깅을 통해 해결한 것이므로 좋은 방법이 아닐 가능성이 높습니다. &lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;참고만 해주시고 더 좋은 방법이 있으시다면, 또는 더 좋은 테스트 방법에 대해서 조언해주시면 감사하겠습니다 :)&lt;/b&gt;&lt;/span&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;해당 복습 내용에 대한 코드가 있는 GitHub 주소&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://github.com/Doosic/monsterGrowth&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/Doosic/monsterGrowth&lt;/a&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654914808444&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - Doosic/monsterGrowth: 강의내용 복습 및 정리&quot; data-og-description=&quot;강의내용 복습 및 정리. Contribute to Doosic/monsterGrowth development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/Doosic/monsterGrowth&quot; data-og-url=&quot;https://github.com/Doosic/monsterGrowth&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b2aeVd/hyOJw2aTw7/j83I7IMaKG2FK1FD6kmjBK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/Doosic/monsterGrowth&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/Doosic/monsterGrowth&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b2aeVd/hyOJw2aTw7/j83I7IMaKG2FK1FD6kmjBK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - Doosic/monsterGrowth: 강의내용 복습 및 정리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;강의내용 복습 및 정리. Contribute to Doosic/monsterGrowth development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;참고했던 블로그들&lt;/span&gt;&lt;/b&gt;&lt;/h3&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;a title=&quot;Mokito란?&quot; href=&quot;https://scshim.tistory.com/439&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Mokito란?&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;@EqualsAndHashCode&quot; href=&quot;https://seulog.netlify.app/SpringBoot/Entity/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@EqualsAndHashCode&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;동등성과 동일성&quot; href=&quot;https://steady-coding.tistory.com/534&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;동등성과 동일성&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;순환참조는 뭐가 문제일까?&quot; href=&quot;https://siyoon210.tistory.com/170&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;순환 참조는 뭐가 문제일까?&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;Mock개념&quot; href=&quot;https://www.crocus.co.kr/1555&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Mock개념&lt;/a&gt;&lt;/p&gt;</description>
      <category>개발/Troubleshooting</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/13</guid>
      <comments>https://doosicee.tistory.com/entry/SpringBoot-TestCode-Error-%EC%A0%95%EB%A6%AC#entry13comment</comments>
      <pubDate>Sat, 11 Jun 2022 11:40:12 +0900</pubDate>
    </item>
    <item>
      <title>Spring framework MVC 패턴 알아보기</title>
      <link>https://doosicee.tistory.com/entry/Spring-framework-MVC-%ED%8C%A8%ED%84%B4</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;웹 개발을 한다면 MVC패턴이라는 말을 한번씩 듣게 될것이다. 이것 외에도 다른 패턴들이 있지만 필자는 Spring framework를 사용하기 때문에 MVC패턴이 무엇인지에 대해서 알아보자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;MVC 패턴을 사용하게된 이유&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;너무 많은 역할&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt; 하나의 서블릿, jsp만으로 비즈니스 로직과 뷰 렌더링까지 모두 처리하게 되면, 너무 많은 역할을 하게 되고, 결과적으로 유지보수가 어려워진다. 비즈니스 로직을 호출하는 부분이 변경되도 해당 코드를 손대야 하고, UI를 변경할 일이 있어도 비즈니스 로직과 함께있는 파일을 건드려야 한다. 자, 여기서 UI에 버튼을 하나 변경하기위해 html을 수정한다 했을때에 수백줄의 자바코드가 함께 뒤엉켜 있다고 생각해보자... 그 반대도 마찬가지다. &lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;서로다른 라이프 사이클&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt; 뷰와, 비즈니스 로직에 라이프 사이클은 다르다. 예를 들어 UI를 일부 수정하는 일과 비즈니스 로직을 수정하는 일은 각각 다르게 발생할 가능성이 매우 높고, 대부분 서로에게 영향을 주지 않는다. 이렇게 서로 다르게 움직이는 라이프 사이클을 하나의 코드로 관리하는 것은 유지보수하기 좋지 않다. 그리고 코드의 복잡도가 올라가 인수인계 하기도 매우 어렵다. &lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;기능 특화&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt; 특히 JSP같은 뷰 템플릿은 화면을 렌더링 하는데 최적화 되어 있다. 그렇기에 이 부분에 업무만을 담당하는 것이 가장 효과적이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;MVC 패턴 이란?&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;MVC 패턴이란 위의 문제점들을 해결하기 위해 만들어진&amp;nbsp; &lt;a style=&quot;color: #000000;&quot; href=&quot;https://doosicee.tistory.com/entry/Architecture-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;아키텍처 패턴&lt;/a&gt;이며, MVC패턴은 Model(모델) , View(뷰) , Controller(컨트롤러) 세 가지 구성 요소로 나뉜다.&amp;nbsp; MVC 패턴을 성공적으로 사용한다면 아키텍처 패턴의 많은 장점들이 적용되며, 사용자 인터페이스로부터 비즈니스 로직을 분리해서 애플리케이션의 시각적인 요소나 그 뒷단에서 실행되는 비즈니스 로직을 서로 영향없이 고칠 수 있는 애플리케이션을 만들 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;880&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXmksL/btrCZREDokl/yyUORfxeyh6VyPRzueCgw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXmksL/btrCZREDokl/yyUORfxeyh6VyPRzueCgw1/img.png&quot; data-alt=&quot;출처 :&amp;amp;amp;nbsp;https://ko.wikipedia.org/wiki/%EB%AA%A8%EB%8D%B8-%EB%B7%B0-%EC%BB%A8%ED%8A%B8%EB%A1%A4%EB%9F%AC?tableofcontents=1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXmksL/btrCZREDokl/yyUORfxeyh6VyPRzueCgw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXmksL%2FbtrCZREDokl%2FyyUORfxeyh6VyPRzueCgw1%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;415&quot; height=&quot;457&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;880&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 :&amp;amp;nbsp;https://ko.wikipedia.org/wiki/%EB%AA%A8%EB%8D%B8-%EB%B7%B0-%EC%BB%A8%ED%8A%B8%EB%A1%A4%EB%9F%AC?tableofcontents=1&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;모델(Model)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;잠깐!&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;모델이라 하면 어떤 분은 DTO의 역할 즉,&amp;nbsp; 클라이언트의 요청에 포함된 데이터를 담아 서버측에 전달하고, 서버측의 응답 데이터를 담아 클라이언트에게 전달하는 계층간(Controller, View, Business Layer, Persistent Layer) 전달자 역할을 떠올리시는 분들이 있을것이다. 그러나 모델을 문맥에 따라 여러 용어로 정의 할 수 있고 모델을&amp;nbsp; service,&amp;nbsp; dao(Repository), dto(Domain) 까지 묶는 경우도 있다. 이번 글에서는 모델을 service, dao, dto를 포함하는것으로 설명할 것이다.&lt;/span&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;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;DATA, 정보들을 가공하는 컴포넌트를 말합니다.(애플리케이션의 정보, 데이터와 관련된 부분입니다)&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;내부 비즈니스 로직을 처리하기 위한 역할을 하며&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;주로 상태 변화를 처리한다.[최근에는 Entity, VO, Aggregate로 나뉘어서 관리합니다.(도메인 주도 설계)]&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;애플리케이션의 정보, 데이터를 나타낸다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt; 뷰나 컨트롤러의 정보를 전혀 가지고 있지 않는다&lt;/span&gt;. &lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;단지, &lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;정보만 반환하거나 설정을 할 수 있는 행동을 갖는 객체&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;이다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;모델의 특징들&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt; 사용자가 사용하길 원하는 모든 데이터들을 가지고 있어야 한다.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;즉, 유저의 정보, 게시판의 작성된 글의 정보, 사진의 정보와 저장위치 등... 을 가지고 있어야 한다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;뷰나 컨트롤러에 대해서 어떤 정보도 알지 말아야 한다.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;데이터의 변경이 일어났을 때 모델에서 화면 UI를 직접 조정해서 수정할 수 있도록 뷰를 참조하는 내부 속성값을 가져서는 안된다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;모델의 상태에 변화가 있을 때 컨트롤러와 뷰에 변경 통지에 대한 처리방법을 구현해야만 한다.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;이와같은 통보를 통해 뷰는 최신 결과를 보여줄 수 있고, 컨트롤러는 모델의 변화에 따른 적용 가능한 명령을 추가.제거.수정할 수 있다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;뷰(View)&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;사용자에게 보여지는 부분이며, 데이터를 기반으로 사용자들이 볼 수 있는 화면이다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;웹에서는 웹 브라우저로 렌더링 되는 페이지가 해당된다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;컨트롤러가 전달해준 모델이 처리한 데이터를 받아서 합산하고 사용자(클라이언트)의 브라우저로 렌더링 되는 페이지이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;데이터 및 객체의 입력, 그리고 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;보여주는 출력을 담당한다&lt;/span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;뷰의 특징들&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt; 뷰에서는 별도의 데이터를 보관하지 않는다.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;뷰는 사용자가 제어하고 데이터를 확인할 수 있는 영역입니다. 뷰에서 입력받고 출력해주는 모든 데이터는 모델을 사용해야 한다.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;모델이나 컨트롤러와 같이 다른 구성요소들을 몰라야 한다.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;뷰는 그저 데이터를 받으면 화면에 표시하고, 제어에 대한 통지를 해주는 역할을 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;컨트롤러(Controller)&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;모델과 뷰 사이를 이어주는 브릿지(일종의 중개자) 역할을 한다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;사용자가 버튼을 클릭하면 이벤트는 뷰에서 발생하지만 내부 처리는 컨트롤러에서 관리한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;사용자의 요청(웹 브라우저로 들어오는 요청)을 가장 먼저 마주한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;컨트롤러는 사용자의 요청에 맞는 비즈니스 로직을 실행하여 모델에 데이터를 담아준다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;처리한 모델의 값을 뷰에 전달해서 반환한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;컨트롤러의 특징들&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt; 모델과 뷰에 대해서 알고 있어야 한다.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;모델이나 뷰는 서로의 존재를 모르고, 변경을 외부로 알리고, 수신하는 방법만 가지고 있는데 이를 컨트롤러가 중개하기 위해 모델과 그에 관련된 뷰에서 알고 있어야 한다.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;모델과 뷰의 변경사항을 모니터링 해야 한다.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;모델이나 뷰의 변경 통지를 받으면 이를 해석해서 각각의 구성 요소에게 통지를 해야 합니다. 또한, 애플리케이션의 메인 로직은 컨트롤러가 담당하게 된다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;MVC 패턴의 장점은 무엇인가?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;프론트엔드와 백엔드를 독립적으로 나눌 수 있어 동시다발적으로 개발할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;모델, 뷰, 컨트롤러로 책임 영역이 구분되고, 해당 영역에서의 집중도가 올라가 효율적으로 일을 처리할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;서로 분리되어 각자의 역할에 집중할 수 있게하여, 그 상태로 개발을 진행하고 애플리케이션을 그렇게 만든다면 유지보수성, 애플리케이션의 확장성, 그리고 유연성의 증가, 중복코딩의 문제점이 사라지게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;유연성이란?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;여기서 말하는 유연성이란 클라이언트의 새로운 요구사항에 대해 최소한의 비용으로 보다 유연하게 대처할 수 있는 것을 말한다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;&lt;b&gt;MVC 패턴의 단점&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;MVC패턴의 단점때문에 mvc패턴을 사용하지 않을 일은 없기때문에 그냥 알아만 두자.&lt;/span&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;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;코드의 전체적인 처리 과정을 이해하기 위한 배경지식이 필요하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;모델, 뷰, 컨트롤러가 각자의 역할에서 벗어나지 않도록 주의깊게 관리해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;완벽한 프로그램이란 없듯이 MVC패턴에도 한계가 존재한다. 복잡한 대규모 프로그램의 경우 다수의 뷰와 모델이 컨트롤러를 통해 연결되기 때문에 컨트롤러가 불필요하게 커지는 현상이 발생한다. 복잡한 화면을 구성하는 경우에도 동일한 현상이 발생하는데 이를 'Massive-View-Controller' 라고 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1799&quot; data-origin-height=&quot;991&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qc0sP/btrC5LFhhvX/ymyPDUFaNkjyrKkeKxubT1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qc0sP/btrC5LFhhvX/ymyPDUFaNkjyrKkeKxubT1/img.jpg&quot; data-alt=&quot;출처 :&amp;amp;amp;nbsp;https://www.infoq.com/news/2014/05/facebook-mvc-flux/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qc0sP/btrC5LFhhvX/ymyPDUFaNkjyrKkeKxubT1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqc0sP%2FbtrC5LFhhvX%2FymyPDUFaNkjyrKkeKxubT1%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;1799&quot; height=&quot;991&quot; data-origin-width=&quot;1799&quot; data-origin-height=&quot;991&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 :&amp;amp;nbsp;https://www.infoq.com/news/2014/05/facebook-mvc-flux/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;이런 문제점들을 보안하기 위해 다양한 패턴들이 파생되었으나 MVC패턴에 대해 공부하는 글이므로 다른 패턴들이 있다는 것에 대해서만 알아두자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;마무리&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;마무리 요약&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;결국 MVC패턴은 개발하기 좋은 즉, 각각의 구역별로 역할을 분담하여 개발하기 좋은 환경을 만들기 위한 패턴이라는 것이다.&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;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;다시한번 되세기기&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;모델, 뷰, 컨트롤러 별로 각자 자기가 맡은 영역에 대해서 집중할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;개발 시에 발생하는 다양한 에러의 원인과 내용들을 좀 더 쉽게 파악할 수 있고, 시행착오가 줄어들어 개발 시간이 단축됩니다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;협업시에 공통된 아키텍처를 공유할 수 있어 의사소통이 편해지고,&amp;nbsp; 시스템의 구조를 이해하는 것이 쉬워 새로운 개발자가 온다 하더라도 프로그램 내에 체계적인 구조와 패턴을 활용하여 작성된 코드 덕분에 좀 더 쉽게 프로그램을 이해할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;참조&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a title=&quot;towardsdatascience.com&quot; href=&quot;https://towardsdatascience.com/10-common-software-architectural-patterns-in-a-nutshell-a0b47a1e9013&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;towardsdatascience.com&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a title=&quot;우아한 테크 mvc패턴 리뷰&quot; href=&quot;https://murphymoon.tistory.com/entry/%EC%9A%B0%EC%95%84%ED%95%9C-%ED%85%8C%ED%81%AC-MVC-%EB%A6%AC%EB%B7%B0-%EB%A0%88%EC%9D%B4%EC%96%B4-MVC-%ED%8C%A8%ED%84%B4-5%EB%A0%88%EC%9D%B4%EC%96%B4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;우아한 테크 mvc패턴 리뷰4&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a title=&quot;MVC 패턴이란?&quot; href=&quot;https://m.blog.naver.com/jhc9639/220967034588&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MVC 패턴이란?&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a title=&quot;MVC Pattern&quot; href=&quot;https://junhyunny.github.io/information/design-pattern/mvc-pattern/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MVC Pattern&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/Tech Notes</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/11</guid>
      <comments>https://doosicee.tistory.com/entry/Spring-framework-MVC-%ED%8C%A8%ED%84%B4#entry11comment</comments>
      <pubDate>Sun, 22 May 2022 14:08:00 +0900</pubDate>
    </item>
    <item>
      <title>Spring framework 는 무엇인가</title>
      <link>https://doosicee.tistory.com/entry/Spring-framework%EB%9E%80</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;378&quot; data-origin-height=&quot;97&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pGKlI/btrCw54C1rA/aWKQssqCJsIUdB9SlSL4yK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pGKlI/btrCw54C1rA/aWKQssqCJsIUdB9SlSL4yK/img.jpg&quot; data-alt=&quot;출처 :&amp;amp;amp;nbsp;https://spring.io/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pGKlI/btrCw54C1rA/aWKQssqCJsIUdB9SlSL4yK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpGKlI%2FbtrCw54C1rA%2FaWKQssqCJsIUdB9SlSL4yK%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;500&quot; height=&quot;128&quot; data-origin-width=&quot;378&quot; data-origin-height=&quot;97&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 :&amp;amp;nbsp;https://spring.io/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Spring framework 란?&lt;/span&gt;&lt;/b&gt;&lt;/h2&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;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;Spring framework란 자바 플랫폼을 위한 오픈 소스 애플리케이션 프레임워크이며 엔터프라이즈급 애플리케이션을 개발하기 위한 기능을 종합적으로 제공하는 솔루션이다. 간단히 Spring이라고도 한다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;엔터프라이즈급(Enterpris) 애플리케이션 이란?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;대규모 조직에서 강력하고 확장 가능하도록 설계된 응용 프로그램을 나타내는 말입니다. 즉, 대규모 데이터 처리와 트랜잭션이 동시에 여러 사용자로 부터 행해지는 매우 큰 규모의 환경을 엔터프라이즈급 환경이라 한다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Spring framework의 특징들&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;1. 생명주기 관리&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;스프링 프레임워크는 경량컨테이너로 Java 객체를 직접 담고 관리한다. 객체의 생성, 소멸을 직접 관리하여 언제든 Spring 컨테이너로 부터 필요한 객체만 사용할 수 있다.&lt;/span&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;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;2. 제어 역전(Inversion of Control, IoC)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;Ioc란 &quot;제어의 역전&quot;이라는 의미로, 메소드나 객체의 호출작업을 개발자가 결정하는 것이 아니라, 외부에서 결정되는 것을 의미한다. 기존의 프로그래밍에서는 개발자가 작성한 프로그램이 외부 라이브러리의 코드를 호출했으나, 제어 역전은 이와 반대로 외부 라이브러리 코드가 개발자의 코드를 호출하게된다. 즉, 제어권이 프레임워크에게 있어 필요에 따라 스프링 프레임워크가 사용자의 코드를 호출한다.&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;스프링에서 객체가 만들어지고 실행되는 순서&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;1. 객체 생성&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;2. 의존성 객체 주입 (스스로가 만드는것이 아닌 제어권을 스프링에게 위임하여 스프링이 만들어놓은 객체를 주입한다.)&lt;br /&gt;3.의존성 객체 메소드 호출&lt;br /&gt;스프링은 스프링이 실행될때에 모든 의존성 객체를 다 만들어주고 필요한 곳에 주입시켜줌으로써 Bean들은&amp;nbsp;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;싱글턴 패턴&lt;/span&gt;의 특징을 가지며, 제어의 흐름을 사용자가 아닌 스프링에게 맡겨 작업을 처리한다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;스프링 빈(Spring Bean)이란?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;스프링 IoC 컨테이너에 의해서 생성되고 관리되는 객체이다. 애플리케이션의 핵심을 이루는 객체들을 스프링 빈(Beans)이라고 한다. 빈은 스프링 컨테이너에 의해서 인스턴스화 되어 조립되고 관리됩니다. 스프링 컨테이너가 관리해준다는 점을 제외하면 자바 객체이다. 현재는 Annotaion 기반으로 Bean으로 등록한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;Annotaion 사용 예 : @Bean, @Controller, @Service&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;싱글톤 패턴(Singleton patten)이란?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴이다. 최초에 스프링이 한번 기동될때에 New로 인스턴스를 생성해두거나 최초로 필요해질때에 만들어두고 서버가 내려가기 전까지는 계속 유지하여 반복 재활용을 하여 사용한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;(클라이언트들이 스프링 빈을 요구할 때 같은 참조값을 가진 빈 객체를 반환해준다.)&lt;/span&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;379&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dszyKX/btrCAw1H8Fp/y6AbAxamol9XK587mmMUf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dszyKX/btrCAw1H8Fp/y6AbAxamol9XK587mmMUf1/img.png&quot; data-alt=&quot;출처 :&amp;amp;amp;nbsp; https://cantcoding.tistory.com/47&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dszyKX/btrCAw1H8Fp/y6AbAxamol9XK587mmMUf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdszyKX%2FbtrCAw1H8Fp%2Fy6AbAxamol9XK587mmMUf1%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; alt=&quot;singleTone 패턴에 관한 이미지&quot; loading=&quot;lazy&quot; width=&quot;770&quot; height=&quot;379&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;379&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 :&amp;amp;nbsp; https://cantcoding.tistory.com/47&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt; &lt;b&gt;IoC 컨테이너란?&lt;/b&gt; &lt;/span&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;왜 컨테이너 일까?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc;&quot;&gt;굉장히 많은 화물을 담아 보내주는 화물 컨테이너 처럼 스프링에 컨테이너도 여러 빈과 기능들을 담고있다 하여 컨테이너 라고 부른다.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;컨테이너의 개념&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc;&quot;&gt;컨테이너는 보통 객체의 생명주기를 관리, 생성된 인스턴스들에게 추가적인 기능을 제공하도록 하는 것. &lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc;&quot;&gt;즉, IoC 컨테이너란 스프링 프레임워크에서&lt;/span&gt;&lt;b&gt;객체를 생성하고, 관리하고, 책임지고, 의존성을 관리해주는 컨테이너다&lt;/b&gt;&lt;span style=&quot;background-color: #fcfcfc;&quot;&gt;.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;어떻게 동작을 하는걸까?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;SpringApplicationContext것이 컨테이너 안에서 계속 동작을 하고있고 우리가 만든 클래스들을 Bean으로 등록하겠다는 설정을 해주면 컨테이너 안에 Bean으로 등록해주는 일을 해준다.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;Bean으로 등록하는 의미는 무엇일까?&lt;/span&gt;&lt;br /&gt;&lt;/b&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;Bean으로 등록하는 의미는 우리가 만든 클래스를 실제 인스턴스화 한다는 것이다. 근데 이 클래스들을 그냥 쓰는것이 아니라 SpringApplicationContext가 가지고있는 온갖 설정 값들을 클래스에 입혀준다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;인스턴스의 생성부터 소멸까지 인스턴스 생명주기를 개발자가 아닌 컨테이너가 대신해준다. 그렇기에 객체관리의 주체가 프레임워크(Container)가 되기 때문에 개발자는 로직에 집중할 수 있는 큰 장점이 있다.&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&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;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;3. 의존성 주입(Dependency Injection, DI)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;DI는 &quot;의존성 주입&quot;이라는 의미로 프로그래밍에서 구성요소 간의 의존 관계가 소스코드 내부가 아닌 외부에서 설정을 통해 정의되는 방식이다. 즉, 객체를 직접 생성하는게 아닌 외부에서 생성한 후 주입 시켜주는 방식이다. DI의 장점은 DI를 통해서 모듈간의 결합도를 낮춰 유연성이 높아지고 코드 재사용률을 높여 소스코드를 다양한 곳에 사용할 수 있다.&lt;/span&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;700&quot; data-origin-height=&quot;467&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MKkkc/btrCwF6UC2I/3mNgVyqfBGiKDAh5LyFyfk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MKkkc/btrCwF6UC2I/3mNgVyqfBGiKDAh5LyFyfk/img.jpg&quot; data-alt=&quot;출처 :&amp;amp;amp;nbsp;https://velog.io/@gillog/Spring-DIDependency-Injection&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MKkkc/btrCwF6UC2I/3mNgVyqfBGiKDAh5LyFyfk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMKkkc%2FbtrCwF6UC2I%2F3mNgVyqfBGiKDAh5LyFyfk%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; alt=&quot;의존성 주입에 관한 이미지1&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;467&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;467&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 :&amp;amp;nbsp;https://velog.io/@gillog/Spring-DIDependency-Injection&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;첫번째 방법은 A객체가 B와 C객체를 new생성자를 통해 직접 생성하는 방법이고, 두번째 방법은 외부에서 생성된 객체를 setter()또는 생성자를 통해 사용하는 방법이다. 두번째 방식이 의존성 주입의 예시이다. 즉, A객체에서 직접 생성하는 것이 아닌&lt;span style=&quot;background-color: #dddddd;&quot;&gt;외부(IoC컨테이너)&lt;/span&gt;에서 생성된 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;B,C객체를 조립(주입)&lt;/span&gt;시켜 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;setter() 또는 생성자&lt;/span&gt;를 통해 사용하는 방식이다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;520&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x4VlF/btrCAq8d47h/fj1RS7kKKHK3eUiZM8SUl1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x4VlF/btrCAq8d47h/fj1RS7kKKHK3eUiZM8SUl1/img.jpg&quot; data-alt=&quot;출처 :&amp;amp;amp;nbsp;https://velog.io/@gillog/Spring-DIDependency-Injection&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x4VlF/btrCAq8d47h/fj1RS7kKKHK3eUiZM8SUl1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx4VlF%2FbtrCAq8d47h%2Ffj1RS7kKKHK3eUiZM8SUl1%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; alt=&quot;의존성 주입에 관한 이미지2&quot; loading=&quot;lazy&quot; width=&quot;450&quot; height=&quot;334&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;520&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 :&amp;amp;nbsp;https://velog.io/@gillog/Spring-DIDependency-Injection&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;각 클래스간의 의존관계를 빈 설정(Bean Definition)정보를 바탕으로 컨테이너가 자동으로 연결해준다. 위의 이미지에 IOC컨테이너 안에 생성된 객체들을 Bean이라고 하는 것이다.&amp;nbsp;&lt;/span&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;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;4. AOP(Aspect Oriented Programming)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;AOP는 관점 지향 프로그래밍이라고 불린다. 관점 지향은 쉽게 말해&amp;nbsp;어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어서 보고 그 관점을 기준으로 각각 모듈화하겠다는 것이다. 여기서 모듈화란 어떤 공통된 로직이나 기능을 하나의 단위로 묶는 것을 말한다. 대표적인 예로는 트랜잭션 관리 기능이 있다. 출처 :&lt;/span&gt; &lt;a title=&quot;스프링 AOP&quot; href=&quot;https://engkimbs.tistory.com/746&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;스프링 AOP&lt;/a&gt;&lt;/span&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;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;장점 : 특정 타이밍, 시점에 어떠한 기능을 넣어주고 싶을때에 AOP를 사용하면 기존 로직을 건드리지 않고 코드에 녹여내기 좋다. 공통적이지만 특정 몇몇 공통적인곳에 쓰는 기법이라고 보면 된다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;단점 : 실무에서 AOP를 사용하면 코드 분석에 어려워지는 부분이 있어 꼭 사용이 필요한 곳에만 사용하는 것이 좋다고 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;AOP의 기본 개념들&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;/b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Aspect&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;여러 클래스나 기능에 걸쳐서 있는 관심사, 그리고 그것들을 모듈화함 AOP중에서 가장 많이 활용되는 부분은 @Transactional(트랜잭션 관리)기능.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Advice&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;조언, AOP에서 실제로 적용하는 기능(로깅,트랜잭션,인증 등)을 뜻함&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Join point&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;모듈화된 특정 기능이 실행될 수 있는 연결 포인트. 모든 흐름에 AOP를 심을수 없기에 특정 심을수 있는 포인트를 조인 포인트라고 칭함(Aspect를 심을 수 있는 포인트)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Pointcut&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;Join point 중에서 해당 Aspect를 적용할 대상을 뽑을 조건식. 심어지는 포인트들을 계속해서 발생한다면 번거로워지기 때문에 특정 조건식을 사용하여 Aspect를 심어줄 위치를 지정해준다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Target Object&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;Advice가 적용될 대상 오브젝트&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;AOP Proxy&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;대상 오브젝트에 Aspect를 적용하는 경우 Advice를 덧붙이기 위해 하는 작업을 AOP Proxy라고 한다.&amp;nbsp;주로 CGLIB(실행 중에 실시간으로 코드를 생성하는 라이브러리) 프록시를 사용하여 프록싱 처리를 한다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Weaving&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;Advice를 비즈니스 로직 코드에 삽입하는 것을 말함&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;5. 포조(Plain Old Java Object, POJO)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;스프링 프레임워크는 POJO방식의 프레임워크이다. 포조란 Plain Old Java Object란 말 그대로 평범한 자바 오브젝트를 뜻하며, 일반적으로 우리가 알고 있는 getter, setter 같이 기본적인 기능만 가진 자바 객체를 말한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1653054242914&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class User{
	private int id;
    private String name;
    private String phonNum;
    private Date birthDay;
    
    public int getId(){
    	return id;
    }
    public String getName(){
    	return name;
    }
    public String getEmail(){
    	return email;
    }
    public Date getBirthDay(){
    	return birthDay;
    }
    
    public void setId(int id){
    	this.id = id;
    }
    public void setName(String name){
    	this.name = name;
    }
    public void setEmail(String email){
    	this.email = email;
    }
    public void setBirthDay(Date birthDay){
    	this.birthDay = birthDay;
    }
 }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;EJB 란?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이전에 자바를 이용해 비즈니스 서비스를 개발할 때 비즈니스 로직 뿐만 아니라 트랜잭션,보안 등 로우레벨의 로직까지 작성해야하는 부담감이 있었다. 그래서 부담감을 없애고자 재사용이 가능한 로직을 개발하기 위해 EJB(Enterprise Java Beans)가 탄생했다.&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Light';&quot;&gt;EJB의 문제점&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;그러나 EJB는 한 두가지의 기능을 사용하기 위해 EJB를 상속받거나 implements하게 되어 가벼운 서비스 조차도 무겁게 만들어 졌고, 다른 기능으로 대체하기 위해서는 전체 코드를 수정해야 하는 문제점이 있었다. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;해결방안과 POJO를 기반으로 둔 이유&lt;/span&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Java의 기본 개념인 객체지향에 집중하고, 특정 클래스나 라이브러리에 종속되지 않는 POJO구성으로 코드를 작성한다면 이런 문제점을 해결할 수 있을 것이라고 생각하여 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;SpringFramework는 POJO를 기반으로 두었다&lt;/span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt;단순 오브젝트는 의존성이 없고 추후 테스트 및 유지보수가 편리하여 유연성의 장점을 가진다.&lt;/span&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Light'; color: #000000;&quot;&gt; SpringFramework에 기본 개념들을 간단하게 정리해봤다. 잘못 이해하거나 설명한 개념이 있다면 언제든지 말씀 해주시면 감사하겠습니다.&lt;/span&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;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;참고했던 블로그들과 강의&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a title=&quot;한 번에 끝내는 Spirng 완전판 초격차 패키지&quot; href=&quot;https://fastcampus.co.kr/dev_online_spring&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;한 번에 끝내는 Spirng 완전판 초격차 패키지&lt;/a&gt;&lt;/span&gt;&lt;/b&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a title=&quot;SpringFramework란? 기본 개념 핵심 정리&quot; href=&quot;https://khj93.tistory.com/entry/Spring-Spring-Framework%EB%9E%80-%EA%B8%B0%EB%B3%B8-%EA%B0%9C%EB%85%90-%ED%95%B5%EC%8B%AC-%EC%A0%95%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SpringFramework란? 기본 개념 핵심 정리&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;a title=&quot;Spring의 기본 특징 POJO&quot; href=&quot;https://velog.io/@galaxy/Spring%EC%9D%98-%EA%B8%B0%EB%B3%B8-%ED%8A%B9%EC%A7%95-POJO&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Spring의 기본 특징 POJO&lt;/a&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;a title=&quot;나무위키 Spring&quot; href=&quot;https://namu.wiki/w/Spring(%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;나무위키 Spring&lt;/a&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;a title=&quot;Spring DI, IoC 정리&quot; href=&quot;https://velog.io/@gillog/Spring-DIDependency-Injection&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Spring DI, IoC 정리&lt;/a&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Tech Notes</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/7</guid>
      <comments>https://doosicee.tistory.com/entry/Spring-framework%EB%9E%80#entry7comment</comments>
      <pubDate>Tue, 17 May 2022 22:10:23 +0900</pubDate>
    </item>
    <item>
      <title>비전공 개발자의 2021 회고록</title>
      <link>https://doosicee.tistory.com/entry/%EB%B9%84%EC%A0%84%EA%B3%B5-%EA%B0%9C%EB%B0%9C%EC%9E%90%EC%9D%98-2021-%ED%9A%8C%EA%B3%A0%EB%A1%9D</link>
      <description>&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 과거&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;2021년 회고록이지만 조금 과거로 돌아가 청소년기 때부터의 이야기를 해보려 한다&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;[꿈을 좇던 소년]&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;청소년기의 나는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;꿈만을 좇던&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;소년이었다.&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;'돈을 많이 벌지는 못해도 내가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;하고 싶은&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;일을 하며&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;살 거야!'라는&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;생각을 가지고 베이스를 배워 유명한 세션&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;연주자를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;꿈꾸기도 하고&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;밴드를 하며&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Muse(영국의 유명 밴드)처럼 되는 꿈을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;꾸기도 하고&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;끝에는 음악과 관련이 없지만&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;신학을 공부하며 목사를 꿈꾸기도 하였었다.&lt;/span&gt;&lt;br /&gt;그렇게 꿈만을 좇아가던&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;나는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;무엇 하나&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;제대로 된&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;결과를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;낸 것&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;없이 2016.12.05 군에 입대를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;하게 되었다.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;군에 입대한 나는 1년 9개월이라는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;시간 동안 주변 사람들의 많은 이야기를 들으며 현실은 조금 뒤로하고 꿈을 좇던&lt;br /&gt;나와는 달리 현실을 바라보는 사람들을 보게 되었고&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;'아 나는 너무 내가 하고 싶은 것 즐거운 것만 하며 살아왔던 게 아닐까?'라는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;생각을 가지게 되었다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;나는 돈을 많이 못 벌어도 내가 즐거운 일을 하겠어라는 꽃밭에 구르는 즐거운 꿈을 꾸고 살았다는 걸 깨달았고&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;언제까지&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;꿈만 좇으며&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;살 수는 없다.라는 결론을 냄과 동시에&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;앞으로 어떤 일을 해야 할까?라는&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;고민을 시작하였다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;나는 진로를 정하기에 앞서 '내가 무엇을 잘할 수 있을까?'라는 생각을 먼저 하였다.&lt;br /&gt;내가 무엇을 잘할 수 있을지 알기 위해서 내 장점에 대해 고민하였고&lt;br /&gt;고민한 결과 특별한 장점을 가지게 되었다는 것을 알게 되었다.&lt;br /&gt;&lt;br /&gt;바로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;'환한 인상'&lt;/b&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;'역지사지의 입장으로 생각해보는 것'&lt;/b&gt;이다.&lt;br /&gt;나는 항상 어떠한 말과 행동을 할 때에 상대방의 입장에서 생각한 후에 행동하였고,&lt;br /&gt;항상 웃는 얼굴로 인사하는 것이 나의 장점들이었다.&lt;br /&gt;&lt;br /&gt;나는 나의 장점을 '어느 직종에 가면 활용할 수 있을까?'라는 고민을 하였고&lt;br /&gt;어떠한 상황에도 웃을 수 있다는 것과 남들의 입장에서 먼저 생각해본다는 장점은&lt;br /&gt;서비스 업에서 정말 큰 장점이 되겠다는 생각을 하여 전역 후 서비스업으로&lt;br /&gt;진로를 잡아야겠다 라는 마음을 먹었지만 실제로 서비스업에 종사해본 경험이 없어서&lt;br /&gt;구체적으로 어떠한 일을 해야 할지 정하지 못한 상태로 나는 2018.09.04 화요일 전역을 하게 되었다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[뭐라도 시작해보자!]&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;군에서 전역한 나는 '서비스업 중에서도 구체적으로 어떠한 일을 해야 할까?'라는 고민을 하였다&lt;br /&gt;서비스업은 너무나도 방대하기 때문에 무엇을 해야 좀 더 잘할지 알 수가 없었기 때문이다.&lt;br /&gt;&lt;br /&gt;그래서 나는 서비스 업 중에서도 내가 좀 더 잘할 수 있는 것을 찾기로 하였는데&lt;br /&gt;어렸을 때부터 떡볶이를 즐겨 만들고 좋아했던 것이 생각이나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;(부모님 두 분 다 일을 나가셔서&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666;&quot;&gt;동생들에게 밥을 차려줘야 할 일이 많았는데 떡볶이를 자주 해주었다)&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;떡볶이에 대해서&lt;br /&gt;배워보기로 마음을 먹고 2018.09.08 토요일 프랜차이즈 떡볶이집에서 알바를 시작하였다.&lt;br /&gt;&lt;br /&gt;나는 주방 서브를 시작으로 순차적으로 일을 배워나갔고 어느 순간 나는 이 일에 대한 관심이 커지기 시작하며&lt;br /&gt;나만에 가게를 차려보자는 꿈을 가지게 되었다.&lt;br /&gt;&lt;br /&gt;내가 가게를 차리자는 꿈을 가지게 된 계기는 2가지가 있다.&lt;br /&gt;&lt;br /&gt;첫 번째로는 일을 하며 많은 주문처리와 뜨거운 화로 앞에서 일하는 것은 힘들지만&lt;br /&gt;손님들에게 맛있게 먹었다는 한마디를 들을 때에 너무나도 뿌듯하였고,&lt;br /&gt;단골손님들이 자주 주문하는 모습을 보며 누군가가 내가 만든 음식을 좋아하고&lt;br /&gt;계속해서 찾아주시는 것에 굉장한 매력을 느꼈다.&lt;br /&gt;&lt;br /&gt;두 번째로는 내가 일을 하였던 곳은 본점이었기에 예비 점주님들이 와서 가게를 차리기 위해&lt;br /&gt;교육을 받았는데 자신의 가게를 차리며 꿈을 키워가는 시간들이 너무나도 빛나 보였고&lt;br /&gt;값져보였기에 '나도 저렇게 하고 싶다'라는 생각을 가지며 더욱더 관심을 가지게 되었다.&lt;br /&gt;&lt;br /&gt;그렇게 관심이 커지고 꿈을 가지게 되던 시점에 평소에 나를 좋게 보아주셨는지 대표님께서&lt;br /&gt;&lt;b&gt;&quot;강남에 직영점을 오픈하는데 매니저로 가서 일해보는 건 어때?&quot;&lt;/b&gt;라는 제안을 받게 되었다.&lt;br /&gt;&lt;br /&gt;일을 한지 반년밖에 안된 시기에 함께 일하던 사람들을 떠나 새로운 매장에 가서 매니저란 직무를 맡아&lt;br /&gt;일을 해야 된다는 것이 부담이 되었으나 매장을 전반적으로 관리하며 일을 배우는 것은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;기회&lt;/b&gt;라는&lt;br /&gt;생각이 들어 수락하게 되었고 2019년 3월경 나는 매니저의 일을 시작하였다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; 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;1280&quot; data-origin-height=&quot;960&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxNxkS/btrz1iSshBc/ukKWCYtk5ZiJzG0nfwoUa1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxNxkS/btrz1iSshBc/ukKWCYtk5ZiJzG0nfwoUa1/img.jpg&quot; data-alt=&quot;여름이라 떡과 소스가 변하지 않도록 차갑게 관리하던 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxNxkS/btrz1iSshBc/ukKWCYtk5ZiJzG0nfwoUa1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxNxkS%2Fbtrz1iSshBc%2FukKWCYtk5ZiJzG0nfwoUa1%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;1280&quot; height=&quot;960&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;여름이라 떡과 소스가 변하지 않도록 차갑게 관리하던 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;매니저의 일을 시작한 나는 매장을 관리하고 홍보하는 방법을 착실히 배워나갔다.&lt;br /&gt;리뷰 관리, 배달 지연에 의한 기사님들과의 마찰, 배달 전문점이기에 사람이 많이 필요하지 않아&lt;br /&gt;2명이서 근무하였기에 혼자 있는 시간이 많았는데 저녁 8시 이후 새벽 1시까지 혼자 마감할 때의 외로움과 혼자서 일을&lt;br /&gt;처리할 때의 바쁨이 너무나도 힘들었지만 늘어나는 주문량과 단골손님이 생기며 보람을 느꼈고,&lt;br /&gt;나중에 나의 가계를 차리기 전에 미리 많은 것을 배우고 경험할 수 있다는 것에 만족하며 일을 하였다.&lt;br /&gt;&lt;br /&gt;1년 차가 되던 시점 점점 늘어나는 매출량과는 다르게 나의 월급은 고정이었고 월 250을 벌어 200씩 저축하였으나 이렇게 벌어서는 '내 가게를 차리기에는 너무나도 오래 걸린다'라는 생각을 하였고 1년 차가 되던 시점 이 정도면 내 가게를&lt;br /&gt;차리기에는 충분히 배웠다는 생각을 하여 더 빨리 가게를 차리기 위해 돈을 더 벌 수 있는 일을 찾기 시작하였고&lt;br /&gt;2019년 8월경 나는 매니저의 일을 그만두었고 2019.09.10 은행 청원경찰 일을 시작하게 되었다.&lt;br /&gt;&lt;br /&gt;돈을 빨리 벌기 위해 시작한 일답게 은행 청원경찰임에도 불구하고 매달 310~350만 원의 돈을 벌기 시작하였고&lt;br /&gt;월 270 ~ 300이라는 돈을 저축하기 시작하였다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; 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;1280&quot; data-origin-height=&quot;960&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cczCgR/btrz2qQEaHb/MwqNGhKEswL14fIC07maD1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cczCgR/btrz2qQEaHb/MwqNGhKEswL14fIC07maD1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cczCgR/btrz2qQEaHb/MwqNGhKEswL14fIC07maD1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcczCgR%2Fbtrz2qQEaHb%2FMwqNGhKEswL14fIC07maD1%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;1280&quot; height=&quot;960&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;청원경찰이 그렇게 돈을 많이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;벌어?라는&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;생각을 할 수 있으나 돈을 많이 번 비결은 당직을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;많이 섰기&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;때문이며, 또한 남자들만 모여있고 분위기가 험한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;탓인지&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;직원들의 잦은 퇴사에 대타가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;필요한 때가&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;많아 당직의 빈자리를 받아 근무했기 때문이다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;나는 돈을 빨리 벌어서 빨리 가게를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;차리는 걸&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;목표하였기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;당직 근무가&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;많아서 좋았고 분명 힘든 부분이 있지만&lt;/span&gt;&lt;br /&gt;그 와중&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;좋은 사람들을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;사귀어&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;힘을 낼 수 있었고 앞으로 2년만 더&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;일을 하면&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;가게를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;차릴 수&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;있겠다!라는&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;생각에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;기분 좋게&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;다녔으나 1년 차가&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;다 되어가는 시점 다리에 문제가 생겼다.&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;청원경찰 일은&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;cs 업무뿐만&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;아니라 주요&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;고객의 전&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;및 임원 의전을 맡아&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;보이는 게&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;중요했기 때문에 온종일 서서&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;근무하였고 은행 본점답게 노조와 돈 문제로 시위대가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;많이 찾아와&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;몸으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;바리케이드를&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;하는 훈련을 자주&lt;/span&gt;&lt;br /&gt;진행하였었다.&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;(실제로&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;노조와 시위대를 막기도 하였다)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;또한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;당직 시에는&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;건물 보안을 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;꼭대기부터&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;지하까지 30층을 계단을 통해 순찰을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;해야 했는데&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;1년간 다리에 무리가 많이 갔는지&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;어느 순간&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;오른쪽 발목에 통증이 찾아오기 시작하였다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;다리를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;회복하기 위해&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;정형외과를 다니며 물리치료를 받았지만 다리가 회복될&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;시간 없이&lt;span style=&quot;color: #666666;&quot;&gt;(당직의&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;특성상 결원이 발생하면 대타를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;구해야 했으며&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;며칠&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;쉬면 회복된다고 장담할 수 없었다)&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;근무를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;하다 보니&lt;br /&gt;회복은커녕&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;더욱더 악화되어갔고 1년이 되는 시점인 2020.09.11 금요일을 끝으로 일을 그만두게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 현재 (개발자로서의&lt;/b&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;시작)&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;나의 개발자로서의 삶을 시작하게 된 계기와 어떤 노력과 과정을 거쳐왔는지에 대한 이야기이다&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;청원경찰의 일을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;관둔 뒤로&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;앞으로 무엇을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;해야 할지&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;고민을 하던 와중 코로나에 의해 자영업자들이 힘들어하는 상황을 보며&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;프랜차이즈를&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;차리려던 생각은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;접게 되고&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;'좀 더 미래에 안정적이게 일을 할 수 있는 기술을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;배워보자'라는&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;생각을 가지게 되었다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[국민 취업지원 제도&lt;span style=&quot;background-color: #ffffff;&quot;&gt;]&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;나는 반년이라는 고민의 시간을 가졌고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;국민 취업&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;지원 제도라는&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;것이 있다는 것을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;알게 되어&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;신청하였다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;고용노동부에 찾아가 상담사님과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;상담을 하며&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;적성검사를 하였고 개발자는 어떻냐는 상담사님에 말에&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;마침 컴퓨터&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;보안 쪽으로&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;공부를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;하고 있던&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;친구에게 의견을 구하였고 친구에게 돌아온 대답은&lt;/span&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&quot;굉장히&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;힘들 거다.&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;하지만 노력해서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;못할 건&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;아무것도 없다 노력할 각오가 되어 있다면 정말 좋은 길이라고 생각한다.&quot;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;라는 말을 들었다. 그 말을 듣고 나는 이때까지 살아오며 '무언가 하나를 제대로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;끝마쳐본 게&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;있었나?'&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;라는 생각을 하였고 앞으로 선택하는 길은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;모든 걸&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;불태울 각오로 하겠다고 다짐하였다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;개발자를 선택하기 앞서 나와 적성이 맞는지 실제로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;알아보기 위해&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;유튜브(생활코딩)와 백준 단계별 알고리즘&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;풀이를 통해 공부하였고 문제를 생각하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;해결하는 것과&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;코드를 짜서 무언가를 만들어&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;낸다는 것이&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;너무나도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;'재미있었다'&lt;/b&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;코딩을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;하는 것이&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;나와 잘 맞는다는 생각이 들어 그대로 나는 국비지원 학원을 신청하였다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[국비지원 학원]&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;국비 학원에서&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;공부를 시작한 나는 미리 예습을 한다고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;하긴 했지만&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;2주 만에&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;모든 지식이 털렸고&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;꾸역꾸역 따라가는 학생이 되어있었다. 조금 어려운 숙제가 나오기&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;시작할 때부터는&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;새벽까지 작업하기 일쑤였다...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;그렇게 두 달 차가 시작되는 시점 학원 친구에게 스터디를 제안받았고 나는 코딩이 재미있었기에 재미있기에&lt;br /&gt;더 잘하고 싶어서 일말의 고민도 없이 냅다 하겠다고 대답하였고 스터디를 시작하였다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageslideblock alignCenter&quot; data-image=&quot;[{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/Khu8N/btrzS2YtXbv/FAPwsCBSJVXvEJRGlapum0/img.png&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/bfSQtb/btrzZAfDChk/Okq5MPW0l52Z3xR58wD1G1/img.png&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/kL4E4/btrzZ5sVT4n/rtJpG5JkEgbNLknCs4HhpK/img.png&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/SNfNp/btrz3ln1xao/rURgKD0KCInnXHZ1Y7PIhK/img.png&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/55jU5/btrzS2YtXl8/MrujPvYkBKGdGkkAvrPrWk/img.png&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/IxyvB/btrzXWcjzht/S5E83tsRszzDrrjVQ5gjAK/img.png&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/Jzr0P/btrzYD4nc0D/0h9NO1UsjVC28BftbXj2gK/img.png&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/xggMi/btrz3lhfemB/WX6L0Gzp600RgkdTRskngK/img.png&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/bL1WER/btrz0D33rW7/H2YLmTYk5jkLY1slQdem8K/img.png&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/DorYW/btrzZyWplVo/JJpG3YbVfBmMc5SfA0em9K/img.png&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/bvX674/btrzUzn9SZy/oloB6OZiYBmgdjyyG9Q5TK/img.png&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/c01dqX/btrzZAGJ0Of/xjf01bnzC8IYrHLN0Wp7Fk/img.png&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/bGsWpv/btrz0Dv9mj5/KOkgGpPAKzDiv1Ki3k6b9k/img.png&amp;quot;},{&amp;quot;src&amp;quot;:&amp;quot;https://blog.kakaocdn.net/dn/42l7a/btrzXUyMW4K/Q2T37ZQU1WTn8RQXJy5nVK/img.png&amp;quot;}]&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span class=&quot;image-wrap selected&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Khu8N/btrzS2YtXbv/FAPwsCBSJVXvEJRGlapum0/img.png&quot; data-url=&quot;https://blog.kakaocdn.net/dn/Khu8N/btrzS2YtXbv/FAPwsCBSJVXvEJRGlapum0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Khu8N/btrzS2YtXbv/FAPwsCBSJVXvEJRGlapum0/img.png&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKhu8N%2FbtrzS2YtXbv%2FFAPwsCBSJVXvEJRGlapum0%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; data-origin-width=&quot;662&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfSQtb/btrzZAfDChk/Okq5MPW0l52Z3xR58wD1G1/img.png&quot; data-url=&quot;https://blog.kakaocdn.net/dn/bfSQtb/btrzZAfDChk/Okq5MPW0l52Z3xR58wD1G1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfSQtb/btrzZAfDChk/Okq5MPW0l52Z3xR58wD1G1/img.png&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfSQtb%2FbtrzZAfDChk%2FOkq5MPW0l52Z3xR58wD1G1%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; data-origin-width=&quot;662&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kL4E4/btrzZ5sVT4n/rtJpG5JkEgbNLknCs4HhpK/img.png&quot; data-url=&quot;https://blog.kakaocdn.net/dn/kL4E4/btrzZ5sVT4n/rtJpG5JkEgbNLknCs4HhpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kL4E4/btrzZ5sVT4n/rtJpG5JkEgbNLknCs4HhpK/img.png&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkL4E4%2FbtrzZ5sVT4n%2FrtJpG5JkEgbNLknCs4HhpK%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; data-origin-width=&quot;662&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SNfNp/btrz3ln1xao/rURgKD0KCInnXHZ1Y7PIhK/img.png&quot; data-url=&quot;https://blog.kakaocdn.net/dn/SNfNp/btrz3ln1xao/rURgKD0KCInnXHZ1Y7PIhK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SNfNp/btrz3ln1xao/rURgKD0KCInnXHZ1Y7PIhK/img.png&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSNfNp%2Fbtrz3ln1xao%2FrURgKD0KCInnXHZ1Y7PIhK%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; data-origin-width=&quot;662&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/55jU5/btrzS2YtXl8/MrujPvYkBKGdGkkAvrPrWk/img.png&quot; data-url=&quot;https://blog.kakaocdn.net/dn/55jU5/btrzS2YtXl8/MrujPvYkBKGdGkkAvrPrWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/55jU5/btrzS2YtXl8/MrujPvYkBKGdGkkAvrPrWk/img.png&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F55jU5%2FbtrzS2YtXl8%2FMrujPvYkBKGdGkkAvrPrWk%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; data-origin-width=&quot;662&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IxyvB/btrzXWcjzht/S5E83tsRszzDrrjVQ5gjAK/img.png&quot; data-url=&quot;https://blog.kakaocdn.net/dn/IxyvB/btrzXWcjzht/S5E83tsRszzDrrjVQ5gjAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IxyvB/btrzXWcjzht/S5E83tsRszzDrrjVQ5gjAK/img.png&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIxyvB%2FbtrzXWcjzht%2FS5E83tsRszzDrrjVQ5gjAK%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; data-origin-width=&quot;662&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Jzr0P/btrzYD4nc0D/0h9NO1UsjVC28BftbXj2gK/img.png&quot; data-url=&quot;https://blog.kakaocdn.net/dn/Jzr0P/btrzYD4nc0D/0h9NO1UsjVC28BftbXj2gK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Jzr0P/btrzYD4nc0D/0h9NO1UsjVC28BftbXj2gK/img.png&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJzr0P%2FbtrzYD4nc0D%2F0h9NO1UsjVC28BftbXj2gK%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; data-origin-width=&quot;662&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xggMi/btrz3lhfemB/WX6L0Gzp600RgkdTRskngK/img.png&quot; data-url=&quot;https://blog.kakaocdn.net/dn/xggMi/btrz3lhfemB/WX6L0Gzp600RgkdTRskngK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xggMi/btrz3lhfemB/WX6L0Gzp600RgkdTRskngK/img.png&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxggMi%2Fbtrz3lhfemB%2FWX6L0Gzp600RgkdTRskngK%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; data-origin-width=&quot;662&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bL1WER/btrz0D33rW7/H2YLmTYk5jkLY1slQdem8K/img.png&quot; data-url=&quot;https://blog.kakaocdn.net/dn/bL1WER/btrz0D33rW7/H2YLmTYk5jkLY1slQdem8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bL1WER/btrz0D33rW7/H2YLmTYk5jkLY1slQdem8K/img.png&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbL1WER%2Fbtrz0D33rW7%2FH2YLmTYk5jkLY1slQdem8K%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; data-origin-width=&quot;662&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DorYW/btrzZyWplVo/JJpG3YbVfBmMc5SfA0em9K/img.png&quot; data-url=&quot;https://blog.kakaocdn.net/dn/DorYW/btrzZyWplVo/JJpG3YbVfBmMc5SfA0em9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DorYW/btrzZyWplVo/JJpG3YbVfBmMc5SfA0em9K/img.png&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDorYW%2FbtrzZyWplVo%2FJJpG3YbVfBmMc5SfA0em9K%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; data-origin-width=&quot;662&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvX674/btrzUzn9SZy/oloB6OZiYBmgdjyyG9Q5TK/img.png&quot; data-url=&quot;https://blog.kakaocdn.net/dn/bvX674/btrzUzn9SZy/oloB6OZiYBmgdjyyG9Q5TK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvX674/btrzUzn9SZy/oloB6OZiYBmgdjyyG9Q5TK/img.png&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvX674%2FbtrzUzn9SZy%2FoloB6OZiYBmgdjyyG9Q5TK%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; data-origin-width=&quot;662&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c01dqX/btrzZAGJ0Of/xjf01bnzC8IYrHLN0Wp7Fk/img.png&quot; data-url=&quot;https://blog.kakaocdn.net/dn/c01dqX/btrzZAGJ0Of/xjf01bnzC8IYrHLN0Wp7Fk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c01dqX/btrzZAGJ0Of/xjf01bnzC8IYrHLN0Wp7Fk/img.png&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc01dqX%2FbtrzZAGJ0Of%2Fxjf01bnzC8IYrHLN0Wp7Fk%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; data-origin-width=&quot;662&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGsWpv/btrz0Dv9mj5/KOkgGpPAKzDiv1Ki3k6b9k/img.png&quot; data-url=&quot;https://blog.kakaocdn.net/dn/bGsWpv/btrz0Dv9mj5/KOkgGpPAKzDiv1Ki3k6b9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGsWpv/btrz0Dv9mj5/KOkgGpPAKzDiv1Ki3k6b9k/img.png&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGsWpv%2Fbtrz0Dv9mj5%2FKOkgGpPAKzDiv1Ki3k6b9k%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; data-origin-width=&quot;662&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;span class=&quot;image-wrap &quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/42l7a/btrzXUyMW4K/Q2T37ZQU1WTn8RQXJy5nVK/img.png&quot; data-url=&quot;https://blog.kakaocdn.net/dn/42l7a/btrzXUyMW4K/Q2T37ZQU1WTn8RQXJy5nVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/42l7a/btrzXUyMW4K/Q2T37ZQU1WTn8RQXJy5nVK/img.png&quot; loading=&quot;lazy&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F42l7a%2FbtrzXUyMW4K%2FQ2T37ZQU1WTn8RQXJy5nVK%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; data-origin-width=&quot;662&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;button class=&quot;btn btn-prev&quot;&gt;&lt;span class=&quot;ico-prev&quot;&gt;이전&lt;/span&gt;&lt;/button&gt;&lt;button class=&quot;btn btn-next&quot;&gt;&lt;span class=&quot;ico-next&quot;&gt;다음&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;
  &lt;div class=&quot;mark&quot;&gt;&lt;span data-index=&quot;0&quot;&gt;0&lt;/span&gt;&lt;span data-index=&quot;1&quot;&gt;1&lt;/span&gt;&lt;span data-index=&quot;2&quot;&gt;2&lt;/span&gt;&lt;span data-index=&quot;3&quot;&gt;3&lt;/span&gt;&lt;span data-index=&quot;4&quot;&gt;4&lt;/span&gt;&lt;span data-index=&quot;5&quot;&gt;5&lt;/span&gt;&lt;span data-index=&quot;6&quot;&gt;6&lt;/span&gt;&lt;span data-index=&quot;7&quot;&gt;7&lt;/span&gt;&lt;span data-index=&quot;8&quot;&gt;8&lt;/span&gt;&lt;span data-index=&quot;9&quot;&gt;9&lt;/span&gt;&lt;span data-index=&quot;10&quot;&gt;10&lt;/span&gt;&lt;span data-index=&quot;11&quot;&gt;11&lt;/span&gt;&lt;span data-index=&quot;12&quot;&gt;12&lt;/span&gt;&lt;span data-index=&quot;13&quot;&gt;13&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;코로나로 인해 혼자 자습할때에 내용을 정리하여 카톡에 공유하였다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;스터디 인원은 3명으로 시작하였으나 나중에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;한 명이&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;더 추가되어 총 4명이 진행하였다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;처음 스터디는 '&lt;/span&gt;섰다 게임을&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;만들어보자!', '체스를 만들어보자!' 등...&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;패기 있게&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;시작하였지만&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;부끄럽게도 숙제가 너무 어려운 나머지 4명의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;인원 모두&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;다 같이&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;모여 숙제를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;할 때가&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;많았다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;그럼에도 불구하고 꾸준하게 스터디를 진행하며 공부하는 시간을 갖다 보니 1차 프로젝트를 시작할 시점에는&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;학원에서 중상위권의 실력을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;갖게 되었었다.&lt;br /&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;(학원을 수료한 시점인 현재는 둘만 남았지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;협업 능력&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;상승과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;실력 향상을&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;토이 프로젝트를&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;계속&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;진행 중이다)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[국비 학원 프로젝트]&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;학원에서는 총 2번의 프로젝트를 진행했었다.&lt;br /&gt;1차 프로젝트는 첫 프로젝트라 잘할 수 있을까라는 걱정이 됐지만 디스코드를 통해 다 같이 소통하고&lt;br /&gt;gidhub와 공유 db를 통해 협업을 진행하여 만족스러운 결과물이 나왔고 진행 과정 가운데&lt;br /&gt;&lt;br /&gt;팀장의 코드를 보고 박탈감과 동시에 많은 자극을 받고 팀장이 쓴 코드를 공부해 응용하며&lt;br /&gt;조금 더 객체지향적인 코드를 생각하게 됐다.&lt;br /&gt;&lt;span style=&quot;color: #666666;&quot;&gt;(1차 프로젝트 종료 후에는 더 좋은 코드를 짜기 위해서 백준 풀이 및 미래를 대비한 스프링 예습을 진행하였다)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;#1차 프로젝트&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;a href=&quot;https://github.com/ohsoou/LibrarySystem&quot;&gt;https://github.com/ohsoou/LibrarySystem&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;opengraph&quot; data-og-title=&quot;GitHub - ohsoou/LibrarySystem: 학교 무인 대출반납기&quot; data-ke-align=&quot;alignCenter&quot; data-og-description=&quot;학교 무인 대출반납기. Contribute to ohsoou/LibrarySystem development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/ohsoou/LibrarySystem&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/N5hUh/hyMpcZoa8X/6xKT384iQbDWMdtvEnLAf0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot; data-og-url=&quot;https://github.com/ohsoou/LibrarySystem&quot;&gt;&lt;a href=&quot;https://github.com/ohsoou/LibrarySystem&quot; data-source-url=&quot;https://github.com/ohsoou/LibrarySystem&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/N5hUh/hyMpcZoa8X/6xKT384iQbDWMdtvEnLAf0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - ohsoou/LibrarySystem: 학교 무인 대출반납기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;학교 무인 대출반납기. Contribute to ohsoou/LibrarySystem development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;2차 프로젝트는 스터디를 끝까지 함께 진행하는 열정적인 친구와 함께 작업하던 토이 프로젝트를&lt;br /&gt;팀 프로젝트로 가져간 것이었다.&lt;br /&gt;&lt;br /&gt;1차 프로젝트 당시 넣고 싶은 기능은 많았으나 과하다는 제지를 받기도 하고 수업 시간이 시작될 때에 나타나고&lt;br /&gt;끝나면 순식간에 사라지는 팀원들을 보며 '모두의 열정이 나와 같은 건 아니구나'라는 걸 느꼈었다.&lt;br /&gt;&lt;br /&gt;2차 프로젝트에서는 '마음이 맞는 팀원들과 함께 다 같이 하고 싶은 주제로 하면 더 열심히 할 수 있지 않을까?'&lt;br /&gt;라는 생각에 토이 프로젝트로 진행하고 있던 제주도 여행 프로젝트를 사전 발표하여&lt;br /&gt;좋은 팀원들을 만나게 되었고 정말 만족할 만한 결과물을 내놓게 되었다.&lt;br /&gt;&lt;br /&gt;돌이켜보면 아쉬운 점이 없었다면 거짓말인 것 같다&lt;br /&gt;3주라는 시간밖에 주어지지 않았었고 지금의 내가 보기에도 수정할 곳이 정말 많은 것 같다&lt;br /&gt;하지만 나는 후회 없을 만큼 노력했다.&lt;br /&gt;&lt;br /&gt;#2차 프로젝트&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;a href=&quot;https://github.com/JejuislandToyProject/JejuIsland&quot;&gt;https://github.com/JejuislandToyProject/JejuIsland&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;opengraph&quot; data-og-title=&quot;GitHub - JejuislandToyProject/JejuIsland: 제주도 홍보 토이 프로젝트&quot; data-ke-align=&quot;alignCenter&quot; data-og-description=&quot;제주도 홍보 토이 프로젝트. Contribute to JejuislandToyProject/JejuIsland development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/JejuislandToyProject/JejuIsland&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/pS9rS/hyMo3g5K09/QKo2zGgR9kJ4Z0R3NSQo00/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot; data-og-url=&quot;https://github.com/JejuislandToyProject/JejuIsland&quot;&gt;&lt;a href=&quot;https://github.com/JejuislandToyProject/JejuIsland&quot; data-source-url=&quot;https://github.com/JejuislandToyProject/JejuIsland&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/pS9rS/hyMo3g5K09/QKo2zGgR9kJ4Z0R3NSQo00/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - JejuislandToyProject/JejuIsland: 제주도 홍보 토이 프로젝트&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;제주도 홍보 토이 프로젝트. Contribute to JejuislandToyProject/JejuIsland development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2-1. 현재 (꾸준함의 결과물&lt;/b&gt;&lt;b&gt;)&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;학원 과정을 밟아가며 꾸준히 노력하였던 것들이 좋은 결과가 된 이야기이다&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;사실 이건 내가 뿌듯하기도 하고 자랑하고 싶어서 쓰는 글이다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[토이 프로젝트]&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;# 베이스볼 게임 토이 프로젝트&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;링크제거&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;1차 프로젝트를 시작하기 전 내 실력 향상에 가장 큰 도움이 되었던 프로젝트가 아닌가 싶다.&lt;br /&gt;지금 와서 보면 정말 별거 없고 왜 저걸 저렇게 고생해서 만들었을까 싶지만 그 당시에는 정말 많은 고민을&lt;br /&gt;하며 만들었던 토이 프로젝트이다.&lt;br /&gt;&lt;br /&gt;BaseBall 토이 프로젝트는 나와 열정적인 친구 둘이서 진행하였다.&lt;br /&gt;&lt;br /&gt;# 시약관리 웹 사이트 토이 프로젝트&lt;br /&gt;링크제거&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;시약 관리 웹 사이트는 현재 진행형이다(2021.11.22)&lt;br /&gt;2차 프로젝트로 진행했던 제주도 프로젝트에서는 게시판에 부족한 부분이 많았고&lt;br /&gt;내가 맡아서 진행했던 페이지가 아니기에 좀 더 게시판을 만드는 것에 대해서 공부하고 싶다는 생각이 들어&lt;br /&gt;진행 중이며 이 글을 작성하는 현시점에서는 로그인, 회원가입, 게시판 불러오기 및 페이징 기능뿐이다&lt;br /&gt;앞으로 이메일 인증 및 게시판 작성 수정 삭제 등... 여러 가지 기능이 계속 추가될 예정이다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[백준 코딩 테스트]&lt;/b&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;a href=&quot;https://choidoosic.tistory.com/category/%EA%B8%B0%EB%8A%A5%2C%EA%B0%9C%EB%85%90%20%26%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot;&gt;https://choidoosic.tistory.com/category/%EA%B8%B0%EB%8A%A5%2C%EA%B0%9C%EB%85%90%20%26%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;opengraph&quot; data-og-title=&quot;'기능,개념 &amp;amp; 알고리즘/알고리즘' 카테고리의 글 목록&quot; data-ke-align=&quot;alignCenter&quot; data-og-description=&quot;개발자의 성장 기록&quot; data-og-host=&quot;choidoosic.tistory.com&quot; data-og-source-url=&quot;https://choidoosic.tistory.com/category/%EA%B8%B0%EB%8A%A5%2C%EA%B0%9C%EB%85%90%20%26%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cbCelG/hyMofi6oKu/7HoVqKsLVRkKjCsZolmxZ0/img.jpg?width=1280&amp;amp;height=960&amp;amp;face=0_0_1280_960,https://scrap.kakaocdn.net/dn/lgUBW/hyMoeYP7S6/SRCKKAjHZRNlhUhmPShW01/img.jpg?width=1280&amp;amp;height=960&amp;amp;face=0_0_1280_960,https://scrap.kakaocdn.net/dn/b2VEJM/hyMocUebxO/8N77R70Kof71RS8JJzp0E1/img.png?width=1100&amp;amp;height=541&amp;amp;face=0_0_1100_541&quot; data-og-url=&quot;https://choidoosic.tistory.com/category/%EA%B8%B0%EB%8A%A5%2C%EA%B0%9C%EB%85%90%20%26%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot;&gt;&lt;a href=&quot;https://choidoosic.tistory.com/category/%EA%B8%B0%EB%8A%A5%2C%EA%B0%9C%EB%85%90%20%26%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot; data-source-url=&quot;https://choidoosic.tistory.com/category/%EA%B8%B0%EB%8A%A5%2C%EA%B0%9C%EB%85%90%20%26%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cbCelG/hyMofi6oKu/7HoVqKsLVRkKjCsZolmxZ0/img.jpg?width=1280&amp;amp;height=960&amp;amp;face=0_0_1280_960,https://scrap.kakaocdn.net/dn/lgUBW/hyMoeYP7S6/SRCKKAjHZRNlhUhmPShW01/img.jpg?width=1280&amp;amp;height=960&amp;amp;face=0_0_1280_960,https://scrap.kakaocdn.net/dn/b2VEJM/hyMocUebxO/8N77R70Kof71RS8JJzp0E1/img.png?width=1100&amp;amp;height=541&amp;amp;face=0_0_1100_541');&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;'기능,개념 &amp;amp; 알고리즘/알고리즘' 카테고리의 글 목록&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개발자의 성장 기록&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choidoosic.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;1차 프로젝트 이후 팀장님이 짠 코드를 보며 많은 자극을 받았었고&lt;br /&gt;조금 더 간결하고 효율적인 좋은 코드를 짜기 위해 백준 알고리즘 문제를 풀며 실력을 향상했다&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[인프런 강의를 통한 예습]&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;647&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuPd3m/btrz0vEwlOE/jP8Firumr9eCjk9sgNNuWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuPd3m/btrz0vEwlOE/jP8Firumr9eCjk9sgNNuWK/img.png&quot; data-alt=&quot;코딩 테스트와 병행하느라 전부 듣지는 못하였다! (조금 남았다)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuPd3m/btrz0vEwlOE/jP8Firumr9eCjk9sgNNuWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcuPd3m%2Fbtrz0vEwlOE%2FjP8Firumr9eCjk9sgNNuWK%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;1226&quot; height=&quot;647&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;647&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;코딩 테스트와 병행하느라 전부 듣지는 못하였다! (조금 남았다)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;'학원에서 배울 내용 돈 주고 미리 뭐 하러 예습해?'라는 말을 듣기도 하였지만 내 대답은 &lt;b&gt;&quot;더 잘하고 싶어서였다&quot;&lt;/b&gt;강의를 들으며 그냥 듣고 흘리지 않고 블로그에 배운 내용을 작성하며 기억하려고 노력했었다. 학원에서 스프링을 배울 시점에는 예습해둔 것이 많은 도움이 되었다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[블로그]&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;블로그는 현재 회고록이 작성되고 있는 블로그이다.&lt;br /&gt;사실 처음에는 블로그를 포스팅할 생각이 없었는데 스터디를 하는 친구가 블로그를 강력히 추천하기에 시작하였고&lt;br /&gt;그 결과는 강력히 추천할 만했다는 결과가 나왔다.&lt;br /&gt;&lt;br /&gt;블로그를 포스팅하며 내가 배운 것들에 대한 정리를 한 번 더 하게 되었으며&lt;br /&gt;학원에서 풀었던 문제에 대한 코드를 글로 적다가도&lt;br /&gt;내가 대충 이해했던 것이 발견되면 그걸 설명하기 위해서라도 더욱더 문제를 파고들었고&lt;br /&gt;그런 것들이 쌓이고 쌓여 실력으로 return 되었다.&lt;br /&gt;&lt;br /&gt;그리고 내가 쓴 코드들을 포스팅할 때에는 코드 리팩터링 할 부분도 발견되어 '이렇게 쓰면 더 좋겠는데?'&lt;br /&gt;라는 부분이 생각보다 많이 발견되었다.&lt;br /&gt;&lt;br /&gt;정말 많은 부분들에 있어서 도움이 되는 블로그는 꾸준히 작성해 나아갈 것이다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 미래 (앞의로의 계획&lt;/b&gt;&lt;b&gt;)&lt;/b&gt;&lt;/h3&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;[ 첫 번째 목표 ] (2021.12.01 취업 완료)&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;당장의 첫 번째 목표는 취업이라고 할 수 있다.&lt;br /&gt;학원을 수료한 시점에 빠르게 취업을 하여 풀어지지 않고 끊임없이 성장하는 게 첫 번째 목표다.&lt;br /&gt;&lt;br /&gt;개발자들이 소통하는 영상을 보던 도중 이러한 말을 들었다.&lt;br /&gt;&lt;b&gt;&quot;개발자들이 퇴사하는 이유 중 하나가 이 회사에서 성장할 수 없다고 느낄 때 즉, 내 실력을 쫓아오고 자극하는 사람이&lt;/b&gt;&lt;br /&gt;&lt;b&gt;없을 때에 회사를 떠나기도 한다&quot;라고.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;나는 이 문제를 해결할 수 있는 사람 중 하나라고 생각한다.&lt;br /&gt;느리게 성장하는 듯싶지만 꾸준함을 무기로 선임 개발자들이 방심하는 사이 빠르게 기술을 배워&lt;br /&gt;눈앞에 당도해 있을 것이다.&lt;br /&gt;&lt;br /&gt;나는 실력 향상에 목이 마른 사람이다.&lt;br /&gt;그러므로 좋은 회사에 취직해 좋은 코드를 보고 좋은 선임을 만나 성장하고 싶다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[ 두 번째 목표 ]&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;꾸준한 스터디를 두 번째 목표로 둔다.&lt;br /&gt;사는 건 물이 흐르는 것과 같아서 내가 조금만 멈춰도 남들이 발버둥 치며 계속 전진하기에&lt;br /&gt;멈추는 것은 도태되는 것이라고 생각한다.&lt;br /&gt;12월부터 2월까지 매주 토요일에는 SQLD 자격증을 목표로 공부하기로 다짐하였다.&lt;br /&gt;&lt;br /&gt;데이터베이스를 1차 때에는 팀원들과 함께 구성하였고&lt;br /&gt;2차 프로젝트 때에는 팀원 한 명과 디비를 구성하였는데 부족함을 많이 느꼈다&lt;br /&gt;SQLD 자격증을 목표로 공부하며 부족한 부분을 좀 더 보완해보고자 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1154&quot; data-origin-height=&quot;618&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Es61P/btrzYgBCZ0x/cuocFYBRdlmsWlhTHZYJnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Es61P/btrzYgBCZ0x/cuocFYBRdlmsWlhTHZYJnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Es61P/btrzYgBCZ0x/cuocFYBRdlmsWlhTHZYJnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEs61P%2FbtrzYgBCZ0x%2FcuocFYBRdlmsWlhTHZYJnk%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;1154&quot; height=&quot;618&quot; data-origin-width=&quot;1154&quot; data-origin-height=&quot;618&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;606&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhtGZT/btrzYF9xrZT/rplF6Tn7wTp48RBSTXZgIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhtGZT/btrzYF9xrZT/rplF6Tn7wTp48RBSTXZgIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhtGZT/btrzYF9xrZT/rplF6Tn7wTp48RBSTXZgIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhtGZT%2FbtrzYF9xrZT%2FrplF6Tn7wTp48RBSTXZgIk%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;490&quot; height=&quot;1035&quot; data-origin-width=&quot;606&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[세 번째 목표]&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;꾸준한 블로그 작성이다.&lt;br /&gt;블로그 작성은 나에게 많은 도움이 되었고 앞으로도 그러할 것이라고 생각한다&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[ 마무리 ]&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;개발자로서 아직은 많이 미숙하고 부족하기에&lt;br /&gt;내년은 신입 개발자로서 뭐든 할 수 있다는 마음을 가지고 나아가려고 한다&lt;br /&gt;2022년에 내가 가지고 갈 문장은&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;할 수 있다, 하면 된다, 해보자&quot;&lt;/b&gt;이다.&lt;/p&gt;</description>
      <category>기록</category>
      <category>2021 개발자</category>
      <category>2021 회고록</category>
      <category>개발자</category>
      <category>회고록</category>
      <author>I move forward every day.</author>
      <guid isPermaLink="true">https://doosicee.tistory.com/1</guid>
      <comments>https://doosicee.tistory.com/entry/%EB%B9%84%EC%A0%84%EA%B3%B5-%EA%B0%9C%EB%B0%9C%EC%9E%90%EC%9D%98-2021-%ED%9A%8C%EA%B3%A0%EB%A1%9D#entry1comment</comments>
      <pubDate>Thu, 21 Apr 2022 09:45:08 +0900</pubDate>
    </item>
  </channel>
</rss>