<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>윤개발</title>
    <link>https://codinghack.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Thu, 9 Apr 2026 19:54:17 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>DEV_SJ</managingEditor>
    <image>
      <title>윤개발</title>
      <url>https://tistory1.daumcdn.net/tistory/3105585/attach/3bb62bbf9f2244dda8bd45d18893bc1c</url>
      <link>https://codinghack.tistory.com</link>
    </image>
    <item>
      <title>Mongodb 도큐먼트 삭제(delete document)</title>
      <link>https://codinghack.tistory.com/99</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이제 데이터베이스에 있는 데이터를 삭제해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;417&quot; data-origin-height=&quot;418&quot; width=&quot;269&quot; height=&quot;270&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/04lCT/btrg4K7Od47/2gXoYmK6RKIj2bGFGdeeck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/04lCT/btrg4K7Od47/2gXoYmK6RKIj2bGFGdeeck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/04lCT/btrg4K7Od47/2gXoYmK6RKIj2bGFGdeeck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F04lCT%2Fbtrg4K7Od47%2F2gXoYmK6RKIj2bGFGdeeck%2Fimg.png&quot; data-origin-width=&quot;417&quot; data-origin-height=&quot;418&quot; width=&quot;269&quot; height=&quot;270&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Nanum Gothic';&quot;&gt;&lt;b&gt;도큐먼트 삭제&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;&quot;&gt;삭제는 &lt;b&gt;deleteOne과 deleteMany&lt;/b&gt;를 제공한다. 두 메서드 모두 첫 번째 매개변수로 제거할 기준을 지정한다. 예를 들어 &quot;_id&quot; 값이 4인 도큐먼트는 아래와 같이 삭제할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1633574748832&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;db.movies.deleteOne({&quot;_id&quot;:4})&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1633574778999&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{ &quot;acknowledged&quot; : true, &quot;deleteCount&quot; : 1}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&quot;_id&quot; 값이 컬렉션에서 고유하기 때문에 하나만 삭제할 수 있었지만 여러 도큐먼트와 일치하는 필터도 지정할 수 있다. 이 때 d&lt;b&gt;eleteOne은 필터와 일치하는 첫 번째 도큐먼트를 삭제&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: 'Nanum Gothic';&quot;&gt;필터와 일치하는 모든 도큐먼트를 삭제하려면 deleteMany를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1633575054108&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;db.movies.deleteMany({&quot;year&quot; : &quot;1994&quot;})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;전체 컬렉션을 제거하려면 아래와 같이 빈 값을 넘겨주면 된다. 그러나 전체 컬렉션을 삭제하려면 drop을 사용하는 편이 더 빠르다.&lt;/p&gt;
&lt;pre id=&quot;code_1633575148976&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;db.movies.deleteMany({})&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1633575164705&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;db.movies.drop()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;데이터는 한 번 제거하면 영원히 사라진다. 이전에 백업된 데이터를 복원하는 방법 외에 delete 또는 drop 작업을 취소하거나 삭제된 도큐먼트를 복구하는 방법은 없다. 백업 및 복원 방법에 대해서는 나중에 알아보자.&lt;/p&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;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;출처 및 참고&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot;&gt;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1633574971002&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;books.book&quot; data-og-title=&quot;[전자책] MongoDB 완벽 가이드&quot; data-og-description=&quot;몽고DB 입문자를 위한 기초부터 실제 배포에 적용할 수 있는 실용적이고 깊이 있는 내용까지 담았다. 개정 3판에서는 성능이 강화된 몽고DB 최신 버전을 반영해 복제와 샤딩을 더 깊이 다루며 개&quot; data-og-host=&quot;www.aladin.co.kr&quot; data-og-source-url=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot; data-og-url=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/chRBdE/hyLSsaYQ8g/Pn4fRWYnGac25wW1zS92g0/img.png?width=500&amp;amp;height=642&amp;amp;face=0_0_500_642,https://scrap.kakaocdn.net/dn/bMg6EN/hyLSCScy01/DAItQazYoLgDKIx948ojlk/img.png?width=500&amp;amp;height=642&amp;amp;face=0_0_500_642&quot;&gt;&lt;a href=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/chRBdE/hyLSsaYQ8g/Pn4fRWYnGac25wW1zS92g0/img.png?width=500&amp;amp;height=642&amp;amp;face=0_0_500_642,https://scrap.kakaocdn.net/dn/bMg6EN/hyLSCScy01/DAItQazYoLgDKIx948ojlk/img.png?width=500&amp;amp;height=642&amp;amp;face=0_0_500_642');&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;[전자책] MongoDB 완벽 가이드&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;몽고DB 입문자를 위한 기초부터 실제 배포에 적용할 수 있는 실용적이고 깊이 있는 내용까지 담았다. 개정 3판에서는 성능이 강화된 몽고DB 최신 버전을 반영해 복제와 샤딩을 더 깊이 다루며 개&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.aladin.co.kr&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백엔드/mongoDB</category>
      <author>DEV_SJ</author>
      <guid isPermaLink="true">https://codinghack.tistory.com/99</guid>
      <comments>https://codinghack.tistory.com/99#entry99comment</comments>
      <pubDate>Thu, 7 Oct 2021 11:53:48 +0900</pubDate>
    </item>
    <item>
      <title>Mongodb 도큐먼트 생성(Insert document)</title>
      <link>https://codinghack.tistory.com/98</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이번에는 몽고DB의 기본적인 데이터 입력을 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;417&quot; data-origin-height=&quot;418&quot; width=&quot;275&quot; height=&quot;276&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l140q/btrg104z06y/qgnmfQZfiEQjA0ql21suz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l140q/btrg104z06y/qgnmfQZfiEQjA0ql21suz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l140q/btrg104z06y/qgnmfQZfiEQjA0ql21suz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl140q%2Fbtrg104z06y%2FqgnmfQZfiEQjA0ql21suz0%2Fimg.png&quot; data-origin-width=&quot;417&quot; data-origin-height=&quot;418&quot; width=&quot;275&quot; height=&quot;276&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Nanum Gothic';&quot;&gt;&lt;b&gt;도큐먼트 삽입&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;삽입은 몽고DB에 데이터를 추가하는 기본 방법이다. &lt;b&gt;도큐먼트를 삽입하려면 컬렉션의 insertOne 메서드를 사용&lt;/b&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1633528039281&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; db.movies.insertOne({&quot;title&quot; : &quot;Movie 1&quot;})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러면 도큐먼트에 &quot;_id&quot; 키가 추가되고 몽고DB에 저장된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1633528297062&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	&quot;acknowledged&quot; : true,
	&quot;insertedId&quot; : ObjectId(&quot;615da8db82227ce1f4f7d899&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;또한 &lt;b&gt;여러 도큐먼트를 삽입하려면 insertMany를 사용&lt;/b&gt;하면 된다. 각 도큐먼트에 대해 데이터베이스에 왕복하지 않고 삽입하므로 훨씬 더 효율적이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1633528286026&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; db.movies.insertMany([{&quot;title&quot;:&quot;Movie 2&quot;},{&quot;title&quot;:&quot;Movie 3&quot;},{&quot;title&quot;:&quot;Movie 4&quot;}])&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1633528309191&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	&quot;acknowledged&quot; : true,
	&quot;insertedIds&quot; : [
		ObjectId(&quot;615da9d182227ce1f4f7d89a&quot;),
		ObjectId(&quot;615da9d182227ce1f4f7d89b&quot;),
		ObjectId(&quot;615da9d182227ce1f4f7d89c&quot;)
	]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;수천 개의 도큐먼트를 한 번에 전송하면 도큐먼트 삽입이 매우 빨라진다. 다만 다중 삽입 시에 중간에 오류가 발생한다면 정렬 연산(Ordered)인지 비정렬 연산(Unordered)인지에&amp;nbsp; 따라 발생하는 상황이 달라진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;따라서 insertMany의 두 번째 매개변수로 옵션 도큐먼트를 지정할 수 있다.(기본 값은 정렬 삽입이다.)&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: 'Nanum Gothic';&quot;&gt;해당 옵션이 지정되면 배열에서 해당 지점을&amp;nbsp;&lt;b&gt;벗어난 이후의 도큐먼트는 삽입되지 않는다.&lt;/b&gt; &lt;b&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;삽입 유효성 검사&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;몽고DB는 삽입된 데이터에 최소한의 검사를 수행한다. 도큐먼트의 기본 구조를 검사해 &quot;_id&quot; 필드가 존재하지 않으면 새로 추가하고, 모든 도큐먼트는 16메가 바이트보다 작아야하므로 크기를 검사한다.&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot;&gt;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&lt;/a&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1633528933535&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;books.book&quot; data-og-title=&quot;[전자책] MongoDB 완벽 가이드&quot; data-og-description=&quot;몽고DB 입문자를 위한 기초부터 실제 배포에 적용할 수 있는 실용적이고 깊이 있는 내용까지 담았다. 개정 3판에서는 성능이 강화된 몽고DB 최신 버전을 반영해 복제와 샤딩을 더 깊이 다루며 개&quot; data-og-host=&quot;www.aladin.co.kr&quot; data-og-source-url=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot; data-og-url=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/e0nJY/hyLRi1L2rK/4xfgvTKHN6f3fvWQ0rZoM0/img.png?width=500&amp;amp;height=642&amp;amp;face=0_0_500_642,https://scrap.kakaocdn.net/dn/jpOQb/hyLSDiTMPr/F0QXrzI5OueaIf3ViG5Qnk/img.png?width=500&amp;amp;height=642&amp;amp;face=0_0_500_642&quot;&gt;&lt;a href=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/e0nJY/hyLRi1L2rK/4xfgvTKHN6f3fvWQ0rZoM0/img.png?width=500&amp;amp;height=642&amp;amp;face=0_0_500_642,https://scrap.kakaocdn.net/dn/jpOQb/hyLSDiTMPr/F0QXrzI5OueaIf3ViG5Qnk/img.png?width=500&amp;amp;height=642&amp;amp;face=0_0_500_642');&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;[전자책] MongoDB 완벽 가이드&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;몽고DB 입문자를 위한 기초부터 실제 배포에 적용할 수 있는 실용적이고 깊이 있는 내용까지 담았다. 개정 3판에서는 성능이 강화된 몽고DB 최신 버전을 반영해 복제와 샤딩을 더 깊이 다루며 개&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.aladin.co.kr&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>백엔드/mongoDB</category>
      <author>DEV_SJ</author>
      <guid isPermaLink="true">https://codinghack.tistory.com/98</guid>
      <comments>https://codinghack.tistory.com/98#entry98comment</comments>
      <pubDate>Wed, 6 Oct 2021 23:02:10 +0900</pubDate>
    </item>
    <item>
      <title>MongoDB 기본(document, collection, _id)</title>
      <link>https://codinghack.tistory.com/97</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;몽고DB는 매우 강력하면서도 진입장벽이 낮다. 몽고DB의 기본 개념에 대해 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;417&quot; data-origin-height=&quot;418&quot; width=&quot;301&quot; height=&quot;302&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nF4Vs/btrg3sF2qBs/o6z23l58S437ojCuz2ko50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nF4Vs/btrg3sF2qBs/o6z23l58S437ojCuz2ko50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nF4Vs/btrg3sF2qBs/o6z23l58S437ojCuz2ko50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnF4Vs%2Fbtrg3sF2qBs%2Fo6z23l58S437ojCuz2ko50%2Fimg.png&quot; data-origin-width=&quot;417&quot; data-origin-height=&quot;418&quot; width=&quot;301&quot; height=&quot;302&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Nanum Gothic';&quot;&gt;&lt;b&gt;도큐먼트&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;몽고DB의 핵심은 &lt;b&gt;정렬된 키와 연결된 값의 집합으로 이뤄진 도큐먼트&lt;/b&gt;다. 도큐먼트 표현 방식은 프로그래밍 언어마다 다르지만 자바스크립트 객체로 표현하겠다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1633521795489&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{&quot;name&quot; : &quot;Hello world!&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 간단한 도큐먼트는 name 키 값과 벨류를 가진다. 대부분의 도큐먼트는 이보다 복잡한 다중 키/값 쌍을 가진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;또한 몽고DB는 &lt;b&gt;데이터형과 대소문자를 구별하고 중복된 키를 넣을 수 없다&lt;/b&gt;. 아래 도큐먼트는 올바른 도큐먼트가 아니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1633521896005&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{&quot;name&quot; : &quot;123&quot;, &quot;name&quot; : &quot;456&quot;}&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: 'Nanum Gothic';&quot;&gt;&lt;b&gt;컬렉션&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컬렉션은 도큐먼트의 모음이다. 몽고DB의 도큐먼트가 관계형 데이터베이스의 행에 대응된다면 &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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;동적 컬렉션&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&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: 'Nanum Gothic';&quot;&gt;예를 들어 다음 도큐먼트들을 하나의 컬렉션에 저장할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1633522018256&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{&quot;name&quot;:&quot;123&quot;}
{&quot;hello&quot;:&quot;world&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&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: 'Nanum Gothic';&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: 'Nanum Gothic';&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: 'Nanum Gothic';&quot;&gt;애플리케이션 스키마는 기본적으로 필요하지는 않지만 정의하면 좋다. 몽고DB의 도큐먼트 유효성 검사기능과 객체-도큐먼트 매핑 라이브러리를 이용하는 많은 프로그래밍 언어에서 사용 가능하다.&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;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;서브 컬렉션&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컬렉션의 네임스페이스에 .(마침표) 문자를 사용해 컬렉션을 체계화한다. 예를 들어 블로그 기능이 있는 애플리케이션은 blog.posts와 blog.authors라는 컬렉션을 가질 수 있다. 이는 &lt;b&gt;단지 체계화를 위함이며 아무런 관계는 없다&lt;/b&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;내장 도큐먼트&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&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: 'Nanum Gothic';&quot;&gt;예를 들어 한사람의 정보를 나타내는 도큐먼트에 그의 주소를 저장하려면 정보를 &quot;address&quot; 내장 도큐먼트로 중첩한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1633523916274&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;name&quot; : &quot;yoon&quot;,
  &quot;address&quot; : {
    &quot;city&quot; : &quot;bundang&quot;,
    &quot;street&quot; : &quot;migeum111&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&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: 'Nanum Gothic';&quot;&gt;&lt;b&gt;_id와 ObjectId&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;몽고DB에 저장된 모든 도큐먼트는 &quot;_id&quot; 키를 가진다.&lt;/b&gt; &quot;_id&quot; 키 값은 어떤 데이터형이어도 상관 없지만 &quot;ObjectId&quot;가 기본이다. 하나의 컬렉션에서 모든 도큐먼트는 고유한 &quot;_id&quot; 값을 가지며, 이 값은 컬렉션 내 모든 도큐먼트가 고유하게 식별되게 한다.&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;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;ObjectIds&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;ObjectId는 &quot;_id&quot;의 기본 데이터형&lt;/b&gt;이다. ObjectId 클래스는 경량으로 설계됐으면서도 여러 장비에 걸쳐 전역적으로 유일한 방법으로 생성하기도 쉽다. 자동 증가하는 기본 키처럼 전통적인 것이 아닌 ObjectId를 사용하는 주요 이유는 몽고DB의 분산 특성 떄문이다. &lt;b&gt;여러 서버에 걸쳐 자동으로 증가하는 기본 키를 동기화 하는 작업은 어렵고 시간이 걸린다.&lt;/b&gt; &lt;b&gt;몽고DB는 분산 데이터베이스로 설계됐기 때문에 샤딩된 환경에서 고유 식별자를 생성하는 것이 매우 중요&lt;/b&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;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;ObjectId는 12바이트 스토리지&lt;/b&gt;를 사용하며 24자리 16진수 문자열 표현이 가능하다. 바이트당 2자리를 사용한다. 여러개의 새로운 ObjectId를 연속으로 생성하면 매번 마지막 숫자 몇개만 바뀐다. 몇 초 간격을 두고 생성하면 중간 숫자 몇개가 바뀐다. 이는 생성되는 방식 때문이다.&lt;/span&gt;&lt;/p&gt;
&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: 'Nanum Gothic';&quot;&gt;&lt;b&gt;ObectId의 첫 4바이트는 타임스탬프다&lt;/b&gt;. 1970년 1월 1일부터의 시간을 1/1000초 단위로 저장하는 타임스탬프이며 유용한 속성을 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp; - 타임스탬프는 4바이트 이후 뒤의 값 5바이트~ 묶일 때 초단위의 유일성을 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp; - 타임스탬프가 맨 처음에 온다는 것은 ObjectId가 대략 입력 순서대로 정렬된다는 의미다. 이는 확실히 보장되지는 않지만 효율적으로 인&amp;nbsp; &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: 'Nanum Gothic';&quot;&gt;&lt;b&gt;다음 5바이트는 랜덤 값이다.&amp;nbsp;&lt;/b&gt;최종 3바이트는 서로 다른 시스템에서 충돌하는 ObjectId들을 생성하지 않도록 랜덤 값으로 시작하는 카운터다. ObjectId의 앞 9바이트는 1초 동안 여러 장비와 프로세스에 걸쳐 &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: 'Nanum Gothic';&quot;&gt;&lt;b&gt;마지막 3바이트는 단순히 증분하는 숫자&lt;/b&gt;로 1초 내 단일 프로세스의 유일성을 보장한다. 고유한 ObjectId는 프로세스당 1초에 256^3(1677만7216)개까지 생성된다.&lt;/span&gt;&lt;/p&gt;
&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: 'Nanum Gothic';&quot;&gt;도큐먼트를 입력할 때 &quot;_id&quot; 키를 명시하지 않으면 키가 자동으로 추가된다. 이는 몽고DB 서버에서 관리할 수 있지만 일반적으로 클라이언트 쪽 드라이버에서 관리한다.&lt;/span&gt;&lt;/p&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: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot;&gt;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&lt;/a&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1633525079312&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;books.book&quot; data-og-title=&quot;[전자책] MongoDB 완벽 가이드&quot; data-og-description=&quot;몽고DB 입문자를 위한 기초부터 실제 배포에 적용할 수 있는 실용적이고 깊이 있는 내용까지 담았다. 개정 3판에서는 성능이 강화된 몽고DB 최신 버전을 반영해 복제와 샤딩을 더 깊이 다루며 개&quot; data-og-host=&quot;www.aladin.co.kr&quot; data-og-source-url=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot; data-og-url=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/e0nJY/hyLRi1L2rK/4xfgvTKHN6f3fvWQ0rZoM0/img.png?width=500&amp;amp;height=642&amp;amp;face=0_0_500_642,https://scrap.kakaocdn.net/dn/jpOQb/hyLSDiTMPr/F0QXrzI5OueaIf3ViG5Qnk/img.png?width=500&amp;amp;height=642&amp;amp;face=0_0_500_642&quot;&gt;&lt;a href=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/e0nJY/hyLRi1L2rK/4xfgvTKHN6f3fvWQ0rZoM0/img.png?width=500&amp;amp;height=642&amp;amp;face=0_0_500_642,https://scrap.kakaocdn.net/dn/jpOQb/hyLSDiTMPr/F0QXrzI5OueaIf3ViG5Qnk/img.png?width=500&amp;amp;height=642&amp;amp;face=0_0_500_642');&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;[전자책] MongoDB 완벽 가이드&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;몽고DB 입문자를 위한 기초부터 실제 배포에 적용할 수 있는 실용적이고 깊이 있는 내용까지 담았다. 개정 3판에서는 성능이 강화된 몽고DB 최신 버전을 반영해 복제와 샤딩을 더 깊이 다루며 개&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.aladin.co.kr&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백엔드/mongoDB</category>
      <author>DEV_SJ</author>
      <guid isPermaLink="true">https://codinghack.tistory.com/97</guid>
      <comments>https://codinghack.tistory.com/97#entry97comment</comments>
      <pubDate>Wed, 6 Oct 2021 22:09:30 +0900</pubDate>
    </item>
    <item>
      <title>MongoDB 소개 및 특정</title>
      <link>https://codinghack.tistory.com/96</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;몽고DB는 &lt;b&gt;강력하고 유연하며 확정성 높은&lt;/b&gt; &lt;b&gt;데이터베이스&lt;/b&gt;다. 몽고DB의 특징에 대해 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;417&quot; data-origin-height=&quot;418&quot; width=&quot;301&quot; height=&quot;302&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uIbIc/btrgYkpd4AA/VEPkZGpDn5za6eVpPSQKk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uIbIc/btrgYkpd4AA/VEPkZGpDn5za6eVpPSQKk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uIbIc/btrgYkpd4AA/VEPkZGpDn5za6eVpPSQKk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuIbIc%2FbtrgYkpd4AA%2FVEPkZGpDn5za6eVpPSQKk1%2Fimg.png&quot; data-origin-width=&quot;417&quot; data-origin-height=&quot;418&quot; width=&quot;301&quot; height=&quot;302&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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: 'Nanum Gothic';&quot;&gt;1. 손쉬운 사용&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;몽고DB는 관계형 데이터베이스가 아니라 &lt;b&gt;도큐먼트 지향&lt;/b&gt; 데이터베이스다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;관계형 모델을 사용하지 않는 주된 이유는 &lt;b&gt;분산 확장(Scale-out)&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: 'Nanum Gothic';&quot;&gt;도큐먼트 지향 데이터베이스에서는 행 개념 대신에 보다 유연한 모델인 &lt;b&gt;document&lt;/b&gt;를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;내장 도큐먼트와 배열을 허용함으로써 document 지향 모델은 복&lt;b&gt;잡한 계층관계를 하나의 레코드로 표현&lt;/b&gt;할 수 있다.&amp;nbsp;이 방식은 최신 객체 지향 언어를 사용하는 개발자의 관점에 매우 적합하다.&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: 'Nanum Gothic';&quot;&gt;또한 몽고DB에서는 도큐먼트의 키와 값을 미리 정의하지 않는다. 따라서 &lt;b&gt;고정된 스키마가 없다&lt;/b&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;고정된 스키마가 없으므로 &lt;b&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2. 확장 가능한 설계&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;애플리케이션 데이터의 크기는 시간이 지날수록 증가하고 있다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;데이터가 증가함에 따라 개발자는 '&lt;b&gt;데이터베이스를 어떻게 확장할 것인가'&lt;/b&gt;와 같은 의사결정을 해야하는 상황에 직면한다. 확장은 결국 더 큰 장비로 업그레이드하는&amp;nbsp;&lt;b&gt;Scale-up&lt;/b&gt;을 할지 혹은 여러 장비에 데이터를 분산 저장하는&amp;nbsp;&lt;b&gt;Scale-out&lt;/b&gt;을 할지 결정해야한다.&amp;nbsp;&amp;nbsp;일반적으로 성능 확장이 더 편한 길이지만 단점이 있다. 대형 장비는 가격이 비싼 편이고 나중에는 결국 물리적 한계에 부딪히고 만다. 반면에 분산 확장은 수천 대의 장비를 운영해야 하기 때문에 하나의 장비만 관리할 때보다 관리가 더 어려워진다.&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: 'Nanum Gothic';&quot;&gt;&lt;b&gt;몽고 DB는 분산 확장을 염두에 두고 설계&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-origin-width=&quot;704&quot; data-origin-height=&quot;454&quot; data-filename=&quot;스크린샷 2021-10-06 오후 7.56.34.png&quot; width=&quot;445&quot; height=&quot;287&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d1evku/btrgYkbAi3Q/eryyiiQKh7KOUIxulc0K70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d1evku/btrgYkbAi3Q/eryyiiQKh7KOUIxulc0K70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d1evku/btrgYkbAi3Q/eryyiiQKh7KOUIxulc0K70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd1evku%2FbtrgYkbAi3Q%2FeryyiiQKh7KOUIxulc0K70%2Fimg.png&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;454&quot; data-filename=&quot;스크린샷 2021-10-06 오후 7.56.34.png&quot; width=&quot;445&quot; height=&quot;287&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이를 통해 개발자는 애플리케이션을 확장하는 것이 아닌 프로그래밍에 집중할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&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;font-family: 'Nanum Gothic';&quot;&gt;3. 다양한 기능&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;몽고DB는 범용 데이터베이스로 만들어졌기 떄문에 데이터의 CRUD 외에도 DBMS의 대부분의 기능과 더불어 다음 기능을 제공한다.&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;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&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: 'Nanum Gothic';&quot;&gt;몽고DB는 일반적인 보조 인덱스(Secondary-index)를 지원하며 Unique, compound, Full-text 인덱싱 기능도 제공한다. 또한 중첩된 도큐먼트 및 배열과 같은 계층 구조의 보조 인덱스도 지원하며 개발자가 자신의 애플리케이션에 가장 적합한 방식으로 활용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&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: 'Nanum Gothic';&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: 'Nanum Gothic';&quot;&gt;몽고DB는 데이터 처리 파이프라인 개념을 기반으로 한 집계 프로임워크를 제공한다. 서버 측에서 비교적 간단한 단계로 복잡한 분석 엔진을 구축할 수 있다.&lt;/span&gt;&lt;/p&gt;
&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: 'Nanum Gothic';&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: 'Nanum Gothic';&quot;&gt;몽고DB는 로그와 같은 최신 데이터를 유지하고자 세션이나 고정 크기 컬렉션과 같이 특정 시간에 만료해야하는 데이터에 대한 유효 시간 컬렉션을 지원한다.&lt;/span&gt;&lt;/p&gt;
&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: 'Nanum Gothic';&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: 'Nanum Gothic';&quot;&gt;몽고DB는 큰 파일과 파일 메타데이터를 편리하게 저장하는 프로토콜을 지원한다.&lt;/span&gt;&lt;/p&gt;
&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: 'Nanum Gothic';&quot;&gt;관계형 데이터베이스에 공통적으로 사용되는 일부 기능, &lt;b&gt;복잡한 조인은 몽고DB에서 존재하지 않는다&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;결국 몽고DB는 확장성이 높으며 유연하고 빠른, 완전한 기능을 갖춘 데이터 스토리지를 만드는 일이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;앞으로 몽고DB의 개발 과정에서 내린 결정과 동기, 이유에 대해서 살펴볼 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이를 통해 몽고DB의 철학을 알아보도록 하자.&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;a href=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot;&gt;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1633522443323&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;books.book&quot; data-og-title=&quot;[전자책] MongoDB 완벽 가이드&quot; data-og-description=&quot;몽고DB 입문자를 위한 기초부터 실제 배포에 적용할 수 있는 실용적이고 깊이 있는 내용까지 담았다. 개정 3판에서는 성능이 강화된 몽고DB 최신 버전을 반영해 복제와 샤딩을 더 깊이 다루며 개&quot; data-og-host=&quot;www.aladin.co.kr&quot; data-og-source-url=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot; data-og-url=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/e0nJY/hyLRi1L2rK/4xfgvTKHN6f3fvWQ0rZoM0/img.png?width=500&amp;amp;height=642&amp;amp;face=0_0_500_642,https://scrap.kakaocdn.net/dn/jpOQb/hyLSDiTMPr/F0QXrzI5OueaIf3ViG5Qnk/img.png?width=500&amp;amp;height=642&amp;amp;face=0_0_500_642&quot;&gt;&lt;a href=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=268367408&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/e0nJY/hyLRi1L2rK/4xfgvTKHN6f3fvWQ0rZoM0/img.png?width=500&amp;amp;height=642&amp;amp;face=0_0_500_642,https://scrap.kakaocdn.net/dn/jpOQb/hyLSDiTMPr/F0QXrzI5OueaIf3ViG5Qnk/img.png?width=500&amp;amp;height=642&amp;amp;face=0_0_500_642');&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;[전자책] MongoDB 완벽 가이드&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;몽고DB 입문자를 위한 기초부터 실제 배포에 적용할 수 있는 실용적이고 깊이 있는 내용까지 담았다. 개정 3판에서는 성능이 강화된 몽고DB 최신 버전을 반영해 복제와 샤딩을 더 깊이 다루며 개&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.aladin.co.kr&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>백엔드/mongoDB</category>
      <author>DEV_SJ</author>
      <guid isPermaLink="true">https://codinghack.tistory.com/96</guid>
      <comments>https://codinghack.tistory.com/96#entry96comment</comments>
      <pubDate>Wed, 6 Oct 2021 22:09:12 +0900</pubDate>
    </item>
    <item>
      <title>DIP 아키텍처 설계</title>
      <link>https://codinghack.tistory.com/95</link>
      <description>&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;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;아키텍처를 설계할 때 출현하는 전형적인 영역은 그림과 같은 4가지 영역 표현, 응용, 도메인, 인프라입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1015&quot; data-origin-height=&quot;179&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caea5V/btra10CXux9/5n9tKonm8kXP6SZF2lGqiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caea5V/btra10CXux9/5n9tKonm8kXP6SZF2lGqiK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caea5V/btra10CXux9/5n9tKonm8kXP6SZF2lGqiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcaea5V%2Fbtra10CXux9%2F5n9tKonm8kXP6SZF2lGqiK%2Fimg.png&quot; data-origin-width=&quot;1015&quot; data-origin-height=&quot;179&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;- 표현 계층&lt;/b&gt;은 흔히 Controller로 불립니다. 어플리케이션의 최상단에서 유저 또는 웹 요청을 받고 응용계층에 로직을 위임하고 적절한 응답을 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;- 응용 계층&lt;/b&gt;은 Service로 많이 불리는데 처리해야할 로직을 중재하는 역할을 합니다. 원래는 응용계층에서 대부분의 로직 처리가 이루어졌으나 &lt;b&gt;도메인 중심 개발에서는 도메인에게 로직 수행을 위임&lt;/b&gt;합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;(메서드를 호출)하고 도메인은 해당 메시지를 적절한 행동을 실행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;- 인프라&lt;/b&gt;는 데이터베이스, 메일 sender 등 외부 시스템에 직접적으로 연관된 시스템입니다.&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';&quot;&gt;아키텍처를 보면 표현-&amp;gt;응용-&amp;gt;도메인-&amp;gt;인프라 로 상위 계층이 하위계층에 의존하는 모습을 보이고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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 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;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;을 사용하는 것이 더 알맞을 때가 있습니다. 다음 코드는 CalcurateDiscountService(응용계층)가 Drools라는 룰엔진(인프라 계층)에 의존하는 상황입니다.&lt;/span&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';&quot;&gt;&lt;b&gt;&lt;span&gt;RuleEngine&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627954900351&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class DroolsRuleEngine {
    public Money evaluate(List&amp;lt;OrderLine&amp;gt; orderLines, Customer customer){
        // 세부 로직...
        return new Money();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&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;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;evaluate 메소드&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';&quot;&gt;&lt;b&gt;&lt;span&gt;CalculateDiscountService&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627955042528&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class CalculateDiscountService {
    private DroolsRuleEngine ruleEngine;

    public Money calculateDiscount(List&amp;lt;OrderLine&amp;gt; orderLines, String customerId){
        Customer customer = findById(customerId);
        return ruleEngine.evaluate(orderLines, customer);
    }

    // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;다음으로는 DroolsRuleEngine을 가지고 있는 CalcurateDiscountService 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;calculateDiscount 에서 ruleEngine을 직접적으로 참조하여 사용하고 있습니다. 따라서 현재 의존관계는 아래와 같습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;360&quot; width=&quot;449&quot; height=&quot;256&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOD5BQ/btra1Z5jzBi/k1TZF1ZW8O1LeAfG8eGduk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOD5BQ/btra1Z5jzBi/k1TZF1ZW8O1LeAfG8eGduk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOD5BQ/btra1Z5jzBi/k1TZF1ZW8O1LeAfG8eGduk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOD5BQ%2Fbtra1Z5jzBi%2Fk1TZF1ZW8O1LeAfG8eGduk%2Fimg.png&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;360&quot; width=&quot;449&quot; height=&quot;256&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;그림과 같은 의존 관계라면 DroolsRuleEngine에 변경이 발생한다면 CalculateDiscountService 또한 변경이 필수적으로 일어납니다. &lt;/span&gt;&lt;span&gt;따라서 고수준 모듈인 Service가 저수준 모듈인 RuleEngine에 의존 하고 있습니다.&amp;nbsp;&lt;/span&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';&quot;&gt;&lt;span&gt;이렇게 되면 DroolsRuleEngine을 이용하지 않고는 CalculateDiscountService 만의 &lt;b&gt;테스트가 어렵고&lt;/b&gt;, 다른 룰엔진으로의 변경이 일어난다면 &lt;b&gt;기능확장&lt;/b&gt;에 어려움이 생기게 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;다음과 같은 문제를 DIP를 적용하여 해결해봅시다.&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 Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;DIP 적용&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;DIP를 이용해&lt;b&gt; 저수준 모듈이 고수준 모듈에 의존&lt;/b&gt;하도록 변경해 봅시다. 방법은 &lt;b&gt;추상화한 인터페이스&lt;/b&gt;를 사용하는 것 입니다. CalculateDiscountService 입장에서는 룰 적용을 Drools 로 하였는지 다른 것으로 구현하였는지 중요하지 않습니다. 단지 &lt;b&gt;'고객 정보와 구매 정보에 룰을 적용한 할인 금액을 구한다'&lt;/b&gt; 라는 것이 중요할 뿐입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;따라서 다음과 같이 추상화한 인터페이스를 구현합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627955954052&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface RuleDiscounter {
    Money evaluate(List&amp;lt;OrderLine&amp;gt; orderLines, Customer  customer);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;또한 Service에서는 RuleDiscounter를 참조하도록 변경합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1627956006284&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class CalculateDiscountService {
    private RuleDiscounter ruleDiscounter;

    public Money calculateDiscount(List&amp;lt;OrderLine&amp;gt; orderLines, String customerId){
        Customer customer = findById(customerId);
        return ruleDiscounter.evaluate(orderLines, customer);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;추상화 인터페이스를 통해 다음과 같이 의존관계가 변경되었습니다. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;762&quot; data-origin-height=&quot;360&quot; width=&quot;648&quot; height=&quot;306&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbDXeP/btra34ZvOr0/cNTwknkhbMmssKgCWKWsIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbDXeP/btra34ZvOr0/cNTwknkhbMmssKgCWKWsIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbDXeP/btra34ZvOr0/cNTwknkhbMmssKgCWKWsIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbDXeP%2Fbtra34ZvOr0%2FcNTwknkhbMmssKgCWKWsIk%2Fimg.png&quot; data-origin-width=&quot;762&quot; data-origin-height=&quot;360&quot; width=&quot;648&quot; height=&quot;306&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;이제 저수준 모듈이 고수준 모듈에 의존하게 되었습니다. 이를 DIP(Dependency Inversion Priciple, 의존관계 역전 원칙) 이라고 부릅니다.&lt;/span&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';&quot;&gt;&lt;span&gt;DIP를 통해 앞선 &lt;b&gt;2가지의 문제점이 해결&lt;/b&gt;되었습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;DroolsRuleEngine 없이는&lt;b&gt; 테스트에 어려움&lt;/b&gt;이 있던 CacluateDiscountService는 RuleDiscount 인터페이스에 Mock 객체를 주입하여 테스트하면 되도록 변경되었습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;또한 기능확장에 어려움이 있던 부분은 RuleDiscount를 새로 구현하기만 하면 되도록 수정되었습니다.&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 Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;DIP 적용 주의점&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;DIP를 잘못 생각하면 단순히 인터페이스와 구현 클래스를 분리하는 정도로 받아들일 수도 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;DIP 핵심은 고수준 모듈이 저수준 모듈에 의존하지 않도록 하기 위함인데 그림과 같이 저수준 모듈에서 인터페이스를 추출하는 경우가 있습니다. &lt;/span&gt;다음 그림은 잘못된 구조입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;762&quot; data-origin-height=&quot;360&quot; width=&quot;641&quot; height=&quot;303&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l6IkJ/btrbe6V1oml/OvMkICfwsNTpgf23IV2nCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l6IkJ/btrbe6V1oml/OvMkICfwsNTpgf23IV2nCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l6IkJ/btrbe6V1oml/OvMkICfwsNTpgf23IV2nCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl6IkJ%2Fbtrbe6V1oml%2FOvMkICfwsNTpgf23IV2nCk%2Fimg.png&quot; data-origin-width=&quot;762&quot; data-origin-height=&quot;360&quot; width=&quot;641&quot; height=&quot;303&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&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 Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;어플리케이션을 개발하거나 운영할 때 변경은 필수적으로 일어납니다. 이런 변경에 영향을 최소화 하기위해서는 적절한 의존관계를 설계해야하며 포스팅과 같은 DIP를 이용한 설계를 해보는 것도 좋습니다.&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;h4 data-ke-size=&quot;size20&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ddd start - 최범균 저&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백엔드/Java</category>
      <author>DEV_SJ</author>
      <guid isPermaLink="true">https://codinghack.tistory.com/95</guid>
      <comments>https://codinghack.tistory.com/95#entry95comment</comments>
      <pubDate>Tue, 3 Aug 2021 11:16:46 +0900</pubDate>
    </item>
    <item>
      <title>2021 네이버 상반기 공채 합격 후기</title>
      <link>https://codinghack.tistory.com/94</link>
      <description>&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #409d00; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #ffffff;&quot;&gt;2021 네이버 상반기 공채에 합격했습니다.&lt;/span&gt;&lt;/h2&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. 서류전형&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서류는 3개의 항목으로 되어있었고 사람인이나 채용 사이트등 에서 자소서 항목을 공개중입니다.&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';&quot;&gt;&lt;b&gt;1번&lt;/b&gt;은 희망 직무를 간단하게 작성하는 것입니다. 예시 - &lt;span style=&quot;color: #000000;&quot;&gt;1)&amp;nbsp;&amp;nbsp;BE&amp;nbsp;개발&amp;nbsp;2)FE&amp;nbsp;개발&amp;nbsp;&amp;nbsp;3)Android&amp;nbsp;개발&lt;/span&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';&quot;&gt;&lt;b&gt;2번&lt;/b&gt;은 좋아하는 과목과 성적, 그리고 그 이유 작성입니다. 저는 아래와 같이 작성하였습니다.&lt;/span&gt;&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;- 운영체제 / A+ / 운영체제의 역할과 내부 알고리즘에 대해 배울 수 있는 수업이었습니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- 컴퓨터 보안 / A+ / 공개키 암호화 방식등의 기초 컴퓨터 보안에 대해 배울 수 있는 수업이었습니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- 웹프로그래밍 / A+ / Node.js 를 이용하여 웹 전체 풀스택에 대한 개념을 잡고 개발해보는 수업이었습니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- 캡스톤디자인1 / A+ / 팀원과 협업하고 커뮤니케이션하며 새로운 기술을 사용하여 프로젝트를 진행할 수 있는 수업이었습니다.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- 객체지향프로그래밍 / A+ / Java의 이론에 대해 배우고 객체지향 언어의 특징을 배울 수 있는 수업이었습니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- 고급객체지향프로그래밍 / A+ / 객체지향을 이해하며 실제 객체 지향 프로젝트를 진행할 수 있는 수업이었습니다.&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';&quot;&gt;&lt;b&gt;3번&lt;/b&gt;은 기술적으로 어려운 문제를 해결한 경험 작성입니다. 사실 자기소개서에 작성할게 이항목뿐입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;저 같은 경우에는 블로그에 있는 &lt;a href=&quot;https://codinghack.tistory.com/74&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;시트 조회 시 다수의 쿼리 발생(N+1 문제)&lt;/a&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';&quot;&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';&quot;&gt;서류는 따로 합격은 없고 적합, 부적합으로 나뉘는 것 같았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;/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;2. 코딩 테스트&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;615&quot; data-origin-height=&quot;770&quot; data-filename=&quot;코테합격가린거.png&quot; width=&quot;359&quot; height=&quot;449&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xgEgA/btq9PUpAcTE/Vphwtr2v1tPRPfFBHFwIlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xgEgA/btq9PUpAcTE/Vphwtr2v1tPRPfFBHFwIlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xgEgA/btq9PUpAcTE/Vphwtr2v1tPRPfFBHFwIlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxgEgA%2Fbtq9PUpAcTE%2FVphwtr2v1tPRPfFBHFwIlK%2Fimg.png&quot; data-origin-width=&quot;615&quot; data-origin-height=&quot;770&quot; data-filename=&quot;코테합격가린거.png&quot; width=&quot;359&quot; height=&quot;449&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;네이버의 코딩 테스트는 어려운 편은 아녔습니다. 4개의 문제에 2시간이었지만 4번 문제는 제한 시간 안에 풀라고 낸 문제가 아니어서 2시간 3문제라고 보면 될 것 같고, 저는 3개를 풀긴 했지만 3번 문제에서 조금의 오류가 있어 2솔로 합격했다고 생각 중입니다. (테스트 케이스가 없어서 맞았는지 알 수가 없어요) 제 예상에는 2솔+서류상, 3솔 이 합격기준이지 않았을까 생각합니다.&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';&quot;&gt;어려운 편은 아니지만 IDE 사용금지, 인터넷 사용금지, 테스트 케이스 미공개로 인해 난이도가 확 올라가는 것 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;저 같은 경우는 올해에 백준 약 500문제를 풀면서 준비하였고 실버 3-골드 1 위주의 문제를 꾸준히 풀었습니다.&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';&quot;&gt;서류+코딩 테스트의 결과 발표는 약 1달 정도가 걸렸던 걸로 생각합니다. 그만큼 상세하게 보셨다는 거겠지요?&lt;/span&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;3. 1차 면접&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;673&quot; data-origin-height=&quot;827&quot; data-filename=&quot;1차 합격가린거.png&quot; width=&quot;361&quot; height=&quot;444&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eiVFRV/btq9JOxwcgP/QcOSjyCSxrGd3ew22Ax9R0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eiVFRV/btq9JOxwcgP/QcOSjyCSxrGd3ew22Ax9R0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eiVFRV/btq9JOxwcgP/QcOSjyCSxrGd3ew22Ax9R0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeiVFRV%2Fbtq9JOxwcgP%2FQcOSjyCSxrGd3ew22Ax9R0%2Fimg.png&quot; data-origin-width=&quot;673&quot; data-origin-height=&quot;827&quot; data-filename=&quot;1차 합격가린거.png&quot; width=&quot;361&quot; height=&quot;444&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1차 면접은 세분의 면접관이 들어오셨고 약간 정해진 문제를 풀어가는 스타일이며&amp;nbsp;간단한 CS 지식을 물어보셨습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&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;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';&quot;&gt;&lt;b&gt;알고리즘 및 손 코딩&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;전체적으로 알고리즘과 손 코딩 준비는 인프런의 백기선님 강의를 활용했습니다. &lt;a href=&quot;https://www.inflearn.com/course/%EA%B0%9C%EB%B0%9C%EC%9E%90-%EC%9D%B8%ED%84%B0%EB%B7%B0&quot;&gt;백기선님 - 더 개발자&lt;/a&gt; 강의가 무지하게 비싸지만(22만원) 저는 개발에 대한 건 투자를 아끼지 않아서 그냥 결제했습니다. 네이버 면접뿐 아니라 나중에 FANNG(&lt;a href=&quot;https://namu.wiki/w/%ED%8E%98%EC%9D%B4%EC%8A%A4%EB%B6%81&quot;&gt;&lt;b&gt;F&lt;/b&gt;acebook&lt;/a&gt;&lt;span style=&quot;color: #373a3c;&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://namu.wiki/w/Apple&quot;&gt;&lt;b&gt;A&lt;/b&gt;pple&lt;/a&gt;&lt;span style=&quot;color: #373a3c;&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://namu.wiki/w/%EC%95%84%EB%A7%88%EC%A1%B4%EB%8B%B7%EC%BB%B4&quot;&gt;&lt;b&gt;A&lt;/b&gt;mazon&lt;/a&gt;&lt;span style=&quot;color: #373a3c;&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://namu.wiki/w/%EB%84%B7%ED%94%8C%EB%A6%AD%EC%8A%A4&quot;&gt;&lt;b&gt;N&lt;/b&gt;etflix&lt;/a&gt;&lt;span style=&quot;color: #373a3c;&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://namu.wiki/w/%EA%B5%AC%EA%B8%80&quot;&gt;&lt;b&gt;G&lt;/b&gt;oogle&lt;/a&gt;)에 갈 때도 도움이 될만한 강의 같습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;그리고 파이썬으로 하다 보니 &lt;a href=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=245495826&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;파이썬 알고리즘 인터뷰&lt;/a&gt; 책도&amp;nbsp; 공부하였습니다.&lt;/span&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';&quot;&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;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;운영체제는 &lt;a href=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=153419028&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;쉽게 배우는 운영체제&lt;/a&gt; 책을 12번 읽었습니다. 다독한다는 기분으로 보시고 운영체제만큼은 꼭 책으로 공부하시길 바랍니다.&amp;nbsp; 이 책을 벗어나는 면접 질문은 없을 거라 생각이 됩니다.&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';&quot;&gt;&lt;b&gt;네트워크&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;네트워크는 &lt;a href=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=191467927&quot;&gt;TCP/IP가 보이는 그림책&lt;/a&gt; 이 책으로 전체 개념을 잡았고 우아한형제들 유튜브에 학생들이 발표해둔 것들이 굉장히 많은데 여러 번 보았어요. 네트워크는 전체적인 흐름을 아는 것이 중요한 것 같습니다. 웹에서 naver를 입력했을 때 발생하는 일을 30분은 설명할 수 있을 정도로 공부하는 걸 추천드립니다.(&lt;a href=&quot;https://www.youtube.com/watch?v=1pfTxp25MA8&quot;&gt;우아한 형제들 - 히히의 OSI 7계층&lt;/a&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';&quot;&gt;&lt;b&gt;데이터베이스&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터베이스는 책을 사기는 했지만 1번 정도만 대충 읽고 따로 책으로 공부하지는 않았습니다. 워낙 이론이 많아서 면접에서 물어볼까 싶었어요. 면접에서 나오는 주제는 아무리 생각해봐도 인덱스, 리플리케이션, 샤딩, nosql 등이어서 &lt;a href=&quot;https://github.com/JaeYeopHan/Interview_Question_for_Beginner&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;한재엽님의 github 면접 질문&lt;/a&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';&quot;&gt;&lt;b&gt;&lt;span&gt;JAVA&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;java 공부하면서 정말 애를 많이 먹었습니다. 사실 JAVA는 생각에 따라 위의 3개를 합친 거보다 양이 많을 수도 적을 수도 있습니다. 대체 어디까지 공부해야 할까? 그래서 그냥 아래 책 읽으면서 다했습니다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이상민님 - 자바의신1, 2&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&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;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;토비님 - 토비의 스프링1, 2&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&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;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;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;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;스프링으로 프로젝트를 하셨다면 &lt;a href=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=19505747&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;토비의 스프링&lt;/a&gt;&lt;span&gt;을 꼭 읽어보시길 추천드릴게요. 이것도 모르고 스프링부트를 썻다고? 하고 자책하실겁니다. &lt;/span&gt;솔직히 제가 재밌어서 한 거고 자바의 신 1, 2와 성능 튜닝 이야기, 토비의 스프링 정도만 해도 될 거라 생각됩니다.&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';&quot;&gt;&lt;b&gt;후기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;악명 높은 네이버 면접에 비해 저는 재밌게 면접을 보았습니다. 1시간 반의 시간이었는데 1시간 정도 면접을 진행하고 30분은 잡담과 제가 질문하는 시간을 가졌어요. 떨어질 거라는 생각이 거의 들지 않았습니다. 10프로 정도..?&lt;/span&gt;&lt;/span&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;4. 2차 면접&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;2차면접은 면접관 두분으로 진행되었습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;따로 엄청 준비하지는 않았고 평소처럼 개발하며 지냈습니다. 그동안 했던 프로젝트에서 제가 했던 고민을 정리하고 잘 설명하는 연습을 하였습니다. 또한 블로그에 대해서 많이 물어보셨는데 여기서 많은 점수를 받은 것 같습니다. 꼭 블로그 시작하세요!&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;2차도 40분 면접 예정이었지만 30분 진행 후 제가 하는 질문시간을 가졌습니다. 2차는 정말 99.99% 합격이라는 생각이 들었어요.&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 Demilight', 'Noto Sans KR';&quot;&gt;5. 최종 합격&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;673&quot; data-origin-height=&quot;906&quot; data-filename=&quot;최종합격가린거.png&quot; width=&quot;503&quot; height=&quot;677&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mN3aE/btq9NXUuUJe/4AH162xCua5mKBBK44ka0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mN3aE/btq9NXUuUJe/4AH162xCua5mKBBK44ka0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mN3aE/btq9NXUuUJe/4AH162xCua5mKBBK44ka0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmN3aE%2Fbtq9NXUuUJe%2F4AH162xCua5mKBBK44ka0k%2Fimg.png&quot; data-origin-width=&quot;673&quot; data-origin-height=&quot;906&quot; data-filename=&quot;최종합격가린거.png&quot; width=&quot;503&quot; height=&quot;677&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;다행히 합격하였습니다. 개발을 좋아하는 저로써는 정말 좋은 기회를 얻었다고 생각 들고 더열심히 개발공부를 할 생각입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #ffffff; background-color: #409d00;&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;면접 질문이 아닌 내용은 궁금한점을 댓글(보안서약으로 인해 비밀글은 답변안드립니다)로 남겨주시면 답변 성실하게 드리겠습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;</description>
      <category>취업이야기</category>
      <category>네이버</category>
      <category>네이버1차면접</category>
      <category>네이버2차면접</category>
      <category>네이버코딩테스트</category>
      <category>네이버합격</category>
      <category>네이버합격후기</category>
      <author>DEV_SJ</author>
      <guid isPermaLink="true">https://codinghack.tistory.com/94</guid>
      <comments>https://codinghack.tistory.com/94#entry94comment</comments>
      <pubDate>Sat, 17 Jul 2021 14:58:37 +0900</pubDate>
    </item>
    <item>
      <title>TDD - 테스트 주도 개발 by 켄트 백</title>
      <link>https://codinghack.tistory.com/93</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;TDD 책을 읽으며 작성한 내용입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=37469717&quot;&gt;Test Driven Development: By Example - 저자: 캔트백&lt;/a&gt;&lt;/p&gt;
&lt;hr style=&quot;box-sizing: content-box; height: 0.25em; overflow: hidden; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: var(--color-border-primary); border: 0px; margin: 24px 0px; padding: 0px; color: #adbac7; font-family: -apple-system, system-ui, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;a id=&quot;user-content-테스트-주도-개발의-궁극적인-목표는-작동하는-깔끔한-코드-이다&quot; href=&quot;https://github.com/Ysungjae/TDD#%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%A3%BC%EB%8F%84-%EA%B0%9C%EB%B0%9C%EC%9D%98-%EA%B6%81%EA%B7%B9%EC%A0%81%EC%9D%B8-%EB%AA%A9%ED%91%9C%EB%8A%94-%EC%9E%91%EB%8F%99%ED%95%98%EB%8A%94-%EA%B9%94%EB%81%94%ED%95%9C-%EC%BD%94%EB%93%9C-%EC%9D%B4%EB%8B%A4&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;b&gt;테스트 주도 개발의 궁극적인 목표는 &quot;작동하는 깔끔한 코드&quot; 이다.&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오직 자동화된 테스트가 실패할 경우에만 새로운 코드를 작성한다.&lt;/li&gt;
&lt;li&gt;중복을 제거한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr style=&quot;box-sizing: content-box; height: 0.25em; overflow: hidden; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: var(--color-border-primary); border: 0px; margin: 24px 0px; padding: 0px; color: #adbac7; font-family: -apple-system, system-ui, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;a id=&quot;user-content-tdd의-주문&quot; href=&quot;https://github.com/Ysungjae/TDD#tdd%EC%9D%98-%EC%A3%BC%EB%AC%B8&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;b&gt;TDD의 주문&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빨강 - 실패하는 작은 테스트를 작성한다. (컴파일 조차 되지 않을 수 있다)&lt;/li&gt;
&lt;li&gt;초록 - 빨리 테스트가 통과하게끔 만든다. (이를 위해 어떤 죄악을 저질러도 된다)&lt;/li&gt;
&lt;li&gt;리팩토링 - 통과하게만 하는 와중에 생겨난 중복을 제거한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr style=&quot;box-sizing: content-box; height: 0.25em; overflow: hidden; background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: var(--color-border-primary); border: 0px; margin: 24px 0px; padding: 0px; color: #adbac7; font-family: -apple-system, system-ui, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;a id=&quot;user-content-일반적인-tdd의-주기&quot; href=&quot;https://github.com/Ysungjae/TDD#%EC%9D%BC%EB%B0%98%EC%A0%81%EC%9D%B8-tdd%EC%9D%98-%EC%A3%BC%EA%B8%B0&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;b&gt;일반적인 TDD의 주기&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테스트를 작성한다. 어떤식으로 나타나길 원하는지 이야기를 써내려나간다. 올바른 답을 얻기 위해 필요한 이야기의 모든 요소를 포함시켜라.&lt;/li&gt;
&lt;li&gt;실행 가능하게 만든다. 무엇보다 중요한 것은 빨리 초록 막대를 보는 것이다. 깔끔하고 단순한 해법이 명백히 보인다면 그것을 입력하라. 만약 몇분정도 걸릴 거 같으면 일단 적어놓은 뒤에 초록막대를 보는 것으로 돌아오자.&lt;/li&gt;
&lt;li&gt;올바르게 만든다. 이제 시스템이 작동하므로 직전에 저질렀던 죄악을 수습하자. 중복을 제거하고 초록막대로 되돌리자.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;a id=&quot;user-content-빠른-초록색을-보기위한-전략&quot; href=&quot;https://github.com/Ysungjae/TDD#%EB%B9%A0%EB%A5%B8-%EC%B4%88%EB%A1%9D%EC%83%89%EC%9D%84-%EB%B3%B4%EA%B8%B0%EC%9C%84%ED%95%9C-%EC%A0%84%EB%9E%B5&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;b&gt;빠른 초록색을 보기위한 전략&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가짜로 구현하기: 상수를 반환하게 만들고 진짜 코드를 얻을 때 까지 단계적으로 상수를 변수로 변경한다.&lt;/li&gt;
&lt;li&gt;명백한 구현 사용하기: 실제 구현을 입력한다.(뭘 입력해야 할지 알때)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;a id=&quot;user-content-핵심&quot; href=&quot;https://github.com/Ysungjae/TDD#%ED%95%B5%EC%8B%AC&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;&lt;b&gt;핵심&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tdd의 핵심은 테스트를 먼저 개발해서 피드백을 빠르게 받는 것이다. 자동화된 코드에 의해 테스트를 받자. 기능을 많이 변경했을 때 두려움을 걱정을 지루함으로 바꿔주는 기능이다. 작은 step을 밝아서 성공시키는 과정 자신감이 있으면 큰 step을 밟는다.&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;Money 예제 코드&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Ysungjae/TDD&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/Ysungjae/TDD&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1625212326987&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;Ysungjae/TDD&quot; data-og-description=&quot;Contribute to Ysungjae/TDD development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/Ysungjae/TDD&quot; data-og-url=&quot;https://github.com/Ysungjae/TDD&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ctmoZy/hyKLvfoWnF/Q2FDkAyxOQpvOmysgpxqYK/img.png?width=1200&amp;amp;height=600&amp;amp;face=971_140_1057_233&quot;&gt;&lt;a href=&quot;https://github.com/Ysungjae/TDD&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/Ysungjae/TDD&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ctmoZy/hyKLvfoWnF/Q2FDkAyxOQpvOmysgpxqYK/img.png?width=1200&amp;amp;height=600&amp;amp;face=971_140_1057_233');&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;Ysungjae/TDD&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to Ysungjae/TDD 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>테스트</category>
      <author>DEV_SJ</author>
      <guid isPermaLink="true">https://codinghack.tistory.com/93</guid>
      <comments>https://codinghack.tistory.com/93#entry93comment</comments>
      <pubDate>Fri, 2 Jul 2021 16:53:02 +0900</pubDate>
    </item>
    <item>
      <title>Test Doubles(테스트 더블) &amp;mdash; Dummy, Fakes, Mocks, Spy and Stubs</title>
      <link>https://codinghack.tistory.com/92</link>
      <description>&lt;p data-ke-size=&quot;size18&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 data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예를 들어 사용자를 조회하는 로직을 테스트한다고 한다면 UserService에서 UserRepository, 그리고 DB까지 연결되어있습니다.&amp;nbsp; User&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Service만 테스트하고 싶어도 이어지는 연결로 인해 &lt;b&gt;독립적인 테스트&lt;/b&gt;가 힘들어집니다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;또한 아직 UserRepository가 구현되지 않은 경우에도 테스트가 힘들어지죠.&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';&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;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;용어 자체는 제라드 메스자로스(Gerard Meszaros)가 만든 용어로,&amp;nbsp; &lt;/span&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Stunt_double&quot;&gt;스턴트 더블&lt;/a&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(영화 촬영에서 말하는 스턴트 대역 배우)에서 아이디어를 얻어서 만든 용어입니다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;194&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cj7FwV/btq8FdxA5AF/rrKVCQj0d5eD8wLfISsKO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cj7FwV/btq8FdxA5AF/rrKVCQj0d5eD8wLfISsKO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cj7FwV/btq8FdxA5AF/rrKVCQj0d5eD8wLfISsKO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcj7FwV%2Fbtq8FdxA5AF%2FrrKVCQj0d5eD8wLfISsKO1%2Fimg.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;194&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&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;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;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;UserService만 테스트가 가능해지는 것입니다. &lt;/span&gt;&lt;/span&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;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&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;/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 Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Dummy&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;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Dummy는 가장 기본적인 테스트 더블입니다. 객체가 필요하지만 내부 기능이 필요하지는 않을 때 사용하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어 테스트 중에 &lt;b&gt;함수 파라미터로는 전달되지만 내부에서 사용되지 않는 경우&lt;/b&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;또 아래와 같은 경우도 Dummy Test로 볼 수가 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1625203496763&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface AccountDao {
    void showMember();
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1625203507587&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class AccountDaoDummy implements AccountDao{
    @Override
    public void showMember() {
        // dummy
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;AccountDaoDummy는 아무런 기능을 하지 않고 반환 값도 없습니다. AccountDao를 사용하는 Client 입장에서는 Dummy를 호출하기만 하면 되는 테스트이므로 내부 동작과는 상관없이 테스트는 성공하게 됩니다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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 Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Fakes&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Fakes는 실제로 사용된 객체는 아니지만 같은 동작을 하는 구현된 객체입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Fakes는 원래 객체의 단순화된 버전입니다. 동작의 구현은 되어있지만 프로덕션에서 사용할 수는 없는 객체입니다. 아래 사진으로 이해해봅시다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;494&quot; width=&quot;555&quot; height=&quot;392&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OI5SH/btq8Bk5CbWz/IpSqoqfAK1VHWyKC84vWmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OI5SH/btq8Bk5CbWz/IpSqoqfAK1VHWyKC84vWmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OI5SH/btq8Bk5CbWz/IpSqoqfAK1VHWyKC84vWmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOI5SH%2Fbtq8Bk5CbWz%2FIpSqoqfAK1VHWyKC84vWmk%2Fimg.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;494&quot; width=&quot;555&quot; height=&quot;392&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;LoginService를 테스트하기 위해서는 AccountDAO를 이용해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하지만 AccountDao가 아직 구현되지 않았거나&amp;nbsp; 독립적인 테스트를 하고싶다면 Fake 객체를 사용하며 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;FakeAccountDAO객체는 임의의 HashMap 객체를 생성하고 마치 진짜인 것처럼 LoginService가 보낸 메시지에 반응합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625200095035&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class FakeAccountRepository implements AccountRepository {
       
       Map&amp;lt;User, Account&amp;gt; accounts = new HashMap&amp;lt;&amp;gt;();
       
       public FakeAccountRepository() {
              this.accounts.put(new User(&quot;john@bmail.com&quot;), new UserAccount());
              this.accounts.put(new User(&quot;boby@bmail.com&quot;), new AdminAccount());
       }
       
       String getPasswordHash(User user) {
              return accounts.get(user).getPasswordHash();
       }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Stub&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;stub은 Dummy 데이터가 실제로 동작하도록 만들어둔 객체입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&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;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;테스트를 위해 프로그래밍된 항목이며 이외의 항목에는 응답하지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;494&quot; width=&quot;575&quot; height=&quot;406&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsGZQs/btq8DRBjsoP/qb6AZVx61Xe2iEnwYGP0yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsGZQs/btq8DRBjsoP/qb6AZVx61Xe2iEnwYGP0yk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsGZQs/btq8DRBjsoP/qb6AZVx61Xe2iEnwYGP0yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsGZQs%2Fbtq8DRBjsoP%2Fqb6AZVx61Xe2iEnwYGP0yk%2Fimg.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;494&quot; width=&quot;575&quot; height=&quot;406&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;averageGrades 메서드 호출에 응답하기 위해 데이터베이스에서 데이터를 가져와야 하는 상황입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;실제 객체 대신 Stub을 도입하고 어떤 데이터를 반환해야 하는지 정의 후 리턴하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625202103816&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Before
    public void setUp() throws Exception {
        gradebook = mock(Gradebook.class);
        student = new Student();
    }

    @Test
    public void calculates_grades_average_for_student() {
        when(gradebook.gradesFor(student)).thenReturn(grades(8, 6, 10)); //stubbing gradebook
        double averageGrades = new GradesService(gradebook).averageGrades(student);
        assertThat(averageGrades).isEqualTo(8.0);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;when을 이용하여 반환할 데이터를 미리 정의한 후 테스트하는 코드입니다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr style=&quot;margin: 20px auto 0px; border: none; cursor: pointer !important; z-index: 1; font-size: 0px; line-height: 0; background: url('../image/divider-line.svg') center -256px / 200px 420px repeat-x; height: 2px; padding: 21px 0px; color: #333333; font-family: -apple-system, system-ui, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; 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 Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Spy&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;스파이는 Stub의 역할을 하면서 약간의 정보를 더 기록합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&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;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예를 들어 이메일을 몇 번 발송했는지 기록하는 테스트 용도로 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625208995237&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class MailingService {
    private int sendMailCount = 0;
    private Collection&amp;lt;Mail&amp;gt; mails = new ArrayList&amp;lt;&amp;gt;();

    public void sendMail(Mail mail) {
        sendMailCount++;
        mails.add(mail);
    }

    public long getSendMailCount() {
        return sendMailCount;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;sendMailCount를 이용해 메일의 발송 횟수를 더 기록하는 코드입니다.&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 Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Mock&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Mock은 행위를 검증&lt;/b&gt;하기 위해 가짜 객체를 만들고 테스트하는 방법입니다. 위에서 본 &lt;b&gt;Stub은 상태를 검증할 때&lt;/b&gt; 사용합니다.&lt;span style=&quot;background-color: #f1f1f1; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&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;mockito 코드 Sample&lt;/p&gt;
&lt;pre id=&quot;code_1625209987302&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Test
    public void mockTest(){
        List mockedList = mock(List.class);
	
    	// 행위 추가
        mockedList.add(&quot;one&quot;);
        mockedList.clear();

		// 행위 검증
        verify(mockedList).add(&quot;one&quot;);
        verify(mockedList).clear();
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Mock은 다음과 같이 행위가 일어났는지를 검증합니다. Mock에 대한 내용은 하나의 포스팅 분량이므로 다음 포스팅에서 따로 다루도록 하겠습니다.&lt;/p&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;b&gt;마무리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;테스트를 진행한다면 위의 항목들 중에서 어떤 테스트가 필요할지 결정하고, 결정한 테스트가 경계를 벗어나는지 보며&amp;nbsp;&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;Dummy -&amp;gt; Stub -&amp;gt; Fake -&amp;gt; Spy -&amp;gt; Mock 입니다.&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;&amp;nbsp;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&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;/h4&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://martinfowler.com/bliki/TestDouble.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://martinfowler.com/bliki/TestDouble.html&lt;/a&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1625204005786&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;bliki: TestDouble&quot; data-og-description=&quot;Test Double is generic term for fakes, mocks, stubs, dummies and spies.&quot; data-og-host=&quot;martinfowler.com&quot; data-og-source-url=&quot;https://martinfowler.com/bliki/TestDouble.html&quot; data-og-url=&quot;https://martinfowler.com/bliki/TestDouble.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bXS5xF/hyKLqrxcMk/Rj53LRQTpKaukNcX1kItU1/img.png?width=144&amp;amp;height=144&amp;amp;face=0_0_144_144&quot;&gt;&lt;a href=&quot;https://martinfowler.com/bliki/TestDouble.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://martinfowler.com/bliki/TestDouble.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bXS5xF/hyKLqrxcMk/Rj53LRQTpKaukNcX1kItU1/img.png?width=144&amp;amp;height=144&amp;amp;face=0_0_144_144');&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;bliki: TestDouble&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Test Double is generic term for fakes, mocks, stubs, dummies and spies.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;martinfowler.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://martinfowler.com/articles/mocksArentStubs.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://martinfowler.com/articles/mocksArentStubs.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1625209120635&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Mocks Aren't Stubs&quot; data-og-description=&quot;Explaining the difference between Mock Objects and Stubs (together with other forms of Test Double). Also the difference between classical and mockist styles of unit testing.&quot; data-og-host=&quot;martinfowler.com&quot; data-og-source-url=&quot;https://martinfowler.com/articles/mocksArentStubs.html&quot; data-og-url=&quot;https://martinfowler.com/articles/mocksArentStubs.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/md3BJ/hyKKyELXUM/oALNIkag6Zl6vQAcS6XjH0/img.png?width=144&amp;amp;height=144&amp;amp;face=0_0_144_144&quot;&gt;&lt;a href=&quot;https://martinfowler.com/articles/mocksArentStubs.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://martinfowler.com/articles/mocksArentStubs.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/md3BJ/hyKKyELXUM/oALNIkag6Zl6vQAcS6XjH0/img.png?width=144&amp;amp;height=144&amp;amp;face=0_0_144_144');&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;Mocks Aren't Stubs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Explaining the difference between Mock Objects and Stubs (together with other forms of Test Double). Also the difference between classical and mockist styles of unit testing.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;martinfowler.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://blog.pragmatists.com/test-doubles-fakes-mocks-and-stubs-1a7491dfa3da&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://blog.pragmatists.com/test-doubles-fakes-mocks-and-stubs-1a7491dfa3da&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1625193003906&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Test Doubles &amp;mdash; Fakes, Mocks and Stubs.&quot; data-og-description=&quot;In automated testing it is common to use objects that look and behave like their production equivalents, but are actually simplified. This reduces complexity, allows to verify code independently from&amp;hellip;&quot; data-og-host=&quot;blog.pragmatists.com&quot; data-og-source-url=&quot;https://blog.pragmatists.com/test-doubles-fakes-mocks-and-stubs-1a7491dfa3da&quot; data-og-url=&quot;https://blog.pragmatists.com/test-doubles-fakes-mocks-and-stubs-1a7491dfa3da&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bgvyWi/hyKLqkFX6A/PAT2qc0o4j2k8KhxBTGhOK/img.png?width=1024&amp;amp;height=724&amp;amp;face=0_0_1024_724,https://scrap.kakaocdn.net/dn/ckAqI1/hyKLrqlkVv/g76k8ax9wq4tJs0Xdosjw1/img.png?width=60&amp;amp;height=42&amp;amp;face=0_0_60_42,https://scrap.kakaocdn.net/dn/c4sas4/hyKLp6808A/4098vOMQ3w3qZ8e84kZUk1/img.png?width=60&amp;amp;height=42&amp;amp;face=0_0_60_42&quot;&gt;&lt;a href=&quot;https://blog.pragmatists.com/test-doubles-fakes-mocks-and-stubs-1a7491dfa3da&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.pragmatists.com/test-doubles-fakes-mocks-and-stubs-1a7491dfa3da&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bgvyWi/hyKLqkFX6A/PAT2qc0o4j2k8KhxBTGhOK/img.png?width=1024&amp;amp;height=724&amp;amp;face=0_0_1024_724,https://scrap.kakaocdn.net/dn/ckAqI1/hyKLrqlkVv/g76k8ax9wq4tJs0Xdosjw1/img.png?width=60&amp;amp;height=42&amp;amp;face=0_0_60_42,https://scrap.kakaocdn.net/dn/c4sas4/hyKLp6808A/4098vOMQ3w3qZ8e84kZUk1/img.png?width=60&amp;amp;height=42&amp;amp;face=0_0_60_42');&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;Test Doubles &amp;mdash; Fakes, Mocks and Stubs.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;In automated testing it is common to use objects that look and behave like their production equivalents, but are actually simplified. This reduces complexity, allows to verify code independently from&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.pragmatists.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://woowacourse.github.io/tecoble/post/2020-09-19-what-is-test-double/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://woowacourse.github.io/tecoble/post/2020-09-19-what-is-test-double/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1625203992065&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Test Double을 알아보자&quot; data-og-description=&quot;테스트 더블(Test Double)이란? xUnit Test Patterns의 저자인 제라드 메스자로스(Gerard Meszaros&amp;hellip;&quot; data-og-host=&quot;woowacourse.github.io&quot; data-og-source-url=&quot;https://woowacourse.github.io/tecoble/post/2020-09-19-what-is-test-double/&quot; data-og-url=&quot;https://woowacourse.github.io/tecoble//tecoble/post/2020-09-19-what-is-test-double/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c4CA7U/hyKKDeYoPq/qtKvMVOkTLf8X7z9bkN6K1/img.jpg?width=700&amp;amp;height=416&amp;amp;face=0_0_700_416&quot;&gt;&lt;a href=&quot;https://woowacourse.github.io/tecoble/post/2020-09-19-what-is-test-double/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://woowacourse.github.io/tecoble/post/2020-09-19-what-is-test-double/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c4CA7U/hyKKDeYoPq/qtKvMVOkTLf8X7z9bkN6K1/img.jpg?width=700&amp;amp;height=416&amp;amp;face=0_0_700_416');&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;Test Double을 알아보자&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;테스트 더블(Test Double)이란? xUnit Test Patterns의 저자인 제라드 메스자로스(Gerard Meszaros&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;woowacourse.github.io&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://brunch.co.kr/@tilltue/55&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://brunch.co.kr/@tilltue/55&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1625205315805&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Test Doubles 정리&quot; data-og-description=&quot;Dummy, Fake, Stub, Spy, Mock | 테스트 더블이란? 실제 객체를 대신해서 테스팅에서 사용하는 모든 방법을 일컬여 호칭하는 것이다. (영화 촬영시 위험한 역활을 대신하는 스턴트 더블에서 비롯되었다.)&quot; data-og-host=&quot;brunch.co.kr&quot; data-og-source-url=&quot;https://brunch.co.kr/@tilltue/55&quot; data-og-url=&quot;https://brunch.co.kr/@tilltue/55&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Y08Yc/hyKLqE5iCC/14ybgreMU9EHWslgXSz0yK/img.jpg?width=1280&amp;amp;height=960&amp;amp;face=0_0_1280_960,https://scrap.kakaocdn.net/dn/cxiUUi/hyKLoAvq7w/muKoIFE457QVkXPmotHtg0/img.jpg?width=500&amp;amp;height=500&amp;amp;face=0_0_500_500,https://scrap.kakaocdn.net/dn/t9XIa/hyKLtu4kBa/huv9gUAzuvizMUFR8WAtyk/img.png?width=1280&amp;amp;height=1125&amp;amp;face=0_0_1280_1125&quot;&gt;&lt;a href=&quot;https://brunch.co.kr/@tilltue/55&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://brunch.co.kr/@tilltue/55&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Y08Yc/hyKLqE5iCC/14ybgreMU9EHWslgXSz0yK/img.jpg?width=1280&amp;amp;height=960&amp;amp;face=0_0_1280_960,https://scrap.kakaocdn.net/dn/cxiUUi/hyKLoAvq7w/muKoIFE457QVkXPmotHtg0/img.jpg?width=500&amp;amp;height=500&amp;amp;face=0_0_500_500,https://scrap.kakaocdn.net/dn/t9XIa/hyKLtu4kBa/huv9gUAzuvizMUFR8WAtyk/img.png?width=1280&amp;amp;height=1125&amp;amp;face=0_0_1280_1125');&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;Test Doubles 정리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Dummy, Fake, Stub, Spy, Mock | 테스트 더블이란? 실제 객체를 대신해서 테스팅에서 사용하는 모든 방법을 일컬여 호칭하는 것이다. (영화 촬영시 위험한 역활을 대신하는 스턴트 더블에서 비롯되었다.)&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;brunch.co.kr&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://www.crocus.co.kr/1555&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.crocus.co.kr/1555&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1625209073315&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Mockito] Mock 개념(Mock Object)&quot; data-og-description=&quot;단위 테스트를 하기 위해서는 한번에 메서드 하나만을 실행해 보는 것인데 이러한 메서드가 다른 네트워크, 데이터베이스 등등 제어하기 어려운 것들에 의존하고 있다면 어떻게 단위 테스트를 &quot; data-og-host=&quot;www.crocus.co.kr&quot; data-og-source-url=&quot;https://www.crocus.co.kr/1555&quot; data-og-url=&quot;https://www.crocus.co.kr/1555&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bPNWLQ/hyKKLRD1h0/W8DnycN6vVZUIDqyEQV7Rk/img.png?width=600&amp;amp;height=386&amp;amp;face=0_0_600_386,https://scrap.kakaocdn.net/dn/dKKa30/hyKKx0awii/MT5aU3QyExL0Z6kfkDxOw1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/nRMsn/hyKKxy7FQC/sanOhPwe1HvhVpALATdaS1/img.png?width=600&amp;amp;height=386&amp;amp;face=0_0_600_386&quot;&gt;&lt;a href=&quot;https://www.crocus.co.kr/1555&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.crocus.co.kr/1555&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bPNWLQ/hyKKLRD1h0/W8DnycN6vVZUIDqyEQV7Rk/img.png?width=600&amp;amp;height=386&amp;amp;face=0_0_600_386,https://scrap.kakaocdn.net/dn/dKKa30/hyKKx0awii/MT5aU3QyExL0Z6kfkDxOw1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/nRMsn/hyKKxy7FQC/sanOhPwe1HvhVpALATdaS1/img.png?width=600&amp;amp;height=386&amp;amp;face=0_0_600_386');&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;[Mockito] Mock 개념(Mock Object)&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;www.crocus.co.kr&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://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1625210002913&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Mockito - mockito-core 3.11.2 javadoc&quot; data-og-description=&quot;Latest version of org.mockito:mockito-core https://javadoc.io/doc/org.mockito/mockito-core Current version 3.11.2 https://javadoc.io/doc/org.mockito/mockito-core/3.11.2 package-list path (used for javadoc generation -link option) https://javadoc.io/doc/org&quot; data-og-host=&quot;javadoc.io&quot; data-og-source-url=&quot;https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html&quot; data-og-url=&quot;https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Mockito - mockito-core 3.11.2 javadoc&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Latest version of org.mockito:mockito-core https://javadoc.io/doc/org.mockito/mockito-core Current version 3.11.2 https://javadoc.io/doc/org.mockito/mockito-core/3.11.2 package-list path (used for javadoc generation -link option) https://javadoc.io/doc/org&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;javadoc.io&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>테스트</category>
      <author>DEV_SJ</author>
      <guid isPermaLink="true">https://codinghack.tistory.com/92</guid>
      <comments>https://codinghack.tistory.com/92#entry92comment</comments>
      <pubDate>Fri, 2 Jul 2021 16:46:13 +0900</pubDate>
    </item>
    <item>
      <title>AssertJ</title>
      <link>https://codinghack.tistory.com/90</link>
      <description>&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;AssertJ란?&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';&quot;&gt;Assertj는 많은 Assertion, 오류 메시지 테스트를 제공하고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;테스트 코드 가독성을 향상 시키며 쉽게 사용할 수 있도록 설계된 Java 라이브러리입니다.&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';&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';&quot;&gt;Assertj를 사용하기 위해선 의존성을 추가해주어야 합니다.&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;maven dependency&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1625142612335&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
  &amp;lt;groupId&amp;gt;org.assertj&amp;lt;/groupId&amp;gt;
  &amp;lt;artifactId&amp;gt;assertj-core&amp;lt;/artifactId&amp;gt;
  &amp;lt;!-- use 2.9.1 for Java 7 projects --&amp;gt;
  &amp;lt;version&amp;gt;3.20.2&amp;lt;/version&amp;gt;
  &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(자바 7 은 2.9.1을 사용하라고 명시되어있습니다.)&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;gradle dependency 추가&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1625142627952&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;testImplementation &quot;org.assertj:assertj-core:3.20.2&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;항상 Java 버전을 확인하고 사용해주세요!&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;AssertJ Core 3.x requires Java 8 or higher&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;AssertJ Core 2.x requires Java 7 or higher&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;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;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;의존성 추가 후 아래 import를 통해 모든 라이브러리를 사용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625142644175&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import static org.assertj.core.api.Assertions.*;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&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;/h4&gt;
&lt;pre id=&quot;code_1625142673326&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Test
void a_few_simple_assertions(){
    assertThat(&quot;The Lord of the Rings&quot;).isNotNull()
            .startsWith(&quot;The&quot;)
            .contains(&quot;Lord&quot;)
            .endsWith(&quot;Rings&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&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;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Supported type assertions&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #edd9a6; color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;AssertJ는 Java의 거의 모든 타입을 다 지원하는듯 보입니다.&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;style5&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;BigDecimal&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;BigInteger&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;CharSequence&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Class&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Date&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;File&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Future / CompletableFuture&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;InputStream&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Iterable (including any kind of Collection)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Iterator&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;List&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Map&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Object&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Object[] and Object[][]&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&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;Optional&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;OptionalInt / OptionalLong / OptionalDouble&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Path&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Predicate&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Stream&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;String&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Throwable / Exception&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Primitive types and their wrapper:&lt;/span&gt;&lt;br /&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;short / Short&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;int / Integer&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;long / Long&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;byte / Byte&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;char / Character&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;float / Float&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;double / Double&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Primitive type arrays:&lt;/span&gt;&lt;br /&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;short[]&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;int[]&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;long[]&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;byte[]&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;char[]&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;float[]&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;double[]&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Primitive type 2D arrays:&lt;/span&gt;&lt;br /&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;short[][]&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;int[][]&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;long[][]&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;byte[][]&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;char[][]&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;float[][]&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;double[][]&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;style5&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Instant&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;LocalDate&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;LocalDateTime&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;LocalTime&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;OffsetDateTime&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;OffsetTime&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ZonedDateTime&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Period&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Assertion description&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;as를 붙혀서 간단하게 사용할 수 있습니다. 테스트가 Fail일 때 아래와 같이 볼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625143325213&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Test
    void describe(){
        Person person = new Person(20, &quot;Yoon&quot;);
        assertThat(person.getAge()).as(&quot;check %s's age&quot;, person.getAge())
                .isEqualTo(30);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;테스트 결과&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;163&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oBSPi/btq8zxD0ZHK/zBMtrZxIYKJAGrtBJA1dHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oBSPi/btq8zxD0ZHK/zBMtrZxIYKJAGrtBJA1dHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oBSPi/btq8zxD0ZHK/zBMtrZxIYKJAGrtBJA1dHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoBSPi%2Fbtq8zxD0ZHK%2FzBMtrZxIYKJAGrtBJA1dHk%2Fimg.png&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;163&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;또한 withFailErrorMessage()를 사용해 다음과 같이 나타낼 수도 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625143460748&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Test
    void failMessage(){
        Person person = new Person(20, &quot;Yoon&quot;);
        assertThat(person.getAge()).withFailMessage(&quot;check %s's age&quot;, person.getAge())
                .isEqualTo(30);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;테스트 결과&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;429&quot; data-origin-height=&quot;53&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cT7OwL/btq8w5AHUmo/7qfWTB3fK4fkQ0IvrFNm41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cT7OwL/btq8w5AHUmo/7qfWTB3fK4fkQ0IvrFNm41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cT7OwL/btq8w5AHUmo/7qfWTB3fK4fkQ0IvrFNm41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcT7OwL%2Fbtq8w5AHUmo%2F7qfWTB3fK4fkQ0IvrFNm41%2Fimg.png&quot; data-origin-width=&quot;429&quot; data-origin-height=&quot;53&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&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';&quot;&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;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;assertJ를 사용할때 꼭 알아야할 유의해야할 점이 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625143568028&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Test
    void badAssert(){
        Person person = new Person(20, &quot;Yoon&quot;);
        assertThat(person.equals(null));
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;이와 같은 테스트는 어떤 결과를 반환할까요?&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;AssertJ의 사용법을 모르고 다음과 같이 했다면 테스트과 통과됩니다. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;올바른 방법은 아래와 같습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625143813771&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Test
    void goodAssert(){
        Person person = new Person(20, &quot;Yoon&quot;);
        assertThat(person).isEqualTo(person);
        //or
        assertThat(person.equals(person)).isTrue();
    }&lt;/code&gt;&lt;/pre&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';&quot;&gt;assertj에는 굉장히 많은 메소드들이 있으며 활용범위가 넓습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&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;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;a href=&quot;https://assertj.github.io/doc/#common-types&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://assertj.github.io/doc/#common-types&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1625143080689&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;AssertJ - fluent assertions java library&quot; data-og-description=&quot;Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Pascal Schumacher, BJ Hargrave, Raymond Aug&amp;eacute;, Thomas Wei&amp;szlig;schuh, Maciej Wajcht, Hayden Meloche, Filip Hrisafov, Jayati Goyal, Gyumin Kim, Clemens Grabmann, Roman Leventov, Fr J&quot; data-og-host=&quot;assertj.github.io&quot; data-og-source-url=&quot;https://assertj.github.io/doc/#common-types&quot; data-og-url=&quot;https://assertj.github.io/doc/#common-types&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bJUyEy/hyKKM3FUmi/jro5nq28WlGC5PKlIT68V0/img.png?width=880&amp;amp;height=294&amp;amp;face=0_0_880_294,https://scrap.kakaocdn.net/dn/pBgQA/hyKLzhko1u/YP8coauHEKVHdIO6ZDc3W1/img.png?width=970&amp;amp;height=224&amp;amp;face=0_0_970_224,https://scrap.kakaocdn.net/dn/4C3ul/hyKKFpUUkE/IrrBeDQcaQ8CG6oh4t4bZK/img.png?width=790&amp;amp;height=266&amp;amp;face=0_0_790_266&quot;&gt;&lt;a href=&quot;https://assertj.github.io/doc/#common-types&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://assertj.github.io/doc/#common-types&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bJUyEy/hyKKM3FUmi/jro5nq28WlGC5PKlIT68V0/img.png?width=880&amp;amp;height=294&amp;amp;face=0_0_880_294,https://scrap.kakaocdn.net/dn/pBgQA/hyKLzhko1u/YP8coauHEKVHdIO6ZDc3W1/img.png?width=970&amp;amp;height=224&amp;amp;face=0_0_970_224,https://scrap.kakaocdn.net/dn/4C3ul/hyKKFpUUkE/IrrBeDQcaQ8CG6oh4t4bZK/img.png?width=790&amp;amp;height=266&amp;amp;face=0_0_790_266');&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;AssertJ - fluent assertions java library&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Thanks to all the contributors of this release: Erhard Pointl, Stefano Cordio, Pascal Schumacher, BJ Hargrave, Raymond Aug&amp;eacute;, Thomas Wei&amp;szlig;schuh, Maciej Wajcht, Hayden Meloche, Filip Hrisafov, Jayati Goyal, Gyumin Kim, Clemens Grabmann, Roman Leventov, Fr J&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;assertj.github.io&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>테스트</category>
      <author>DEV_SJ</author>
      <guid isPermaLink="true">https://codinghack.tistory.com/90</guid>
      <comments>https://codinghack.tistory.com/90#entry90comment</comments>
      <pubDate>Thu, 1 Jul 2021 21:55:35 +0900</pubDate>
    </item>
    <item>
      <title>스프링의 객체 주입 &amp;amp; 동일한 객체를 추가로 생성하여 주입하는 경우</title>
      <link>https://codinghack.tistory.com/89</link>
      <description>&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. 스프링의 싱글톤&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;스프링은 기본적으로 Bean으로 등록된 객체를 싱글턴 방식을 사용하여 관리합니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예를 들어 @Bean, @Controller, @Component 등의 어노테이션이 붙은 Bean들은 스프링 컨테이너가 실행 시점에 등록된 Bean, 컴포넌트 스캔을 하여 &lt;b&gt;딱 1번만 생성&lt;/b&gt;됩니다. 이후에는 요청이 들어와도 새로 객체를 생성하지 않고 공유해서 쓰게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;563&quot; data-origin-height=&quot;257&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTDJKy/btq6Ad0Og4Z/ytQtXlBPkRSsUrdLYwVJnK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTDJKy/btq6Ad0Og4Z/ytQtXlBPkRSsUrdLYwVJnK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTDJKy/btq6Ad0Og4Z/ytQtXlBPkRSsUrdLYwVJnK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTDJKy%2Fbtq6Ad0Og4Z%2FytQtXlBPkRSsUrdLYwVJnK%2Fimg.jpg&quot; data-origin-width=&quot;563&quot; data-origin-height=&quot;257&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&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;/h4&gt;
&lt;p data-ke-size=&quot;size18&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;Gabage Collecting&lt;/b&gt;이 일어나기 때문입니다. 예를 들어 서버로 10000명의 사용자가 요청을 보낼 시 싱글톤이 아니라면 10000개의 객체를 생성해야 하니 낭비가 심하겠죠?&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';&quot;&gt;당연히 싱글톤을 이용하면서의 주의점도 있습니다. 싱글톤으로 공유가 되기에 상태를 유지하지 않도록 코드를 작성을 해야 하는데요. 이를 &lt;b&gt;무상태성(Stateless)&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 Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;2. 객체 자동 주입&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&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;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;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1622816184490&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Component
public class OrderServiceImpl implements OrderService {

	private final MemberRepository memberRepository;
	private final DiscountPolicy discountPolicy;

	@Autowired // 생략 가능
	public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
		this.memberRepository = memberRepository;
		this.discountPolicy = discountPolicy;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;코드와 같이 생성자 주입은 OrderServiceImpl이 생성되는 시점에 딱&lt;b&gt; 1번만 호출되는 것이 보장&lt;/b&gt;됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;인 의존관계에 사용되며 생성자가 하나만 있으면 @Autowired를 생략할 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;요즘은 Lombok을 많이 이용하기 때문에 @RequiredArgsConstructor를 사용해서&amp;nbsp; 생성자 자체를 생략할 수도 있습니다.&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';&quot;&gt;&lt;b&gt;수정자 주입 (setter 사용)&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1622817207238&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Component
public class OrderServiceImpl implements OrderService {

    private MemberRepository memberRepository;
    private DiscountPolicy discountPolicy;

    @Autowired
    public void setMemberRepository(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Autowired
    public void setDiscountPolicy(DiscountPolicy discountPolicy) {
        this.discountPolicy = discountPolicy;
    }
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;수정자 주입은 setter에 @Autowired를 붙여서 사용합니다. 그러면 스프링 컨테이너가 해당 Bean을 찾아서 setter에 자동으로 주입해줍니다.&amp;nbsp; 그렇다면 실수로 @Autowired를 붙이지 않으면 어떻게 될까요?&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&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;/h4&gt;
&lt;pre id=&quot;code_1622817838276&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//    @Autowired 빠트렸다!
    public void setMemberRepository(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1228&quot; data-origin-height=&quot;166&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EhwHe/btq6zubdy28/5NxLdmBG65kkQJ3EYdO0K1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EhwHe/btq6zubdy28/5NxLdmBG65kkQJ3EYdO0K1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EhwHe/btq6zubdy28/5NxLdmBG65kkQJ3EYdO0K1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEhwHe%2Fbtq6zubdy28%2F5NxLdmBG65kkQJ3EYdO0K1%2Fimg.png&quot; data-origin-width=&quot;1228&quot; data-origin-height=&quot;166&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;시점에는 &lt;b&gt;NullpointerException&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';&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;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;pre id=&quot;code_1622818193162&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Component
public class OrderServiceImpl implements OrderService {

    @Autowired
    private MemberRepository memberRepository;

    @Autowired
    private DiscountPolicy discountPolicy;
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;필드 주입은 &lt;b&gt;@Autowired&lt;/b&gt;를 붙여서 주입됩니다. 생성자 주입, 수정자 주입보다 코드가 정말 간단하죠? &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;385&quot; data-origin-height=&quot;226&quot; width=&quot;443&quot; height=&quot;260&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqOPkr/btq6z4QnKxs/Znim5pAzBl1wrHtZFhEK3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqOPkr/btq6z4QnKxs/Znim5pAzBl1wrHtZFhEK3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqOPkr/btq6z4QnKxs/Znim5pAzBl1wrHtZFhEK3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqOPkr%2Fbtq6z4QnKxs%2FZnim5pAzBl1wrHtZFhEK3k%2Fimg.png&quot; data-origin-width=&quot;385&quot; data-origin-height=&quot;226&quot; width=&quot;443&quot; height=&quot;260&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&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;b&gt;노란 줄이&lt;/b&gt; 그어집니다!&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;코드는 깔끔하고 좋은데 어떤 경우에 문제가 될까요?&lt;/span&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';&quot;&gt;&lt;span&gt;순수한 자바 테스트 코드를 작성하는 경우에는 당연히 @Autowired가 동작하지 않습니다. @SpringBootTest처럼 의존관계를 주입해줄 스프링 프레임워크가 필요합니다.&amp;nbsp; &lt;/span&gt;&lt;span style=&quot;font-size: 1.12em; letter-spacing: 0px;&quot;&gt;즉 &lt;/span&gt;Spring이 아니면 해당 필드에 Injection을 할 수 있는 방법이 없습니다. 그렇다면 Setter를 써야 할 텐데... 그럴 거면 수정자 주입을 사용하는 것이 좋겠지요?&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';&quot;&gt;&lt;span&gt;그래서 요즘에는 안 쓰는 게 좋다고 합니다. &lt;b&gt;BUT!&lt;/b&gt; 애플리케이션과 관계없는 스프링 테스트 코드에서는 편하게 사용할 수 있습니다. 어디서 가져다 쓰는 게 아니라 문제 되지 않으니까요.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;에서는&amp;nbsp;&lt;b&gt;Constructor Injection&lt;/b&gt;을, &lt;b&gt;선택적인 의존성&lt;/b&gt;에서는&amp;nbsp;&lt;b&gt;Setter Injection를&lt;/b&gt; 사용하라고 합니다.&amp;nbsp;&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';&quot;&gt;자 이제 제가 말하려던 같은 객체가 2개 있을 땐 어떻게 주입하지?라는 본론으로 넘어가 보겠습니다.&amp;nbsp;&lt;/span&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;span&gt;3.&amp;nbsp; 2개가&amp;nbsp; 필요했던 경우&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;동일한 객체이지만 다른 설정을 가지는 2개의 Bean을 스프링은 어떻게 관리할까요? 또 이런 경우는 언제 일어날까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&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;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';&quot;&gt;&lt;span&gt;내용은 기존 Gitlab 프로젝트를 새로운 Gitlab으로 Migration 하는 것이었는데요.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;처음에는 간단하게 Migration 요청이 들어온 프로젝트를 쉘 스크립트로 Clone 받아서 신규 서버에 밀어 넣을 계획이었습니다. 하지만 이렇게 되면 기존 커밋 이력은 넘어가지 않고 소스코드만 넘어가게 돼서 고민이었는데&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;역시나 java gitlab api가 maven으로 이미 만들어져 있더군요.. ㅎ_ㅎ&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://github.com/gitlab4j/gitlab4j-api#importexportapi&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/gitlab4j/gitlab4j-api#importexportapi&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1622820806689&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;gitlab4j/gitlab4j-api&quot; data-og-description=&quot;GitLab4J API (gitlab4j-api) provides a full featured Java client library for working with GitLab repositories via the GitLab REST API - gitlab4j/gitlab4j-api&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/gitlab4j/gitlab4j-api#importexportapi&quot; data-og-url=&quot;https://github.com/gitlab4j/gitlab4j-api&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/sYqqi/hyKthn5j1c/7XbmNPJh7Krkyk0tIRlXDk/img.png?width=640&amp;amp;height=320&amp;amp;face=0_0_640_320&quot;&gt;&lt;a href=&quot;https://github.com/gitlab4j/gitlab4j-api#importexportapi&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/gitlab4j/gitlab4j-api#importexportapi&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/sYqqi/hyKthn5j1c/7XbmNPJh7Krkyk0tIRlXDk/img.png?width=640&amp;amp;height=320&amp;amp;face=0_0_640_320');&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;gitlab4j/gitlab4j-api&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;GitLab4J API (gitlab4j-api) provides a full featured Java client library for working with GitLab repositories via the GitLab REST API - gitlab4j/gitlab4j-api&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;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;921&quot; data-origin-height=&quot;487&quot; width=&quot;792&quot; height=&quot;419&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l9JNx/btq6zqs9hLt/Uaaum5SnZVkR73pVl4RfDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l9JNx/btq6zqs9hLt/Uaaum5SnZVkR73pVl4RfDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l9JNx/btq6zqs9hLt/Uaaum5SnZVkR73pVl4RfDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl9JNx%2Fbtq6zqs9hLt%2FUaaum5SnZVkR73pVl4RfDK%2Fimg.png&quot; data-origin-width=&quot;921&quot; data-origin-height=&quot;487&quot; width=&quot;792&quot; height=&quot;419&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;좀 더 상세히 설명드리면 그림과 같습니다. RabbitMQ에 마이그레이션 요청이 들어온 ID를 빼와서&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;기존 Gitlab Export =&amp;gt; 신규 Gitlab Import를&lt;/b&gt; 하는 과정입니다. 기존 Gitlab, 신규 Gitlab 뭔가 동일한 객체가 2개 필요할 것 같지 않으신가요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1622820854884&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Create a GitLabApi instance to communicate with your GitLab server
GitLabApi gitLabApi = new GitLabApi(&quot;http://your.gitlab.server.com&quot;, &quot;YOUR_PERSONAL_ACCESS_TOKEN&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;java gitlab api를 확인해보면 gitlab server와 access token으로 객체를 생성하고 있습니다. 앞서 말씀드렸다시피 요청이 들어올 때마다 객체를 생성하면 낭비가 심하기 때문에 저는 GitlabApi를 Bean으로 관리하기로 하여 아래와 같이 Configuration을 작성하였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1622821659816&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
public class GitlabApiConfiguration {

	// 생략

    @Bean
    public GitLabApi oldGitLabApi(){
        return new GitLabApi(oldGitlabUrl, oldGitlabKey);
    }

    @Bean
    public GitLabApi newGitLabApi(){
        return new GitLabApi(newGitlabUrl, newGitlabKey);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span&gt;어.. 근데 스프링이 기존 거랑 신규를 어떻게 구별해서 주입해줄까요...?&amp;nbsp; &lt;/span&gt;&lt;span&gt;기존 꺼에선 Export, 신규에선 Import를 해야 해서 2개가 다 필요한데요 ㅜ_ㅜ;;&amp;nbsp; &lt;/span&gt;&lt;span&gt;지금까지 개발을 하면서 항상 한 가지 Bean에 대한 경우만 주입했던 것 같습니다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1622821856891&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class GitlabMigrationService {

    private final GitLabApi oldGitLabApi;

    private final GitLabApi newGitLabApi;

    public GitlabMigrationService(GitLabApi oldGitLabApi, GitLabApi newGitLabApi) {
        this.oldGitLabApi = oldGitLabApi;
        this.newGitLabApi = newGitLabApi;
    }
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Bean을 주입받아 사용할 Service에서 어떻게 구분하지..! 사실 토비님의 스프링 책 또는 김영한 님의 스프링 강좌를 들으셨다면 @Qualifier의 존재에 대해서 알 것입니다.&lt;/span&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;4. @Qualifier&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;몇 번 보기는 했지만 처음 써보는 어노테이션이므로 알아보고 사용하도록 합시다. 먼저 당당하게 소스코드를 까 보았습니다만.. 역시 뭐가 없습니다. value만 선언이 되어있네요.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1622822442653&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {
    String value() default &quot;&quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그래서 spring docs에서 검색한 결과 아래와 같이 설명되어 있습니다.&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';&quot;&gt;&lt;b&gt;Fine-tuning&amp;nbsp;Annotation-based&amp;nbsp;Autowiring&amp;nbsp;with&amp;nbsp;Qualifiers&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1622822674209&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Primary is an effective way to use autowiring by type with several instances 
when one primary candidate can be determined. 
When you need more control over the selection process, 
you can use Spring&amp;rsquo;s @Qualifier annotation.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;@Primary 어노테이션은 몇몇의 후보 빈이 있을 때 주입할 빈을 결정한다고 합니다. 만약 더 많은 결정이 필요하다면 @Qualifier를 사용하라고 되어있네요. 즉 여러개의 빈중에 하나를 주입하려면 @Primary를 사용하고 여러개의 빈을 모두 사용하려면 @Qualifier를 사용해야하는 합니다. &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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;간단한 Student 객체&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1622823494259&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Student {
   private Integer age;
   private String name;
   // 생략
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;student1과 student2를 빈으로 생성&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1622823544115&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;   &amp;lt;!-- Definition for student1 bean --&amp;gt;
   &amp;lt;bean id = &quot;student1&quot; class = &quot;com.Student&quot;&amp;gt;
      &amp;lt;property name = &quot;name&quot; value = &quot;Zara&quot; /&amp;gt;
      &amp;lt;property name = &quot;age&quot; value = &quot;11&quot;/&amp;gt;
   &amp;lt;/bean&amp;gt;

   &amp;lt;!-- Definition for student2 bean --&amp;gt;
   &amp;lt;bean id = &quot;student2&quot; class = &quot;com.Student&quot;&amp;gt;
      &amp;lt;property name = &quot;name&quot; value = &quot;Nuha&quot; /&amp;gt;
      &amp;lt;property name = &quot;age&quot; value = &quot;2&quot;/&amp;gt;
   &amp;lt;/bean&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;원하는 Bean을 명시&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1622823663514&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Profile {
   @Autowired
   @Qualifier(&quot;student1&quot;)
   private Student student;
   
   @Autowired
   @Qualifier(&quot;student2&quot;)
   private Student student;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&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;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;테스트를 위해 @Autowired를 사용했는데 아래 저의 프로젝트와 같이 생성자 주입 시에도 어노테이션 활용이 가능합니다.&lt;/span&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';&quot;&gt;그러면 프로젝트에 적용시켜보겠습니다. 원래의 Configuration Bean에 다음과 같이 이름을 붙여줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1622822932452&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Bean
    @Qualifier(&quot;oldGitlab&quot;)
    public GitLabApi oldGitLabApi(){
        return new GitLabApi(oldGitlabUrl, oldGitlabKey);
    }

    @Bean
    @Qualifier(&quot;newGitlab&quot;)
    public GitLabApi newGitLabApi(){
        return new GitLabApi(newGitlabUrl, newGitlabKey);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그리고 생성자 주입받는 Service을 아래와 같이 수정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1622822967019&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class GitlabMigrationService {

    private final GitLabApi oldGitLabApi;

    private final GitLabApi newGitLabApi;

    public GitlabMigrationService(@Qualifier(&quot;oldGitlab&quot;)GitLabApi oldGitLabApi,
                                  @Qualifier(&quot;newGitlab&quot;)GitLabApi newGitLabApi) {
        this.oldGitLabApi = oldGitLabApi;
        this.newGitLabApi = newGitLabApi;
    }
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이렇게 같은 객체임에도 두 개의 다른 Bean을 등록하였고 저는 성공적으로 마이그레이션을 할 수 있었습니다.&lt;/span&gt;&lt;/p&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;5. 마치며&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&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;size18&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;/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 href=&quot;https://docs.spring.io/spring-framework/docs/5.2.3.RELEASE/spring-framework-reference/core.html#beans-setter-injection&quot;&gt;https://docs.spring.io/spring-framework/docs/5.2.3.RELEASE/spring-framework-reference/core.html#beans-setter-injection&lt;/a&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://sightstudio.tistory.com/20&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://sightstudio.tistory.com/20&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 href=&quot;https://yaboong.github.io/spring/2019/08/29/why-field-injection-is-bad/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://yaboong.github.io/spring/2019/08/29/why-field-injection-is-bad/&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 href=&quot;https://www.tutorialspoint.com/spring/spring_qualifier_annotation.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.tutorialspoint.com/spring/spring_qualifier_annotation.htm&lt;/a&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>DEV_SJ</author>
      <guid isPermaLink="true">https://codinghack.tistory.com/89</guid>
      <comments>https://codinghack.tistory.com/89#entry89comment</comments>
      <pubDate>Sat, 5 Jun 2021 01:27:39 +0900</pubDate>
    </item>
  </channel>
</rss>