<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>feel_2</title>
    <link>https://feel2.tistory.com/</link>
    <description>안녕하세요, 대체 불가능한 개발자(NFE) 박경태입니다.</description>
    <language>ko</language>
    <pubDate>Mon, 3 Aug 2026 01:28:14 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>feel2</managingEditor>
    <image>
      <title>feel_2</title>
      <url>https://tistory1.daumcdn.net/tistory/5360187/attach/8b5d238bc73d4a188c4c702b1c64ac19</url>
      <link>https://feel2.tistory.com</link>
    </image>
    <item>
      <title>[비개발서적] 마흔에 읽는 쇼펜하우어: 독서록</title>
      <link>https://feel2.tistory.com/164</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;서론&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 마흔이 얼마 남지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;십대 때를 생각하면 마흔의 나이는 정말 어른처럼 보였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그때는 뭐든 커 보일 나이였으니까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뒤돌아 생각해 보면, 그때 어른들은 모두 &amp;lsquo;&lt;span&gt;&lt;b&gt;어른인 척&lt;/b&gt;&lt;/span&gt;&amp;rsquo;을 하고 있었던 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그저 어쩌다 보니 아이를 낳아 부모가 됐고, 어쩌다 보니 가정을 책임지게 되었고, 어쩌다 보니 희생하게 되어 버린.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 어른이라는 이유만으로 모든 것을 떠안지 않았던가.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 시대가 변했다. 사회생활이 늦어지면서 결혼도 점점 늦어지기 시작했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자연스럽게 부모가 되는 시기도 미뤄지고, 어른의 경계는 점점 뒤로 밀려나고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 언제쯤 어른이 될까? 아직 마음속에 있는 소년을 떠나보내기 싫어하는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장자는 마흔이면 &lt;span&gt;&lt;b&gt;불혹&lt;/b&gt;&lt;/span&gt;이라 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인생의 흔들림을 극복하고, 자신의 길을 굳건히 걸어갈 때라고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나도 그런 마흔이 될 수 있을까?&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고령화 시대다. 100세 시대라고도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 따지면 아직 나는 3분의 1밖에 살지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 아침 8시밖에 되지 않았다는 얘기다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금부터 인생을 잘 살아간다면 멋진 어른이 될 수 있지 않을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 책은 이런 나에게 길잡이가 되어 준 친구다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;인상 깊었던 구절&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&amp;hellip; 산다는 것은 괴로운 것이다. - 1장. 마흔, 왜 인생이 괴로운가. 39p&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 왜 살아갈까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리의 의지로 태어난 것은 아니라고 생각할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇지만 내 생각은 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 3억 분의 1의 확률로 태어났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로또 1등에 수십 번 당첨될 확률보다 어려운 확률이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 수많은 어려움을 이겨내 수정이 되어 나라는 존재가 태어났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 어렵게 태어난 우리는 왜 살면서 고통을 받는 것일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 생각했을 때 우리의 삶이 괴롭게 느껴지는 이유는 &lt;span&gt;&lt;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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고통에서 벗어나 행복에 더 가까워질 수 있지 않을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이왕 태어난 거, 생각을 바꿔 보면 어떨까?&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&amp;hellip; 삶은 진자처럼 고통과 무료함 사이를 왔다 갔다 하는데, 사실 이 두 가지가 삶의 궁극적인 요소다. - 1장. 마흔, 왜 인생이 괴로운가. 52p&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리의 삶은 매우 다이내믹하다. 마치 롤러코스터처럼 언제 갑자기 치고 올라갔다가 떨어질지 모른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 중립을 원한다. 너무 좋지도, 그렇다고 너무 나쁘지도 않은 중간.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 삶은 나를 그렇게 내버려 두지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;끊임없이 진자처럼 고통과 무료함 사이를 왔다 갔다하며 우리를 시험한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 어느 한쪽으로 너무 치우치지 않게 중립이 중요하다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인간은 욕망의 동물이기에 없으면 없다고, 많으면 많다고 불평한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 반대편을 바라보기보다 가까운 나무를 보는 습관을 기르면 되지 않을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 들어 헛헛함이 내 뱃속을 가득 채웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무료함이 내 뱃속에서 증식한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제는 다시 토해낼 때다. 그래야 중심이 맞으니까.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;현자는 쾌락이 아니라 고통이 없는 상태를 추구한다. - 1장. 마흔, 왜 인생이 괴로운가. 74p&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현시대는 쾌락의 시대다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금만 눈을 돌려도 나를 쾌락으로 물들일 수 있는 것들이 차고 넘친다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도박, 술, 담배&amp;hellip; 손대는 건 쉽지만, 빠져나오기는 개미지옥처럼 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 나는 한 번씩 &lt;span&gt;&lt;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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;남들 눈에는 내 인생이 재미없어 보일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책을 읽거나, 헬스를 하거나, 산책을 하거나, 가끔 치킨을 시켜 먹거나&amp;hellip;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 나는 누구보다 묵묵히 나의 할 일을 하며 살아간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;굳이 뭔가에 쫓기고 싶지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다고 쫓고 싶지도 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나의 속도에 맞춰 나아갈 뿐이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;물고기는 물에 있어야, 새는 공중에 있어야, 두더지는 땅속에 있어야만 행복하다. - 2장. 왜 있는 그대로 인정해야 하는가. 89p&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 물고기일까? 새일까? 두더지일까? 아니면 또 다른 무엇일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나에게 맞는 일을 찾는 것은 정말 중요한 일이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마 평생 찾아 헤맬 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;천직이란 정말 존재할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 구절은 나에게 두 가지 의미로 와닿았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째는 안분지족, 내 분수를 지키며 만족하며 사는 삶이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;황새가 뱁새를 따라 하다 다리가 찢어진다고 하지 않는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 아니다 싶으면 포기할 줄 아는 것도 용기라고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째는 첫 번째와 상반되는 이야기인데, 여러 가지 도전을 해봐야 한다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것이 나와 맞는지 안 맞는지는 해 보기 전에는 모르지 않는가!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어차피 한 번 사는 인생, 조금 부딪히고 깨지면 어떠한가.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 그곳에 새살이 돋아나고, 더 단단해져 좀 더 높은 곳에 도전할 수 있게 될 텐데.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;서로 견딜 수 있는 적당한 간격을 발견했다. 그것은 바로 정중함과 예의다. - 4장. 어떤 사람으로 살아야 하는가.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;누군가의 선을 넘어본 적 있는가? 그 반대는?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인간은 사회적 동물이다. 누군가와의 관계를 통해 나의 가치를 증명한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 인류가 모두 멸망하고 나만 살아 있다면 나라는 존재는 무슨 가치가 있겠는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 이런 교류 과정 속에서 누군가에게 상처를 줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 인간은 어쩔 수 없는 &lt;span&gt;&lt;b&gt;이기적인 생물&lt;/b&gt;&lt;/span&gt;이기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 때 필요한 것이 &lt;span&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리의 마음속 외침은 너무 작기 때문에 그들에게 잘 들리지 않기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;20대 때는 이런 일들로 상처를 받은 적도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그때는 밀어내는 법을 몰랐다. 그저 침략당하며 내 마음의 공터에 상처만 주었을 뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제는 성벽을 쌓았다. 그리고 그 영역을 침범하려 하면 대포도 주저하지 않고 날린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그것만이 나를 지키는 동시에 상대방을 지키는 길이라는 것을 이제는 알기에.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;마지막&lt;span&gt;&amp;nbsp;&lt;/span&gt;느낀 점&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 책을 읽으며 어떻게 더 행복해질까보다는 어떻게 덜 불안해질까에 대해 배운 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행복이란 아주 찰나의 순간과 같아서, 사람은 어차피 다시 불행해진다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 그 불안의 깊이를 낮춰 좀 더 행복의 순간을 자주 경험하면 되는 것 아닐까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소확행이라는 말이 생각난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행복의 역치를 낮춘다면 이런 행복의 순간은 자주 나를 찾아오게 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 하루 눈을 뜬 것에 대해,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동료와 웃으며 이야기할 수 있는 것에 대해,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엄마의 변하지 않는 잔소리를 듣는 것에 대해,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따뜻한 보금자리가 있는 것에 대해,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세상을 둘러보면 이미 행복한 것들 투성이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시선을 조금만 낮추면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Book Notes</category>
      <category>독서</category>
      <category>독서감상문</category>
      <category>독서록</category>
      <category>마흔</category>
      <category>마흔에읽는쇼펜하우어</category>
      <category>쇼펜하우어</category>
      <category>인문학</category>
      <author>feel2</author>
      <guid isPermaLink="true">https://feel2.tistory.com/164</guid>
      <comments>https://feel2.tistory.com/164#entry164comment</comments>
      <pubDate>Mon, 2 Feb 2026 23:46:10 +0900</pubDate>
    </item>
    <item>
      <title>[비개발서적] 유난한 도전 - 경계를 부수는 사람들, 토스팀 이야기: 독서록</title>
      <link>https://feel2.tistory.com/163</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;서론&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 책을 고를 때 제목도 중요하지만, 부제도 유심히 보는 편이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lsquo;경계를 부순다&amp;rsquo;는 게 어떤 의미일까? 처음 이 책의 제목이 눈에 띄었지만, 부제가 나의 궁금증을 해결해 줄 수 있을지 궁금하기도 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 책은 제3자의 시선에서 토스팀이 어떻게 성장했는지를 서술한다. 이미 10년도 지난 이야기부터 시작하기 때문에 인터뷰와 자료 수집에 많은 노력이 들어갔다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼에도 저자는 자신이 속한 토스팀이 어떻게 지금의 규모와 서비스를 만들 수 있었는지를 최대한 과감하게 기록하고 싶어 했다는 인상을 받았다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 책을 읽기 전까지 토스가 비바리퍼블리카의 첫 번째 프로젝트인 줄 알았다. 그런데 알고 보니 토스는 무려 &lt;span&gt;&lt;b&gt;아홉 번째 프로젝트&lt;/b&gt;&lt;/span&gt;였다. 이렇게 훌륭한 서비스를 만들기까지 그렇게 많은 시행착오가 있었다는 사실이 놀라웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비바리퍼블리카의 첫 프로젝트는 &amp;lsquo;울라블라&amp;rsquo;라는 서비스였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;친구들끼리 만나서 추억을 기록하고 공유하는 소셜 네트워크 앱이었다고 한다. 2013년 당시를 떠올려 보면, 페이스북이 한창 인기를 끌던 시기였다. 그래서 자연스럽게 소셜 네트워크 서비스를 떠올렸을지도 모른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 기대와 달리 울라블라는 1년 4개월 만에 서비스를 종료했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토스가 지금까지도 지켜오고 있는 제1원칙인 &lt;b&gt;&amp;lsquo;고객 중심주의&amp;rsquo;&lt;/b&gt;는 여기서부터 시작되었다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 서비스를 쓰는 건 고객이다. 우리가 아무리 좋은 서비스를 만들었다고 생각해도, 고객이 사용하지 않으면 아무 의미가 없다는 사실을 뼈저리게 깨닫게 된 것이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 실패 이후에도 토스는 여러 프로젝트를 시도했지만, 대부분 오래가지 못하고 실패를 반복했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 상황의 심각성을 느낀 이승건 대표는 팀원들이 전국으로 흩어져 아이디어를 모아오도록 했다. 그리고 그 과정에서 나온 아이디어 중 하나가 바로 토스였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후부터는 토스가 어떤 문제들을 어떻게 하나씩 해결해 나갔는지가 책에 자세히 담겨 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;읽으면서 신기했던 점은, 매번 위기의 순간마다 &lt;/span&gt;&lt;b&gt;그 문제를 해결할 수 있는 사람이 적절한 시기에 등장한다는 것&lt;/b&gt;&lt;span&gt;이었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 하나 인상 깊었던 건 문화였다. 문화란 모든 구성원이 함께 만들어 갈 때 비로소 힘을 가진다고 생각하는데, 토스 구성원들은 마치 그 문화를 DNA처럼 공유하고 있는 느낌이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 해결하기 위해 며칠 밤을 새우기도 하고, 의견이 달라도 자신의 신념을 끝까지 밀어붙여 증명해 보이기도 하며, 하루 종일 지표를 모니터링하다가 작은 성과에도 함께 기뻐하는 모습까지.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lsquo;진짜 자기 일에 자부심과 애정을 가지면 사람이 이렇게까지 몰입할 수 있구나&amp;rsquo;라는 생각을 많이 하게 됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;인상 깊었던 구절&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&amp;ldquo;토스팀의 구조와 문화, 제도는 모든 구성원을 뛰어난 역량과 높은 책임의식을 가진 어른으로 대우한다는 기본 전제에서 시작했다. 이러한 대원칙은 토스팀이 5명에서 2000명에 이르는 큰 조직이 되어가는 동안 한 번도 흔들리지 않았다.&amp;rdquo; - 2장 정성스럽게 그러나 포악하게, 95p&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 놀라웠던 점은 직위나 직책으로 사람을 수직적으로 나누는 대신, 모두를 수평적으로 바라보며 &lt;span&gt;&lt;b&gt;잠재력을 가진 어른으로 대우한다는 점&lt;/b&gt;&lt;/span&gt;이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 권한에는 책임이 따르기 때문에, 많은 사람들은 책임지는 자리에 서는 것을 부담스러워한다. 잘못되면 그 책임을 스스로 져야 하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 토스는 다르다. 모두가 실권자이고, 잘못되면 스스로 책임진다. 이것이야말로 진정한 어른의 모습이 아닐까.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&amp;ldquo;토스팀의 문화에는 공화주의적 면모가 녹아들어 있다. 회사명을 &amp;lsquo;공화국 만세!&amp;rsquo;라는 뜻의 비바리퍼블리카라 정했을 만큼 이승건은 공화정을 흠모했다.&amp;rdquo; - 2장 정성스럽게 그러나 포악하게, 97p&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공화주의 사회의 시민은 스스로 규칙을 만들고 지키는 책임감과 도덕성을 가진다. 개인의 자유보다 공동체의 이익을 더 중시한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책 속에서도 누구든 대표에게 직접 의견을 전할 수 있고, 대표 역시 설득된다면 자신의 생각을 바꾸는 모습을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사람은 나이가 들수록 고집이 세진다고들 하지만, 토스는 달랐다. 모두가 성인은 아니지만, 적어도 &lt;span&gt;&lt;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;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&amp;ldquo;&amp;hellip;유능한 인재의 99%는 제한 없이 신뢰받는다고 느낄 때 훨씬 더 역량을 발휘한다.&amp;rdquo; - 3장 세상에서 가장 빨리 크는 스타트업 97p&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신뢰란 어디까지 가능할까? 정말 모든 권한을 맡겨도 괜찮을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 회사는 직급 체계를 통해 책임의 범위를 나눈다. 하지만 토스는 모두 같은 수평선 위에 있다. 개발자라도 확신이 있다면 PO 역할을 맡을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사람이 많아질수록 이런 문화가 유지될 수 있을지 의문이 들 법도 한데, 토스는 그것을 실제로 해내고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 대목에서 개인적인 경험이 떠올랐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전 직장에서 잠시 팀장 역할을 맡은 적이 있다. 당시 나는 4년 차였고, 개발자 중 최연소 팀장이었다. 조직 개편 과정에서 당시 팀장님이 나를 추천해 주셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 신뢰를 저버리고 싶지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트에 투입되어 팀원들과 함께 일했는데, 모두가 각자의 역할을 정말 잘 해주었다. 만약 그때 그런 믿음이 없었다면, 내가 과연 그렇게 해낼 수 있었을까 하는 생각이 든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&amp;ldquo;... 금융에서 사람이 가장 자주 하는 행위는 송금과 조회, 그리고 결제입니다. 결제시장에서 성공하는 것은 토스를 계속 쓸 수밖에 없는 이유를 만드는 아주 중요한 부분입니다.&amp;rdquo; - 5장 위대한 도전이라는 신호 238p&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현대 사회에서 사업의 핵심은 결국 &lt;b&gt;&amp;lsquo;계속 쓰게 만드는 이유&amp;rsquo;&lt;/b&gt;라고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사람이 계속 사용하는 서비스에는 공통점이 있다. 간편하고, 직관적이며, 불필요한 복잡함이 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &amp;lsquo;Simple is the Best&amp;rsquo;라는 말이 떠올랐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토스는 사람들이 어디서 불편함을 느끼는지를 끊임없이 고민한다. 항상 사용자 입장에서 생각한다. 그 점이 지금의 성장을 만든 가장 큰 이유가 아닐까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;마지막 느낀 점&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나 역시 한 명의 개발자로서, 언젠가 꼭 함께 일해 보고 싶은 회사 중 하나가 &lt;b&gt;토스다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 이유를 묻는다면 이렇게 말하고 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;끊임없이 고민하고 도전하며 무언가를 만들어냈을 때, 내가 한 단계 더 성장해 있을 것 같기 때문입니다.&amp;rdquo;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나도 그런 신뢰 속에서, 그런 자율성 안에서 과연 어디까지 성장할 수 있을지 스스로에게 묻게 된다.&lt;/p&gt;</description>
      <category>Book Notes</category>
      <category>독서</category>
      <category>독서감상문</category>
      <category>독서록</category>
      <category>유난한 도전</category>
      <category>인문학</category>
      <category>토스</category>
      <author>feel2</author>
      <guid isPermaLink="true">https://feel2.tistory.com/163</guid>
      <comments>https://feel2.tistory.com/163#entry163comment</comments>
      <pubDate>Sun, 1 Feb 2026 23:16:48 +0900</pubDate>
    </item>
    <item>
      <title>[개발서적] 도메인 주도 설계 첫걸음 4부(ch16) 요약 (2)</title>
      <link>https://feel2.tistory.com/162</link>
      <description>&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Ch16. 데이터 메시&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이번 장에서는 &lt;b&gt;분석 데이터 관리 아키텍처(analytical data management architecture), 일명 메시(data mesh)에 대해서&lt;/b&gt; 배워보자.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[분석 데이터 모델과 트랜잭션 데이터 모델의 비교]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분석 데이터는 회사에 축적된 &lt;b&gt;데이터를 활용하여&lt;/b&gt; &lt;b&gt;비즈니스를 최적화하는 방법에 대한 통찰을 얻고&lt;/b&gt; 고객의 요구사항을 더 잘 이해하며 &lt;b&gt;기계 학습(ML) 모델의 훈련을 통해 자동으로 의사결정을 내릴 수 있는&lt;/b&gt; 힘을 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분석 모델(OLAP)과 실시간 데이터 모델(OLTP)은 &lt;b&gt;서로 다른 유형의 사용자를 지원하고&lt;/b&gt;, 다른 종류의 유스케이스를 구현하며, 그래서 결국에는 &lt;b&gt;다른 설계 원칙을 따른다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실시간 데이터 모델은&lt;/p&gt;
&lt;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;b&gt;실시간 비즈니스 트랜잭션을 지원&lt;/b&gt;하도록 최적화되야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;410&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbRvpb/dJMcafSS2g7/7tbuOnXHJyr2xvAhe9T6k1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbRvpb/dJMcafSS2g7/7tbuOnXHJyr2xvAhe9T6k1/img.png&quot; data-alt=&quot;그림 16-1. 실시간 데이터 모델에 속한 엔티티 간의 관계를 설명하는 관계형 데이터베이스 스키마&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbRvpb/dJMcafSS2g7/7tbuOnXHJyr2xvAhe9T6k1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbRvpb%2FdJMcafSS2g7%2F7tbuOnXHJyr2xvAhe9T6k1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;742&quot; height=&quot;410&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;410&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 16-1. 실시간 데이터 모델에 속한 엔티티 간의 관계를 설명하는 관계형 데이터베이스 스키마&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 분석 모델은&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;실시간 데이터 처리 시스템에 대한 다양한 통찰을 제공하도록&lt;/b&gt; 고안됨&lt;/li&gt;
&lt;li&gt;비즈니스 활동의 성과에 대한 &lt;b&gt;통찰&lt;/b&gt;을 제공을 목표&lt;/li&gt;
&lt;li&gt;더 중요한 건 &lt;b&gt;더 많은 비즈니스 가치를 얻도록 운영을 최적화하는 방법&lt;/b&gt; 제공을 목표&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;팩트 테이블&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팩트(fact)는 &lt;b&gt;이미 발생한 비즈니스 활동&lt;/b&gt;을 나타낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 팩트 테이블 Fact_Sales는 확약된 판매 레코드를 담는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;283&quot; data-origin-height=&quot;319&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bapXiI/dJMcadHtWCw/b7KbZB9T7LRbqE2nbYjuCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bapXiI/dJMcadHtWCw/b7KbZB9T7LRbqE2nbYjuCk/img.png&quot; data-alt=&quot;그림 16-2. 회사의 지원 데스크에서 해결한 사례의 기록을 담은 팩트 테이블&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bapXiI/dJMcadHtWCw/b7KbZB9T7LRbqE2nbYjuCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbapXiI%2FdJMcadHtWCw%2Fb7KbZB9T7LRbqE2nbYjuCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;283&quot; height=&quot;319&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;283&quot; data-origin-height=&quot;319&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 16-2. 회사의 지원 데스크에서 해결한 사례의 기록을 담은 팩트 테이블&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 도메인 이벤트와 비슷하게 팩트 레코드는 &lt;b&gt;절대로 삭제되거나 수정되지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 데이터가 만료됐다는 것을 표현하는 유일한 방법은 &lt;b&gt;새로운 레코드를 추가하는 것이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;810&quot; data-origin-height=&quot;388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRH4GS/dJMcaivfyr0/x0yvpO2Lt9OyL3GPv95cPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRH4GS/dJMcaivfyr0/x0yvpO2Lt9OyL3GPv95cPK/img.png&quot; data-alt=&quot;그림 16-3. 지원 사례의 수명주기 동안 상태의 변경을 설명하는 팩트 테이블&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRH4GS/dJMcaivfyr0/x0yvpO2Lt9OyL3GPv95cPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRH4GS%2FdJMcaivfyr0%2Fx0yvpO2Lt9OyL3GPv95cPK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;810&quot; height=&quot;388&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;810&quot; data-origin-height=&quot;388&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 16-3. 지원 사례의 수명주기 동안 상태의 변경을 설명하는 팩트 테이블&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OLAP와 OLTP 모델의 또 다른 차이점은 &lt;b&gt;데이터의 세분화 정도&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실시간 데이터 처리 시스템은 &lt;b&gt;가장 정밀한 데이터가 필요하다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;디멘전 테이블&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분석 모델에서 또 다른 중요한 구성요소는 디멘전이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팩트가 &lt;b&gt;비즈니스 절차 또는 동작&lt;/b&gt;을 표현한다면(동사), 디멘전은 팩트를 &lt;b&gt;묘사한다&lt;/b&gt;(형용사).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디멘전은 팩트의 속성을 설명하도록 고안되어 &lt;b&gt;팩트 테이블에 있는 외부 키로 디멘전 테이블을 참조&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;810&quot; data-origin-height=&quot;598&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lXET0/dJMcacBQKch/zLhr0QPxAqzZECc13QpmF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lXET0/dJMcacBQKch/zLhr0QPxAqzZECc13QpmF1/img.png&quot; data-alt=&quot;그림 16-4. 디멘전으로 둘러싸인 SolvedCases 팩트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lXET0/dJMcacBQKch/zLhr0QPxAqzZECc13QpmF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlXET0%2FdJMcacBQKch%2FzLhr0QPxAqzZECc13QpmF1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;810&quot; height=&quot;598&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;810&quot; data-origin-height=&quot;598&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 16-4. 디멘전으로 둘러싸인 SolvedCases 팩트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디멘전이 고도로 정규화된 이유는 &lt;b&gt;분석 시스템에서 유연한 질의를 지원해야 하기 때문&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 분석 모델은 정규화를 통해서 &lt;b&gt;동적인 질의 및 필터링을 지원&lt;/b&gt;하고, 다양한 팩트 데이터에 대한 &lt;b&gt;그룹화를 지원한다.&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;분석 모델&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 16-5에 표현된 테이블 구조를 &lt;b&gt;스타 스키마(star schema)라고&lt;/b&gt; 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팩트와 디멘전의 관계가 &lt;b&gt;다대일(many-to-one)인 경우&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;547&quot; data-origin-height=&quot;428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cq6vtw/dJMcacV8xjy/OvYaJrcuKUEo3VUNOvwZsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cq6vtw/dJMcacV8xjy/OvYaJrcuKUEo3VUNOvwZsK/img.png&quot; data-alt=&quot;그림 16-5. 팩트와 디멘전의 관계가 다대일인 경우&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cq6vtw/dJMcacV8xjy/OvYaJrcuKUEo3VUNOvwZsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcq6vtw%2FdJMcacV8xjy%2FOvYaJrcuKUEo3VUNOvwZsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;547&quot; height=&quot;428&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;547&quot; data-origin-height=&quot;428&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 16-5. 팩트와 디멘전의 관계가 다대일인 경우&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 다른 지배적은 분석 모델은 &lt;b&gt;스노플레이크 스키마(snowflake schema)이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스타 스키마와 다른점은 디멘전이 &lt;b&gt;여러 수준으로 구성&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적인 정규화로 인해 스노플레이크 스키마는 &lt;b&gt;더 작은 공간에 디멘전 데이터를 저장할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스타 시크마와 스노플레이크 스키마 모두 데이터 분석가가 &lt;b&gt;비즈니스 성과를 분석하고 무엇을 최적화할지&lt;/b&gt;에 대한 통찰을 얻게 하며 &lt;b&gt;BI(Business Intelligence) 리포트를 만들 수 있게 한다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;573&quot; data-origin-height=&quot;404&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4iSRl/dJMcabXeRYQ/KPZSPCQKi9NXsMJISkvbw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4iSRl/dJMcabXeRYQ/KPZSPCQKi9NXsMJISkvbw0/img.png&quot; data-alt=&quot;그림 16-6. 스노플레이크 스키마의 여러 수준 디멘전&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4iSRl/dJMcabXeRYQ/KPZSPCQKi9NXsMJISkvbw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4iSRl%2FdJMcabXeRYQ%2FKPZSPCQKi9NXsMJISkvbw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;573&quot; height=&quot;404&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;573&quot; data-origin-height=&quot;404&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 16-6. 스노플레이크 스키마의 여러 수준 디멘전&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[분석 데이터 관리 플랫폼]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제부터 데이터를 생성하고 분석 데이터를 제공하는 &lt;b&gt;데이터 관리 아키텍처&lt;/b&gt;에 대해 논의해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 절에는 &lt;b&gt;데이터 웨어하우스와 데이터 레이크&lt;/b&gt;, 두개의 일반적은 분석 데이터 아키텍처에 대해 논의해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;데이터 웨어하우스&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 웨어하우스(DWH)의 아키텍처는 비교적 간단하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기업의 모든 실시간 데이터 처리 시스템에서 &lt;b&gt;데이터를 추출해 분석 모델로 변환 후,&lt;/b&gt; &lt;b&gt;분석 지향 데이터베이스에 적재한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 데이터베이스가 바로 &lt;b&gt;데이터 웨어하우스&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 관리 아키텍처는 기본적으로 &lt;b&gt;ETL(extract-transform-load) 스크립트를 기반으로&lt;/b&gt; 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터는 &lt;b&gt;실시간 데이터 처리 데이터베이스, 스트림 이벤트, 로그 등 다양한 원천에서 수집&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원천 데이터를 팩트/디멘전 기반 모델로 변환하는 것과 더불어 변환 단계에서는&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;민감한 데이터 삭제 및 중복 레코드 제거&lt;/li&gt;
&lt;li&gt;이벤트의 순서 조정 및 작은 크기의 이벤트를 합치는&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등의 추가 작업도 진행될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;573&quot; data-origin-height=&quot;325&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZXTG2/dJMcaaquuHW/ejWck4V6X0o9Z53FzFwfD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZXTG2/dJMcaaquuHW/ejWck4V6X0o9Z53FzFwfD0/img.png&quot; data-alt=&quot;그림 16-7. 전형적인 엔터프라이즈 데이터 웨어하우스 아키텍처&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZXTG2/dJMcaaquuHW/ejWck4V6X0o9Z53FzFwfD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZXTG2%2FdJMcaaquuHW%2FejWck4V6X0o9Z53FzFwfD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;573&quot; height=&quot;325&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;573&quot; data-origin-height=&quot;325&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 16-7. 전형적인 엔터프라이즈 데이터 웨어하우스 아키텍처&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림을 살펴보면 우선 데이터 웨어하우스 아키텍처의 중심에는 &lt;b&gt;엔터프라이즈 전반의 모델을 구축하는 목표&lt;/b&gt;가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델은 &lt;b&gt;기업의 모든 시스템에서 생성되는 데이터를 묘사&lt;/b&gt;하고, &lt;b&gt;다양한 분석 데이터의 사용 사례를 다뤄야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(비즈니스 최적화, 운영 비용 절감, 지능적인 비즈니스 의사결정, 리포팅, ML 모델 훈련 등)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 상황을 아우르는 모델을 구축하기 어려울 땐 &lt;b&gt;데이터 마트(data mart)를 통해&lt;/b&gt; 해결할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 마트는 단일 비즈니스 부서의 분석과 같이, &lt;b&gt;잘 정의된 분석 요구사항에 관련된 데이터를 저장하는 일종의 데이터베이스다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;573&quot; data-origin-height=&quot;347&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPzGI8/dJMcacoi4vI/Xxw3JMChjTmekkENc77l7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPzGI8/dJMcacoi4vI/Xxw3JMChjTmekkENc77l7k/img.png&quot; data-alt=&quot;그림 16-8. 데이터 마트로 확장한 엔터프라이즈 데이터 웨어하우스 아키텍처&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPzGI8/dJMcacoi4vI/Xxw3JMChjTmekkENc77l7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPzGI8%2FdJMcacoi4vI%2FXxw3JMChjTmekkENc77l7k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;573&quot; height=&quot;347&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;573&quot; data-origin-height=&quot;347&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 16-8. 데이터 마트로 확장한 엔터프라이즈 데이터 웨어하우스 아키텍처&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 웨어하우스 아키텍처의 어려운 점은 &lt;b&gt;&lt;span data-token-index=&quot;1&quot;&gt;ETL 프로세스 분석가(OLAP) 시스템&lt;/span&gt;&lt;/b&gt;과 &lt;b&gt;&lt;span data-token-index=&quot;3&quot;&gt;실시간 데이터 처리(OLTP) 시스템 &lt;/span&gt;간에 &lt;span data-token-index=&quot;5&quot;&gt;강력한 결합&lt;/span&gt;&lt;/b&gt;을 만든다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;9.png&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brlvxN/dJMcahpCNjd/tMetWMlKAtBprutzNJh0kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brlvxN/dJMcahpCNjd/tMetWMlKAtBprutzNJh0kk/img.png&quot; data-alt=&quot;그림 16-9. 연동 지향 퍼블릭 인터페이스를 무시한 채 실시간 데이터 처리 시스템 데이터베이스에서 직접 데이터를 가져오는 데이터 웨어하우스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brlvxN/dJMcahpCNjd/tMetWMlKAtBprutzNJh0kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrlvxN%2FdJMcahpCNjd%2FtMetWMlKAtBprutzNJh0kk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;490&quot; height=&quot;196&quot; data-filename=&quot;9.png&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;196&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 16-9. 연동 지향 퍼블릭 인터페이스를 무시한 채 실시간 데이터 처리 시스템 데이터베이스에서 직접 데이터를 가져오는 데이터 웨어하우스&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 몇 가지 단점은 &lt;b&gt;데이터 레이크 아키텍처(data lake architecture)에서&lt;/b&gt; 해결한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;데이터 레이크&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 레이크 기반 시스템은 &lt;b&gt;실시간 데이터 처리 시스템으로부터 데이터를 받는다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 바로 변환하는 것이 아니라 원본 형태, 즉 &lt;b&gt;원래의 실시간 데이터 모델로 보관&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러므로 원본 데이터는 데이터 분석의 요건에 맞지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 엔지니어와 BI 엔지니어는 데이터 레이크의 데이터를 이해하고 분석 모델을 생성하는 &lt;b&gt;ETL 스크립트를 구현하며, 이를 데이터 웨어하우스에 제공해야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 16-10에 데이터 레이크 아키텍처를 표현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;10.png&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;221&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ql5VR/dJMcacu4V81/PcDLhK908UcMCIXhgubc41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ql5VR/dJMcacu4V81/PcDLhK908UcMCIXhgubc41/img.png&quot; data-alt=&quot;그림 16-10. 데이터 레이크 아키텍처&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ql5VR/dJMcacu4V81/PcDLhK908UcMCIXhgubc41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fql5VR%2FdJMcacu4V81%2FPcDLhK908UcMCIXhgubc41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;490&quot; height=&quot;221&quot; data-filename=&quot;10.png&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;221&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 16-10. 데이터 레이크 아키텍처&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실시간 데이터 처리 시스템의 데이터는 원본 형태로 저장되고 나중에 변환되므로 데이터 레이크에서는 &lt;b&gt;다양한 작업 지향 분석 모델을 작동시키는 것이 가능하다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 어떤 모델은 리포팅에, 다른 모델은 ML 훈련에 사용하는 식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;11.png&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZQF3Y/dJMcaiPxZ9T/fBZ6L3IuGewpe0qdprZj3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZQF3Y/dJMcaiPxZ9T/fBZ6L3IuGewpe0qdprZj3K/img.png&quot; data-alt=&quot;그림 16-11. 다양한 버전의 실시간 데이터 모델을 수용하기 위한 여러 버전의 동일한 ETL 스크립트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZQF3Y/dJMcaiPxZ9T/fBZ6L3IuGewpe0qdprZj3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZQF3Y%2FdJMcaiPxZ9T%2FfBZ6L3IuGewpe0qdprZj3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;490&quot; height=&quot;216&quot; data-filename=&quot;11.png&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;216&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 16-11. 다양한 버전의 실시간 데이터 모델을 수용하기 위한 여러 버전의 동일한 ETL 스크립트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;데이터 웨어하우스와 데이터 레이크 아키텍처의 도전과제&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델링 관점에서 보면 두 아키텍처 모두 실시간 데이터 처리 시스템의 경계를 침범해서 &lt;b&gt;구현 상세에 대한 의존성을 생성한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 같은 구현 모델에 대한 결합도는 종종 분석 시스템의 ETL 작업이 깨지지 않도록 실시간 데이터 모델에 대한 변경을 막는 지경까지 이르게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 웨어하우스와 데이터 레이크의 이러한 한계는 새로운 분석 데이터 관리 아키텍처인 &lt;b&gt;데이터 메시&lt;/b&gt;의 탄생에 영감을 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[데이터 메시]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 의미에서 데이터 메시 아키텍처는 &lt;b&gt;분석 데이터를 위한 도메인 주도 설계&lt;/b&gt;라고 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 메시 아키텍처는 &lt;b&gt;분석 데이터에 대한 모델과 소유 경계를 정의하고 프로젝션&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 메시 아키텍처는&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;도메인 기준의 데이터 분리&lt;/li&gt;
&lt;li&gt;제품 관점에서 데이터 다루기&lt;/li&gt;
&lt;li&gt;자율성 활성화&lt;/li&gt;
&lt;li&gt;에코시스템 구축&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의 네 가지 핵심 원칙을 기반으로 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;도메인 기준의 데이터 분리&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 메시 아키텍처는 모놀리식 분석 모델을 구축하는 대신, 실시간 데이터를 위한 솔루션, 즉 &lt;b&gt;원천 데이터에 분석 모델을 일치시켜서&lt;/b&gt; 데이터를 사용하므로 여러 분석 모델을 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 분석 모델의 소유권 경계를 자연스럽게 &lt;b&gt;바운디드 컨텍스트의 경계와 일치시키게&lt;/b&gt; 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;12.png&quot; data-origin-width=&quot;341&quot; data-origin-height=&quot;464&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwtrWe/dJMcabiDTN7/vrnSgvSXtWiL6NkQGDtnoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwtrWe/dJMcabiDTN7/vrnSgvSXtWiL6NkQGDtnoK/img.png&quot; data-alt=&quot;그림 16-12. 분석 모델의 소유권 경계와 바운디드 컨텍스트 경계의 일치&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwtrWe/dJMcabiDTN7/vrnSgvSXtWiL6NkQGDtnoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdwtrWe%2FdJMcabiDTN7%2FvrnSgvSXtWiL6NkQGDtnoK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;341&quot; height=&quot;464&quot; data-filename=&quot;12.png&quot; data-origin-width=&quot;341&quot; data-origin-height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 16-12. 분석 모델의 소유권 경계와 바운디드 컨텍스트 경계의 일치&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 바운디드 컨텍스트는 이제 자신의 실시간 데이터 처리(OLTP) 모델과 분석(OLAP) 모델을 소유한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 &lt;b&gt;실시간 데이터 모델을 소유한 팀이 이제 그것을 분석 모델로 변환하는 책임&lt;/b&gt;을 진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;제품 관점에서 데이터 다루기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제품 관점에서 데이터 다루기 원칙에서는 &lt;b&gt;분석 데이터를 제일 중요하게&lt;/b&gt; 다뤄야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 메시 기반 시스템에서는 그림 16-13의 예시처럼 바운디드 컨텍스트가 잘 정의된 &lt;b&gt;출력 포트를 통해 분석 데이터를 제공한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;13.png&quot; data-origin-width=&quot;431&quot; data-origin-height=&quot;183&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bW6GNi/dJMcaa458e6/X6a5IXLB1ZONXBZM3vBSZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bW6GNi/dJMcaa458e6/X6a5IXLB1ZONXBZM3vBSZ1/img.png&quot; data-alt=&quot;그림 16-13. 분석 데이터를 사용자에게 노출하는 다양한 데이터 앤드포인트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bW6GNi/dJMcaa458e6/X6a5IXLB1ZONXBZM3vBSZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbW6GNi%2FdJMcaa458e6%2FX6a5IXLB1ZONXBZM3vBSZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;431&quot; height=&quot;183&quot; data-filename=&quot;13.png&quot; data-origin-width=&quot;431&quot; data-origin-height=&quot;183&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 16-13. 분석 데이터를 사용자에게 노출하는 다양한 데이터 앤드포인트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분석 데이터는 통상적인 퍼블릭 API와 &lt;b&gt;동일하게&lt;/b&gt; 취급돼야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;필요한 앤드포인트인 데이터 출력 포트를 쉽게 찾을 수 있어야 한다.&lt;/li&gt;
&lt;li&gt;분석 엔드포인트는 제공하는 데이터와 형식을 설명하는 잘 정의된 스키마를 가져야 한다.&lt;/li&gt;
&lt;li&gt;분석 데이터는 신뢰할 수 있어야 하고 서비스 수준 계약(SLA)을 정의하고 모니터링 해야 한다.&lt;/li&gt;
&lt;li&gt;분석 모델은 버전 관리를 하고, 연동을 망가뜨리는 변경을 관리해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분석 데이터 관리 아키텍처의 목표는 조직의 데이터 분석 요건을 충족할 수 있도록 &lt;b&gt;작은 크기의 분석 모델이 엮일 수 있게 하는 것이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 사용자마다 &lt;b&gt;여러 형태의 분석 데이터가&lt;/b&gt; 필요할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 데이터 제품은 다양한 사용자의 요구사항을 충족하는 &lt;b&gt;여러 형태의 데이터를&lt;/b&gt; 제공해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;자율성 활성화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제품 팀은 자신의 데이터 제품을 만들 수도 있고, 다른 바운디드 컨텍스트에서 제공하는 데이터 제품도 사용할 수 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 데이터 제품은 &lt;b&gt;상호운용이 가능해야 한다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분석 데이터를 제공하기 위해 각 팀이 자신의 솔루션을 구축하는 것은 소모적이고, 효과적이지 않으며 연동도 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 방지하려면 플랫폼이 상호운용이 가능한 데이터 제품의 구축, 실행, 유지보수의 복잡성을 &lt;b&gt;추상화해야&lt;/b&gt; 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;에코시스템 구축&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 분석 데이터 관점에서 상호운용과 에코시스템을 가능하게 할 연합 거버넌스 기구를 임명하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거버넌스 그룹은 상호운용이 가능한 정상적인 에코시스템을 보장하는 규칙을 정의할 책임이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;14.png&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;461&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAHRNk/dJMcaiIMT9o/sask34yAkMEIljiJxGfDX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAHRNk/dJMcaiIMT9o/sask34yAkMEIljiJxGfDX0/img.png&quot; data-alt=&quot;그림 16-14. 분산 데이터 분석 에코시스템이 상호운용이 가능하고 정상적이며 조직의 요구사항을 해결하도록 보장하는 거버넌스 그룹&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAHRNk/dJMcaiIMT9o/sask34yAkMEIljiJxGfDX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAHRNk%2FdJMcaiIMT9o%2Fsask34yAkMEIljiJxGfDX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;582&quot; height=&quot;461&quot; data-filename=&quot;14.png&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;461&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 16-14. 분산 데이터 분석 에코시스템이 상호운용이 가능하고 정상적이며 조직의 요구사항을 해결하도록 보장하는 거버넌스 그룹&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;데이터 메시와 도메인 주도 설계 엮기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 메시 아키텍처가 기반으로 하는 네 가지 규칙이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;유비쿼터스 언어와 결과 도메인 지식은 분석 모델 설계를 위한 필수 요소다.&lt;/li&gt;
&lt;li&gt;자신의 실시간 데이터 모델과 다른 모델로 바운디드 컨텍스트 데이터를 노출하는 것은 &lt;b&gt;오픈 호스트 패턴이다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;CQRS 패턴은 동일한 데이터에 대한 여러 모델을 쉽게 생성해준다.&lt;/li&gt;
&lt;li&gt;데이터 메시 아키텍처는 분석 유스케이스를 구현하기 위해 다양한 바운디드 컨텍스트 모델을 묶는다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;때문에 실시간 데이터 모델을 위한 바운디드 컨텍스트의 연동 패턴은 &lt;b&gt;분석 모델에도 적용된다&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;15.png&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;316&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mehia/dJMcaihLkmE/3A6Zb2GWiCf96jNWxtvj5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mehia/dJMcaihLkmE/3A6Zb2GWiCf96jNWxtvj5k/img.png&quot; data-alt=&quot;그림 16-15. 분석 데이터를 동시에 두 개의 다른 스키마 버전으로 제공하는데 활용된 CQRS 패턴&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mehia/dJMcaihLkmE/3A6Zb2GWiCf96jNWxtvj5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmehia%2FdJMcaihLkmE%2F3A6Zb2GWiCf96jNWxtvj5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;582&quot; height=&quot;316&quot; data-filename=&quot;15.png&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;316&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 16-15. 분석 데이터를 동시에 두 개의 다른 스키마 버전으로 제공하는데 활용된 CQRS 패턴&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[결론]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 메시 아키텍처는 전통적인 데이터 관리 아키텍처의 어려움을 해결하는 데 목적이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발전 과정은&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 웨어 하우스 &amp;rarr; 데이터 레이크 &amp;rarr; 데이터 메시&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 메시 아키텍처는 도메인 주도 설계와 동일한 원칙이 적용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 CQRS와 바운디드 컨텍스트 연동 패턴은 데이터 메시 아키텍처의 구현을 지원한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-end=&quot;3532&quot; data-start=&quot;3486&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;✅ Ch16 요약 섹션&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-end=&quot;3560&quot; data-start=&quot;3534&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;핵심 포인트 (Key Takeaways)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3864&quot; data-start=&quot;3561&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3673&quot; data-start=&quot;3561&quot;&gt;데이터 웨어하우스는 기업 전반의 분석 모델을 목표로 하지만, ETL이 OLTP와 강한 결합을 만들 수 있어 운영 부담이 크다.&lt;/li&gt;
&lt;li data-end=&quot;3760&quot; data-start=&quot;3674&quot;&gt;이를 보완하는 방식으로 데이터 마트 등 분석 요구에 맞춘 확장 방식이 등장한다.&lt;/li&gt;
&lt;li data-end=&quot;3864&quot; data-start=&quot;3761&quot;&gt;즉 분석 아키텍처는 단순 저장이 아니라, &amp;ldquo;조직 전체 의사결정/리포팅/ML&amp;rdquo;을 지원하기 위한 구조적 선택이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;3894&quot; data-start=&quot;3866&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;실무 연결 포인트 (How to apply)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4071&quot; data-start=&quot;3895&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3954&quot; data-start=&quot;3895&quot;&gt;운영 DB로 분석까지 해결하려는 순간 병목/결합이 생긴다 &amp;rarr; &lt;b&gt;분석 모델을 별도로 분리&lt;/b&gt;해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;4010&quot; data-start=&quot;3955&quot;&gt;결국 데이터 설계는 기능 개발과 별개로, &amp;ldquo;조직이 무엇을 보고 의사결정하는지&amp;rdquo;와 직접 연결된다.&lt;/li&gt;
&lt;li data-end=&quot;4071&quot; data-start=&quot;4011&quot;&gt;광고/배치/정산 시스템처럼 지표가 중요한 조직일수록 데이터 아키텍처는 성능보다 &amp;ldquo;결합 제거&amp;rdquo;가 핵심이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;4085&quot; data-start=&quot;4073&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;한 줄 인사이트&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-end=&quot;4148&quot; data-start=&quot;4086&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;4148&quot; data-start=&quot;4088&quot; data-ke-size=&quot;size16&quot;&gt;트랜잭션 모델이 &amp;lsquo;정확한 처리&amp;rsquo;를 위한 것이라면, 분석 모델은 &lt;b&gt;&amp;lsquo;더 나은 의사결정&amp;rsquo;을 위한 제품&lt;/b&gt;이다.&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>Book Notes</category>
      <category>ddd</category>
      <category>it</category>
      <category>개발</category>
      <category>개발서적</category>
      <category>개발자</category>
      <category>도메인주도설계</category>
      <category>도메인주도설계첫걸음</category>
      <category>필독서</category>
      <author>feel2</author>
      <guid isPermaLink="true">https://feel2.tistory.com/162</guid>
      <comments>https://feel2.tistory.com/162#entry162comment</comments>
      <pubDate>Wed, 14 Jan 2026 22:44:27 +0900</pubDate>
    </item>
    <item>
      <title>[개발서적] 도메인 주도 설계 첫걸음 4부(ch14~15) 요약 (1)</title>
      <link>https://feel2.tistory.com/161</link>
      <description>&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Ch14. 마이크로서비스&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[서비스란 무엇인가?]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OASIS에 따르면, 서비스는 &lt;b&gt;미리 정의된 인터페이스를 사용해 하나 이상의 역량에 접근하기 위한 메커니즘&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;b&gt;미리 정의된 인터페이스&lt;/b&gt;란 &lt;b&gt;서비스로부터 데이터를 넣고 빼는 모든 메커니즘&lt;/b&gt;을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;635&quot; data-origin-height=&quot;186&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7K4sI/dJMcabbQF1W/yJkBYI66BG2N02hp4Gt6eK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7K4sI/dJMcabbQF1W/yJkBYI66BG2N02hp4Gt6eK/img.png&quot; data-alt=&quot;그림 14-1. 서비스 간 커뮤니케이션&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7K4sI/dJMcabbQF1W/yJkBYI66BG2N02hp4Gt6eK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7K4sI%2FdJMcabbQF1W%2FyJkBYI66BG2N02hp4Gt6eK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;635&quot; height=&quot;186&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;635&quot; data-origin-height=&quot;186&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 14-1. 서비스 간 커뮤니케이션&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;랜디 숍(Randy shoup)은 서비스의 인터페이스를 &lt;b&gt;외부에 노출되는 시스템 영역(front door)&lt;/b&gt;에 두는 것을 좋아한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스의 퍼블릭 인터페이스는 서비스 자체, 즉 &lt;b&gt;서비스가 노출하는 기능을 정의&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;525&quot; data-origin-height=&quot;277&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x2SCt/dJMcac2RNM2/1cg7MqAobKKLwKUzPS0JB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x2SCt/dJMcac2RNM2/1cg7MqAobKKLwKUzPS0JB0/img.png&quot; data-alt=&quot;14-2. 서비스의 퍼블릭 인터페이스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x2SCt/dJMcac2RNM2/1cg7MqAobKKLwKUzPS0JB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx2SCt%2FdJMcac2RNM2%2F1cg7MqAobKKLwKUzPS0JB0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;525&quot; height=&quot;277&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;525&quot; data-origin-height=&quot;277&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;14-2. 서비스의 퍼블릭 인터페이스&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 염두에 두고 마이크로서비스의 정의를 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[마이크로서비스란 무엇인가?]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이크로서비스는 자신의 마이크로 퍼블릭 인터페이스, 즉 &lt;b&gt;마이크로 프론트 도어(micro-front door)에 의해 정의되는 서비스&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이크로서비스는 자신의 데이터베이스를 내부에 감싸고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 데이터는 훨씬 간단하고 연동 지향적인 &lt;b&gt;퍼블릭 인터페이스를 통해서만&lt;/b&gt; 접근할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;서비스형 메서드: 완벽한 마이크로서비스?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 14-3에 백로그 관리 서비스가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 서비스의 퍼블릭 인터페이스는 여덟개의 퍼블릭 메서드로 구성되고, &amp;lsquo;&lt;b&gt;서비스 하나에 메서드 하나&lt;/b&gt;&amp;rsquo; 규칙을 적용할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;899&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LcbOp/dJMcaajIdKF/NqMinQC5Mr6uTeXCqX8EU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LcbOp/dJMcaajIdKF/NqMinQC5Mr6uTeXCqX8EU0/img.png&quot; data-alt=&quot;그림 14-3. 초보적인 분해&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LcbOp/dJMcaajIdKF/NqMinQC5Mr6uTeXCqX8EU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLcbOp%2FdJMcaajIdKF%2FNqMinQC5Mr6uTeXCqX8EU0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;899&quot; height=&quot;398&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;899&quot; data-origin-height=&quot;398&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 14-3. 초보적인 분해&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 서비스는 잘 동작하는 마이크로서비스이므로 &lt;b&gt;각 서비스가 자신의 데이터베이스를 감싸고 있다.&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 서비스도 다른 서비스의 데이터베이스에 직접 접근할 수 없고 &lt;b&gt;퍼블릭 인터페이스를 통해서만 가능하다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 만약 서비스 간에 협업을 해야 한다면 연동 관심사를 처리하기 위해 &lt;b&gt;서비스의 인터페이스를 확장해야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;597&quot; data-origin-height=&quot;603&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKlVAc/dJMcadAGzbV/OPor8u3MVxtvsU8VF4Sb11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKlVAc/dJMcadAGzbV/OPor8u3MVxtvsU8VF4Sb11/img.png&quot; data-alt=&quot;그림 14-4. 연동의 복잡성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKlVAc/dJMcadAGzbV/OPor8u3MVxtvsU8VF4Sb11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKlVAc%2FdJMcadAGzbV%2FOPor8u3MVxtvsU8VF4Sb11%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;597&quot; height=&quot;603&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;597&quot; data-origin-height=&quot;603&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 14-4. 연동의 복잡성&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템을 이처럼 작은 단위의 서비스로 분해하면 확실히 서비스의 외부 노출 시스템 영역은 최소화된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 전체적인 시스템의 기능을 구현하기 위해서는 각 서비스에 &lt;b&gt;&amp;lsquo;스태프만 출입 가능한&amp;rsquo;&lt;/b&gt; 수많은 출입구를 추가해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;설계 목표&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 서비스가 단일 메서드만 갖도록 분해하는 간단한 휴리스틱을 적용하는 것은 여러 이유로 &lt;b&gt;차선책임이&lt;/b&gt; 증명됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이크로 서비스 아키텍처의 목표는 &lt;b&gt;유연한 시스템을 만드는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단일 컴포넌트에만 설계 노력을 집중하고, 나머지 연동을 무시하는 다음과 같은 시스템의 정의에는 부합하지 않다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함께 작동하는 연동된 것 또는 디바이스&lt;/li&gt;
&lt;li&gt;특정 목적을 위해 함께 사용되는 컴퓨터 장비 및 프로그램&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;시스템의 복잡성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글렌포드 마이어스의 책 &amp;lsquo;Composite/Structured Design&amp;rsquo;에서는 절차지향적 코드의 &lt;b&gt;복잡성을 줄이기 위한 방법을 논의&lt;/b&gt;한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡성이라는 주제에는 프로그램의 한 부분에 대한 로컬 복잡성을 최소화하려는 단순한 시도보다 더 많은 것이 있다. 더 중요한 복잡성의 유형은 글로벌 복잡성, 즉 프로그램 또는 시스템의 전체적인 구조에 관한 복잡성이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 말을 이 책에 적용해보면&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;로컬 복잡성&lt;/b&gt;: 각각의 개별 마이크로 서비스의 복잡성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;글로벌 복잡성:&lt;/b&gt; 전체 시스템의 복잡성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로컬 복잡성은 &lt;b&gt;서비스의 구현에 따라&lt;/b&gt; 달라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글로벌 복잡성은 &lt;b&gt;서비스 간의 상호작용과 의존성&lt;/b&gt;으로 정의된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이크로서비스 시스템을 설계할 때는 어느 복잡성의 최적화가 더 중요할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글로벌 복잡성을 줄이는 것은 &lt;b&gt;놀랍도롭 쉽다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단지 시스템 구성요소 간의 &lt;b&gt;상호작용을 없애기만&lt;/b&gt; 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 모든 기능을 &lt;b&gt;단일 모놀리식 서비스로 구현&lt;/b&gt;하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한편 로컬 복잡성만 최적화하고 시스템의 글로벌 복잡성을 무시하면 어떻게 되는지 알고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 다음과 같은 관계로 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;410&quot; data-origin-height=&quot;294&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0m52G/dJMcabQrZWp/FTCu7USGYAi8q4N4kBpWO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0m52G/dJMcabQrZWp/FTCu7USGYAi8q4N4kBpWO1/img.png&quot; data-alt=&quot;그림 14-5. 서비스의 크기와 시스템의 복잡성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0m52G/dJMcabQrZWp/FTCu7USGYAi8q4N4kBpWO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0m52G%2FdJMcabQrZWp%2FFTCu7USGYAi8q4N4kBpWO1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;410&quot; height=&quot;294&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;410&quot; data-origin-height=&quot;294&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 14-5. 서비스의 크기와 시스템의 복잡성&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적절한 마이크로서비스 기반 시스템을 설계하려면 &lt;b&gt;글로벌 복잡성과 로컬 복잡성 모두를 최적화해야&lt;/b&gt; 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;깊은 서비스로서의 마이크로서비스&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 시스템에서 또는 모든 시스템에서 모듈은 &lt;b&gt;자신의 함수와 로직에 정의된다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;함수(function)&lt;/b&gt;는 모듈이 해야 하는 일, 즉 &lt;b&gt;비즈니스 기능&lt;/b&gt;을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;로직(logic)&lt;/b&gt;은 모듈의 비즈니스 로직, 즉 &lt;b&gt;모듈이 자신의 비즈니스 기능을 구현하는 방법&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;존 우스터하우트(John Ousterhout)는 자신의 책 &amp;lsquo;The Philosophy of Software Design&amp;rsquo;에서 모듈화의 개념에 대해 간단하지만 강력한 시각적 휴리스틱인 &amp;lsquo;&lt;b&gt;깊이(depth)&amp;rsquo;&lt;/b&gt;를 제시했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;373&quot; data-origin-height=&quot;227&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxcR4z/dJMcadUZshc/zN4FiYrW2kWkaZFexmOxH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxcR4z/dJMcadUZshc/zN4FiYrW2kWkaZFexmOxH0/img.png&quot; data-alt=&quot;그림 14-6. 깊은 모듈&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxcR4z/dJMcadUZshc/zN4FiYrW2kWkaZFexmOxH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxcR4z%2FdJMcadUZshc%2FzN4FiYrW2kWkaZFexmOxH0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;373&quot; height=&quot;227&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;373&quot; data-origin-height=&quot;227&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 14-6. 깊은 모듈&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 14-6처럼 우스터하우트는 모듈을 사각형으로 시각화하는 것을 제안했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사각형의 상단 끝은 &lt;b&gt;모듈의 기능을 표현하거나 퍼블릭 인터페이스의 복잡성&lt;/b&gt;을 나타낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;넓은 사각형은 &lt;b&gt;폭 넓은 기능&lt;/b&gt;을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좁은 사각형은 더욱 제한된 기능을 가져서 &lt;b&gt;간단한 퍼블릭 인터페이스&lt;/b&gt;를 갖는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모델에 따르면 복잡성은 &lt;b&gt;도형의 깊이&lt;/b&gt;로 나타내는데, &lt;b&gt;깊이가 깊을수록 복잡성이 높다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;pre id=&quot;code_1768227769953&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int AddTwoNumbers(int a, int b)
{
	return a + b;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 극단적인 얕은 모듈의 예다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 같은 모듈은 수많은 &amp;lsquo;&lt;b&gt;유동적인 부분&lt;/b&gt;&amp;rsquo;을 만들어 내고, 결국 시스템 전체에 우발적 복잡성을 발생시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;깊은 모듈로서의 마이크로서비스&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깊은 모듈의 개념은 마이크로서비스 패턴과 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 14-3에 나타낸 단일 비즈니스 메서드를 구현하는 서비스는 &lt;b&gt;얕은 모듈&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템의 복잡성 관점에서 보면 &lt;b&gt;깊은 모듈&lt;/b&gt;은 시스템의 &lt;b&gt;글로벌 복잡성을 줄여주는&lt;/b&gt; 반면, &lt;b&gt;얕은 모듈&lt;/b&gt;은 &lt;b&gt;글로벌 복잡성을 증가시킨다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템을 마이크로서비스로 분해할 때 임계치는 마이크로서비스를 시스템의 일부로 사용하려고하는 &lt;b&gt;유스케이스에 의해 정의된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모놀리식 시스템을 서비스로 분리하면 &lt;b&gt;변경에 드는 비용은 감소&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 임계치를 지나서 계속 분해하면 &lt;b&gt;깊은 서비스가 점점 얇은 서비스로 변한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;395&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r0beP/dJMcaaRyhfn/zSM8bAx1g4BqzWlYc3WfWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r0beP/dJMcaaRyhfn/zSM8bAx1g4BqzWlYc3WfWk/img.png&quot; data-alt=&quot;14-7. 서비스의 크기와 변경 비용&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r0beP/dJMcaaRyhfn/zSM8bAx1g4BqzWlYc3WfWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr0beP%2FdJMcaaRyhfn%2FzSM8bAx1g4BqzWlYc3WfWk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;406&quot; height=&quot;395&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;395&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;14-7. 서비스의 크기와 변경 비용&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[도메인 주도 설계와 마이크로서비스의 경계]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이크로서비스와 마찬가지로, 앞 장에서 논의한 도메인 주도 설계 패턴의 대부분은 &lt;b&gt;경계에 관한 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;바운디드 컨텍스트&lt;/b&gt;: 모델의 경계&lt;/li&gt;
&lt;li&gt;&lt;b&gt;하위 도메인&lt;/b&gt;: 비즈니스 역량의 경계&lt;/li&gt;
&lt;li&gt;&lt;b&gt;에그리게이트와 오브젝트 벨류:&lt;/b&gt; 트랜잭션의 경계&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;바운디드 컨텍스트&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이크로서비스와 바운디드 컨텍스트는 공통점이 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이크로서비스와 바운디드 컨텍스트 모두 &lt;b&gt;물리적 경계다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실상 &lt;b&gt;마이크로서비스가 바운디드 컨텍스트다&lt;/b&gt;. (마이크로서비스 &amp;rarr; 바운디드 컨텍스트)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 반대 관계도 성립할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;407&quot; data-origin-height=&quot;234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4niTo/dJMcai23UOK/e3Lc5VuJxXu4bZ4gkhMeoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4niTo/dJMcai23UOK/e3Lc5VuJxXu4bZ4gkhMeoK/img.png&quot; data-alt=&quot;그림 14-8. 바운디드 컨텍스트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4niTo/dJMcai23UOK/e3Lc5VuJxXu4bZ4gkhMeoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4niTo%2FdJMcai23UOK%2Fe3Lc5VuJxXu4bZ4gkhMeoK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;407&quot; height=&quot;234&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;407&quot; data-origin-height=&quot;234&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 14-8. 바운디드 컨텍스트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3장에서 배웠듯이, 바운디드 컨텍스트는 &lt;b&gt;유비쿼터스 언어와 모델의 일관성을 보호한다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 시스템에 리드 외에는 충돌하는 모델이 없다고 가정하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 도메인에 모델 충돌이 없다면 그림 14-9에 나타낸 모든 분해는 모두 완전하게 유효한 바운디드 컨텍스트다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;9.png&quot; data-origin-width=&quot;521&quot; data-origin-height=&quot;428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnTXo3/dJMcagRLr4l/SDlTxc9a3Su6fnkjkiOsz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnTXo3/dJMcagRLr4l/SDlTxc9a3Su6fnkjkiOsz1/img.png&quot; data-alt=&quot;그림 14-9. 바운디드 컨텍스트 분해의 다양한 예시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnTXo3/dJMcagRLr4l/SDlTxc9a3Su6fnkjkiOsz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnTXo3%2FdJMcagRLr4l%2FSDlTxc9a3Su6fnkjkiOsz1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;521&quot; height=&quot;428&quot; data-filename=&quot;9.png&quot; data-origin-width=&quot;521&quot; data-origin-height=&quot;428&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 14-9. 바운디드 컨텍스트 분해의 다양한 예시&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 요구사항은 바운디드 컨텍스트를 &lt;b&gt;여러 형태로 분해하게&lt;/b&gt; 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 팀의 크기, 구조, 수명주기 의존성 등이 그런 요구사항이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트는 유효한 거대한 모놀리식의 경계를 표현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 유비쿼터스 언어 또는 비즈니스 도메인 모델의 일관성을 보호하는 유효한 설계 옵션이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 14-10에 바운디드 컨텍스트와 마이크로서비스의 상관관계를 시각화했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;10.png&quot; data-origin-width=&quot;432&quot; data-origin-height=&quot;267&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b68szG/dJMcacBPRMJ/joDkEeMx581Nsk6IXz7aHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b68szG/dJMcacBPRMJ/joDkEeMx581Nsk6IXz7aHK/img.png&quot; data-alt=&quot;그림 14-10. 크기와 모듈&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b68szG/dJMcacBPRMJ/joDkEeMx581Nsk6IXz7aHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb68szG%2FdJMcacBPRMJ%2FjoDkEeMx581Nsk6IXz7aHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;432&quot; height=&quot;267&quot; data-filename=&quot;10.png&quot; data-origin-width=&quot;432&quot; data-origin-height=&quot;267&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 14-10. 크기와 모듈&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;애그리게이트&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트는 가장 넓은 유효한 경계를 설정하지만, 애그리게이트는 그 반대다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트의 경계는 &lt;b&gt;가능한 좁게 설정한다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트와 마찬가지로, 애그리게이트의 경계 또한 마이크로서비스의 경계를 결정한다고 여겨질 때가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트는 내부 비즈니스 규칙과 불변성, 로직의 복잡성을 감싸는 개별적인 비즈니스 단위다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 (이번 장의 초반부에 봤듯이) 마이크로서비스와는 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트와 자신의 하위 도메인에 있는 다른 비즈니스 엔티티와 &lt;b&gt;관계가 강할수록&lt;/b&gt; 얕은 개별 서비스가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;하위 도메인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이크로서비스를 설계하는데 좀 더 균형 잡힌 휴리스틱은 비즈니스 &lt;b&gt;하위 도메인의 경계와 서비스를 일치시키는 것이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스 도메인은 하위 도메인의 역량이 어떻게 구현되는지(기술)보다 &lt;b&gt;비즈니스 역량&lt;/b&gt;을 설명한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기술적 관점에서 보면 하위 도메인은 &lt;b&gt;응집된 유스케이스의 집합이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 14-11처럼 유스케이스 중 하나에서 비즈니스 요구사항을 변경하면 다른 유스케이스도 영향을 받을 가능성이 높다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;11.png&quot; data-origin-width=&quot;591&quot; data-origin-height=&quot;405&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bL7dIu/dJMcahpB3Bj/2pJGcpwvzkal45yuoU1a6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bL7dIu/dJMcahpB3Bj/2pJGcpwvzkal45yuoU1a6k/img.png&quot; data-alt=&quot;그림 14-11. 하위 도메인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bL7dIu/dJMcahpB3Bj/2pJGcpwvzkal45yuoU1a6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbL7dIu%2FdJMcahpB3Bj%2F2pJGcpwvzkal45yuoU1a6k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;591&quot; height=&quot;405&quot; data-filename=&quot;11.png&quot; data-origin-width=&quot;591&quot; data-origin-height=&quot;405&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 14-11. 하위 도메인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 도메인의 크기와 &amp;lsquo;어떻게&amp;rsquo;보다 &amp;lsquo;무엇을&amp;rsquo;에 중점을 둔 기능이 하위 도메인을 자연스럽게 &lt;b&gt;깊은 모듈&lt;/b&gt;로 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 도메인을 설명하는 &amp;lsquo;기능&amp;rsquo;은 더 복잡한 구현 상세인 &lt;b&gt;&amp;lsquo;로직&amp;rsquo;을 캡슐화한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유스케이스를 작은 케이스로 쪼개면 모듈은 더욱 얕아진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 것들이 마이크로서비스 설계를 위한 &lt;b&gt;안전한 경계&lt;/b&gt;로 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 도메인을 마이크로서비스로 만드는 것은 &lt;b&gt;대부분의 마이크로서비스를 위한 최적의 솔루션을 만드는 안전한 휴리스틱이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[마이크로서비스의 퍼블릭 인터페이스 압축하기]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 주도 설계는 서비스의 경계를 찾는데 쓰일 뿐만 아니라, &lt;b&gt;서비스를 깊게 만드는데도 도움을 준다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;오픈 호스트 서비스&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 14-12에서처럼 &lt;b&gt;오픈 호스트 서비스&lt;/b&gt;는 비즈니스 도메인의 바운디드 컨텍스트 모델을 시스템의 다른 구성요소와 연동하는데 사용되는 모델과 &lt;b&gt;분리해준다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연동 지향 모델인 공표된 언어를 도입하면 시스템의 &lt;b&gt;글로벌 복잡성이 줄어든다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 공표된 언어는 좀 더 제한된 모델을 노출한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 연동에 필요한 요구사항에 맞게 설계된다.&lt;/p&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;lsquo;깊이&amp;rsquo; 있어지고, 더 효과적인 마이크로서비스 설계에 기여하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;12.png&quot; data-origin-width=&quot;547&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cW16PD/dJMcacV7NLr/xcV3PXYFV49NeKmqU9A7oK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cW16PD/dJMcacV7NLr/xcV3PXYFV49NeKmqU9A7oK/img.png&quot; data-alt=&quot;그림 14-12. 공표된 언어를 통한 서비스의 연동&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cW16PD/dJMcacV7NLr/xcV3PXYFV49NeKmqU9A7oK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcW16PD%2FdJMcacV7NLr%2FxcV3PXYFV49NeKmqU9A7oK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;547&quot; height=&quot;352&quot; data-filename=&quot;12.png&quot; data-origin-width=&quot;547&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 14-12. 공표된 언어를 통한 서비스의 연동&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;충돌 방지 계층&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;충돌 방지 계층(ACL) 패턴은 다른 방식으로도 작동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 서비스를 &lt;b&gt;다른 바운디드 컨텍스트와 연동할 때 복잡성을 줄여준다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 14-13의 ACL 서비스는 바운디드 컨텍스트를 사용하는 &lt;b&gt;로컬 복잡성과 시스템의 글로벌 복잡성을 모두 줄여준다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;13.png&quot; data-origin-width=&quot;547&quot; data-origin-height=&quot;228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lag2O/dJMcadAGzeG/ealbZYAcjYu5nYiIciALK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lag2O/dJMcadAGzeG/ealbZYAcjYu5nYiIciALK0/img.png&quot; data-alt=&quot;그림 14-13. 독립적 서비스로 구현된 충돌 방지 계층&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lag2O/dJMcadAGzeG/ealbZYAcjYu5nYiIciALK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flag2O%2FdJMcadAGzeG%2FealbZYAcjYu5nYiIciALK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;547&quot; height=&quot;228&quot; data-filename=&quot;13.png&quot; data-origin-width=&quot;547&quot; data-origin-height=&quot;228&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 14-13. 독립적 서비스로 구현된 충돌 방지 계층&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ACL 서비스 덕분에 바운디드 컨텍스트를 사용할 때의 비즈니스 복잡성과 연동할 때의 복잡성이 분리된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[결론]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모든 마이크로 서비스는 바운디드 컨텍스트다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 모든 바운디드 컨텍스트는 마이크로서비스인 것은 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Ch15.&lt;span&gt;&amp;nbsp;&lt;/span&gt;이벤트 주도 아키텍처&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이크로서비스와 마찬가지로 &lt;b&gt;이벤트 주도 아키텍처(EDA)&lt;/b&gt;는 현대 분산 시스템 어디에서나 찾아볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 사람이 &lt;b&gt;느슨하게 결합&lt;/b&gt;하고, &lt;b&gt;확장 가능&lt;/b&gt;하며, &lt;b&gt;내결함성&lt;/b&gt;을 가진 분산 시스템을 설계할 떄 이벤트 주도 커뮤니케이션을 기본 통합 메커니즘으로 사용할 것을 권고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 주도 아키텍처는 종종 도메인 주도 설계와 연결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 EDA는 이벤트를 기반으로 하고, 이벤트는 DDD에서 두드러진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[이벤트 주도 아키텍처]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 주도 아키텍처는 시스템 컴포넌트가 &lt;b&gt;이벤트 메시지를 교환하면서 비동기적으로 서로 커뮤니케이션&lt;/b&gt;하는 아키텍처 스타일이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;14.png&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dIHiyB/dJMcajgChX1/j4tAf40L3pWaSls2nUTlT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dIHiyB/dJMcajgChX1/j4tAf40L3pWaSls2nUTlT0/img.png&quot; data-alt=&quot;그림 15-1. 비동기 통신&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dIHiyB/dJMcajgChX1/j4tAf40L3pWaSls2nUTlT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdIHiyB%2FdJMcajgChX1%2Fj4tAf40L3pWaSls2nUTlT0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;633&quot; height=&quot;280&quot; data-filename=&quot;14.png&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 15-1. 비동기 통신&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 컴포넌트는 시스템에서 발생한 이벤트를 구독하고 그에 따라 반응할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사가 패턴&lt;/b&gt;이 그 대표적인 예다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 주도 아키텍처와 이벤트 소싱 모두 이벤트를 기반으로 하지만, 개념이 다르다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;EDA:&lt;/b&gt; 서비스간 통신&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이벤트 소싱&lt;/b&gt;: 서비스 내부간 통신, 즉 서비스에서 구현된 &lt;b&gt;상태 전환을 위한 것&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[이벤트]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EDA 시스템에서 이벤트 교환은 &lt;b&gt;구성요소를 연동해서 시스템으로 만들기 위한 핵심 통신 메커니즘&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;이벤트, 커멘드, 메시지&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메시지에는 두가지 유형이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;이벤트(Event)&lt;/b&gt;: 이미 발생한 변화를 설명하는 메시지&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커맨드(Command)&lt;/b&gt;: 수행돼야 할 작업을 설명하는 메시지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 이벤트는 이미 일어난 일이고, 커맨드는 어떤 일을 하라는 지시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트는 이미 발생한 일이므로 &lt;b&gt;이벤트 이름은 과거 시제&lt;/b&gt;로 표현해야 한다.(예: DeliveryScheduled, ShipmentCompleted, DeliveryConfirmed)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;구조&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트는 선택한 메시징 플랫폼을 사용하여 직렬화하고 전송할 수 있는 데이터 레코드다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768310531548&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	&quot;type&quot;: &quot;delivery-confirmed&quot;,
	&quot;event-id&quot;: &quot;123123-sdsad-1241asdf-14asdfd&quot;,
	&quot;correlation-id&quot;: &quot;1zxfg03-dfzdf231-jyrtet23&quot;,
	&quot;delivery-id&quot;: &quot;0124124-fdef-124as-sea1-56saqww4&quot;,
	&quot;timestamp&quot;: 12347332,
	&quot;payload&quot;: {
		&quot;confirmed-by&quot;: &quot;124dfs-bbbb1-064d-f124ef0ea&quot;,
		&quot;delivery-time&quot;: 1246431
	
	}
}&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;이벤트의 페이로드(payload)는 &lt;b&gt;이벤트가 전달하는&lt;/b&gt; &lt;b&gt;정보&lt;/b&gt;를 설명할 뿐만 아니라 &lt;b&gt;이벤트의 유형&lt;/b&gt;도 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;이벤트 유형&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트는 &lt;b&gt;이벤트 알림, 이벤트를 통한 상태 전송, 도메인 이벤트&lt;/b&gt;의 세가지 유형 중 하나로 분류 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;이벤트 알림&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 알림은 다른 컴포넌트가 반응할 &lt;b&gt;비즈니스 도메인의 변경에&lt;/b&gt; 관한 메시지다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이해 당사자에게 &lt;b&gt;이벤트를 알리는 것이 목적이므로&lt;/b&gt; 이벤트에 모든 정보를 포함해서는 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768310564222&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	&quot;type&quot;: &quot;delivery-generated&quot;,
	&quot;event-id&quot;: &quot;123123-sdsad-1241asdf-14asdfd&quot;,
	&quot;delivery-id&quot;: &quot;0124124-fdef-124as-sea1-56saqww4&quot;,
	&quot;timestamp&quot;: 12347332,
	&quot;payload&quot;: {
		&quot;employee-id&quot;: &quot;451242&quot;,
		&quot;link&quot;: &quot;/paychecks/451242/2021/01&quot;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예제를 보면 급여와 관련된 모든 정보를 담고 있지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;15.png&quot; data-origin-width=&quot;504&quot; data-origin-height=&quot;238&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qIpTt/dJMcai24sJA/dg3asDDyKXYDLk0LY2x85K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qIpTt/dJMcai24sJA/dg3asDDyKXYDLk0LY2x85K/img.png&quot; data-alt=&quot;그림 15-2. 이벤트 알림 흐름&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qIpTt/dJMcai24sJA/dg3asDDyKXYDLk0LY2x85K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqIpTt%2FdJMcai24sJA%2Fdg3asDDyKXYDLk0LY2x85K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;504&quot; height=&quot;238&quot; data-filename=&quot;15.png&quot; data-origin-width=&quot;504&quot; data-origin-height=&quot;238&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 15-2. 이벤트 알림 흐름&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 의미에서 이벤트 알림 메시지를 통한 통합은 미국의 긴급 재난 문자(WEA) 시스템 및 유럽의 EU-Alert와 유사하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 짧은 메시지는 긴급 상황을 알리기에는 충분하지만, 자세한 내용을 보려면 다른 정보 소스를 적극적으로 사용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;16.png&quot; data-origin-width=&quot;455&quot; data-origin-height=&quot;275&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dUKswR/dJMcacBQied/4WXikzRJ6fctsgWOpprd1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dUKswR/dJMcacBQied/4WXikzRJ6fctsgWOpprd1K/img.png&quot; data-alt=&quot;그림 15-3. 비상 경보 시스템&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dUKswR/dJMcacBQied/4WXikzRJ6fctsgWOpprd1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdUKswR%2FdJMcacBQied%2F4WXikzRJ6fctsgWOpprd1K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;455&quot; height=&quot;275&quot; data-filename=&quot;16.png&quot; data-origin-width=&quot;455&quot; data-origin-height=&quot;275&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 15-3. 비상 경보 시스템&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 다음과 같은 시나리오에서 이벤트 알림은 선호된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;보안&lt;/b&gt;: 민감한 정보가 메시징 인프랑를 통해 공유되는 것을 막고, 데이터 접근을 위한 추가 권한이 필요하다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동시성&lt;/b&gt;: 정보의 특성이 경쟁조건에 민감한 경우 명시적으로 질의하면 최신 상태를 얻는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;이벤트를 통한 상태 전송&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트를 통한 상태 전송(ECST) 메시지는 구독자에게 &lt;b&gt;제공자의 내부 상태에 대한 변경사항&lt;/b&gt;을 알려준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ECST 메시지는 두가지 형태로 나타날 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1768310634820&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	&quot;type&quot;: &quot;customer-updated&quot;,
	&quot;event-id&quot;: &quot;123123-sdsad-1241asdf-14asdfd&quot;,
	&quot;customer-id&quot;: &quot;1zxfg03-dfzdf231-jyrtet23&quot;,
	&quot;timestamp&quot;: 12347332,
	&quot;payload&quot;: {
		&quot;first-name&quot;: &quot;Carolyn&quot;,
		&quot;last-name&quot;: &quot;Hayes&quot;,
		&quot;phone&quot;: 555-1232,
		&quot;status&quot;: &quot;follow-up-set&quot;,
		&quot;birthday&quot;: &quot;1992/10/14&quot;,
		&quot;version&quot;: 6
	
	}
}&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 data-token-index=&quot;1&quot;&gt;실제로 수정된 필드&lt;/span&gt;만 ECST 메시지에 포함시켜야 합리적이다.&lt;/p&gt;
&lt;pre id=&quot;code_1768310647412&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	&quot;type&quot;: &quot;customer-updated&quot;,
	&quot;event-id&quot;: &quot;123123-sdsad-1241asdf-14asdfd&quot;,
	&quot;customer-id&quot;: &quot;1zxfg03-dfzdf231-jyrtet23&quot;,
	&quot;timestamp&quot;: 12347332,
	&quot;payload&quot;: {
		&quot;status&quot;: &quot;follow-up-set&quot;,
		&quot;follow-up-date&quot;: &quot;2020/03/11&quot;,
		&quot;version&quot;: 9
	
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개념적으로 이벤트를 통한 상태 전송 메시지는 &lt;b&gt;비동기 데이터 복제 메커니즘이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 접근 방식을 사용하면 &lt;b&gt;시스템의 내결함성이 향상&lt;/b&gt;되므로 제공자 서비스가 가용하지 않은 경우라도 사용자는 계속해서 작업할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 &lt;b&gt;여러 소스의 데이터를 처리해야 하는&lt;/b&gt; 컴포넌트의 성능도 향상시킬 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;17.png&quot; data-origin-width=&quot;657&quot; data-origin-height=&quot;392&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bu5oRR/dJMcab3ZLZp/HgDDYw7m3W0xvC07WSqDO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bu5oRR/dJMcab3ZLZp/HgDDYw7m3W0xvC07WSqDO1/img.png&quot; data-alt=&quot;그림 15-4. 프론트엔드를 위한 백엔드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bu5oRR/dJMcab3ZLZp/HgDDYw7m3W0xvC07WSqDO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbu5oRR%2FdJMcab3ZLZp%2FHgDDYw7m3W0xvC07WSqDO1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;657&quot; height=&quot;392&quot; data-filename=&quot;17.png&quot; data-origin-width=&quot;657&quot; data-origin-height=&quot;392&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 15-4. 프론트엔드를 위한 백엔드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;도메인 이벤트&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 이벤트는 이벤트 알림과 ECST 메시지 사이 어딘가에 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘 다 비즈니스 도메인에서 중요한 이벤트를 설명하고, 관련된 모든 데이터를 포함한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;도메인 이벤트와 이벤트 알림의 관계&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 이벤트와 이벤트 알림은 모두 &lt;b&gt;제공자의 비즈니스 도메인에서&lt;/b&gt; 발생한 변경사항을 설명한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같은 차이점이 있는데&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;도메인 이벤트에는 이벤트를 설명하는 모든 정보를 포함한다.&lt;/li&gt;
&lt;li&gt;모델링 의도가 다르다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이벤트 알림은 &lt;b&gt;다른 컴포넌트와의 연동을 돕기 위해&lt;/b&gt; 설계&lt;/li&gt;
&lt;li&gt;도메인 이벤트는 &lt;b&gt;비즈니스 도메인을 모델링하고 설명하기 위한 것&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;도메인 이벤트와 이벤트를 통한 상태 전송의 관계&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 이벤트에 포함된 데이터는 일반적인 ECST 메시지의 스키마와 개념적으로 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ECST 메시지는 제공자 데이터를 로컬 캐시로 보유하기에 &lt;b&gt;충분한 정보&lt;/b&gt;를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 도메인 이벤트는 이러한 풍부한 모델을 노출해서는 안 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;이벤트 유형: 예제&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 예제를 살펴보자.&lt;/p&gt;
&lt;pre id=&quot;code_1768310706175&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;eventNotification = {
	&quot;type&quot;: &quot;marriage-recorded&quot;,
	&quot;person-id&quot;: &quot;01b9a751&quot;,
	&quot;payload&quot;: {
		&quot;person-id&quot;: &quot;123as32&quot;,
		&quot;details&quot;: &quot;/01b9a751/marriage-data&quot;
	}
};

ecst = {
	&quot;type&quot;: &quot;personal-details-changed&quot;,
	&quot;person-id&quot;: &quot;01b9a751&quot;,
	&quot;payload&quot;: {
		&quot;new-last-name&quot;: &quot;Williams&quot;
	}
};

domainEvent = {
	&quot;type&quot;: &quot;married&quot;,
	&quot;person-id&quot;: &quot;01b9a751&quot;,
	&quot;payload&quot;: {
		&quot;person-id&quot;: &quot;01b9a751&quot;,
		&quot;assumed-partner-last-name&quot;: true
	}
};&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;marriage-recorded는 &lt;b&gt;이벤트 알림 메시지&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지정된 아이디를 가진 사람이 결혼했다는 사실 외에는 어떠한 정보도 포함되어 있지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;personal-details-changed는 &lt;b&gt;이벤트를 통한 상태 전송 메시지&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 사람의 개인정보 변경사항, 즉 성이 변경되었음을 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;married는 &lt;b&gt;도메인 이벤트&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 사람의 ID와 그 사람이 배우자의 이름을 따르는지를 나타내는 플래그를 포함한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[이벤트 주도 연동 설계]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3장에서 논의한 바와 같이 소프트웨어 설계는 주로 &lt;b&gt;경계에 관한 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경계는&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;내부에 속한 것&lt;/li&gt;
&lt;li&gt;외부에 남아있는 것&lt;/li&gt;
&lt;li&gt;&lt;b&gt;경계를 넘어서는 것&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;즉,&lt;/b&gt; 컴포넌트가 &lt;b&gt;서로 연동되는 방식&lt;/b&gt;을 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EDA 기반 시스템에서 이벤트는 &lt;b&gt;컴포넌트가 연동하는 방식&lt;/b&gt;과 &lt;b&gt;컴포넌트의 경계 자체에 모두 영향을 주는&lt;/b&gt; 가장 중요한 설계 요소다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 이벤트 유형을 적용하기 위한 휴리스틱을 학습하기 전에 어떻게 이벤트를 사용하면 강한 결합을 가진 커다란 진흙 덩어리를 설계할 수 있는지 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;분산된 커다란 진흙 덩어리&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 15-5에 있는 시스템을 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CRM 바운디드 컨텍스트는 &lt;b&gt;소싱 도메인 모델&lt;/b&gt;을 적용하여 구현된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;광고최작화(AdsOptimization) 바운디드 컨텍스트를 도입했을 때, CRM 바운디드 컨텍스트에서 생성된 정보도 처리해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 다시 한 번 광고최적화가 CRM에서 생성된 모든 도메인 이벤트를 구독하고 광고최적화의 요구사항에 맞는 모델을 프로젝션하기로 결정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;18.png&quot; data-origin-width=&quot;657&quot; data-origin-height=&quot;497&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blfAR5/dJMcahb38o5/wOkd2Qwta2t0Ekh0Rr56Q1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blfAR5/dJMcahb38o5/wOkd2Qwta2t0Ekh0Rr56Q1/img.png&quot; data-alt=&quot;그림 15-5. 강하게 결합된 분산 시스템&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blfAR5/dJMcahb38o5/wOkd2Qwta2t0Ekh0Rr56Q1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblfAR5%2FdJMcahb38o5%2FwOkd2Qwta2t0Ekh0Rr56Q1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;657&quot; height=&quot;497&quot; data-filename=&quot;18.png&quot; data-origin-width=&quot;657&quot; data-origin-height=&quot;497&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 15-5. 강하게 결합된 분산 시스템&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리포팅 바운디드 컨텍스트는 CRM에서 발행한 도메인 이벤트의 일부만 구독했고, 광고최적화 컨텍스트에서 수행한 계산도 가져오기 위해 이벤트 알림 메시지를 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 광고최적화에서 동일한 이벤트를 사용해서 계산을 시작하므로 리포팅 모델에서 구독을 지연시키기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 설계는 &lt;b&gt;끔찍한 설계가 되었다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;시간 결합&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;광고최적화의 리포팅 바운디드 컨텍스트는 시간적으로 결합하여 &lt;b&gt;엄격한 실행 순서에 따라&lt;/b&gt; 달라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 순서가 역전되면 리포팅 시스템에서 일관성 없는 데이터가 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;기능 결합&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마케팅과 광고최적화 바운디드 컨텍스트는 모두 CRM의 도메인 이벤트를 구독하고 결국 &lt;b&gt;동일한 고객 데이터를 프로젝션하도록&lt;/b&gt; 구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 컴포넌트 중 하나에서 프로젝션이 변경된 경우 두 번째 바운디드 컨텍스트에서 변경사항을 복제해야 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;구현 결합&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마케팅과 광고최적화 바운디드 컨텍스트는 CRM의 이벤트 소싱 모델로 생성된 모든 도메인 이벤트를 구독한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 새 도메인 이벤트를 추가하거나, 기존 이벤트의 스키마를 변경하면 이것을 구독하는 양쪽 바운디드 컨텍스트에 모두 반영해야 한다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;이벤트 주도 연동의 리팩토링&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이벤트를 조정하여 설계를 적극적으로 개선하는 방법을 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현 결합과 기능 결합은 모두 제공자(CRM 바운디드 컨텍스트)에서 &lt;b&gt;프로젝션 로직을 캡슐화하여&lt;/b&gt; 결합도를 낮출 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CRM에서는 사용자 주도 컨트랙트 패턴을 따를 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;사용자가 필요로 하는 모델을 프로젝션하고&lt;/b&gt; 이를 바운디드 컨텍스트의 공표된 언어의 일부로 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 사용자는 필요한 모든 데이터를 얻을 뿐 &lt;b&gt;CRM의 구현 모델을 알지 못한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;광고최적화와 리포팅 바운디드 컨텍스트 간의 시간 결합을 처리하기 위해서는 광고최적화 컴포넌트가 이벤트 알림 메시지를 발행하여 리포팅 컴포넌트가 필요한 데이터를 가져오도록 트리거할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;19.png&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;437&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/T0W0h/dJMcab3ZL39/wVY4vohOZpqpRjGh9QWOjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/T0W0h/dJMcab3ZL39/wVY4vohOZpqpRjGh9QWOjK/img.png&quot; data-alt=&quot;그림 15-6. 리팩터링한 시스템&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/T0W0h/dJMcab3ZL39/wVY4vohOZpqpRjGh9QWOjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FT0W0h%2FdJMcab3ZL39%2FwVY4vohOZpqpRjGh9QWOjK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;639&quot; height=&quot;437&quot; data-filename=&quot;19.png&quot; data-origin-width=&quot;639&quot; data-origin-height=&quot;437&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 15-6. 리팩터링한 시스템&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;이벤트 주도 설계 휴리스틱&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 변경에 숨어 있는 설계에 대한 휴리스틱을 정리해보자.&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;b&gt;최악의 상황을 가정하라.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음을 한번 생각해보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네트워크가 느려질 것이다.&lt;/li&gt;
&lt;li&gt;가장 어렵거나 중요한 순간에 서버 장애가 발생한다.&lt;/li&gt;
&lt;li&gt;이벤트가 순서대로 도착하지 않는다.&lt;/li&gt;
&lt;li&gt;이벤트가 중복된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 주도 아키텍처에서 &amp;lsquo;주도(driven)&amp;rsquo;라는 단어는 전체 시스템이 &lt;b&gt;메시지의 성공적인 전달&lt;/b&gt;에 달려 있음을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 다음과 같은 방법으로 무조건 이벤트가 항상 일관되게 전달되도록 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메시지를 안정적으로 발송하기 위해 &lt;b&gt;아웃박스 패턴&lt;/b&gt;을 사용하자.&lt;/li&gt;
&lt;li&gt;메시지를 발송할 때 구독자가 &lt;b&gt;메시지 중복을 제거하고, 순서가 잘못된 메시지를 식별하고 재정렬할 수 있게&lt;/b&gt; 하라.&lt;/li&gt;
&lt;li&gt;보상 조치를 실행해야 하는 교차 바운디드 컨텍스트 프로세스를 조율할 때 &lt;b&gt;사가 패턴과 프로세스 관리자 패턴을 이용하라.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;퍼블릭 이벤트와 프라이빗 이벤트를 사용하라.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 소싱 애그리게이트에서 도메인 이벤트를 발송할 때 &lt;b&gt;세부 정보를 노출하지 않도록&lt;/b&gt; 주의하라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트를 바운디드 컨텍스트의 퍼&lt;b&gt;블릭 인터페이스의 내재된 부분&lt;/b&gt;으로 취급하라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트의 퍼블릭 인터페이스를 설계할 때 &lt;b&gt;다른 유형의 이벤트를 활용하라.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트를 통한 상태 전송 메시지는 &lt;b&gt;필요한 정보만 전달하는&lt;/b&gt; 더욱 간결한 모델을 쓰자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 외부 바운디드 컨텍스트와 통신할 때는 &lt;b&gt;도메인 이벤트를 최소화하여&lt;/b&gt; 사용하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;일관성 요구사항을 평가하라.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 주도 커뮤니케이션을 설계할 때 이벤트 유형 선택을 위한 또 다른 휴리스틱을 적용해보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴포넌트가 궁극적으로 일관된 데이터를 처리할 수 있는 경우, &lt;b&gt;이벤트를 통한 상태 전송 메시지를 사용한다&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;사용자가 제공자의 마지막으로 변경된 상태를 읽어야 하는 경우, 제공자의 최신 정보를 가져오는 &lt;b&gt;후속 질의와 함께 이벤트 알림 메시지를 발행한다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[결론]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 장에서는 세 가지 유형의 이벤트에 대해서 배웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이벤트 알림&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요한 일이 발생했지만, 사용자가 제공자에게 &lt;b&gt;추가 정보를 명시적으로 질의해야 하는 알림&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이벤트를 통한 상태 전송&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메시지 기반 &lt;b&gt;데이터 복제 메커니즘.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 이벤트에는 제공자 데이터의 로컬 캐시를 유지 관리하는데 사용할 수 있는 스냅샷이 포함될 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;도메인 이벤트&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제공자의 비즈니스 도메인 내에서 발생하는 이벤트를 설명하는 메시지&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-end=&quot;3785&quot; data-start=&quot;3730&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;✅ Chapter 14~15 요약 섹션&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-end=&quot;2870&quot; data-start=&quot;2844&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;핵심 포인트 (Key Takeaways)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3195&quot; data-start=&quot;2871&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2970&quot; data-start=&quot;2871&quot;&gt;마이크로서비스 분리는 단순히 &amp;ldquo;쪼개기&amp;rdquo;가 아니라, 변경 비용/복잡도 관점에서 &lt;b&gt;임계치가 존재&lt;/b&gt;한다.&lt;/li&gt;
&lt;li data-end=&quot;3091&quot; data-start=&quot;2971&quot;&gt;&amp;lsquo;깊은 모듈(Deep module)&amp;rsquo; 관점에서, &lt;b&gt;얕은 서비스(기능 1개짜리 서비스)&lt;/b&gt;는 시스템 전체 복잡도를 오히려 증가시킬 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;3195&quot; data-start=&quot;3092&quot;&gt;결국 &amp;ldquo;얼마나 작게 나눴는가&amp;rdquo;가 아니라, &lt;b&gt;서비스 경계가 유스케이스를 기준으로 충분히 깊은가&lt;/b&gt;가 핵심이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;3225&quot; data-start=&quot;3197&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;실무 연결 포인트 (How to apply)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3415&quot; data-start=&quot;3226&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3309&quot; data-start=&quot;3226&quot;&gt;마이크로서비스 도입 논의에서 &amp;ldquo;분리 자체&amp;rdquo;가 목표가 되면 위험하다.&lt;br /&gt;&lt;b&gt;변경 비용 감소 vs 연동 복잡도 증가&lt;/b&gt;의 균형을 계산해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;3366&quot; data-start=&quot;3310&quot;&gt;서비스는 &amp;ldquo;작은 기능&amp;rdquo;이 아니라 &amp;ldquo;하나의 책임 있는 유스케이스 묶음&amp;rdquo;으로 만들어야 운영 가능하다.&lt;/li&gt;
&lt;li data-end=&quot;3415&quot; data-start=&quot;3367&quot;&gt;팀이 분리/확장을 고민할 때 &amp;ldquo;깊은 서비스&amp;rdquo; 개념은 설득력 있는 판단 기준이 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;3429&quot; data-start=&quot;3417&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;한 줄 인사이트&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-end=&quot;3479&quot; data-start=&quot;3430&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;3479&quot; data-start=&quot;3432&quot; data-ke-size=&quot;size16&quot;&gt;마이크로서비스의 본질은 분리가 아니라, &lt;b&gt;글로벌 복잡도를 줄이는 경계 선택&lt;/b&gt;이다.&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>Book Notes</category>
      <category>ddd</category>
      <category>it</category>
      <category>개발</category>
      <category>개발서적</category>
      <category>개발자</category>
      <category>도메인주도설계</category>
      <category>도메인주도설계첫걸음</category>
      <category>필독서</category>
      <author>feel2</author>
      <guid isPermaLink="true">https://feel2.tistory.com/161</guid>
      <comments>https://feel2.tistory.com/161#entry161comment</comments>
      <pubDate>Tue, 13 Jan 2026 22:28:40 +0900</pubDate>
    </item>
    <item>
      <title>[개발서적] 도메인 주도 설계 첫걸음 3부(ch12~13) 요약 (2)</title>
      <link>https://feel2.tistory.com/160</link>
      <description>&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Ch12. 이벤트스토밍&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이번 장에서는 이벤트스토밍에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트스토밍은 사실상 도메인 지식을 공유하고 유비쿼터스 언어를 구축하는 방법 중 하나다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[이벤트스토밍이란?]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트스토밍은 사람들이 모여 비즈니스 프로세스에 관해 &lt;b&gt;브레인스토밍을 하고 신속하게 모델링 하기 위한&lt;/b&gt; 로우테크 활동이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떻게 보면 비즈니스 &lt;b&gt;도메인 지식을 공유하기 위한 전술적 도구다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트스토밍에는 범주(scope), 즉 참가자가 다룰 비즈니스 프로세스가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참가자는 포스트잇을 활용하여 일련의 도메인 이벤트를 시간의 흐름에 따라 표현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델의 모든 구성요소가 비즈니스 프로세스의 작동 방식을 설명할 때까지 단계별로 액터, 커맨드, 외부 시스템 등의 개념을 모델에 추가하여 개선한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[이벤트스토밍에 무엇이 필요한가?]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트스토밍 세션을 진행하는데 무엇이 필요한지 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모델링 공간&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;큰 모델링 공간이 필요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;포스트잇&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;색깔이 다양한 많은 양의 포스트잇이 필요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;마커&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;포스트잇에 적을 때 쓸 마커가 필요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;간식&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반적으로 이벤트스토밍 세션은 두 시간에서 네 시간 정도 소요되니 간식을 준비하자.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;회의실&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;넓은 회의실이 필요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;11.png&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cSMEq8/dJMcadHsCSE/9sb1DTCgu6SxCaI8rahA7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cSMEq8/dJMcadHsCSE/9sb1DTCgu6SxCaI8rahA7K/img.png&quot; data-alt=&quot;그림 12-1. 이벤트스토밍을 위한 모델링 공간&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cSMEq8/dJMcadHsCSE/9sb1DTCgu6SxCaI8rahA7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcSMEq8%2FdJMcadHsCSE%2F9sb1DTCgu6SxCaI8rahA7K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;321&quot; data-filename=&quot;11.png&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 12-1. 이벤트스토밍을 위한 모델링 공간&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[이벤트스토밍 과정]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트스토밍 워크숍은 일반적으로 10단계로 진행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1단계: 자유로운 탐색&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;탐색하려는 비즈니스 도메인에 관련된 &lt;b&gt;도메인 이벤트(domain event)를 브레인스토밍하는&lt;/b&gt; 것부터 시작된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;12.png&quot; data-origin-width=&quot;658&quot; data-origin-height=&quot;397&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLzTiL/dJMcajgBfuv/U5KOGCNryMrNv1HWkwq6W0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLzTiL/dJMcajgBfuv/U5KOGCNryMrNv1HWkwq6W0/img.png&quot; data-alt=&quot;그림 12-2. 자유로운 탐색&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLzTiL/dJMcajgBfuv/U5KOGCNryMrNv1HWkwq6W0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLzTiL%2FdJMcajgBfuv%2FU5KOGCNryMrNv1HWkwq6W0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;658&quot; height=&quot;397&quot; data-filename=&quot;12.png&quot; data-origin-width=&quot;658&quot; data-origin-height=&quot;397&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 12-2. 자유로운 탐색&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 단계에서 모든 참가자는 같은 색의 포스트잇으로 &lt;b&gt;무엇이든 떠오르는 도메인 이벤트를 적어서 붙인다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2단계: 타임라인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로, 참가자는 생성된 도메인 이벤트를 읽어보고 그것을 비즈니스 도메인에서 발생하는 순서대로 정리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;13.png&quot; data-origin-width=&quot;688&quot; data-origin-height=&quot;233&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQvoWz/dJMcafrMsi9/V6gZuZlvWnLmqYjNLTcBF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQvoWz/dJMcafrMsi9/V6gZuZlvWnLmqYjNLTcBF1/img.png&quot; data-alt=&quot;그림 12-3. 자유로운 탐색&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQvoWz/dJMcafrMsi9/V6gZuZlvWnLmqYjNLTcBF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQvoWz%2FdJMcafrMsi9%2FV6gZuZlvWnLmqYjNLTcBF1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;688&quot; height=&quot;233&quot; data-filename=&quot;13.png&quot; data-origin-width=&quot;688&quot; data-origin-height=&quot;233&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 12-3. 자유로운 탐색&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성공적인 비즈니스 시나리오를 설명하는 흐름인 &lt;b&gt;&amp;lsquo;정상 시나리오&amp;rsquo;부터&lt;/b&gt; 시작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3단계: 고충점&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 시간 순서대로 이벤트를 구성했으면 전체 구성을 보고 프로세스에서 &lt;b&gt;주목할 만한 포인트를 식별한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 병목구간, 자동화가 필요한 수작업 단계, 문서가 사라졌거나 도메인 지식이 없는 경우다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;14.png&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;358&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OmT6r/dJMcagYvvoN/JmSCAhpLEwVGX9pUtbhVjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OmT6r/dJMcagYvvoN/JmSCAhpLEwVGX9pUtbhVjK/img.png&quot; data-alt=&quot;그림 12-4. 프로세스에서 주목할 만한 관점을 표시하는 다이아몬드 형태의 핑크색 포스트잇: 예약 프로세스에서 항공권 요금이 어떻게 비교되는지에 관한 사라진 도메인 지식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OmT6r/dJMcagYvvoN/JmSCAhpLEwVGX9pUtbhVjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOmT6r%2FdJMcagYvvoN%2FJmSCAhpLEwVGX9pUtbhVjK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;638&quot; height=&quot;358&quot; data-filename=&quot;14.png&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;358&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 12-4. 프로세스에서 주목할 만한 관점을 표시하는 다이아몬드 형태의 핑크색 포스트잇: 예약 프로세스에서 항공권 요금이 어떻게 비교되는지에 관한 사라진 도메인 지식&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4단계: 중요 이벤트&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨텍스트나 국면이 바뀌는 것을 나타내는 중대한 비즈니스 이벤트를 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 &lt;b&gt;중요 이벤트(pivotal event)&lt;/b&gt;라고 하며, &lt;b&gt;이 이벤트 전후로 세로로 선을 긋는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;15.png&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;215&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q5AKO/dJMcaivd6RY/AEyGlZOTsep3ullLUpRb71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q5AKO/dJMcaivd6RY/AEyGlZOTsep3ullLUpRb71/img.png&quot; data-alt=&quot;그림 12-5. 이벤트 흐름에서 컨텍스트 변경을 나타내는 중요 이벤트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q5AKO/dJMcaivd6RY/AEyGlZOTsep3ullLUpRb71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq5AKO%2FdJMcaivd6RY%2FAEyGlZOTsep3ullLUpRb71%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;638&quot; height=&quot;215&quot; data-filename=&quot;15.png&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;215&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 12-5. 이벤트 흐름에서 컨텍스트 변경을 나타내는 중요 이벤트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;5단계: 커맨드&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 이벤트가 이미 발생한 것을 설명하는 반면, 커맨드는 무엇이 이벤트 또는 이벤트의 흐름을 시작하게 하는지를 설명한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;캠페인을 게시한다.&lt;/li&gt;
&lt;li&gt;트랜잭션을 롤백한다.&lt;/li&gt;
&lt;li&gt;주문을 제출한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커맨드는 파란색 포스트잇에 작성해서 &lt;b&gt;커맨드가 생성하는 이벤트 앞에 붙인다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;16.png&quot; data-origin-width=&quot;559&quot; data-origin-height=&quot;289&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5SN6i/dJMcag5i6wZ/3Z4EiwH98wKw4b11d2mEy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5SN6i/dJMcag5i6wZ/3Z4EiwH98wKw4b11d2mEy1/img.png&quot; data-alt=&quot;그림 12-6. 고객(액터)이 &amp;amp;lsquo;주문을 제출한다&amp;amp;rsquo; 커맨드를 실행한 후, 이어서 세 개의 이벤트가 생성된다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5SN6i/dJMcag5i6wZ/3Z4EiwH98wKw4b11d2mEy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5SN6i%2FdJMcag5i6wZ%2F3Z4EiwH98wKw4b11d2mEy1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;559&quot; height=&quot;289&quot; data-filename=&quot;16.png&quot; data-origin-width=&quot;559&quot; data-origin-height=&quot;289&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 12-6. 고객(액터)이 &amp;lsquo;주문을 제출한다&amp;rsquo; 커맨드를 실행한 후, 이어서 세 개의 이벤트가 생성된다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;6단계: 정책&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 경우 커맨드에는 관련 액터가 없다. 이 단계에서는 커맨드를 실행할 수도 있는 자동화 정책을 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자동화 정책(automation policy)&lt;/b&gt;은 이벤트가 &lt;b&gt;커맨드의 실행을 시작하는&lt;/b&gt; 시나리오다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;17.png&quot; data-origin-width=&quot;363&quot; data-origin-height=&quot;237&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cj35L9/dJMcahJUxmc/GeEAIW9TyEJQa7J8ILgkL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cj35L9/dJMcahJUxmc/GeEAIW9TyEJQa7J8ILgkL0/img.png&quot; data-alt=&quot;그림 12-7. &amp;amp;lsquo;배송이 승인됐다&amp;amp;rsquo; 이벤트가 나타날 때 &amp;amp;lsquo;주문을 배송한다&amp;amp;rsquo; 커맨드를 실행하는 자동화 정책&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cj35L9/dJMcahJUxmc/GeEAIW9TyEJQa7J8ILgkL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcj35L9%2FdJMcahJUxmc%2FGeEAIW9TyEJQa7J8ILgkL0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;437&quot; height=&quot;237&quot; data-filename=&quot;17.png&quot; data-origin-width=&quot;363&quot; data-origin-height=&quot;237&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 12-7. &amp;lsquo;배송이 승인됐다&amp;rsquo; 이벤트가 나타날 때 &amp;lsquo;주문을 배송한다&amp;rsquo; 커맨드를 실행하는 자동화 정책&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;7단계: 읽기 모델&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽기 모델은 도메인에서 액터가 &lt;b&gt;커맨드를 실행하는 의사결정을 내릴 때&lt;/b&gt; 사용하는 시각적 데이터다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 시스템의 스크린, 리포트, 알림 등이 될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;18.png&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;338&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t9OhO/dJMcaaD0eCf/U5MHwNkiyVVLWdn6kJU0e1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t9OhO/dJMcaaD0eCf/U5MHwNkiyVVLWdn6kJU0e1/img.png&quot; data-alt=&quot;그림 12-8. 고객(액터)이 주문(커맨드)을 제출하는 의사결정을 위해 필요한 &amp;amp;lsquo;쇼핑 카트&amp;amp;rsquo; 뷰(읽기 모델)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t9OhO/dJMcaaD0eCf/U5MHwNkiyVVLWdn6kJU0e1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft9OhO%2FdJMcaaD0eCf%2FU5MHwNkiyVVLWdn6kJU0e1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;612&quot; height=&quot;338&quot; data-filename=&quot;18.png&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;338&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 12-8. 고객(액터)이 주문(커맨드)을 제출하는 의사결정을 위해 필요한 &amp;lsquo;쇼핑 카트&amp;rsquo; 뷰(읽기 모델)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;8단계: 외부 시스템&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 단계에서는 외부 시스템 연동 정보를 보강한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;탐색 중인 도메인에 포함되지 않는 모든 시스템이 외부 시스템에 해당된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;19.png&quot; data-origin-width=&quot;586&quot; data-origin-height=&quot;338&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zAhd8/dJMcabpm2OW/nxjPNqakKko9OCHIoRdHa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zAhd8/dJMcabpm2OW/nxjPNqakKko9OCHIoRdHa1/img.png&quot; data-alt=&quot;그림 12-9. 커맨드의 실행을 외부 시스템(왼쪽)과 외부 시스템에 전달되는 이벤트의 승인(오른쪽)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zAhd8/dJMcabpm2OW/nxjPNqakKko9OCHIoRdHa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzAhd8%2FdJMcabpm2OW%2FnxjPNqakKko9OCHIoRdHa1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;586&quot; height=&quot;338&quot; data-filename=&quot;19.png&quot; data-origin-width=&quot;586&quot; data-origin-height=&quot;338&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 12-9. 커맨드의 실행을 외부 시스템(왼쪽)과 외부 시스템에 전달되는 이벤트의 승인(오른쪽)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;9단계: 애그리게이트&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 모든 이벤트와 커맨드가 표현되면 애그리게이트의 개념을 포함하여 모델을 구성할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트는 커맨드를 받고 이벤트를 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20.png&quot; data-origin-width=&quot;524&quot; data-origin-height=&quot;273&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRfzGn/dJMcahiPyvs/NgKSDdNujCKeYvkeqIbALK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRfzGn/dJMcahiPyvs/NgKSDdNujCKeYvkeqIbALK/img.png&quot; data-alt=&quot;그림 12-10. 애그리게이트에 구성된 커맨드와 이벤트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRfzGn/dJMcahiPyvs/NgKSDdNujCKeYvkeqIbALK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRfzGn%2FdJMcahiPyvs%2FNgKSDdNujCKeYvkeqIbALK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;524&quot; height=&quot;273&quot; data-filename=&quot;20.png&quot; data-origin-width=&quot;524&quot; data-origin-height=&quot;273&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 12-10. 애그리게이트에 구성된 커맨드와 이벤트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;10단계: 바운디드 컨텍스트&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트스토밍의 마지막 단계에서는 서로 연관된 애그리게이트를 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트는 기능이 밀접하게 연관되거나 정책을 통해 연관될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 12-11처럼 에그리게이트의 그룹은 바운디드 컨텍스트 경계의 자연스러운 후보가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;21.png&quot; data-origin-width=&quot;672&quot; data-origin-height=&quot;376&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lJATH/dJMcadHsCWl/8yokRQBwWuF6DIRuEdoogk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lJATH/dJMcadHsCWl/8yokRQBwWuF6DIRuEdoogk/img.png&quot; data-alt=&quot;그림 12-11. 시스템을 바운디드 컨텍스트로 분리한 예시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lJATH/dJMcadHsCWl/8yokRQBwWuF6DIRuEdoogk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlJATH%2FdJMcadHsCWl%2F8yokRQBwWuF6DIRuEdoogk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;672&quot; height=&quot;376&quot; data-filename=&quot;21.png&quot; data-origin-width=&quot;672&quot; data-origin-height=&quot;376&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 12-11. 시스템을 바운디드 컨텍스트로 분리한 예시&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[변형]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트스토밍의 창시자 알베르토 브랜돌리니는 이벤트스토밍의 진행 과정을 반드시 따라야 하는 고정된 규칙이 아니라고 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 여러분의 상황에 잘 맞는 비법을 찾기 위해 자유롭게 실험해도 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[결론]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트스토밍은 협업을 통해 비즈니스 프로세스를 모델링하는 워크숍이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도출된 모델 외에도 지식 공유라는 중요한 이점을 얻을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Ch13.&lt;span&gt; 실무에서의 도메인 주도 설계&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 주도 설계에서 가치를 얻기 위한 모든 패턴을 실무에 적용할 필요는 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적당한 기간 안에, 특히 브라운필드 프로젝트에 모든 DDD 패턴을 적용하고 실무에 도입하는 것은 실질적으로 불가능한 일이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 장에서는 브라운필드 프로젝트와 이상적이지 않은 환경에서 실제로 도메인 주도 설계 도구의 패턴을 적용하기 위한 전략을 배운다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[전략적 분석]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에 도메인 주도 설계 패턴을 적용하는 순서에 따라 DDD를 도입하는 가장 좋은 출발점은 조&lt;b&gt;직의 비즈니스 전략과 시스템 아키텍처의 현 상황을 이해하는데 시간을 투자하는 것이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;비즈니스 도메인 이해하기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 회사의 비즈니스 도메인을 파악한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;조직의 비즈니스 도메인은 무엇인가?&lt;/li&gt;
&lt;li&gt;고객은 누구인가?&lt;/li&gt;
&lt;li&gt;조직이 고객에게 제공하는 서비스 또는 가치는 무엇인가?&lt;/li&gt;
&lt;li&gt;경쟁 회사 또는 그들의 제품은 무엇인가?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;핵심 하위 도메인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사의 핵심 하위 도메인을 식별하려면 &lt;b&gt;경쟁업체와 차별화되는 점을&lt;/b&gt; 찾아라.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;경쟁업체에 없는 회사의 &amp;lsquo;비법 소스&amp;rsquo;는 무엇인가?&lt;/li&gt;
&lt;li&gt;경쟁 우위인 핵심 하위 도메인이 반드시 기술적인 것은 아니라는 점을 명심해라.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 하위 도메인을 식별하는 또 하나의 강력하지만 유감스러운 휴리스틱은 최악으로 설계된 소프트웨어 컴포넌트, 즉 커다란 진흙 덩어리를 찾아내는 것이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;일반 하위 도메인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 하위 도메인을 식별하려면 &lt;b&gt;상용 솔루션이나 구독 서비스, 또는 연동할 수 있는 오픈소스 소프트웨어&lt;/b&gt;를 찾아라. (ex) 메시징 서비스, 인사 관리 서비스, 권한 관리 서비스 등)&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;지원 하위 도메인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지원 하위 도메인을 식별하려면 &lt;b&gt;상용 솔루션으로 대체할 수 없지만&lt;/b&gt;, &lt;b&gt;직접 경쟁 우위를 제공하지 않는&lt;/b&gt; 나머지 소프트웨어 컴포넌트를 찾아라.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;현재 설계 탐색&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 도메인에 한 번 익숙해지면 그것의 솔루션 및 설계와 관련된 결정을 계속 살펴볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 상위 수준 컴포넌트부터 시작하라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 컴포넌트의 특성 중 수명주기를 분리할 수 있는지 찾아라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 시스템이 같은 소스 관리 저장소에서 관리되거나 모든 컴포넌트가 하나의 모놀리식 코드베이스에 있는 경우에도 어느 것이 다른 컴포넌트와 독립적으로 개선되고 테스트되고 배포될 수 있는지 확인하라.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;전술적 설계 평가&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 상위 수준 컴포넌트에 대해 그것이 어느 비즈니스 하위 도메인을 포함하고 어떤 기술적 설계 의사결정을 내렸는지 확인하라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스 로직을 구현하고 컴포넌트의 아키텍처를 정의하는데 어느 패턴을 사용했는가?&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;전략적 설계 평가&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상위 수준 컴포넌트에 대한 지식을 사용하여 이러한 컴포넌트가 바운디드 컨텍스트인 것처럼 현재 설계의 컨텍스트 맵을 차트로 표시하라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 바운디드 컨텍스트 연동 패턴 관점에서 컴포넌트 간의 관계를 식별하고 추적하라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 결과 컨텍스트 맵을 분석하고 도메인 주도 설계 관점에서 아키텍처를 평가하라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동일한 상위 수준의 컴포넌트에 대해 작업하는 여러 팀&lt;/li&gt;
&lt;li&gt;핵심 하위 도메인의 중복 구현&lt;/li&gt;
&lt;li&gt;하청 회사가 핵심 하위 도메인을 구현&lt;/li&gt;
&lt;li&gt;자주 실패하는 연동으로 인한 마찰&lt;/li&gt;
&lt;li&gt;외부 서비스와 레거시 시스템에서 확산되는 어색한 모델&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[현대화 전략]&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔지니어가 시스템을 처음부터 다시 작성하려고 하는 &amp;lsquo;대대적인 재작성(big rewrite)&amp;rsquo; 노력은 거의 성공하지 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 시스템을 다시 올바르게 설계하고 구현하기란 매우 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 시스템의 설계를 개선하기 위한 좀 더 안전한 방법은 &lt;b&gt;크게 생각하되 작게 시작하는 것이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해 각 하위 도메인을 제대로 된 바운디드 컨텍스트로 나눈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 그림 13-1과 같이 최소한 논리적 경계(기술 스택에 따라 네임스페이스, 모듈, 패키지)가 하위 도메인의 경계와 일치하는지 확인하는 것부터 시작하자.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;22.png&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UfXmc/dJMcaiWi7Kf/Rkgm2FuO3KHQHzIGgNk321/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UfXmc/dJMcaiWi7Kf/Rkgm2FuO3KHQHzIGgNk321/img.png&quot; data-alt=&quot;그림 13-1. 기술적 구현 패턴이 아닌 비즈니스 하위 도메인 경계를 반영하도록 바운디드 컨텍스트의 모듈을 재구성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UfXmc/dJMcaiWi7Kf/Rkgm2FuO3KHQHzIGgNk321/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUfXmc%2FdJMcaiWi7Kf%2FRkgm2FuO3KHQHzIGgNk321%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;678&quot; height=&quot;240&quot; data-filename=&quot;22.png&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;240&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 13-1. 기술적 구현 패턴이 아닌 비즈니스 하위 도메인 경계를 반영하도록 바운디드 컨텍스트의 모듈을 재구성&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;시스템의 모듈을 조정하는 것은 비교적 안전한 형태의 리팩토링이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;전략적 현대화&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리적 경계를 물리적 경계로 바꿔 바운디드 컨텍스트를 추출하는 과정은 그림 13-2와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같은 질문을 스스로에게 해보라.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 팀이 동일한 코드베이스에서 작업하고 있는가?&lt;/li&gt;
&lt;li&gt;서로 다른 컴포넌트에서 충돌하는 모델을 사용하고 있는가?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;23.png&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;419&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w8gLK/dJMcaa44D3A/vZn7wedjXsDCsAkAzFDWv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w8gLK/dJMcaa44D3A/vZn7wedjXsDCsAkAzFDWv1/img.png&quot; data-alt=&quot;그림 13-2. 논리적 경계를 물리적 경계로 전환하여 바운디드 컨텍스트 추출&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w8gLK/dJMcaa44D3A/vZn7wedjXsDCsAkAzFDWv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw8gLK%2FdJMcaa44D3A%2FvZn7wedjXsDCsAkAzFDWv1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;678&quot; height=&quot;419&quot; data-filename=&quot;23.png&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;419&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 13-2. 논리적 경계를 물리적 경계로 전환하여 바운디드 컨텍스트 추출&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;유비쿼터스 언어 육성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성공적인 현대화 설계의 전제조건은 비즈니스 도메인 지식과 비즈니스 도메인의 효과적인 모델을 만드는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 지식을 수집하기 위한 도메인 주도 설계의 지름길인 &lt;b&gt;이벤트스토밍을 잊지 말자&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 지식과 해당 모델을 갖췄다면 논의 중인 비즈니스 기능에 &lt;b&gt;가장 적합한 비즈니스 로직 구현 패턴을 결정하라.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;스트랭글러 패턴&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트랭글러 패턴은 일반적으로 파사드 패턴과 함께 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;파사드 패턴&lt;/b&gt;의 얇은 추상화 계층은 &lt;b&gt;퍼블릭 인터페이스 역할&lt;/b&gt;을 하며, 레거시 또는 현대화된 바운디드 컨텍스트로 &lt;b&gt;요청을 전달해 처리하는 역할&lt;/b&gt;을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이그레이션이 완료되면 파사드는 더 이상 필요하지 않으므로 제거한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;24.png&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uftNK/dJMcag5i6Ba/sLcb4EUDhp9CGcr72OHDlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uftNK/dJMcag5i6Ba/sLcb4EUDhp9CGcr72OHDlk/img.png&quot; data-alt=&quot;그림 13-4. 레거시에서 현대화된 시스템으로 기능을 마이그레이션하는 상태에 따라 요청을 전달하는 파사드 레이어. 마이그레이션이 완료되면 파사드와 레거시 시스템 모두 제거함.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uftNK/dJMcag5i6Ba/sLcb4EUDhp9CGcr72OHDlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuftNK%2FdJMcag5i6Ba%2FsLcb4EUDhp9CGcr72OHDlk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;755&quot; height=&quot;356&quot; data-filename=&quot;24.png&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 13-4. 레거시에서 현대화된 시스템으로 기능을 마이그레이션하는 상태에 따라 요청을 전달하는 파사드 레이어. 마이그레이션이 완료되면 파사드와 레거시 시스템 모두 제거함.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트당 하나의 데이터베이스 규칙을 적용하기 위해 빠르게 레거시 컨텍스트를 폐기하고 현대화된 시스템에서 독점적으로 데이터베이스를 이용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;25.png&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cShAzB/dJMcafZBHaB/oBogF6DqFE0FL1uFSQ4RL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cShAzB/dJMcafZBHaB/oBogF6DqFE0FL1uFSQ4RL1/img.png&quot; data-alt=&quot;그림 13-5. 레거시와 현대화된 시스템 모두 일시적으로 동일한 데이터베이스에서 작동&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cShAzB/dJMcafZBHaB/oBogF6DqFE0FL1uFSQ4RL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcShAzB%2FdJMcafZBHaB%2FoBogF6DqFE0FL1uFSQ4RL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;755&quot; height=&quot;356&quot; data-filename=&quot;25.png&quot; data-origin-width=&quot;755&quot; data-origin-height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 13-5. 레거시와 현대화된 시스템 모두 일시적으로 동일한 데이터베이스에서 작동&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;전술적 설계 의사결정 리팩터링&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레거시 코드베이스를 현대화할 때 두 가지 미묘한 차이점을 알 필요가 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;작은 점진적인 조치가 대규모 재작성보다 안전하다.&lt;/li&gt;
&lt;li&gt;도메인 모델로의 리팩터링이 한번에 이루어질 필요는 없다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[결론]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 장에서는 실제 시나리오에서 도메인 주도 설계 도구를 활용하기 위한 다양한 기술을 배웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 말해, 브라운필드 프로젝트와 레거시 코드베이스에서 작업할 때 반드시 DDD 전문가 팀과 함께 작업할 필요는 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항상 비즈니스 도메인 분석부터 시작하여, 최고의 비즈니스 가치를 얻고자 노력하라.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-end=&quot;3351&quot; data-start=&quot;3296&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;✅ Chapter 12~13 요약 섹션&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-end=&quot;2245&quot; data-start=&quot;2219&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;핵심 포인트 (Key Takeaways)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2502&quot; data-start=&quot;2246&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2411&quot; data-start=&quot;2246&quot;&gt;이벤트스토밍은 도메인을 이해하기 위한 강력한 협업 도구이며, 단순히 이벤트만 나열하는 게 아니라&lt;br /&gt;&lt;b&gt;커맨드 &amp;rarr; 정책 &amp;rarr; 읽기 모델 &amp;rarr; 외부 시스템 &amp;rarr; 애그리게이트 &amp;rarr; 바운디드 컨텍스트&lt;/b&gt;까지 확장해 모델을 구체화한다.&lt;/li&gt;
&lt;li data-end=&quot;2502&quot; data-start=&quot;2412&quot;&gt;이벤트스토밍 절차는 고정된 규칙이 아니라, 상황에 맞춰 변형할 수 있는 &amp;ldquo;프레임&amp;rdquo;이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;2532&quot; data-start=&quot;2504&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;실무 연결 포인트 (How to apply)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2718&quot; data-start=&quot;2533&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2580&quot; data-start=&quot;2533&quot;&gt;신규 도메인/복잡한 요구사항일수록 문서보다 이벤트스토밍이 빠르게 합의점을 만든다.&lt;/li&gt;
&lt;li data-end=&quot;2652&quot; data-start=&quot;2581&quot;&gt;특히 실무에서는 &amp;ldquo;DDD를 한다/안한다&amp;rdquo;보다&lt;br /&gt;&lt;b&gt;팀 내 유비쿼터스 언어 + 경계 합의&lt;/b&gt;를 만드는 효과가 훨씬 크다.&lt;/li&gt;
&lt;li data-end=&quot;2718&quot; data-start=&quot;2653&quot;&gt;배치/알림/웹훅처럼 여러 이해관계자가 얽히는 기능은 이벤트스토밍으로 &amp;ldquo;정책과 흐름&amp;rdquo;을 드러내면 설계가 단단해진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;2732&quot; data-start=&quot;2720&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;한 줄 인사이트&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-end=&quot;2786&quot; data-start=&quot;2733&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2786&quot; data-start=&quot;2735&quot; data-ke-size=&quot;size16&quot;&gt;이벤트스토밍은 설계 기법이 아니라, &lt;b&gt;커뮤니케이션 비용을 설계 비용으로 바꾸는 장치&lt;/b&gt;다.&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>Book Notes</category>
      <category>ddd</category>
      <category>it</category>
      <category>개발</category>
      <category>개발서적</category>
      <category>개발자</category>
      <category>도메인주도설계</category>
      <category>도메인주도설계첫걸음</category>
      <category>필독서</category>
      <author>feel2</author>
      <guid isPermaLink="true">https://feel2.tistory.com/160</guid>
      <comments>https://feel2.tistory.com/160#entry160comment</comments>
      <pubDate>Sun, 11 Jan 2026 19:34:02 +0900</pubDate>
    </item>
    <item>
      <title>[개발서적] 도메인 주도 설계 첫걸음 3부(ch10~11) 요약 (1)</title>
      <link>https://feel2.tistory.com/159</link>
      <description>&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Ch10. 휴리스틱 설계&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이번 장은 1부와 2부의 가교 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, 휴리스틱의 정의가 무엇인지부터 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[휴리스틱]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;휴리스틱은 모든 상황에 맞게 보장되고 수학적으로 검증된 규칙이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오히러 완벽한 것을 보장하지 않지만 당면한 목적에 충분할 만큼의 &lt;b&gt;경험에 기반한 규칙&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 휴리스틱은 &lt;b&gt;가장 중요한 단서에서 느껴지는 것에 집중&lt;/b&gt;하여 &lt;b&gt;효과적으로 문제를 해결하는 접근법&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[바운디드 컨텍스트]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트의 최적의 크기는 무엇일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 바운디드 컨텍스트에 영향을 미치는 소프트웨어의 변경은 비싸고 수많은 조율이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;276&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CERMZ/dJMcahwmmtP/2RcVEiEAoMBnHDkH1GbAz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CERMZ/dJMcahwmmtP/2RcVEiEAoMBnHDkH1GbAz1/img.png&quot; data-alt=&quot;그림 10-1. 여러 바운디드 컨텍스트에 영향을 미치는 변경&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CERMZ/dJMcahwmmtP/2RcVEiEAoMBnHDkH1GbAz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCERMZ%2FdJMcahwmmtP%2F2RcVEiEAoMBnHDkH1GbAz1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;622&quot; height=&quot;276&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;276&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 10-1. 여러 바운디드 컨텍스트에 영향을 미치는 변경&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트의 경계를 무효화하는 변경은 일반적으로 &lt;b&gt;비즈니스 도메인이 잘 알려져 있지 않거나 비즈니스 요구사항이 빈번하게 바뀔 때 발생한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;넓은 바운디드 컨텍스트의 경계 또는 여러 하위 도메인에 걸친 경계는 그 경계 또는 하위 도메인을 포함하는 모델이 잘못돼도 안전하게 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러므로 &lt;b&gt;처음 설계할 때 경계를 넓게 설정하자&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;588&quot; data-origin-height=&quot;423&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qWsoW/dJMcaajHLjC/7dYnjdylvOepaIC7yKxcfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qWsoW/dJMcaajHLjC/7dYnjdylvOepaIC7yKxcfk/img.png&quot; data-alt=&quot;그림 10-2. 넓은 바운디드 컨텍스트 경계&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qWsoW/dJMcaajHLjC/7dYnjdylvOepaIC7yKxcfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqWsoW%2FdJMcaajHLjC%2F7dYnjdylvOepaIC7yKxcfk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;588&quot; height=&quot;423&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;588&quot; data-origin-height=&quot;423&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 10-2. 넓은 바운디드 컨텍스트 경계&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[비즈니스 로직 구현 패턴]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 장에서 우리는 비즈니스 로직을 모델링하는 네 가지 방법을 배웠다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션 스크립트&lt;/li&gt;
&lt;li&gt;액티브 레코드&lt;/li&gt;
&lt;li&gt;도메인 모델&lt;/li&gt;
&lt;li&gt;이벤트 소싱 도메인 모델&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 스크립트와 액티브 레코드 패턴은 &lt;b&gt;간단한&lt;/b&gt; 비즈니스 로직을 포함하는 &lt;b&gt;하위 도메인의 경우&lt;/b&gt; 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 모델과 이벤트 소싱 도메인 모델은 &lt;b&gt;복잡한&lt;/b&gt; 비즈니스 로직을 가진 &lt;b&gt;핵심 하위 도메인에&lt;/b&gt; 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모든 것을 고려한다면, 적절한 구현 패턴을 선택하기 위한 효과적인 휴리스틱은 다음과 같이 질문해보는 것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하위 도메인이 금전 또는 통화의 트랜잭션을 추적하거나, 일관된 감사 로그를 제공하거나, 심층적인 분석을 요청하는가? 그렇다면 &lt;b&gt;이벤트 소싱 도메인 모델을 적용한다.&lt;/b&gt; 그렇지 않다면&lt;/li&gt;
&lt;li&gt;하위 도메인의 비즈니스 로직이 복잡한가? 그렇다면 &lt;b&gt;도메인 모델을 구현한다.&lt;/b&gt; 그렇지 않다면&lt;/li&gt;
&lt;li&gt;하위 도메인이 복잡한 자료구조를 포함하는가? 그렇다면 &lt;b&gt;액티브 레코드 패턴&lt;/b&gt;을 사용한다. 그렇지 않다면&lt;/li&gt;
&lt;li&gt;그것이 아니라면 &lt;b&gt;트랜잭션 스크립트를 구현한다&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;379&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5zcQ7/dJMcaaRxO5x/Q64YaR9xMXVb7ib0bUaNVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5zcQ7/dJMcaaRxO5x/Q64YaR9xMXVb7ib0bUaNVk/img.png&quot; data-alt=&quot;그림 10-3. 비즈니스 로직의 구현 패턴을 위한 의사결정 트리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5zcQ7/dJMcaaRxO5x/Q64YaR9xMXVb7ib0bUaNVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5zcQ7%2FdJMcaaRxO5x%2FQ64YaR9xMXVb7ib0bUaNVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;764&quot; height=&quot;379&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;379&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 10-3. 비즈니스 로직의 구현 패턴을 위한 의사결정 트리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 다른 휴리스틱으로는 일반적으로 복잡한 비즈니스 로직은 &lt;b&gt;복잡한 비즈니스 규칙, 불변성, 알고리즘을 포함한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 유비쿼터스 언어 자체의 복잡성을 평가하는 다른 휴리스틱도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 언어에서 주로 CRUD 동작을 표현하는가? 아니면 좀 더 복잡한 비즈니스 프로세스와 규칙을 설명하는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[아키텍처 패턴]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아키텍처 패턴이 의도한 비즈니스 로직 구현 패턴을 알면 쉽게 선정할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이벤트 소싱 도메인 모델은 &lt;b&gt;CQRS가 필요하다&lt;/b&gt;. 그렇지 않으면 시스템은 데이터 질의 옵션이 극심하게 제한되어 자신의 ID만으로 단일 인스턴스를 가져와야 한다.&lt;/li&gt;
&lt;li&gt;도메인 모델은 &lt;b&gt;포트와 어댑터 아키텍처가 필요하다&lt;/b&gt;. 계층형 아키텍처에서는 영속성에 대한 고려 없이 애그리게이트와 밸류 오브젝트를 만들기가 어렵다.&lt;/li&gt;
&lt;li&gt;액티브 레코드 패턴은 애플리케이션(서비스) 계층을 추가한 &lt;b&gt;계층형 아키텍처와 잘 어울린다&lt;/b&gt;. 이는 액티브 레코드를 제어하는 로직을 위한 것이다.&lt;/li&gt;
&lt;li&gt;트랜잭션 스크립트 패턴은 세 개의 계층만으로 이어진 &lt;b&gt;최소한의&lt;/b&gt; &lt;b&gt;계층형 아키텍처를 적용하여&lt;/b&gt; 구현할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;451&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EWw6l/dJMcaaxeOR5/1lYoekhOvukJec7P1idK0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EWw6l/dJMcaaxeOR5/1lYoekhOvukJec7P1idK0k/img.png&quot; data-alt=&quot;그림 10-4. 아키텍처 패턴의 의사결정 트리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EWw6l/dJMcaaxeOR5/1lYoekhOvukJec7P1idK0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEWw6l%2FdJMcaaxeOR5%2F1lYoekhOvukJec7P1idK0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;662&quot; height=&quot;451&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;451&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 10-4. 아키텍처 패턴의 의사결정 트리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[테스트 전략]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 10-5에 세 가지 테스트 전략을 표현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;381&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5wR8k/dJMcaf6nP1P/4WGLtxl8yVYwUkVBmnNKk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5wR8k/dJMcaf6nP1P/4WGLtxl8yVYwUkVBmnNKk0/img.png&quot; data-alt=&quot;그림 10-5. 테스트 전략&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5wR8k/dJMcaf6nP1P/4WGLtxl8yVYwUkVBmnNKk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5wR8k%2FdJMcaf6nP1P%2F4WGLtxl8yVYwUkVBmnNKk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;843&quot; height=&quot;381&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;381&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 10-5. 테스트 전략&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;피라미드형 테스트&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고전적인 피라미드형 테스트 전략은 단위 테스트를 강조하고, 통합 테스트는 별로 없으며, 앤드-투-앤드 테스트는 더더욱 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;도메인 모델 패턴&lt;/b&gt;을 잘 지원하며, &lt;b&gt;비즈니스 로직을 테스트하기 완벽한 단위다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;다이아몬드형 테스트&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다이아몬드형 테스트는 &lt;b&gt;통합 테스트에&lt;/b&gt; 가장 집중하는 유형이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;액티브 레코드 패턴&lt;/b&gt;이 사용되면 비즈니스 로직이 서비스 계층과 비즈니스 로직 계층으로 흩어지므로 &lt;b&gt;두 계층의 연동에 중점을 둔다면&lt;/b&gt; 다이아몬드형 테스트가 효과적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;역전된 피라미드형 테스트&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역적된 피라미드형 테스트는 &lt;b&gt;엔드-투-엔드 테스트에&lt;/b&gt; 가장 많이 집중한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 접근 방법은 &lt;b&gt;트랜잭션 스크립트 패턴&lt;/b&gt;을 구현한 코드베이스에 가장 잘 어울린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;438&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zFeUA/dJMcaaxeOSi/XALxWp8u44zWd8ei9I0dg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zFeUA/dJMcaaxeOSi/XALxWp8u44zWd8ei9I0dg0/img.png&quot; data-alt=&quot;그림 10-6. 아키텍처 패턴의 의사결정 트리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zFeUA/dJMcaaxeOSi/XALxWp8u44zWd8ei9I0dg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzFeUA%2FdJMcaaxeOSi%2FXALxWp8u44zWd8ei9I0dg0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;622&quot; height=&quot;438&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;438&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 10-6. 아키텍처 패턴의 의사결정 트리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[전술적 설계 의사결정 트리]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 10-7 처럼 하나의 전술적 설계 의사결정 트리로 합쳐서 요약할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;796&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdboNE/dJMcaaKLZWC/MLTtsfPJjVUpDdv6gA2yKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdboNE/dJMcaaKLZWC/MLTtsfPJjVUpDdv6gA2yKK/img.png&quot; data-alt=&quot;그림 10-7. 전술적 설계 의사결정 트리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdboNE/dJMcaaKLZWC/MLTtsfPJjVUpDdv6gA2yKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdboNE%2FdJMcaaKLZWC%2FMLTtsfPJjVUpDdv6gA2yKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;804&quot; height=&quot;796&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;796&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 10-7. 전술적 설계 의사결정 트리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 하위 도메인의 유형을 식별하고 의사결정 트리를 참조하는 것은 &lt;b&gt;필수적인 설계 의사결정을 위한 시작점이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 고정된 규칙이 아닌 &lt;b&gt;휴리스틱을 반복하는 것이 중요하다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 특정 상황에 따라 &lt;b&gt;효과적인 접근 방법은 달라진다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러므로 그림 10-7에 표현한 의사결정 트리는 가이드 규칙정도로만 사용하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[결론]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설계 의사결정을 내리는 것도 중요하지만, 더 중요한 것은 시간이 지나면서 과거의 의사결정이 여전히 유효한지를 검증하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Ch11.&lt;span&gt; 진화하는 설계 의사결정&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빠르게 변화하는 현대 사회에서 기업은 정신을 바짝 차려야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 장에서는 소프트웨어 프로젝트 환경의 변화가 소프트웨어 설계 의사결정에 어떻게 영향을 미칠 수 있는지 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[도메인 변경]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2장에서 우리는 세 가지 유형의 비즈니스 하위 도메인을 알아보고 서로 어떻게 다른지 배웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기업이 경쟁 우위를 확보하기 위해 경쟁자와 도르게 수행하는 활동&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;지원&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;회사가 경쟁자와 다르게 하고 있지만, 경쟁 우위를 제공하지 않는 활동&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;일반&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 회사가 같은 방식으로 하는 일&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 장에서 실행 중인 하위 도메인 유형이 전략적 및 전술적 설계 의사결정에 영향을 미치는 것을 봤다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;바운디드 컨텍스트의 경계를 설계하는 방법&lt;/li&gt;
&lt;li&gt;컨텍스트 간의 연동을 조율하는 방법&lt;/li&gt;
&lt;li&gt;복잡한 비즈니스 로직을 다루기 위해 사용할 디자인 패턴&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스 도메인의 요구사항에 따라 구동되는 소프트웨어를 설계하려면 &lt;b&gt;비즈니스 하위 도메인과 해당 유형을 식별하는 것이 중요하다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 그것이 전부가 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;하위 도메인의 진화에&lt;/b&gt; 주의를 기울이는 것도 마찬가지로 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;핵심에서 일반으로&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BuyIT라는 온라인 소매 회사가 자체 주문 배송 솔루션을 구현했다고 상상해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배송 경로를 최적화하는 혁신적인 알고리즘을 개발하여 경쟁사보다 낮은 배송료를 청구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어느 날 또 다른 회사인 DeliverIT가 배송 업계를 혼란에 빠뜨린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lsquo;외판원 문제&amp;rsquo;를 해결했으며, 더 최적화 경로 서비스를 제공한다고 주장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BuyIT 관점에서 DeliverIT의 솔루션이 상용 제품으로 제공되면 &lt;b&gt;핵심 하위 도메인이 일반 하위 도메인으로 바뀐다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;일반에서 핵심으로&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BuyIT는 재고를 관리하기 위해 상용 솔루션을 사용해 왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 사용하던 솔루션의 재고 예측이 계속해서 잘못되는 것을 발견했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BuyIT는 재고 관리를 위한 사내 시스템 셜계 및 구축에 투자하기로 전략적 결정을 내린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 경우 &lt;b&gt;일반 하위 도메인이 핵심 하위 도메인으로 바뀐다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아마존이 이 사례의 좋은 예제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;지원에서 일반으로&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BuyIT의 마케팅 부서는 협력하는 공급업체와 계약을 관리하기 위한 시스템을 구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 시스템은 특별하거나 복잡하지 않으며, 데이터를 입력하기 위한 일부 CRUD 인터페이스만 필요했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 전형적인 지원 하위 도메인이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 몇 년 후 계약 관리 솔루션이 오픈소스로 나왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 오픈소스는 기존 솔루션의 기능에 OCR과 전문 검색과 같은 고급 기능까지 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 회사는 사내 솔루션을 버리고 오픈 소스 솔루션으로 연동하기로 결정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 &lt;b&gt;지원 하위 도메인이 일반 하위 도메인으로 바뀐다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 사례를 보며 다음 그림을 참고해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;336&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k4XrT/dJMcafyxO2O/VPBSDqETQL2JEswqtQ374k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k4XrT/dJMcafyxO2O/VPBSDqETQL2JEswqtQ374k/img.png&quot; data-alt=&quot;그림 11-1. 하위 도메인 유형의 변경 요인&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k4XrT/dJMcafyxO2O/VPBSDqETQL2JEswqtQ374k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk4XrT%2FdJMcafyxO2O%2FVPBSDqETQL2JEswqtQ374k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;336&quot; height=&quot;352&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;336&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 11-1. 하위 도메인 유형의 변경 요인&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[전술적 설계 문제]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 도메인의 유형 변경을 나타내는 주요 지표는 기존의 기술적 설계가 현재 비즈니스 요구를 지원할 수 없는 경우다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지원 하위 도메인이 핵심 하위 도메인이 되는 예를 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지원 하위 도메인은 비즈니스 로직을 모델링하기 위해 비교적 단순한 트랜잭션 스크립트 또는 액티브 레코드 패턴으로 구현될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이러한 패턴은 &lt;b&gt;복잡한 규칙과 불변성을 가진 비즈니스 로직에는 적합하지 않다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;트랜잭션 스크립트에서 액티브 레코드로&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 트랜잭션 스크립트와 액티브 레코드 패턴은 모두 &lt;b&gt;절차지향 스크립트를 사용하여&lt;/b&gt; 비즈니스 로직을 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 다 자료구조는 모델링하는 방식에 차이가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 트랜잭션 스크립트에서 &lt;b&gt;데이터 작업이 어려워지면&lt;/b&gt; 그것을 액티브레코드 패턴으로 리팩토링 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;액티브 레코드에서 도메인 모델로&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;액티브 레코드를 조작하는 &lt;b&gt;비즈니스 로직이 점점 더 복잡해지고 불일치 및 중복 사례가 많아진다면&lt;/b&gt; 도메인 모델 패턴으로 리팩토링 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리팩토링 과정을 보면&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;밸류 오브잭트를 먼저 식별해봐라.&lt;/li&gt;
&lt;li&gt;자료구조를 분석하고 트랜잭션 경계를 찾아라.&lt;/li&gt;
&lt;li&gt;마지막으로 각 애그리게이트에 대해 루트 또는 퍼블릭 인터페이스의 앤드포인트를 식별하라.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[조직 변화]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템 설계에 영향을 줄 수 있는 또 다른 변화의 유형은 &lt;b&gt;조직 자체의 변화다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 11-2와 같이 이러한 변화의 예시로 개발 센터의 성장을 예로 들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;9.png&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIMleK/dJMcaiBZAPu/UIDihQ31qKKosBzmM9lcpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIMleK/dJMcaiBZAPu/UIDihQ31qKKosBzmM9lcpk/img.png&quot; data-alt=&quot;그림 11-2. 성장하는 엔지니어링 팀을 수용하기 위해 넓은 바운디드 컨텍스트로 분할&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIMleK/dJMcaiBZAPu/UIDihQ31qKKosBzmM9lcpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIMleK%2FdJMcaiBZAPu%2FUIDihQ31qKKosBzmM9lcpk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;778&quot; height=&quot;352&quot; data-filename=&quot;9.png&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 11-2. 성장하는 엔지니어링 팀을 수용하기 위해 넓은 바운디드 컨텍스트로 분할&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[도메인 지식]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 주도 설계의 핵심 신조는 &lt;b&gt;성공적인 소프트웨어 시스템을 설게하는데 도메인 지식이 반드시 필요하다는 것이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전략적 설계 관점에서 볼 때 &lt;b&gt;도메인 지식 수준에 따라&lt;/b&gt; 바운디드 컨텍스트의 경계를 설게하는 것은 &lt;b&gt;유용한 휴리스틱이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;도메인 로직이 불명확하고 자주 변경되는 경우&lt;/b&gt; 바운디드 컨텍스트를 &lt;b&gt;더 넓은 경계로 설계하는 것이&lt;/b&gt; 합리적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 도메인 지식이 발견되면 이를 활용하여 설계를 발전시키고 &lt;b&gt;회복성을 높여야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[성장]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성장은 시스템이 건강하다는 신호다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 기능이 지속해서 추가된다는 것은 시스템이 성공적이라는 신호다. 반대로 성장에는 어두운 면이 따라온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 &amp;lsquo;&lt;b&gt;커다란 진흙 덩어리&lt;/b&gt;&amp;rsquo;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;커다란 진흙 덩어리는 엉터리 구조의 거대하고 허술한 와이어 무더기와 강력 접착 테이프 범벅의 스파게티 코드 정글과도 같다. 이러한 시스템은 규제되지 않은 성장과 반복적이고 편의에 따른 수리의 명백한 징후다.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커다란 진흙 덩어리는 &lt;b&gt;규제 없는 성장을 통해 시스템을 확장한 결과다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성장에 따른 복잡성을 다루는 기본 원칙은 우발적 복잡성, 즉 오래된 설계의 결정으로 발생하는 복잡성을 식별하고 제거하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;하위 도메인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 도메인의 완벽한 경계를 찾기 위해 노력하는 대신 &lt;b&gt;유용한 경계를 찾기 위해&lt;/b&gt; 노력해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해 이미 식별된 하위 도메인을 다시 확인하고, 응집된 유스케이스에서 휴리스틱을 활용하여 하위 도메인을 나누는 지점을 다시 식별하는 것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;10.png&quot; data-origin-width=&quot;819&quot; data-origin-height=&quot;217&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GMure/dJMcahiPypD/m9DhyyYeNEaJemR6urqOD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GMure/dJMcahiPypD/m9DhyyYeNEaJemR6urqOD0/img.png&quot; data-alt=&quot;그림 11-3. 성장을 수용하기 위해 하위 도메인 경계를 최적화&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GMure/dJMcahiPypD/m9DhyyYeNEaJemR6urqOD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGMure%2FdJMcahiPypD%2Fm9DhyyYeNEaJemR6urqOD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;819&quot; height=&quot;217&quot; data-filename=&quot;10.png&quot; data-origin-width=&quot;819&quot; data-origin-height=&quot;217&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 11-3. 성장을 수용하기 위해 하위 도메인 경계를 최적화&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 유형의 세분화된 하위 도메인을 식별할 수 있다면 비즈니스 도메인의 본질적인 복잡성을 관리할 수 있는 중요한 통찰력을 보여줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;바운디드 컨텍스트&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트가 발전하고 성장함에 따라 바운디드 컨텍스트가 초점을 잃고, 다양한 문제와 관련된 로직이 늘어나는 일은 흔한 일이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 하위 도메인과 마찬가지로 바운디드 컨텍스트의 경계를 때때로 살펴보는 것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;애그리게이트&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경험상 애그리게이트는 &lt;b&gt;가능한 한 작게 유지하고&lt;/b&gt;, 비즈니스 도메인에서 &lt;b&gt;강력하게 일관적인 상태를 유지해야 하는 객체&lt;/b&gt;만 포함한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템의 비즈니스 요구사항이 증가함에 따라 애그리게이트를 작게 유지한다는 원칙을 떠올리지 않고, 이미 있는 애그리게이트에 새로운 기능을 배포하는 것이 편할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이는 우발적 복잡성을 유발할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 비즈니스 기능을 전담하는 애그리게이트로 추출하면 원래 애그리게이트가 단순해질 뿐만 아니라 잠재적으로 해당 애그리게이트가 속한 바운디드 컨텍스트도 단순해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[결론]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스 도메인이 발전함에 따라 하위 도메인에 대한 변경사항을 식별하고 시스템 설계에서 조치를 취해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과거의 설계 의사결정이 유효한지 확인하고, 필요한 경우 현재 비즈니스 젼략과 요구사항에 더 맞게 설계를 발전시켜라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 소프트웨어 성장은 원하는 유형의 변화지만, 올바르게 관리되지 않으면 시스템 설계와 아키텍처에 치명적인 영향을 줄 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그러므로 하위 도메인의 기능이 확장되면 더 나은 설계 의사결정을 내릴 수 있도록 더 세분화된 하위 도메인 경계를 식별하려고 노력하라.&lt;/li&gt;
&lt;li&gt;&amp;lsquo;여러 방면에 다재다능한&amp;rsquo; 바운디드 컨텍스트가 되는 것을 허용하지 마라.&lt;/li&gt;
&lt;li&gt;애그리게이트의 경계가 가능한 한 작은지 확인하라.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-end=&quot;2887&quot; data-start=&quot;2832&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;✅ Chapter 10~11 요약 섹션&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-end=&quot;1515&quot; data-start=&quot;1489&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;핵심 포인트 (Key Takeaways)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1878&quot; data-start=&quot;1516&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1629&quot; data-start=&quot;1516&quot;&gt;&lt;b&gt;아키텍처/전술 패턴 선택은 정답이 아니라 의사결정 문제&lt;/b&gt;이며, 상황에 맞는 선택을 돕기 위해 의사결정 트리를 사용할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;1753&quot; data-start=&quot;1630&quot;&gt;설계 의사결정에서 더 중요한 것은 &amp;ldquo;결정 자체&amp;rdquo;가 아니라 &lt;b&gt;시간이 지난 뒤 그 결정이 여전히 유효한지 검증하는 것&lt;/b&gt;이다.&lt;/li&gt;
&lt;li data-end=&quot;1878&quot; data-start=&quot;1754&quot;&gt;하위 도메인의 성격(Core/Supporting/Generic)은 고정이 아니라 변화하고, 이 변화는 BC 경계/패턴 선택/연동 방식까지 영향을 준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;1908&quot; data-start=&quot;1880&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;실무 연결 포인트 (How to apply)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2095&quot; data-start=&quot;1909&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1990&quot; data-start=&quot;1909&quot;&gt;프로젝트 초기에 &amp;ldquo;완벽한 설계&amp;rdquo;보다 중요한 건 &lt;b&gt;결정을 검증 가능한 형태로 남기는 것&lt;/b&gt;&lt;br /&gt;(의사결정 로그, ADR, POC 결과 등)&lt;/li&gt;
&lt;li data-end=&quot;2095&quot; data-start=&quot;1991&quot;&gt;도메인이 변할 수 있다는 가정하에 &lt;b&gt;경계/패턴을 고정하지 말고 진화 가능하게 설계&lt;/b&gt;해야 한다.&lt;br /&gt;즉, &amp;ldquo;한 번 잘 만들면 끝&amp;rdquo;이 아니라 &amp;ldquo;바꿀 수 있게 만드는 것&amp;rdquo;이 목표다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;2109&quot; data-start=&quot;2097&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;한 줄 인사이트&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-end=&quot;2161&quot; data-start=&quot;2110&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2161&quot; data-start=&quot;2112&quot; data-ke-size=&quot;size16&quot;&gt;좋은 설계는 &amp;ldquo;최고의 선택&amp;rdquo;이 아니라, &lt;b&gt;변화 속에서도 계속 검증 가능한 선택&lt;/b&gt;이다.&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>Book Notes</category>
      <category>ddd</category>
      <category>it</category>
      <category>개발</category>
      <category>개발서적</category>
      <category>개발자</category>
      <category>도메인주도설계</category>
      <category>도메인주도설계첫걸음</category>
      <category>필독서</category>
      <author>feel2</author>
      <guid isPermaLink="true">https://feel2.tistory.com/159</guid>
      <comments>https://feel2.tistory.com/159#entry159comment</comments>
      <pubDate>Sun, 11 Jan 2026 19:20:39 +0900</pubDate>
    </item>
    <item>
      <title>[개발서적] 도메인 주도 설계 첫걸음 2부(ch7~9) 요약 (2)</title>
      <link>https://feel2.tistory.com/158</link>
      <description>&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Ch7. 시간 차원의 모델링&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[이벤트 소싱]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프레드 브룩스의 추론을 사용해서 이벤트 소싱 패턴을 정의하고, 이것이 기존의 모델링과 데이터 저장 방식 측면에서 어떻게 다른지 이해해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 표 7-1의 데이터를 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;10.png&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;806&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8aoJj/dJMcacaKDUZ/Dxaglkyvcn15wjaU2gLrmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8aoJj/dJMcacaKDUZ/Dxaglkyvcn15wjaU2gLrmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8aoJj/dJMcacaKDUZ/Dxaglkyvcn15wjaU2gLrmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8aoJj%2FdJMcacaKDUZ%2FDxaglkyvcn15wjaU2gLrmk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;644&quot; height=&quot;806&quot; data-filename=&quot;10.png&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;806&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;11.png&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;219&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AWH2J/dJMcag5i0hQ/Ax4khy6TN7Kbw8v6xsmzL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AWH2J/dJMcag5i0hQ/Ax4khy6TN7Kbw8v6xsmzL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AWH2J/dJMcag5i0hQ/Ax4khy6TN7Kbw8v6xsmzL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAWH2J%2FdJMcag5i0hQ%2FAx4khy6TN7Kbw8v6xsmzL0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;644&quot; height=&quot;219&quot; data-filename=&quot;11.png&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;219&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 텔레마케팅 시스템에서 잠재 고객 또는 리드를 관리하는데 사용하는 테이블임에 분명하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 상태를 조사하여 각 잠재 고객의 처리 주기를 가정할 수도 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;판매 흐름은 NEW_LEAD 상태의 잠재 고객과 함께 시작한다.&lt;/li&gt;
&lt;li&gt;판매 전화는 제안에 관심이 없는 사람(리드가 CLOSED), 후속 전화 예약(FOLLOWUP_SET), 또는 제안 수락(PENDING_PAYMENT)으로 종료될 수 있다.&lt;/li&gt;
&lt;li&gt;결제가 성공하면 리드가 고객으로 전환(CONVERTED)된다. 결제가 실패할 수도 있다(PAYMENT_FALIED)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블의 데이터는 리드의 현재 상태를 문서화하지만 각 리드가 &lt;b&gt;현재 상태에 도달한 이력에 대한 이야기가 누락되었다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 우리가 알 수 있는 건 리드의 &lt;b&gt;현재 상태 뿐이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 누락된 정보를 채우는 방법 중 하나가 &lt;b&gt;이벤트 소싱을 이용하는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 소싱 패턴은 데이터 모델에 &lt;b&gt;시간 차원을 도입&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트의 현재 상태를 반영하는 스키마 대신 수명주기의 모든 변경사항을 문서화하는 이벤트를 유지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표 7-1의 12행에 있는 CONVERTED 고객을 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768104117460&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	&quot;lead-id&quot;: 12,
	&quot;evnet-id&quot;: 0,
	&quot;event-type&quot;: &quot;lead-initinalized&quot;,
	&quot;first-name&quot;: &quot;Casey&quot;,
	&quot;last-name&quot;: &quot;David&quot;,
	&quot;phone-number&quot;: &quot;555-2951&quot;,
	&quot;timestamp&quot;: &quot;2020-05-20T09:52:55.95Z&quot; 
},
{
	&quot;lead-id&quot;: 12,
	&quot;evnet-id&quot;: 1,
	&quot;event-type&quot;: &quot;contacted&quot;,
	&quot;timestamp&quot;: &quot;2020-05-20T12:32:55.95Z&quot; 
},
{
	&quot;lead-id&quot;: 12,
	&quot;evnet-id&quot;: 2,
	&quot;event-type&quot;: &quot;followup-set&quot;,
	&quot;followup-on&quot;: &quot;2020-05-20T12:32:55.95Z&quot;,
	&quot;timestamp&quot;: &quot;2020-05-20T12:32:55.95Z&quot; 
},
{
	&quot;lead-id&quot;: 12,
	&quot;evnet-id&quot;: 3,
	&quot;event-type&quot;: &quot;contacted-details-updated&quot;,
	&quot;first-name&quot;: &quot;Casey&quot;,
	&quot;last-name&quot;: &quot;David&quot;,
	&quot;phone-number&quot;: &quot;555-8101&quot;
	&quot;timestamp&quot;: &quot;2020-05-20T12:32:55.95Z&quot; 
},
{
	&quot;lead-id&quot;: 12,
	&quot;evnet-id&quot;: 4,
	&quot;event-type&quot;: &quot;contacted&quot;,
	&quot;timestamp&quot;: &quot;2020-05-27T12:32:55.95Z&quot; 
},
{
	&quot;lead-id&quot;: 12,
	&quot;evnet-id&quot;: 5,
	&quot;event-type&quot;: &quot;order-submitted&quot;,
	&quot;payment-deadline&quot;: &quot;2020-05-30T12:32:55.95Z&quot;
	&quot;timestamp&quot;: &quot;2020-05-27T12:32:55.95Z&quot; 
},
{
	&quot;lead-id&quot;: 12,
	&quot;evnet-id&quot;: 6,
	&quot;event-type&quot;: &quot;payment-confirmed&quot;,
	&quot;status&quot;: &quot;conveted&quot;
	&quot;timestamp&quot;: &quot;2020-05-27T12:38:55.95Z&quot; 
},&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 목록의 이벤트는 고객의 이야기를 알려준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고객의 상태는 이러한 도메인 이벤트로부터 쉽게 프로젝션할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768104132666&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class LeadSearchModelPrjoection
{
	public long LeadId {get; private set; }
	public HashSet&amp;lt;string&amp;gt; FirstNames {get; private set; }
	public HashSet&amp;lt;string&amp;gt; LastNames {get; private set; }
	public HashSet&amp;lt;PhoneNumber&amp;gt; PhoneNumbers {get; private set; }
	public int Version {get; private set; }
	
	public void Apply(LeadInitialized @event)
	{
		LeadId = @evnet.LeadId;
		FirstNames = new HashSet&amp;lt;string&amp;gt;();
		LastNames = new HashSet&amp;lt;string&amp;gt;();
		PhoneNumbers = new HashSet&amp;lt;PhoneNumbers&amp;gt;();
		FirstNames.Add(@evnet.FirstName);
		LastNames.Add(@event.LastName);
		PhoneNumbers.Add(@evnet.PhoneNumber);
		Verson = 0;
	
	}
	
	public void Apply(ContactDetailsChanged @evnet)
	{
		FirstNames.Add(@evnet.FirstName);
		LastNames.Add(@event.LastName);
		PhoneNumbers.Add(@evnet.PhoneNumber);
		Verson += 1;
	}
	
	public void Apply(Contacted @event)
	{
		Version += 1;
	}
	
	public void Apply(FollwupSet @event)
	{
		Version += 1;
	}
	
	public void Apply(OrderSubmitted @event)
	{
		Version += 1;
	}
	
	public void Apply(PaymentConfirmed @event)
	{
		Version += 1;
	}

}&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;애그리게이트의 이벤트를 반복해서 순서대로 적절히 재정의한 Apply 메서드에 넣으면 정확한 상태 표현을 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;검색&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색 기능을 구현한다고 가정해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 소싱을 사용하면 과거 정보를 쉽게 프로젝션 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768104156829&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class LeadSearchModelProjection
{
	public long LeadId { get; private set; }
	public HashSet&amp;lt;string&amp;gt; FirstNames {get; private set; }
	public HashSet&amp;lt;string&amp;gt; LastNames {get; private set; }
	public HashSet&amp;lt;PhoneNumber&amp;gt; PhoneNumbers {get; private set; }
	public int Version {get; private set; }
	
	public void Apply(LeadInitialized@event)
	{
		LeadId = @evnet.LeadId;
		FirstNames = new HashSet&amp;lt;string&amp;gt;();
		LastNames = new HashSet&amp;lt;string&amp;gt;();
		PhoneNumbers = new HashSet&amp;lt;PhoneNumbers&amp;gt;();
		
		FirstNames.Add(@evnet.FirstName);
		LastNames.Add(@event.LastName);
		PhoneNumbers.Add(@evnet.PhoneNumber);
		
		Verson = 0;
	}
	
	public void Apply(ContactDetailsChanged@evnet)
	{
		FirstNames.Add(@evnet.FirstName);
		LastNames.Add(@event.LastName);
		PhoneNumbers.Add(@evnet.PhoneNumber);
		Verson += 1;
	}
	
	public void Apply(Contacted@event)
	{
		Version += 1;
	}
	
	public void Apply(FollowupSet@event)
	{
		Version += 1;
	}
	
	public void Apply(OrderSubmitted@event)
	{
		Version += 1;
	}
	
	public void Apply(PaymentConfired@event)
	{
		Version += 1;
	}

}&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;이 프로젝션 로직은 LeadInitialized 와 ContactDetailsChanged 이벤트를 이용하여 각 리드의 개인 세부 정보를 채운다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;분석&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 부서에서 좀 더 분석하기 편한 리드 데이터를 요청한다고 가정해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 리드 중에서 후속 전화가 예약된 개수를 얻고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768104178033&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class AnalysisMdelProjection
{
	public long LeadId {get; private set; }
	public int Followups {get; private set; }
	public LeadStatus Status {get; private set; }
	public int Version {get; private set; }
	
	public void Apply(LeadInitialized @evnet)
	{
		LeadId = @event.LeadId;
		Followups = 0;
		Status = LeadStatus.NEW_LEAD;
		Version = 0;
	}
	
	public void Apply(Contacted@evnet)
	{
		Version += 1;
	}
	
	public void Apply(FollowupSet@evnet)
	{
		Status = LeadStatus.FOLLOWUP_SET;
		Followups += 1;
		Version += 1;
	}
	
		public void Apply(ContactDetailsChanged@evnet)
	{
		Version += 1;
	}
	
		public void Apply(OrderSubmitted@evnet)
	{
		Status = LeadStatus.PENDING_PAYMENT;
		Version += 1;
	}
	
		public void Apply(PaymentConfirmed@evnet)
	{
		Status = LeadStatus.CONVERTED;
		Version += 1;
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;원천 데이터&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 소싱 패턴이 작동하려면 &lt;b&gt;객체 상태에 대한 모든 변경사항이 이벤트로 표현되고 저장되어야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 이벤트는 시스템의 원천 데이터가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;12.png&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcHFM5/dJMcaaDZ8k5/Wug6aiNG8JPNqzEInRdrbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcHFM5/dJMcaaDZ8k5/Wug6aiNG8JPNqzEInRdrbk/img.png&quot; data-alt=&quot;그림 7-1. 이벤트 소싱 애그리게이트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcHFM5/dJMcaaDZ8k5/Wug6aiNG8JPNqzEInRdrbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcHFM5%2FdJMcaaDZ8k5%2FWug6aiNG8JPNqzEInRdrbk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;644&quot; height=&quot;208&quot; data-filename=&quot;12.png&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;208&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 7-1. 이벤트 소싱 애그리게이트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템의 이벤트를 저장하는 데이터베이스는 &lt;b&gt;유일하고 강력하게 일관된 저장소인&lt;/b&gt; 시스템의 원천 데이터다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트를 저장하는데 사용되는 데이터베이스를 지칭하는 이름이 &lt;b&gt;이벤트 스토어&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;이벤트 스토어&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 스토어는 추가만 가능하고, 이벤트를 수정하거나 삭제할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 특정 빈즈니스 엔티티에 속한 모든 이벤트를 가져오고 이벤트를 추가하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768104224360&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface IEventStore
{
	IEnumerable&amp;lt;Event&amp;gt; Fecth(Guid instanceId);
	void Append(Guid instanceId, Event[] newEvents, int expectedVersion);
}&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;Append 메서드의 expectedVersion 인수는 &lt;b&gt;낙관적 동시성 제어를 구현하는데&lt;/b&gt; 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[이벤트 소싱 도메인 모델]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 소싱 도메인 모델은 애그리게이트의 수명주기를 모델링하기 위해 &lt;b&gt;독점적으로 도메인 이벤트&lt;/b&gt;를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 소싱 애그리게이트에 대한 각 작업은 다음 단계를 따른다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;애그리게이트의 도메인 이벤트를 로드한다.&lt;/li&gt;
&lt;li&gt;이벤트를 비즈니스 의사결정을 내리는데 사용할 수 있는 상태로 프로젝션해서 상태 표현을 재구성한다.&lt;/li&gt;
&lt;li&gt;애그리게이트의 명령을 실행하여 비즈니스 로직을 실행하고, 결과적으로 새로운 도메인 이벤트를 생성.&lt;/li&gt;
&lt;li&gt;새 도메인 이벤트를 이벤트 스토어에 커밋한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6장의 Ticket 애그리게이트 예제로 돌아가서 이벤트 소싱 애그리게이트로 구현해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768104245174&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class TicketAPI
{
	private ITicketRepository _ticketRepository;
	
	...
	
	public void RequestEscalation(TicketId id, EscalationReason reason)
	{
		var events = _ticketRepository.LoadEvents(id);
		var ticket = new Ticket(events);
		var originalVersion = ticket.Version;
		var cmd = new RequestEscalation(reason);
		ticket.Execute(cmd);
		_ticketRepository.CommitChanges(ticket, originalVersion);
	
	}
	...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768104252822&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Ticket
{
	...
	private List&amp;lt;DomainEvent&amp;gt; _domainEvents = new List&amp;lt;DomainEvent&amp;gt;();
	private TicketState _state;
	
	...
	
	public Ticket(IEnumerable&amp;lt;IDomainEvents&amp;gt; events)
	{
		_state = new TicketState();
		foreach(var e in events)
		{
			AppendEvent(e);
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AppendEvent는 들어오는 이벤트를 TicketState 프로젝션 로직에 전달하여 티켓의 현재 상태에 대한 메모리 내 표현 방식을 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768104264599&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private void AppendEvent(IDomainEvent@event)
{
	_domainEvnets.Append(@evnet);
	// &quot;Apply&quot; 메서드의 올바른 오버로드를 동적으로 호출함.
	((dynamic) state).Apply((dynamic) @event);

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트의 현재 상태만을 데이트베이스에 유지하는 기존 모델에 비해 이벤트 소싱 도메인 모델은 애그리게이트를 모델링하는데 더 많은 노력이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 이 패턴은 많은 시나리오에서 고려해볼만한 가치가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;시간 여행&lt;/b&gt;&lt;/p&gt;
&lt;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;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;심오한 통찰력&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이벤트 소싱은 시스템의 상태와 동작에 대한 깊은 통찰력을 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;감사 로그&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;영속적인 도메인 이벤트는 애그리게이트 상태에 발생한 모든 것에 대한 강력하게 일관된 감사 로그(audit log)를 나타낸다.&lt;/li&gt;
&lt;li&gt;법률에 따라 일부 비즈니스 도메인은 반드시 이러한 감사 로그를 구현해야 하며, 이벤트 소싱은 이를 즉시 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;고급 낙관적 동시성 제어&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;고급 낙관적 동시성 모델은 읽기 데이터가 기록되는 동안 다른 프로세스에 의해 덮어 쓰여지는 경우 예외를 발생시킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이벤트 소싱 도메인에 대한 몇가지 문제애 대해 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;학습 곡선&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;패턴이 데이터를 관리하는 기존 기술과 엄청난 차이가 있다는 명백한 단점이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모델의 진화&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이벤트 소싱 모델을 발전시키는 것은 어려울 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;아키텍처 복잡성&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이벤트 소싱을 구현하면 수많은 아키텍처의 &amp;lsquo;유동적인 부분&amp;rsquo;이 도입되어 전체 설계가 복잡해진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[결론]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 소싱 도메인 모델에서 애그리게이트 상태에 대한 모든 변경사항은 &lt;b&gt;일련의 도메인 이벤트로 표현된다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과 도메인 이벤트는 애그리게이트의 현재 상태를 프로젝션하는데 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴은 분석과 최적화를 위해, 또는 법적으로 감사 로그를 요구하기 때문에 시&lt;b&gt;스템 데이터에 대한 심오한 통찰력이 필요한 경우 적합하다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Ch8.&lt;span&gt; 아키택처 패턴&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[비즈니스 로직과 아키텍처 패턴]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스 로직은 소프트웨어에서 &lt;b&gt;가장 중요한 요소&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드베이스가 처리해야 할 다양한 관심사로 인해 비즈니스 로직이 다양한 구성요소로 흩어지기 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관심사를 구현할 때 엄격하게 구성하지 않으면 &lt;b&gt;코드베이스의 변경이 어려워 진다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아키텍처 패턴은 코드베이스 사이의 구성 원칙을 도입하고 이들 사이의 명확한 경계를 제시한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금부터 세가지 주요 아키텍처 패턴인 &lt;b&gt;계층형 아키텍처, 포트와 어댑터, CQRS&lt;/b&gt;에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[계층형 아키텍처]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계층형 아키텍처(layered architecture)는 가장 일반적인 아키텍처 패턴 중 하나다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수평 계층으로 조직하여 각 계층은 사용자와 상호작용, 비즈니스 로직 구현, DB 저장과 같은 기술 구현으로 나뉜다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;13.png&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;323&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmFUfy/dJMcahQFwrK/lgUWTakMRf7EKDzMivHvhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmFUfy/dJMcahQFwrK/lgUWTakMRf7EKDzMivHvhK/img.png&quot; data-alt=&quot;그림 8-1. 계층형 아키텍처&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmFUfy/dJMcahQFwrK/lgUWTakMRf7EKDzMivHvhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmFUfy%2FdJMcahQFwrK%2FlgUWTakMRf7EKDzMivHvhK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;496&quot; height=&quot;323&quot; data-filename=&quot;13.png&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;323&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 8-1. 계층형 아키텍처&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고전적인 형태로 계층형 아키텍처는&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프레젠테이션 계층(PL)&lt;/li&gt;
&lt;li&gt;비즈니스 로직 계층(BLL)&lt;/li&gt;
&lt;li&gt;데이터 접근 계층(DAL)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로 구성된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;프레젠테이션 계층&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프르젠테이션 계층은 &lt;b&gt;사용자와 상호작용을 위해&lt;/b&gt; 인터페이스를 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 프레젠테이션 계층은 프로그램의 퍼블릭 인터페이스다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;14.png&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;108&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lMgZT/dJMcaiWi061/JAZkKWhu4MwNlm1WvDvHlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lMgZT/dJMcaiWi061/JAZkKWhu4MwNlm1WvDvHlK/img.png&quot; data-alt=&quot;그림 8-2. 프레젠테이션 계층&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lMgZT/dJMcaiWi061/JAZkKWhu4MwNlm1WvDvHlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlMgZT%2FdJMcaiWi061%2FJAZkKWhu4MwNlm1WvDvHlK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;496&quot; height=&quot;108&quot; data-filename=&quot;14.png&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;108&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 8-2. 프레젠테이션 계층&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;비즈니스 로직 계층&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 계층은 &lt;b&gt;비즈니스 로직을 구현하고 묶는 것&lt;/b&gt;을 담당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이곳에서 비즈니스 의사결정을 구현한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;15.png&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;108&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dCTUww/dJMcagc9ImX/CS7iT9vvWsJuw5Kh0xt68k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dCTUww/dJMcagc9ImX/CS7iT9vvWsJuw5Kh0xt68k/img.png&quot; data-alt=&quot;그림 8-3. 비즈니스 로직 계층&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dCTUww/dJMcagc9ImX/CS7iT9vvWsJuw5Kh0xt68k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdCTUww%2FdJMcagc9ImX%2FCS7iT9vvWsJuw5Kh0xt68k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;496&quot; height=&quot;108&quot; data-filename=&quot;15.png&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;108&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 8-3. 비즈니스 로직 계층&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;데이터 접근 계층&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 접근 계층은 &lt;b&gt;영속성 메커니즘에 접근할 수 있게&lt;/b&gt; 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전통적으로는 데이터베이스만 가리켰으나, 현대 시스템에서는 더 넓은 범위의 책임을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;16.png&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;81&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bB47uZ/dJMcahC7g6X/CF4rMS8ZXyqRJKBUkMgnQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bB47uZ/dJMcahC7g6X/CF4rMS8ZXyqRJKBUkMgnQK/img.png&quot; data-alt=&quot;그림 8-4. 데이터 접근 계층&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bB47uZ/dJMcahC7g6X/CF4rMS8ZXyqRJKBUkMgnQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbB47uZ%2FdJMcahC7g6X%2FCF4rMS8ZXyqRJKBUkMgnQK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;496&quot; height=&quot;81&quot; data-filename=&quot;16.png&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;81&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 8-4. 데이터 접근 계층&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;계층 간 커뮤니케이션&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계층은 탑다운(top-down) 커뮤니케이션 모델에 따라 연동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 각 계층은 &lt;b&gt;바로 아래 계층에만 의존&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;17.png&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;332&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/evbUAL/dJMcac9BQJ0/dArugdL08IjzK97KWj0xOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/evbUAL/dJMcac9BQJ0/dArugdL08IjzK97KWj0xOK/img.png&quot; data-alt=&quot;그림 8-5. 계층형 아키텍처&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/evbUAL/dJMcac9BQJ0/dArugdL08IjzK97KWj0xOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FevbUAL%2FdJMcac9BQJ0%2FdArugdL08IjzK97KWj0xOK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;496&quot; height=&quot;332&quot; data-filename=&quot;17.png&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;332&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 8-5. 계층형 아키텍처&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;변종(variation)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계층형 아키텍처 패턴을 확장해서 &lt;b&gt;서비스 계층을 추가한 것을&lt;/b&gt; 흔히 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;서비스 계층&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;가용한 오퍼레이션을 구축하고, 각 오퍼레이션에서 애플리케이션의 응답을 조정하는 서비스 계층을 애플리케이션의 경계에 정의한다.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스 계층은 프로그램의 프래젠테이션 계층과 비즈니스 로직 계층 사이의 &lt;b&gt;중간 역할&lt;/b&gt;을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;18.png&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;401&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cb9Dlt/dJMcagEfdzp/YKnDmzDSAc4mQ8BuaalkzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cb9Dlt/dJMcagEfdzp/YKnDmzDSAc4mQ8BuaalkzK/img.png&quot; data-alt=&quot;그림 8-6. 서비스 계층&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cb9Dlt/dJMcagEfdzp/YKnDmzDSAc4mQ8BuaalkzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcb9Dlt%2FdJMcagEfdzp%2FYKnDmzDSAc4mQ8BuaalkzK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;496&quot; height=&quot;401&quot; data-filename=&quot;18.png&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;401&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 8-6. 서비스 계층&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 서비스 계층은 &lt;b&gt;논리적 경계&lt;/b&gt;가 된다는 것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계층형 아키텍처에 사용되는 다른 용어를 봤을 수도 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프레젠테이션 계층 = 사용자 인터페이스 계층&lt;/li&gt;
&lt;li&gt;서비스 계층 = 애플리케이션 계층&lt;/li&gt;
&lt;li&gt;비즈니스 로직 계층 = 도메인 계층 = 모델 계층&lt;/li&gt;
&lt;li&gt;데이터 접근 계층 = 인프라스트럭처 계층&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;계층형 아키텍처를 사용하는 경우&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스 로직과 데이터 접근 계층 간에는 의존성이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 비즈니스 로직이 트랜잭션 스크립트 또는 액티브 레코드 패턴을 사용한다면 계층형 아키텍처 패턴이 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[포트와 어댑터]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;포트와 어댑터(port &amp;amp; adapter)&lt;/b&gt; 아키텍처는 계층형 아키텍처의 단점을 해결하고 &lt;b&gt;좀 더 복잡한 비즈니스 로직을 구현하는데&lt;/b&gt; 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;의존성 역전 원칙&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의존성 역전 원칙(DIP)에서 비즈니스 로직을 구현하는 상위 수준의 모듈은 하위 수준의 모듈에 의존해서는 안된다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DIP를 전통적인 계층형 아키텍처에 적용하면 다음과 같이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;19.png&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/X8so4/dJMcad1KeJX/s3AhCZ0z7VSLWk378WTV30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/X8so4/dJMcad1KeJX/s3AhCZ0z7VSLWk378WTV30/img.png&quot; data-alt=&quot;그림 8-9. 역 의존성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/X8so4/dJMcad1KeJX/s3AhCZ0z7VSLWk378WTV30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FX8so4%2FdJMcad1KeJX%2Fs3AhCZ0z7VSLWk378WTV30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;496&quot; height=&quot;254&quot; data-filename=&quot;19.png&quot; data-origin-width=&quot;496&quot; data-origin-height=&quot;254&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 8-9. 역 의존성&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 비즈니스 로직 계층은 &lt;b&gt;중심적인 역할&lt;/b&gt;을 하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더이상 시스템의 인프라스트럭처 구성요소에 의지하지 않느다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20.png&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;339&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NIgHU/dJMb99LQSWC/GMSlqk2Q1KV411lH2bTmNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NIgHU/dJMb99LQSWC/GMSlqk2Q1KV411lH2bTmNK/img.png&quot; data-alt=&quot;그림 8-10. 포트와 어댑터 아키텍처의 전통적인 계층&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NIgHU/dJMb99LQSWC/GMSlqk2Q1KV411lH2bTmNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNIgHU%2FdJMb99LQSWC%2FGMSlqk2Q1KV411lH2bTmNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;437&quot; height=&quot;339&quot; data-filename=&quot;20.png&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;339&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 8-10. 포트와 어댑터 아키텍처의 전통적인 계층&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;인프라 구성요소의 연동&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포트와 어댑터 아키텍처의 핵심 목적은 &lt;b&gt;인프라스트럭처 구성요소로부터 시스템의 비즈니스 로직을 분리하는 것이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;21.png&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;324&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byPEMX/dJMb996asA8/f8LUli7eXuIivB1JgESYV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byPEMX/dJMb996asA8/f8LUli7eXuIivB1JgESYV1/img.png&quot; data-alt=&quot;그림 8-11. 포트와 어댑터 아키텍처&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byPEMX/dJMb996asA8/f8LUli7eXuIivB1JgESYV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyPEMX%2FdJMb996asA8%2Ff8LUli7eXuIivB1JgESYV1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;633&quot; height=&quot;324&quot; data-filename=&quot;21.png&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;324&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 8-11. 포트와 어댑터 아키텍처&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인프라스트럭처 구성요소를 직접 참조하는 대신, 비즈니스 로직 계층은 인프라스트럭처 계층이 구현해야 할 &amp;lsquo;포트&amp;rsquo;를 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인프라스트럭처 계층은 &amp;lsquo;어댑터&amp;rsquo;를 구현한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;변형&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포트와 어댑터 아키텍처는 핵사고날 아키텍처, 어니언 아키텍처, 클린 아키텍처로 알려져 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모든 패턴이 비록 동일한 설계 원칙에 기반하지만 사용하는 용어가 조금씩 상이할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;애플리케이션 계층 = 서비스 계층 = 유스케이스 계층&lt;/li&gt;
&lt;li&gt;비즈니스 로직 계층 = 도메인 계층 = 핵심 계층&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[CQRS]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CQRS 패턴은 여러 영속 모델에 시스템의 데이터를 표현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;구현&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름에서 알 수 있듯이 이 패턴은 시스템 모델의 책임을 분리시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에는 &lt;b&gt;커맨드 실행 모델과 읽기 모델의 두 유형이 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;커맨드 실행 모델&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CQRS에는 시스템의 상태를 수정하는 오퍼레이션(시스템 커맨드)을 전담으로 수행하는 단일 모델이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스 엔티티의 일관적 사애를 읽을 수 있어야 하고, 갱신할 때 낙관적 동시성을 지원해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;읽기 모델(프로젝션)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템은 사용자에게 데이터를 보여주거나 다른 시스템에 정보를 제공하기 위해 필요한 만큼 모델을 정의해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽기 모델(read model)은 캐시에서 &lt;b&gt;언제든 다시 추출할 수 있는&lt;/b&gt; 프로젝션이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽기 모델은 읽기 전용이다. 시스템의 어떠한 오퍼레이션도 읽기 모델의 데이터를 직접 수정할 수 없다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;읽기 모델의 프로젝션&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽기 모델이 작동하려면 시스템은 커맨드 실행 모델에서 변경을 모든 읽기 모델로 프로젝션해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;22.png&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;341&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5Nljk/dJMcacu3tkC/6ZqGzvV71R4hjGpKa7QXTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5Nljk/dJMcacu3tkC/6ZqGzvV71R4hjGpKa7QXTK/img.png&quot; data-alt=&quot;그림 8-12. CQRS 아키텍처&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5Nljk/dJMcacu3tkC/6ZqGzvV71R4hjGpKa7QXTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5Nljk%2FdJMcacu3tkC%2F6ZqGzvV71R4hjGpKa7QXTK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;690&quot; height=&quot;341&quot; data-filename=&quot;22.png&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;341&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 8-12. CQRS 아키텍처&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 프로젝션을 생성하는 두 가지 방식인 &lt;b&gt;동기식과 비동기 방식을 살펴보자.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;동기식 프로젝션&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동기식 프로젝션은 격차 해소 구독 모델을 통해 OLTP 데이터의 변경사항을 가져온다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로젝션 엔진이 OLTP 데이터베이스로부터 마지막에 처리했던 체크포인트 이후에 추가되거나 갱신된 레코드를 조회한다.&lt;/li&gt;
&lt;li&gt;프로젝션 엔진이 조회된 데이터를 이용하여 시스템의 읽기 모델을 재생성 또는 갱신한다.&lt;/li&gt;
&lt;li&gt;프로젝션 엔진은 마지막으로 처리 레코드의 체크포인트를 저장한다. 이 값은 다음 처리 때 추가되거나 갱신된 레코드를 조회할 때 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;23.png&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;212&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s2F9P/dJMcagxrLI3/NiDZ6K9AAZ1gRSh3OvvBK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s2F9P/dJMcagxrLI3/NiDZ6K9AAZ1gRSh3OvvBK0/img.png&quot; data-alt=&quot;그림 8-13. 동기식 프로젝션 모델&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s2F9P/dJMcagxrLI3/NiDZ6K9AAZ1gRSh3OvvBK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs2F9P%2FdJMcagxrLI3%2FNiDZ6K9AAZ1gRSh3OvvBK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;690&quot; height=&quot;212&quot; data-filename=&quot;23.png&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;212&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 8-13. 동기식 프로젝션 모델&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;24.png&quot; data-origin-width=&quot;876&quot; data-origin-height=&quot;369&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vXQOR/dJMcag5i0sj/eDBpHtomxFZkZFyFbTlLMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vXQOR/dJMcag5i0sj/eDBpHtomxFZkZFyFbTlLMk/img.png&quot; data-alt=&quot;그림 8-14. 격차 해소 구독을 통한 읽기 모델의 동기식 프로젝션&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vXQOR/dJMcag5i0sj/eDBpHtomxFZkZFyFbTlLMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvXQOR%2FdJMcag5i0sj%2FeDBpHtomxFZkZFyFbTlLMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;876&quot; height=&quot;369&quot; data-filename=&quot;24.png&quot; data-origin-width=&quot;876&quot; data-origin-height=&quot;369&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 8-14. 격차 해소 구독을 통한 읽기 모델의 동기식 프로젝션&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;격차 해소 구독이 작동하려면 커맨드 실행 모델이 추가되거나 갱신되는 모든 데이터베이스 레코드를 체크포인트로 관리해야 한다.&lt;/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;b&gt;비동기식 프로젝션&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기식 프로젝션 시나리오에서 커맨드 실행 모델은 모든 커밋된 변경사항을 메시지 버스에 발행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;25.png&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bek8lg/dJMcahC7hau/B20TwYDX9xSS6qTKEQWdOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bek8lg/dJMcahC7hau/B20TwYDX9xSS6qTKEQWdOk/img.png&quot; data-alt=&quot;그림 8-16. 읽기 모델의 비동기식 프로젝션&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bek8lg/dJMcahC7hau/B20TwYDX9xSS6qTKEQWdOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbek8lg%2FdJMcahC7hau%2FB20TwYDX9xSS6qTKEQWdOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;760&quot; height=&quot;252&quot; data-filename=&quot;25.png&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 8-16. 읽기 모델의 비동기식 프로젝션&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림처럼 시스템의 프로젝션 엔진은 발행된 메시지를 구독하고 읽기 모델을 갱신하는데 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;도전과제&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기식 프로젝션 방식의 확실한 확장성과 성능의 장점에도 불구하고, 분산 컴퓨팅에서 문제가 발생하기 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메시지의 순서가 잘못되거나 중복 처리되면 읽기 모델의 일관성 없는 데이터가 프로젝션 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 새로운 프로젝션을 추가하거나 이미 존재하는 것을 재생성하는 것이 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러므로 &lt;b&gt;가능하면 동기식 프로젝션 방식을 구현하고, 선택적으로 비동기식 프로젝션 방식을 추가하는 것을 권장한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;모델 분리&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CQRS 기반 시스템에 대한 일반적인 오해는 커맨드는 데이터를 수정만 할 수 있고, 데이터를 오직 표현 용도로 읽기 모델을 통해서만 조회할 수 있다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이것은 잘못된 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커맨드는 실행이 성공했는지 실패했는지 &lt;b&gt;항상 호출자에게 알려야 한다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러므로 &lt;b&gt;대부분의 경우 커맨드는 데이터를 반환해야 한다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;CQRS를 사용해야 하는 경우&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CQRS 패턴은 궁극적으로 다양한 종류의 데이터베이스에 저장된 동일한 데이터와 작동할 필요가 있는 애플리케이션에 유용하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 CQRS는 이벤트 소싱 도메인 모델에 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[범위]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리의 목적은 실제 필요성과 비즈니스 전략에 따라 설계 의사결정을 내리는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 8-18 처럼 비즈니스 하위 도메인을 묶는 모듈의 논리적 경계를 분명하게 하고 &lt;b&gt;각각에 맞는 적합한 도구를 사용하는 것이 중요하다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;26.png&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;327&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cb8UCC/dJMcahQFwtE/ki5jpPWjb0C3Y1kvvbWQB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cb8UCC/dJMcahQFwtE/ki5jpPWjb0C3Y1kvvbWQB1/img.png&quot; data-alt=&quot;그림 8-18. 아키텍처 슬라이스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cb8UCC/dJMcahQFwtE/ki5jpPWjb0C3Y1kvvbWQB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcb8UCC%2FdJMcahQFwtE%2Fki5jpPWjb0C3Y1kvvbWQB1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;649&quot; height=&quot;327&quot; data-filename=&quot;26.png&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;327&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 8-18. 아키텍처 슬라이스&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[결론]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계층형 아키텍처는 기술적 관심사에 따라 코드베이스를 분해한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴은 비즈니스 로직과 데이터 접근 구현을 결합시키므로 &lt;b&gt;액티브 레코드 기반 시스템에 적합하다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포트와 어댑터 아키텍처는 관계를 역전시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비즈니스 로직을 중심으로&lt;/b&gt; 모든 인프라스트럭처의 의존성을 역전시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴은 &lt;b&gt;도메인 모델 패턴을 구현하는 비즈니스 로직&lt;/b&gt;에 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CQRS 패턴은 여러 모델에서 동일한 데이터를 표현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴은 &lt;b&gt;이벤트 소싱 도메인 모델&lt;/b&gt;에 기반한 시스템에 적합하지만, &lt;b&gt;다양한 영속 모델을 사용할 필요가 있는&lt;/b&gt; &lt;b&gt;어떤 시스템에도&lt;/b&gt; 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Ch9.&lt;span&gt;&lt;span&gt; 커뮤니케이션 패턴&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[모델 변환]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델의 변환 로직은 스테이트리스 또는 스테이트풀이 될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태를 보존하지 않는 스테이트리스 전환은 수신(OHS) 또는 발신(ACL) 요청이 발행할 때 즉석에서 발생하는 반면, 스테이트풀 변환은 상태 보존을 위해 데이터베이스를 사용하여 좀 더 복잡한 로직을 다룰 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;스테이트리스 모델 변환&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스테이트리스 모델 변환은 &lt;b&gt;프락시 패턴을 구현하여&lt;/b&gt; 수신과 발신 요청을 삽입하고 소스 모델을 바운디드 컨텍스트의 목표 모델에 매핑한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;27.png&quot; data-origin-width=&quot;619&quot; data-origin-height=&quot;98&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BO3m3/dJMcagc9ItB/AdRJJIe8SI0dWdlKOk2KoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BO3m3/dJMcagc9ItB/AdRJJIe8SI0dWdlKOk2KoK/img.png&quot; data-alt=&quot;그림 9-1. 프락시에 의한 모델 변환&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BO3m3/dJMcagc9ItB/AdRJJIe8SI0dWdlKOk2KoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBO3m3%2FdJMcagc9ItB%2FAdRJJIe8SI0dWdlKOk2KoK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;619&quot; height=&quot;98&quot; data-filename=&quot;27.png&quot; data-origin-width=&quot;619&quot; data-origin-height=&quot;98&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 9-1. 프락시에 의한 모델 변환&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프락시 구현은 바운디드 컨텍스트가 동기식을 통신할지 또는 비동기식으로 통신할지에 따라 들다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;동기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동기식 통신에 사용되는 모델을 변환하는 일반적인 방법은 그림 9-2와 같이 바운디드 컨텍스트의 코드베이스에 &lt;b&gt;변환 로직을 포함하는 것이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;28.png&quot; data-origin-width=&quot;619&quot; data-origin-height=&quot;98&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btjKkG/dJMcabJHpuC/UfHCfxbtTDkxTzeSB69df0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btjKkG/dJMcabJHpuC/UfHCfxbtTDkxTzeSB69df0/img.png&quot; data-alt=&quot;그림 9-2. 동기 통신&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btjKkG/dJMcabJHpuC/UfHCfxbtTDkxTzeSB69df0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtjKkG%2FdJMcabJHpuC%2FUfHCfxbtTDkxTzeSB69df0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;619&quot; height=&quot;98&quot; data-filename=&quot;28.png&quot; data-origin-width=&quot;619&quot; data-origin-height=&quot;98&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 9-2. 동기 통신&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경우에 따라 변환 로직을 API 게이트웨이 패턴과 같은 외부 컴포넌트로 넘기는 것이 더 비용 효과적이고 편할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오픈 호스트 패턴을 구현하는 바운디드 컨텍스트의 경우 API 게이트웨이는 &lt;b&gt;내부 모델을 통합에 최적화된 공표된 언어로 변환하는 역할을 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 명시적 API 게이트웨이를 사용하면 API의 여러 버전을 관리하고 제공하는 프로세스를 도울 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;29.png&quot; data-origin-width=&quot;619&quot; data-origin-height=&quot;236&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uz5st/dJMcabJHpuF/W6pkCkrXy7mmoHS990nnE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uz5st/dJMcabJHpuF/W6pkCkrXy7mmoHS990nnE0/img.png&quot; data-alt=&quot;그림 9-3. 공표된 언어의 다른 버전 노출&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uz5st/dJMcabJHpuF/W6pkCkrXy7mmoHS990nnE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fuz5st%2FdJMcabJHpuF%2FW6pkCkrXy7mmoHS990nnE0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;619&quot; height=&quot;236&quot; data-filename=&quot;29.png&quot; data-origin-width=&quot;619&quot; data-origin-height=&quot;236&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 9-3. 공표된 언어의 다른 버전 노출&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API 게이트웨이를 사용하여 구현된 충돌 방지 계층은 여러 다운스트림 바운디드 컨텍스트에서 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;30.png&quot; data-origin-width=&quot;619&quot; data-origin-height=&quot;294&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bC6MaZ/dJMcacu3tlX/MArGRJICizZK1KqkVYxmSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bC6MaZ/dJMcacu3tlX/MArGRJICizZK1KqkVYxmSK/img.png&quot; data-alt=&quot;그림 9-4. 공유 충돌 방지 계층&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bC6MaZ/dJMcacu3tlX/MArGRJICizZK1KqkVYxmSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbC6MaZ%2FdJMcacu3tlX%2FMArGRJICizZK1KqkVYxmSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;619&quot; height=&quot;294&quot; data-filename=&quot;30.png&quot; data-origin-width=&quot;619&quot; data-origin-height=&quot;294&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 9-4. 공유 충돌 방지 계층&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 바운디드 컨텍스트는 종종 &lt;b&gt;교환 컨텍스트&lt;/b&gt;라고도 불린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;비동기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기 통신에 사용하는 모델을 변환하기 위해서 &lt;b&gt;메시지 프락시(message proxy)를&lt;/b&gt; 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메시지 프락시는 소스 바운디드 컨텍스트에서 오는 &lt;b&gt;메시지를 구독하는 중개 컴포넌트다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;31.png&quot; data-origin-width=&quot;699&quot; data-origin-height=&quot;136&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pZVqa/dJMcagxrLQz/1R9tqKWcn3Upq1U2bFzIpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pZVqa/dJMcagxrLQz/1R9tqKWcn3Upq1U2bFzIpK/img.png&quot; data-alt=&quot;그림 9-5. 비동기 통신에서 모델 변환&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pZVqa/dJMcagxrLQz/1R9tqKWcn3Upq1U2bFzIpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpZVqa%2FdJMcagxrLQz%2F1R9tqKWcn3Upq1U2bFzIpK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;699&quot; height=&quot;136&quot; data-filename=&quot;31.png&quot; data-origin-width=&quot;699&quot; data-origin-height=&quot;136&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 9-5. 비동기 통신에서 모델 변환&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메시지 모델을 변환하는 것 외에도 중개 컴포넌트는 관련 없는 메시지를 필터링할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;오픈 호스트 서비스&lt;/b&gt;를 구현할 때는 &lt;b&gt;비동기식 모델 변환이 반드시 필요하다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기 변환을 사용하면 도메인 이벤트를 가로채서 공표된 언어로 변환할 수 있으므로 바운디드 컨텍스트의 구현 상세를 더 잘 캡슐화할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 메시지를 공표된 언어로 변환하면 바운디드 컨텍스트의 내부 요구사항을 위한 프라이빗 이벤트와 퍼블릭 이벤트를 구분할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;32.png&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;186&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/be7sU7/dJMcab3YVip/ZDpdsoMLhzdRDSLUpMd1S0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/be7sU7/dJMcab3YVip/ZDpdsoMLhzdRDSLUpMd1S0/img.png&quot; data-alt=&quot;그림 9-6. 공표된 언어로 된 도메인 이벤트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/be7sU7/dJMcab3YVip/ZDpdsoMLhzdRDSLUpMd1S0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbe7sU7%2FdJMcab3YVip%2FZDpdsoMLhzdRDSLUpMd1S0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;733&quot; height=&quot;186&quot; data-filename=&quot;32.png&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;186&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 9-6. 공표된 언어로 된 도메인 이벤트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;스테이트풀 모델 변환&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 중요한 모델 변환의 경우 스테이트풀 변환이 필요할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 원천 데이터를 집계하거나 여러 개의 요청에서 들어오는 데이터를 단일 모델로 통합해야 하는 변환 메커니즘의 경우다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;들어오는 데이터 집계하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트가 &lt;b&gt;들어오는 요청을 집계하고&lt;/b&gt; &lt;b&gt;성능 최적화를 위한 일괄 처리에 관심&lt;/b&gt; 있다고 가정해 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 동기와 비동기 요청 모두에 대해 집계가 필요할 수 있다.(그림 9-7)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;33.png&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;297&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFljyv/dJMcaaKLUkr/NOkKRKg2O80kpibxHAMBc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFljyv/dJMcaaKLUkr/NOkKRKg2O80kpibxHAMBc1/img.png&quot; data-alt=&quot;그림 9-7. 요청의 일괄 처리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFljyv/dJMcaaKLUkr/NOkKRKg2O80kpibxHAMBc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFljyv%2FdJMcaaKLUkr%2FNOkKRKg2O80kpibxHAMBc1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;733&quot; height=&quot;297&quot; data-filename=&quot;33.png&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;297&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 9-7. 요청의 일괄 처리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소스 데이터를 집계하는 또 다른 유스케이스는 그림 9-8처럼 여러 개의 세분화된 메시지를 단일 메시지로 결합하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;34.png&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;297&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4yuSU/dJMb99SDMWi/zCjr24hOKmgcxQ5dzHrMhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4yuSU/dJMb99SDMWi/zCjr24hOKmgcxQ5dzHrMhk/img.png&quot; data-alt=&quot;그림 9-8. 들어오는 이벤트 통합&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4yuSU/dJMb99SDMWi/zCjr24hOKmgcxQ5dzHrMhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4yuSU%2FdJMb99SDMWi%2FzCjr24hOKmgcxQ5dzHrMhk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;733&quot; height=&quot;297&quot; data-filename=&quot;34.png&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;297&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 9-8. 들어오는 이벤트 통합&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유입되는 데이터를 집계하는 모델 변환은 좀 더 정교한 스테이트풀 처리가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 9-9처럼 변환 로직에 자체 영구 저장소가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;35.png&quot; data-origin-width=&quot;587&quot; data-origin-height=&quot;234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HNVBz/dJMcabQrvqj/cGQjJUTgjMKYe25IP4cMKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HNVBz/dJMcabQrvqj/cGQjJUTgjMKYe25IP4cMKK/img.png&quot; data-alt=&quot;그림 9-9. 스테이트풀 모델 변환&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HNVBz/dJMcabQrvqj/cGQjJUTgjMKYe25IP4cMKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHNVBz%2FdJMcabQrvqj%2FcGQjJUTgjMKYe25IP4cMKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;587&quot; height=&quot;234&quot; data-filename=&quot;35.png&quot; data-origin-width=&quot;587&quot; data-origin-height=&quot;234&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 9-9. 스테이트풀 모델 변환&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일부 유스케이스에서는 상용 제품을 사용함으로써 스테이트풀 변환을 위한 맞춤 제작 솔루션을 구현하지 않는 경우도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 스트림 처리 플랫폼(kafka, AWS Kinesis 등) 또는 일괄 처리 솔루션(NiFi, AWS Glue, Spark)을 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;여러 요청 통합&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 바운디드 컨텍스트를 포함하여 여러 요청에서 집계된 데이터를 처리해야 할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 여러 다른 컨텍스트의 데이터를 처리하고, 이를 위한 복잡한 비즈니스 로직을 구현해야 하는 바운디드 컨텍스트다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;36.png&quot; data-origin-width=&quot;478&quot; data-origin-height=&quot;310&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Qns7Z/dJMb99LQS62/rx41jptJzDbnbGok9OK41k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Qns7Z/dJMb99LQS62/rx41jptJzDbnbGok9OK41k/img.png&quot; data-alt=&quot;그림 9-10. 충돌 방지 계층 패턴을 사용하여 통합 모델을 단순화&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Qns7Z/dJMb99LQS62/rx41jptJzDbnbGok9OK41k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQns7Z%2FdJMb99LQS62%2Frx41jptJzDbnbGok9OK41k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;478&quot; height=&quot;310&quot; data-filename=&quot;36.png&quot; data-origin-width=&quot;478&quot; data-origin-height=&quot;310&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 9-10. 충돌 방지 계층 패턴을 사용하여 통합 모델을 단순화&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[애그리게이트 연동]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트가 시스템의 나머지 부분과 통신하는 방법 중 하나는 &lt;b&gt;도메인 이벤트를 발행하는&lt;/b&gt; 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 어떻게 도메인 이벤트가 메시지 버스에 발행될까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;아웃박스&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아웃박스 패턴(그림 9-11)은 다음 알고리즘을 사용하여 도메인 이벤트의 안정적인 발행을 보장한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;업데이트된 애그리게이트의 상태와 새 도메인 이벤트는 모두 동일한 원자성 트랜잭션으로 커밋한다.&lt;/li&gt;
&lt;li&gt;메시지 릴레이는 데이터베이스에서 새로 커밋된 도메인 이벤트를 가져온다.&lt;/li&gt;
&lt;li&gt;릴레이는 도메인 이벤트를 메시지 버스에 발행한다.&lt;/li&gt;
&lt;li&gt;성공적으로 발행되면 릴레이는 이벤트를 데이터베이스에서 발행한 것으로 표시하거나 완전히 삭제한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;37.png&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;294&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Lvuo6/dJMcajgA9pO/MkIpvs51R3Vc8v2eF0sNK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Lvuo6/dJMcajgA9pO/MkIpvs51R3Vc8v2eF0sNK0/img.png&quot; data-alt=&quot;그림 9-11. 아웃박스 패턴&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Lvuo6/dJMcajgA9pO/MkIpvs51R3Vc8v2eF0sNK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLvuo6%2FdJMcajgA9pO%2FMkIpvs51R3Vc8v2eF0sNK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;557&quot; height=&quot;294&quot; data-filename=&quot;37.png&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;294&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 9-11. 아웃박스 패턴&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관계형 데이터베이스를 사용할 때 그림 9-12와 같이 두 개의 테이블에 원자적으로 커밋하고, 메시지를 저장하기 위한 전용 테이블을 사용하는 데이터베이스 기능을 활용하는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;38.png&quot; data-origin-width=&quot;1032&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9n6bO/dJMcabiCxwG/w3LPneURTMG17LbENbb5J0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9n6bO/dJMcabiCxwG/w3LPneURTMG17LbENbb5J0/img.png&quot; data-alt=&quot;그림 9-12. 아웃박스 테이블&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9n6bO/dJMcabiCxwG/w3LPneURTMG17LbENbb5J0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9n6bO%2FdJMcabiCxwG%2Fw3LPneURTMG17LbENbb5J0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1032&quot; height=&quot;242&quot; data-filename=&quot;38.png&quot; data-origin-width=&quot;1032&quot; data-origin-height=&quot;242&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 9-12. 아웃박스 테이블&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 다중 문서 트랜잭션을 지원하지 않는 NoSQL 를 사용한다면 (메시지 버스로) 전달될 도메인 이벤트는 애그리게이트 레코드에 포함되어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768105191447&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	&quot;campaign-id&quot;: &quot;3414e3r4-asdf134-aedr&quot;,
	&quot;state&quot;: {
		&quot;name&quot;: &quot;Autumn 2017&quot;,
		&quot;publishing-state&quot;: &quot;DEACTIVATED&quot;,
		&quot;ad-locations&quot;: [
		...
		]
	...
	},
	&quot;outbox&quot;: [
		{
			&quot;campaign-id&quot;: &quot;3414e3r4-asdf134-aedr&quot;,
			&quot;type&quot;: &quot;campaign-deactivated&quot;,
			&quot;reason&quot;: &quot;Goals met&quot;,
			&quot;published&quot;: false
		}
	]

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;발행되지 않은 이벤트 가져오기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발행 릴레이는 &lt;b&gt;풀(pull) 기반 또는 푸시(push) 기반으로&lt;/b&gt; 새 도메인 이벤트를 가져올 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;풀:발행자 폴링&lt;/b&gt;&lt;/p&gt;
&lt;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;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;푸시:트랜잭션 로그 추적&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스의 기능을 활용하여 새 이벤트가 추가될 때마다 발행 릴레이를 호출할 수 있다.&lt;/li&gt;
&lt;li&gt;일부 관계형 데이터베이스는 트랜잭션 로그를 추적하여 업데이트/삽입에 대한 알림을 받을 수 있다.&lt;/li&gt;
&lt;li&gt;일부 NoSQL 데이터베이스는 커밋된 변경사항을 이벤트 스트림으로 노출하기도 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아웃박스 패턴은 &lt;b&gt;적어도 한번은 메시지 배달을 보장&lt;/b&gt;한다는 점에 유의하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;사가(Saga)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 애그리게이트 설계 원칙 중 하나는 &lt;b&gt;각 트랜잭션을 애그리게이트의 단일 인스턴스로 제한&lt;/b&gt;하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 여러 애그리게이트에 걸쳐 있는 비즈니스 프로세스를 구현해야 하는 경우가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 광고 캠페인이 활성화되면 캠페인의 광고 자료를 퍼블리셔에게 자동으로 제출해야 한다고 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 흐름은 광고 캠페인과 퍼블리셔라는 두 가지 비즈니스 엔티티에 걸쳐 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이들은 책임도 다르고 다른 바운디드 컨텍스트에 속한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 경우 &lt;b&gt;사가로 구현할 수 있다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사가는 오래 지속되는 비즈니스 프로세스다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 중요한 건 시간 측면이 아니라 &lt;b&gt;트랜잭션 측면에서 보는 것이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;여러 트랜잭션에 걸쳐 있는&lt;/b&gt; 비즈니스 프로세스를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사가는 실행 단계 중 하나가 실패하면 &lt;b&gt;시스템 상태를 일관되게 유지되도록 적절할 보상 조치를 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 9-13를 통해 사가의 흐름을 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;39.png&quot; data-origin-width=&quot;830&quot; data-origin-height=&quot;340&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cC7iRT/dJMcacu3tqy/0e2Dr5iTUP9cQgnorBm0QK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cC7iRT/dJMcacu3tqy/0e2Dr5iTUP9cQgnorBm0QK/img.png&quot; data-alt=&quot;그림 9-13. 사가&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cC7iRT/dJMcacu3tqy/0e2Dr5iTUP9cQgnorBm0QK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcC7iRT%2FdJMcacu3tqy%2F0e2Dr5iTUP9cQgnorBm0QK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;830&quot; height=&quot;340&quot; data-filename=&quot;39.png&quot; data-origin-width=&quot;830&quot; data-origin-height=&quot;340&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 9-13. 사가&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발행 프로세스를 구현하기 위해서 사가는 Campaign 애그리게이트로부터 CampaignActivated 이벤트를, AdPublishing 바운디드 컨텍스트로부터 PublishingConfirmed와 PublishingRejected 이벤트를 기다린다.&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;b&gt;일관성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사가 패턴이 다중 컴포넌트의 트랜잭션을 조율하기는 하지만 관련된 컴포넌트의 상태는 &lt;b&gt;궁극적으로 일관성을 갖는다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[결론]&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 장에서는 시스템 컴포넌트를 연동하기 위한 다양한 패턴을 배웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;충돌 방지 계층 또는 오픈 호스트 서비스를 구현하는데 사용할 수 있는 모델 변환 패턴부터 알아보았다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스테이트리스 모델 변환&lt;/li&gt;
&lt;li&gt;스테이트풀 모델 변환&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아웃박스 패턴은 애그리게이트의 도메인 이벤트를 발행하는 안정적인 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 프로세스 실패에 직면해도 도메인 이벤트를 항상 발행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사가 패턴은 간단한 교차 컴포넌트 비즈니스 프로세스를 구현하는데 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 이벤트에 대한 비동기식 반응과 커맨드 실행에 의존한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-end=&quot;2338&quot; data-start=&quot;2285&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;✅ Chapter 7~9 요약 섹션&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-end=&quot;318&quot; data-start=&quot;292&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;핵심 포인트 (Key Takeaways)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;899&quot; data-start=&quot;319&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;480&quot; data-start=&quot;319&quot;&gt;이벤트 소싱은 &amp;ldquo;현재 상태만 저장하는 방식&amp;rdquo;의 한계를 보완하기 위해 &lt;b&gt;모든 변경을 이벤트로 저장&lt;/b&gt;하며, 이를 통해 &lt;b&gt;상태가 만들어진 &amp;lsquo;이력/스토리&amp;rsquo;까지 복원&lt;/b&gt; 가능해진다.&lt;/li&gt;
&lt;li data-end=&quot;709&quot; data-start=&quot;481&quot;&gt;아키텍처 패턴은 &amp;ldquo;멋있음&amp;rdquo;이 아니라 &lt;b&gt;비즈니스 로직 복잡도/도메인 모델 필요성&lt;/b&gt;에 따라 선택된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;709&quot; data-start=&quot;563&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;600&quot; data-start=&quot;563&quot;&gt;계층형 아키텍처는 트랜잭션 스크립트/액티브 레코드에 적합하고&lt;/li&gt;
&lt;li data-end=&quot;635&quot; data-start=&quot;603&quot;&gt;포트&amp;amp;어댑터는 DIP 기반으로 도메인을 중심에 두며&lt;/li&gt;
&lt;li data-end=&quot;709&quot; data-start=&quot;638&quot;&gt;CQRS는 모델 책임 분리 및 이벤트 소싱과 잘 맞는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;899&quot; data-start=&quot;710&quot;&gt;컨텍스트 간 통신에서 중요한 건 &amp;ldquo;연동&amp;rdquo;이 아니라 &lt;b&gt;모델 보호&lt;/b&gt;다. 프락시/ACL/API 게이트웨이/메시지 프락시 등을 통해 &lt;b&gt;모델 변환을 수행하고&lt;/b&gt;, 공표된 언어를 사용해 내부 모델이 외부에 침식되지 않도록 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;929&quot; data-start=&quot;901&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;실무 연결 포인트 (How to apply)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1335&quot; data-start=&quot;930&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1052&quot; data-start=&quot;930&quot;&gt;&lt;b&gt;이력/감사/정산처럼 &amp;ldquo;왜 이 상태가 됐는지&amp;rdquo;가 중요한 영역&lt;/b&gt;은 이벤트 소싱이 설득력 있는 선택지가 될 수 있다. (상태 저장만으로 부족할 때)&lt;/li&gt;
&lt;li data-end=&quot;1184&quot; data-start=&quot;1053&quot;&gt;도메인 로직이 단순하면 계층형으로 충분하지만, &lt;b&gt;핵심 도메인이 커지고 규칙이 복잡해지는 순간&lt;/b&gt;부터는 포트&amp;amp;어댑터(클린/헥사)로 전환하는 게 장기적으로 유리하다.&lt;/li&gt;
&lt;li data-end=&quot;1335&quot; data-start=&quot;1185&quot;&gt;외부 연동이 많아질수록 중요한 건 &amp;ldquo;API 호출 성공&amp;rdquo;이 아니라 &lt;b&gt;내부 도메인 모델의 무결성 보호&lt;/b&gt;다. &amp;rarr; ACL/공표된 언어/API 게이트웨이는 실무에서 &amp;ldquo;확장 비용을 낮추는 방어선&amp;rdquo;이 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;1349&quot; data-start=&quot;1337&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;한 줄 인사이트&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-end=&quot;1431&quot; data-start=&quot;1350&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1431&quot; data-start=&quot;1352&quot; data-ke-size=&quot;size16&quot;&gt;DDD는 도메인을 예쁘게 모델링하는 기술이 아니라, &lt;b&gt;&amp;ldquo;도메인의 복잡도를 지키면서&amp;rdquo; 변화/연동을 운영 가능한 방식으로 설계하는 방법&lt;/b&gt;이다.&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>Book Notes</category>
      <category>ag ddd</category>
      <category>it</category>
      <category>개발</category>
      <category>개발서적</category>
      <category>개발자</category>
      <category>도메인주도설계</category>
      <category>도메인주도설계첫걸음</category>
      <category>필독서</category>
      <author>feel2</author>
      <guid isPermaLink="true">https://feel2.tistory.com/158</guid>
      <comments>https://feel2.tistory.com/158#entry158comment</comments>
      <pubDate>Sun, 11 Jan 2026 13:21:51 +0900</pubDate>
    </item>
    <item>
      <title>[개발서적] 도메인 주도 설계 첫걸음 2부(ch5~6) 요약 (1)</title>
      <link>https://feel2.tistory.com/157</link>
      <description>&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Ch5. 간단한 비즈니스 로직 구현&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;비즈니스 로직은 소프트웨어에서 &lt;b&gt;가장 중요한 부분&lt;/b&gt;이며, 애초에 소프트웨어를 &lt;b&gt;구현한는 이유&lt;/b&gt;이기도 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 하위 도메인마다 전략적 중요성과 복잡성은 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 장에서는 비즈니스 로직 코드를 모델링하고 구현하는 다양한 방법에 대해 검토해 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[트랜잭션 스크립트]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;프레젠테이션으로부터 단일 요청을 처리하는 여러 프로시저를 모아서 비즈니스 로직을 구현하라&amp;rdquo;&lt;br /&gt;- 마틴 파울러&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템의 퍼블릭 인터페이스는 그림 5-1과 같이 사용자가 실행할 수 있는 &lt;b&gt;비즈니스 트랜잭션의 모음&lt;/b&gt;으로 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 트랜잭션은 시스템에서 관리하는 정보를 검색, 수정 또는 둘 다 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 스크립트 패턴은 &lt;b&gt;프로시저를 기반&lt;/b&gt;으로 시스템의 &lt;b&gt;비즈니스 로직을 구성&lt;/b&gt;하며, 각 프로시저는 &lt;b&gt;퍼블릭 인터페이스를 통해&lt;/b&gt; &lt;b&gt;시스템 사용자가 실행하는 작업을 구현&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;689&quot; data-origin-height=&quot;254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7AyYh/dJMcafk0Z26/FQONdOMFwFchy7ok5wt0Rk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7AyYh/dJMcafk0Z26/FQONdOMFwFchy7ok5wt0Rk/img.png&quot; data-alt=&quot;그림 5-1. 트랜잭션 스크립트 인터페이스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7AyYh/dJMcafk0Z26/FQONdOMFwFchy7ok5wt0Rk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7AyYh%2FdJMcafk0Z26%2FFQONdOMFwFchy7ok5wt0Rk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;689&quot; height=&quot;254&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;689&quot; data-origin-height=&quot;254&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 5-1. 트랜잭션 스크립트 인터페이스&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;구현&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 프로시저는 간단하고 쉬운 &lt;b&gt;절차지향 스크립트(procedural script)로 구현&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저장 장치와 연동하기 위해 얇은 추상화 계층을 사용할 수 있지만 DB에 직접 접근도 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 프로시저가 구현해야 하는 유일한 요구사항은 &lt;b&gt;트랜잭션 동작이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 작업은 &lt;b&gt;성공하거나 실패할 수 있지만, 유효하지 않은 상태를 만들면 안된다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 실행에 실패하더라도 시스템은 오류가 발생할 때까지 변경사항을 롤백하거나 보상조치를 실행하여 &lt;b&gt;일관성을 유지해야 한다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 JSON 파일들을 XML 파일로 변환하는 트랜잭션 스크립트의 예다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768102882155&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;DB.StartTransaction();

var job = DB.LoadNextJob();
var json = LoadFile(job.Source);
var xml = ConvertJsonToXml(json);
WriteFile(job.Destination, xml.ToString());
DB.MarkJobAsCompleted(job);

DB.commit()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;그렇게 쉽지 않다!&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 스크립트 패턴은 다음 장에서 배우게 될 &lt;b&gt;고급 비즈니스 로직 구현 패턴의 기반&lt;/b&gt;이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 스크립트를 올바르게 구현하지 못해 발생하는 데이터 손상의 실제 사례 세 가지를 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;트랜잭션 동작 구현 실패&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 동작 구현에 실패한 간단한 예는 &lt;b&gt;전체를 아우르는 트랜잭션 없이&lt;/b&gt; 여러 업데이트를 하는 경우다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Users 테이블의 레코드를 업데이트하고 VisitsLog 테이블에 레코드를 삽입하는 다음 메서드를 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768102942321&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class LogVisit
{
	...
	
	public void Execute(Guid userId, DataTime visitedOn) {
	  _db.Execute(&quot;UPDATE Users Set last_visit=@p1 WHERE user_id=@p2&quot;,
	  visitedOn, userId);
	  _db.Execute(@&quot;INSERT INTO VisitsLog(user_id, visit_date)
	  VALUES(@p1, @p2)&quot;, userId, visitedOn);
	
	}
}&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;만약 Users 테이블에 레코드가 업데이트가 되고, 로그 레코드를 성공적으로 추가하기 전에 문제가 생긴다면 시스템이 일관된 상태가 되지 않게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 두 데이터 변경을 모두 포함하는 트랜잭션을 만들어서 해결할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768102966243&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class LogVisit
{
	...
	
	public void Execute(Guid userId, DataTime visitedOn) {
	{
		try
			{
				_db.StartTransaction();
				_db.Execute(&quot;UPDATE Users Set last_visit=@p1 WHERE user_id=@p2&quot;,
			  visitedOn, userId);
			  _db.Execute(@&quot;INSERT INTO VisitsLog(user_id, visit_date)
			  VALUES(@p1, @p2)&quot;, userId, visitedOn);
			  _db.Commit();
			} catch {
				_db.Rollback();
				throw;
				}
			}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;분산 트랜잭션&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최신 분산 시스템에서는 데이터베이스의 데이터를 변경한 다음 메시지 버스에 메시지를 발행하여 시스템의 다른 컴포넌트에 변경사항을 알리는 것이 일반적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 예에서 로그를 기록하는 대신 메시지 버스에 메시지를 발행한다고 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768102988158&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class LogVisit
{
	...
	
	public void Execute(Guid userId, DataTime visitedOn) {
	  _db.Execute(&quot;UPDATE Users Set last_visit=@p1 WHERE user_id=@p2&quot;,
	  visitedOn, userId);
	  _messageBus.Publish(&quot;VISITS_TOPIC&quot;,
	  new { UserId = userId, VisitDate = visitedOn });
	}
}&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;앞의 예에서와 같이 Users 테이블에 레코드가 업데이트가 되고, 메시지를 보내기 전에 발생한 모든 오류는 시스템 상태를 손상 시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안타깝게도 문제를 수정하는 것은 쉽지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 해결하기 위해 8장에서는 &lt;b&gt;CQRS 패턴&lt;/b&gt;, 9장에서는 &lt;b&gt;아웃박스 패턴&lt;/b&gt;을 소개한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;암시적 분산 트랜잭션&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 믿을 수 없을 정도로 간단한 방법을 생각해보라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103009081&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class LogVisit
{
	...
	
	public void Execute(Guid userId) {
	  _db.Execute(&quot;UPDATE Users Set visits=visits+1 WHERE user_id=@p1&quot;,
	  userId);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 예제처럼 마지막 방문 날짜를 추적하는 대신 이 메서드는 &lt;b&gt;각 사용자에 대한 방문 카운터를 유지&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드를 호출하면 해당 카운터의 값이 1 증가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 이것은 여전히 잠재적으로 일관성 없는 상태로 이어질 수 있는 분산 트랜잭션이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 예제는 그럼 5-2에서 보듯이 메서드를 호출한 외부 프로세스와 DB에 정보를 전달하기 때문에 분산 트랜잭션을 구성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;689&quot; data-origin-height=&quot;176&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sZ01X/dJMcahb3f4l/4gM9LIKdXyvVUKwVIQsY30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sZ01X/dJMcahb3f4l/4gM9LIKdXyvVUKwVIQsY30/img.png&quot; data-alt=&quot;그림 5-2. 데이터를 업데이트하고 호출하는 자에게 작업의 성공 또는 실패를 알리는 LogVisit 작업&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sZ01X/dJMcahb3f4l/4gM9LIKdXyvVUKwVIQsY30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsZ01X%2FdJMcahb3f4l%2F4gM9LIKdXyvVUKwVIQsY30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;689&quot; height=&quot;176&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;689&quot; data-origin-height=&quot;176&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 5-2. 데이터를 업데이트하고 호출하는 자에게 작업의 성공 또는 실패를 알리는 LogVisit 작업&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;execute 메서드가 void라서 데이터를 반환하지 않지만 작업이 성공 또는 실패했는지 여부는 여전히 호출자에게 전달된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드는 성공했지만 호출자에게 결과를 전달하는데 실패할 경우 어떻게 될까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자는 실패를 가정하고 LogVisit을 다시 호출할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대체로 1이 아닌 2로 증가할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 예제에서 트랜잭션 동작을 보장하는 한 가지 방법은 &lt;b&gt;작업을 멱등성으로 만드는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;같은 요청을 여러 번 하더라도 그 결과는 매번 동일하게 만드는 것이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 사용자에게 카운터 값을 전달하도록 요청한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 작업을 여러 번 실행하더라도 최종 결과는 변하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103059535&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class LogVisit
{
	...
	
	public void Execute(Guid userId, long visits) {
	  _db.Execute(&quot;UPDATE Users Set visits= @p1 WHERE user_id=@p2&quot;,
	  visits, userId);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 다른 해결 방법은 &lt;b&gt;낙관적 동시성 제어&lt;/b&gt;를 사용하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LogVisit 작업을 호출하기 전에 호출자는 카운터의 현재 값을 읽고 매개변수로 LogVisit에 전달했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LogVisit은 호출자가 처음 읽은 값과 동일한 경우에만 카운터 값을 업데이트 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103077577&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class LogVisit
{
	...
	
	public void Execute(Guid userId, long expectedVisits) {
	  _db.Execute(&quot;UPDATE Users Set visits=visits+1 
	  WHERE user_id=@p1, visits = @p2&quot;,
	  userId, visits);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;트랜잭션 스크립트를 사용하는 경우&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 스크립트 패턴은 비즈니스 로직이 단순한 절차적 작업처럼 &lt;b&gt;매우 간단한 문제 도메인에 효과적&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 ETL(추출-변환-적재) 작업에서 각 작업은 원천 시스템에서 데이터를 추출하고 변환 로직을 적용하여 데이터를 다른 형식으로 변환하고 결과를 목적 시스템에 적재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 프로세스는 다음 그림에 나와 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;559&quot; data-origin-height=&quot;131&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l5WEf/dJMcah4cdSc/VetKGebkkoIsFZwDUSzhsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l5WEf/dJMcah4cdSc/VetKGebkkoIsFZwDUSzhsk/img.png&quot; data-alt=&quot;그림 5-3. 추출-변환-적재 데이터 흐름&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l5WEf/dJMcah4cdSc/VetKGebkkoIsFZwDUSzhsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl5WEf%2FdJMcah4cdSc%2FVetKGebkkoIsFZwDUSzhsk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;559&quot; height=&quot;131&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;559&quot; data-origin-height=&quot;131&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 5-3. 추출-변환-적재 데이터 흐름&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 스크립트 패턴은 정의상 &lt;b&gt;비즈니스 로직이 단순한 지원 하위 도메인의 경우&lt;/b&gt; 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 스크립트 패턴의 주요 장점은 &lt;b&gt;단순함이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 핵심 하위 도메인처럼 &lt;b&gt;비즈니스 로직이&lt;/b&gt; &lt;b&gt;복잡한 경우&lt;/b&gt; 사용해서는 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[액티브 레코드]&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;데이터베이스 테이블 또는 뷰의 행을 감싸고 데이터베이스 접근을 캡슐화하고 해당 데이터에 도메인 로직을 추가하는 오브젝트&amp;rdquo; - 마틴 파울러&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 스크립트 패턴과 마찬가지로 액티브 레코드는 &lt;b&gt;비즈니스 로직이 단순한 경우&lt;/b&gt; 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 액티브 레코드는 &lt;b&gt;좀 더 복잡한 자료구조에서도&lt;/b&gt; 비즈니스 로직이 작동할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 그럼 5-4와 같이 더 복잡한 오브젝트 트리와 계층 구조를 가질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;559&quot; data-origin-height=&quot;237&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3SNdx/dJMcai23iHV/qj3ktD4kEEz4VexufsNfNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3SNdx/dJMcai23iHV/qj3ktD4kEEz4VexufsNfNK/img.png&quot; data-alt=&quot;그림 5-4. 일대다 및 다대다 관계가 있는 더 복잡한 데이터 모델&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3SNdx/dJMcai23iHV/qj3ktD4kEEz4VexufsNfNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3SNdx%2FdJMcai23iHV%2Fqj3ktD4kEEz4VexufsNfNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;559&quot; height=&quot;237&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;559&quot; data-origin-height=&quot;237&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 5-4. 일대다 및 다대다 관계가 있는 더 복잡한 데이터 모델&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;구현&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 이 패턴은 &lt;b&gt;액티브 레코드라는 전용 객체를 사용하여&lt;/b&gt; 복잡한 자료구조를 표현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조 외에도 CRUD도 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 결과, 액티브 레코드 객체는 &lt;b&gt;객체 관계 매핑(ORM) 또는 다른 데이터 접근 프레임워크와도&lt;/b&gt; 관련이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 액티브 레코드는 &lt;b&gt;데이터 접근 로직을 구현&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 예제를 살펴보자.&lt;/p&gt;
&lt;pre id=&quot;code_1768103156296&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class CreateUser
{
	...
	public void Execute(userDetails)
	{
		try
		{
			_db.StartTransaction();
			
			var user = new User();
			user.Name = userDetails.Name;
			user.Email = userDetails.Email;
			user.Save();
			_db.Commit();
		}
		catch {
			_db.Rollback();
			throw ;
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴의 목적은 메모리 상의 객체를 데이터베이스 스키마에 매핑하는 복잡성을 숨기는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영속성을 담당하는 것 외에도 액티브 레코드 객체에는 &lt;b&gt;비즈니스 로직이 포함될 수 있다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 액티브 레코드 객체의 고유한 기능은 &lt;b&gt;자료구조와 동작(비즈니스 로직)의 분리&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 액티브 레코드의 필드에는 외부 프로시저가 상태를 수정할 수 있게 퍼블릭 getter와 setter가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;액티브 레코드를 사용하는 경우&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;액티브 레코드는 본질적으로 데이터베이스에 대한 접근을 최적화하는 트랜잭션 스크립트이기 때문에 이 패턴은 기껏해야 사용자 입력의 유효성을 검증하는 &lt;b&gt;CRUD 작업과 같은 비교적 간단한 비즈니스 로직만 지원&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 지원 하위 도메인, 일반 하위 도메인과 외부 솔루션의 연동, 모델 변환 작업에 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;액티브 레코드 패턴은 &lt;b&gt;빈약한 도메인 모델 안티패턴&lt;/b&gt;이라고도 하며, 다시 말해 부적절하게 설계된 도메인 모델이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[실직적인 접근 방법]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비록 비즈니스 데이터가 중요하고 설계 및 개발되는 코드의 무결성도 보호해야 하지만, &lt;b&gt;실용적인 접근 방식이 더 바람직한 경우가 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 대규모로 데이터를 다루는 시스템에서는 데이터의 일관성 보장이 덜 엄격할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, IoT 장치에서 매일 수십억 개의 이벤트를 수집하는 시스템을 구축한다고 가정해 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트의 0.001%가 중복되거나 손실되면 큰일날까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항상 그렇듯이 보편적인 법칙은 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그것은 작업 중인 &lt;b&gt;비즈니스 도메인에 달려있다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[결론]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 장에서는 비즈니스 로직을 구현하기 위해 두 가지 패턴을 배웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;트랜잭션 스크립트&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 패턴은 시스템 작업을 간단하고 쉬운 절차지향 스크립트로 구성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;액티브 레코드&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비즈니스 로직이 단순하지만 복잡한 자료구조에서 작동하는 경우 해당 자료구조를 액티브 레코드로 구현할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Ch6. 복잡한 비즈니스 로직 다루기&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이번장에서는 복잡한 비즈니스 로직에 사용되는 도메인 모델 패턴을 소개한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[배경]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 스크립트와 액티브 레코드 패턴 모두 마틴 파울러의 책 &amp;lsquo;&lt;b&gt;엔터프라이즈 애플리케이션 아키텍처 패턴&amp;rsquo;&lt;/b&gt; 에서 처음 소개됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에반스는 2011년에 &lt;b&gt;&amp;lsquo;도메인주도 설계&amp;rsquo;&lt;/b&gt; 를 집필했는데, 비즈니스 도메인의 하위 모델과 코드를 긴밀하게 연결 짓는데 쓰이는 aggregate, value object, repository 등과 같은 패턴을 제시했다.&lt;/p&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;lsquo;전술적 도메인 주도 설계(tactical domain-driven-design)&amp;rsquo;로 불린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴이 &amp;lsquo;&lt;b&gt;도메인 모델&lt;/b&gt;&amp;rsquo;이고, 애그리게이트와 밸류 오브젝트는 그 &lt;b&gt;구성요소다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[도메인 모델]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 모델 패턴은 &lt;b&gt;복잡한 비즈니스 로직을 다루기 위한 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CRUD 인터페이스 대신 &lt;b&gt;복잡한 상태 전환, 항상 보호해야 하는 규칙인 비즈니스 규칙과 불변성&lt;/b&gt;을 다룬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;헬프데스크 시스템을 구현한다고 가정해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 다음 지원 티켓의 수명주기를 다루는 로직을 설명한 요구사항에서 발췌한 내용을 살펴보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;고객은 직면한 문제를 설명하는 지원 티켓을 연다.&lt;/li&gt;
&lt;li&gt;고객과 지원 할당된 에이전트 모두 메시지를 추가하고 모든 내용은 지원 티켓에서 관리된다.&lt;/li&gt;
&lt;li&gt;각 티켓은 낮음, 중간 ,높음, 긴급의 우선순위를 갖는다.&lt;/li&gt;
&lt;li&gt;에이전트는 티켓의 우선순위에 따른 SLA(응답 제한 시간) 내에 해법을 제시해야 한다.&lt;/li&gt;
&lt;li&gt;할당된 에이전트가 응답 제한 시간 내에 응답하지 못하면 고객은 티켓을 에이전트의 상위 관리자에게 보고할 수 있다.&lt;/li&gt;
&lt;li&gt;티켓이 상위 관리자에게 보고되면 에이전트의 응답 제한 시간이 33% 줄어든다.&lt;/li&gt;
&lt;li&gt;에이전트가 상부 보고된 티켓의 응답 제한 시간의 절반이 지나기 전에 티켓을 열람하지 않으면 자동으로 다른 에이전트에게 할당된다.&lt;/li&gt;
&lt;li&gt;할당된 에이전트의 질문에 고객이 7일 이내에 응답하지 않으면 티켓은 자동으로 닫힌다.&lt;/li&gt;
&lt;li&gt;상부 보고된 티켓은 자동으로 또는 할당된 에이전트에 의해 닫힐 수 없고, 고객 또는 에이전트의 매니저만 닫을 수 있다.&lt;/li&gt;
&lt;li&gt;고객은 티켓이 닫힌 지 7일 이내에 닫힌 티켓을 다시 열 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 같은 요구사항은 다양한 규칙 간에 &lt;b&gt;그물 같은 의존성을 형성&lt;/b&gt;하고, 모든 규칙은 &lt;b&gt;지원 티켓의 수명주기 관리 로직에 영향을 준다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 액티브 레코드 객체를 사용하여 로직을 구현한다면 로직이 중복되거나 일부 비즈니스 규칙이 잘못 구현되어 시스템에 상태를 손상시키기 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;구현&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;도메인 모델&lt;/b&gt;은 &lt;b&gt;행동과 데이터 모두를 포함하는&lt;/b&gt; 도메인의 객체 모델이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDD의 전술 패턴인 애그리게이트, 밸류 오브젝트, 도메인 이벤트, 도메인 서비스는 &lt;b&gt;모두 객체 모델의 구성요소다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 같은 모든 패턴은 &lt;b&gt;비즈니스 로직을 최우선으로 둔다는&lt;/b&gt; 공통 관심사가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;복잡성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 비즈니스 로직은 이미 본질적으로 &lt;b&gt;복잡하므로&lt;/b&gt;, 모델링에 사용되는 객체가 모델에 조금이라도 우발적 복잡성을 추가하면 안 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델에는 데이터베이스 또는 외부 시스템 구성 요소의 호출 구현 같은 &lt;b&gt;인프라 또는 기술적인 관심사를 피해야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 같은 제약에 따르면 모델의 객체는 &lt;b&gt;plain old object(자바의 경우 POJO)&lt;/b&gt;가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 POO는 인프라 또는 프레임워크에 의지하지 않고 비즈니스 로직을 구현하는 객체다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;유비쿼터스 언어&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 모델의 객체가 기술적 관심사가 아닌 비즈니스 로직에 집중하게 하면 바운디드 컨텍스트에서 사용하는 유비쿼터스 언어의 용어를 따르기 쉬워진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이 패턴은 &lt;b&gt;코드에서 유비쿼터스 언어를 사용하게 하고 도메인 전문가의 멘탈 모델을 따르게 된다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;구성요소&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 벨류 오브젝트, 에그리게이트, 도메인 서비스와 같은 DDD에서 제공하는 도메인 모델의 구성요소와 전술적 패턴을 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;밸류 오브젝트(Value Object)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;밸류 오브젝트는 예를 들어, 색(color)처럼 복합적인(composition) 값에 의해 식별되는 객체다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103360480&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Color
{
	int _red;
	int _green;
	int _blue;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빨강, 초록, 파랑의 세 필드 값이 복합적으로 색을 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필드 중 하나의 값이 바뀌면 새로운 색이 탄생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 값을 갖는 두 개 이상의 색은 존재하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 같은 색의 두 인스턴스는 반드시 같은 값을 갖는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;유비쿼터스 언어&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언어의 표준 라이브러리에 포함된 문자열(string), 정수(integer), 딕셔너리(dictionary) 같은 원시 데이터 타입에 전적으로 의존해서 비즈니스 도메인의 개념을 표현하는 것은 &lt;b&gt;원시 집착 코드 징후&lt;/b&gt;로 알려져 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 예제를 살펴보자.&lt;/p&gt;
&lt;pre id=&quot;code_1768103394124&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Person
{
	private int _id;
	private string _firstName;
	private string _lastName;
	private string _email;
	private string _phone;
	
	public Person(...){...}

}

static void Main(string[] args) 
{
	var dave = new Person(
		id: 3066,
		firstName: &quot;Dave&quot;,
		lastName: &quot;Ancelovici&quot;,
		email: &quot;dave@gogle.com&quot;
		phone: &quot;05122321424&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;Person 클래스 구현에서 값의 대부분은 문자열 타입이고, 관례에 따라 값이 할당되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 같은 방식에는 몇 가지 설계 위험이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 &lt;b&gt;유효성 검사 로직이 중복되기 쉽다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘째, 값이 사용되기 전에 &lt;b&gt;유효성 검사 로직을 호출하기 어렵다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 다른 엔지니어가 코드베이스를 개선하는 것과 같은 &lt;b&gt;유지보수가 더 어렵다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 다음과 같이 밸류 오브젝트를 사용하는 설계를 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103413268&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Person
{
	private PersonId _id;
	private Name _firstName;
	private EmailAddress _email;
	private PhoneNumber _phone;
	
	public Person(...){...}

}

static void Main(string[] args) 
{
	var dave = new Person(
		id: new PersonId(3066),
		firstName: new Name(&quot;Dave&quot;, &quot;Ancelovici&quot;),
		email: Email.Parse(&quot;dave@gogle.com&quot;),
		phone: PhoneNumber.Parse(&quot;05122321424&quot;)
	)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 명료성이 향상됐음을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘째, 유효성 검사 로직이 밸류 오브젝트 자체에 들어 있어 값을 할당하기 전에 유효성 검사를 할 필요가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 중요한 점은 밸류 오브젝트를 사용하면 코드에서 유비쿼터스 언어를 사용하게 하므로 &lt;b&gt;코드에서 비즈니스 도메인의 개념을 표현하게 된다는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름(Name), 전화번호(phone Number), 이메일(email)과 같은 개념을 VO로 표현할 때 구현된 시스템의 타입이 얼마나 더 풍부해지고 사용하기에 직관적인지 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;height 변수를 정수 타입으로 했을 때보자 Height 밸류 오브젝트로 구현하면 &lt;b&gt;의도가 명확해지고 특정 도량형에 종속되지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 Height VO를 미터법 또는 영국식 단위를 모두 사용하여 초기화할 수 있어서 다른 단위로 변환하거나 문자열로 표현, 다른 단위의 값과 비교하는 것이 쉬워진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103433270&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var heightMetric = Height.Metric(180);
var heightImperial = Height.Imperial(5, 3);

var string1 = heightMetric.ToString(); // &quot;180com&quot;
var string2 = heightImperial.ToString(); // &quot;5 feet 3 inches&quot;
var string3 = heightMetric.ToImperial().ToString(); // &quot;5 feet 11 inches&quot;

var firstIsHigher = heightMetric &amp;gt; heightImperial; // true&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;PhoneNumber VO의 경우 문자열 값의 파싱, 유효성 검사, 그리고 소속된 국가 또는 유선/무선 전화번호 유형과 같은 다양한 전화번호 속성을 추출하는 로직을 담을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103445205&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var phone = PhoneNumber.Parse(&quot;+3512433433&quot;); 
var country = phone.Country; // &quot;BG&quot;
var phoneType = phone.PhoneType; // &quot;MOBILE&quot;
var isValid = PhoneNumber.IsValid(&quot;+921252423213&quot;); // false&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;밸류 오브젝트는 불변의 객체로 구현되므로 밸류 오브젝트에 있는 필드가 하나라도 바뀌면 다른 값이 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직, 밸류 오브젝트의 필드 중 하나라도 바뀌면 개념적으로 &lt;b&gt;다른 인스턴스가 생성된다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러므로 다음 예제에서 MixWith 메서드에서 새로운 값을 반환하게 하듯이, &lt;b&gt;새로운 인스턴스를 생성해서 반환하게 해야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103471843&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Color
{
	public readonly byte Red;
	public readonly byte Green;
	public readonly byte Blue;
	
	public Color(byte r, byte g, byte b)
	{
		this.Red = r;
		this.Green = g;
		this.Blue = b;
	
	}
	
	public Color MixWith(Color other)
	{
		return new Color(
			r:(byte) Math.Min(this.Red + other.Red, 255),
			g:(byte) Math.Min(this.Green + other.Green, 255),
			b:(byte) Math.Min(this.Blue + other.Blue, 255),
	} 
...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;밸류 오브젝트의 동일성은 id 필드나 참조 대신 값을 기반으로 하므로 &lt;b&gt;동일성 검사 함수를 오버라이딩해서 적절히 구현하는 것이 중요하다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 C#으로 구현한 예제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103489313&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Color
{
	...
	
	public ovverride bool Equals(object obj)
	{
		var other = obj as Color;
		return other != null &amp;amp;&amp;amp;
			this.Red == other.Red &amp;amp;&amp;amp;
			this.Green == other.Green &amp;amp;&amp;amp;
			this.Blue = other.Blue;
	
	}
	
	public static bool operator == (Color lhs, Color rhs)
	{
		if (Object.ReferenceEquals(lhs, null)) {
			return Object.ReferenceEquals(rhs, null);
		}
		return lhs.Equals(rhs);
	}
	
	public static bool operator != (Color lhs, Color rhs)
	{
		return !(lhs == rhs);
	}
	
	public override int GetHashCode()
	{
		return ToSTring().GethashCode();
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;밸류 오브젝트를 사용하는 경우&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 말해 밸류 오브젝트를 &lt;b&gt;가능한 모든 경우에 사용하는 것이 좋다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VO는 &lt;b&gt;코드의 표현력을 높여주고&lt;/b&gt; &lt;b&gt;분산되고 쉬운 비즈니스 로직을 한데 묶어줄 뿐만 아니라 코드를 더욱 안전하게 해준다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 VO는 불변이기 때문에 내포된 동작은 부작용과 동시성 문제가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경험상 비즈니스 도메인 관점에서 유용한 법칙은 다른 객체의 속성을 표현하는 도메인의 요소에 VO를 사용하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VO를 적용한 다른 대표적인 예로는 다양한 상태, 비밀번호, 돈처럼 가치를 표현하는 모든 화폐 등이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;엔티티&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티는 밸류 오브젝트와 정반대다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티는 다른 엔티티 인스턴스와 구별하기 위한 &lt;b&gt;명시적인 식별 필드가 필요하다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 클래스를 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103529826&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Person
{
	public Name Name (get; set; )
	
	public Person(Name name)
	{
		this.Name = name;
	}
}&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;이 클래스는 한 개의 밸류 오브젝트인 name을 가지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 다른 사람이 정확히 같은 이름을 가질 수 있기 때문에 이 설계는 최적이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 식별 필드가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103540144&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Person
{
	public readonly PersonId Id;
	public Name Name (get; set; )
	
	public Person(PersonId id, Name name)
	{
		this.Id = id;
		this.Name = name;
	}
}&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;PersonId는 밸류 오브젝트로, 비즈니스 도메인에서 모든 기본 데이터 타입을 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 Id 필드는 GUID, 숫자, 문자열, 또는 사회 보장 번호와 같은 특정 도메인의 값일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;식별 필드의 핵심 요구사항은 &lt;b&gt;각 엔티티의 인스턴스마다 고유해야 한다는 것이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 6-2의 사람이 그 예다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;436&quot; data-origin-height=&quot;164&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kyJdQ/dJMcabJHo64/mBx6zvhbFBsmGtu8bBNdmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kyJdQ/dJMcabJHo64/mBx6zvhbFBsmGtu8bBNdmk/img.png&quot; data-alt=&quot;그림 6-2. 명시적인 식별자 필드 도입&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kyJdQ/dJMcabJHo64/mBx6zvhbFBsmGtu8bBNdmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkyJdQ%2FdJMcabJHo64%2FmBx6zvhbFBsmGtu8bBNdmk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;436&quot; height=&quot;164&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;436&quot; data-origin-height=&quot;164&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 6-2. 명시적인 식별자 필드 도입&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;밸류 오브젝트와는 반대로 엔티티는 불변이 아니고 &lt;b&gt;변할 것으로 예상된다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 다른 차이점은 밸류 오브젝트는 엔티티의 속성을 설명한다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티는 모든 비즈니스 도메인의 &lt;b&gt;필수 구성요소다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티는 단독으로 구현하지 않고 &lt;b&gt;애그리게이트 패턴의 컨텍스트에서만 엔티티를 구현한다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;애그리게이트&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트는 &lt;b&gt;엔티티&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 명시적인 식별 필드가 필요하고, 인스턴스의 생애 주기 동안 상태가 변할 것으로 예상된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 애그리게이트는 &lt;b&gt;단순한 엔티티가 아닌 그 이상이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴은 &lt;b&gt;데이터의 일관성을 유지하기 위해&lt;/b&gt; 해결해야 할 과제가 있다는 의미도 포함된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;일관성 강화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트의 상태는 변형될 수 있으므로 데이터가 손상될 수 있는 여러 경로가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터의 일관성을 강화하려면 &lt;b&gt;애그리게이트 주변에 명확한 경계를 설정&lt;/b&gt;해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현 관점에서 보면 데이터의 일관성은 &lt;b&gt;애그리게이트의 비즈니스 로직을 통해서만&lt;/b&gt; 상태를 변경하게 변경해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트의 퍼블릭 인터페이스로 노출된 &lt;b&gt;상태 변경 메서드&lt;/b&gt;는 &amp;lsquo;&lt;b&gt;어떤 것을 지시하는 명령&lt;/b&gt;&amp;rsquo;을 뜻하는 의미에서 &lt;b&gt;커맨드&lt;/b&gt;라고도 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커맨드는 &lt;b&gt;두가지 방식&lt;/b&gt;으로 구현가능 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째, 애그리게이트 객체에 평범한 퍼블릭 메서드로 구현하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103613549&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Ticket
{
	...
	
	public void AddMessage(UserId from, string body)
	{
		var message = new Message(from, body);
		_messages.Append(message);
	
	}
	...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 방법으로는 커맨드의 실행에 필요한 모든 입력값을 포함하는 파라미터 객체로 표현하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103624181&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Ticket
{
	...
	
	public void Execute(AddMessage cmd)
	{
		var message = new Message(cmd.from, cmd.body);
		_messages.Append(message);
	}
	...

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 방식으로 구현할지는 선호도의 문제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필자는 명시적으로 커맨드 구조를 정의해서 다형적으로 관련 Execute 메서드에 전달하는 것을 선호한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트의 퍼블릭 인터페이스는 &lt;b&gt;입력값의 유효성을 검사&lt;/b&gt;하고, &lt;b&gt;관련된 모든 비즈니스 규칙과 불변성을 강화하는 것을 담당&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 이러한 엄격한 경계는 애그리게이트와 &lt;b&gt;관련된 모든 비즈니스 로직은 애그리게이트 자체에서 구현&lt;/b&gt;되게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 애그리게이트에서 애플리케이션 계층의 조율 동작을 좀 더 단단하게 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 말해, &lt;b&gt;조율 동작에서 해야 할 모든 일은 결국 애그리게이트의 현재 상태를 적재해서 필요한 동작을 수행하고, 수정된 상태를 저장한 후 오퍼레이션의 결과를 호출자에게 반환하는 것이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103646653&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public ExecutionResult Escalte(TicketId id, EscalationReason reason)
{
	try
	{
		var ticket = _ticketRepository.Load(id);
		var cmd = new Escalate(reason);
		ticket.Execute(cmd);
		_ticketRepository.Save(ticket);
		return ExecutionResult.Success();
	}
	catch (ConcurrencyException ex)
	{
		return ExecutionResult.Error(ex);
	}
}&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;위의 코드에서 catch 절을 주목하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트 상태의 &lt;b&gt;일관성을 유지하는 것이 중요하다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러므로 여러 프로세스가 동시에 동일한 애그리게이트를 갱신하려고할 때, 첫번째 트랜잭션이 커밋한 변경을 나중의 트랜잭션이 은연 중에 덮어쓰지 않게 해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러므로 애그리게이트를 저장하는 데이터베이스는 동시성 관리를 지원해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 간단한 형태는 매번 갱신할 때마다 증가하는 버전 필드를 애그리게이트에서 관리하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103663738&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Ticket
{
	TicketId _id;
	int _version;
	...
}&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 data-token-index=&quot;1&quot;&gt;처음 읽었던 원본의 버전과 동일한지 확인해야 한다&lt;/span&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103675827&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;UPDATE tickets
SET ticket_status = @new_status,
agg_version = agg_version + 1
WHERE ticket_id=@id and agg_version=@expected_version;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;트랜잭션 경계&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트의 상태는 자신의 비즈니스 로직을 통해서만 수정될 수 있기 때문에 애그리게이트가 &lt;b&gt;트랜잭션 경계의 역할을 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 애그리게이트 상태 변경은 &lt;b&gt;원자적인 단일 오퍼레이션으로&lt;/b&gt; 트랜잭션을 처리해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션별로 하나의 애그리게이트 인스턴스만 갖게 제한하면, 애그리게이트의 경계가 &lt;b&gt;비즈니스 도메인의 불변성과 규칙을 따르도록 신중히 설계하게 된다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 만약 동일한 트랜잭션에서 여러 객체를 수정해야 한다면 어떻게 해야 할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;엔티티 계층&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 장의 초반부에 논의했듯이, 엔티티는 독립적 패턴이 아닌 &lt;b&gt;애그리게이트의 일부로서만&lt;/b&gt; 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 엔티티와 애그리게이트의 근본적인 차이점을 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 객체가 하나의 트랜잭션 경계를 공유하는 비즈니스 시나리오가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, &lt;b&gt;둘 다 동시에 변경되거나&lt;/b&gt; &lt;b&gt;객체 하나가 다른 객체의 상태에 의존하는&lt;/b&gt; 비즈니스 규칙이 될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDD에서 비즈니스 도메인이 시스템의 설계를 주도해야 한다고 규정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트도 마찬가지다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;355&quot; data-origin-height=&quot;195&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AulmY/dJMcacV7eJu/G2BMeH40MBc89GKNuBLmR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AulmY/dJMcacV7eJu/G2BMeH40MBc89GKNuBLmR1/img.png&quot; data-alt=&quot;그림 6-3. 엔티티 계층과 유사한 애그리게이트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AulmY/dJMcacV7eJu/G2BMeH40MBc89GKNuBLmR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAulmY%2FdJMcacV7eJu%2FG2BMeH40MBc89GKNuBLmR1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;355&quot; height=&quot;195&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;355&quot; data-origin-height=&quot;195&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 6-3. 엔티티 계층과 유사한 애그리게이트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 6-3처럼 여러 객체의 변경을 원자적인 단일 트랜잭션으로 지원하기 위해 애그리게이트 패턴은 엔티티 계층 구조와 유사하게 모든 트랜잭션을 공유해서 일관성을 유지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴은 &lt;b&gt;동일한 트랜잭션 경계에 속한 비즈니스 엔티티와 밸류 오브젝트를 한데 묶기 때문에&lt;/b&gt; &amp;lsquo;애그리게이트&amp;rsquo;로 명명됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 코드는 애그리게이트 경계에 속한 여러 엔티티에 걸친 비즈니스 규칙의 예다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103734949&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Ticket
{
	...
	List&amp;lt;Message&amp;gt; _messages;
	
	...
	
	public void Execute(EvaluateAutomaticActions cmd)
	{
		if (this.IsEscalated &amp;amp;&amp;amp; this.RemainingTimePercetage &amp;lt; 0.5 &amp;amp;&amp;amp; 
			GetUnreadMessagesCount(for: AssingedAgent) &amp;gt; 0)
			{
				_agent = AssingNewAgent();
			}
	}
	
	public int GetUnreadMessagesCount(UserId id)
	{
		return _messages.Where(x =&amp;gt; x.To == id &amp;amp;&amp;amp; !x.WasRead).Count();
	}
	...

}&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;이 메서드는 티켓이 상부에 보고되었는지, 그리고 남은 처리 시간이 정의된 50% 임계치 아래인지 확인하기 위해 티켓의 값을 검사한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 현재 에이전트가 메시지를 아직 읽기 전인지 검사한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 조건이 충족되면 티켓은 다른 에이전트에게 할당되도록 요청된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇듯 애그리게이트는 &lt;b&gt;일관된 데이터에 대해 모든 조건을 엄격하게 검사하도록&lt;/b&gt; 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;다른 애그리게이트 참조하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트 내의 모든 객체는 같은 트랜잭션 경계를 공유하기 때문에 &lt;b&gt;애그리게이트가 너무 커지면 성능과 확장에 문제가 생길 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터의 일관성은 애그리게이트의 경계를 설계하는데 편리한 가이드 원칙이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트의 비즈니스 로직에 따라 강력하게 일관성이 필요한 정보 외에는 그림 6-4 처럼 애그리게이트 경계 밖에 다른 애그리게이트의 일부로 둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oXxCw/dJMcahpBxVY/eS7NztWZAsY6RAtIZStEUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oXxCw/dJMcahpBxVY/eS7NztWZAsY6RAtIZStEUK/img.png&quot; data-alt=&quot;그림 6-4. 일관된 경계로서의 애그리게이트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oXxCw/dJMcahpBxVY/eS7NztWZAsY6RAtIZStEUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoXxCw%2FdJMcahpBxVY%2FeS7NztWZAsY6RAtIZStEUK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;560&quot; height=&quot;321&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 6-4. 일관된 경계로서의 애그리게이트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경험상 애그리게이트를 가능한 한 작게 유지하고, 애그리게이트의 비즈니스 로직에 따라 강력하게 일관적으로 상태를 유지할 필요가 있는 객체만 포함한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103781378&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Ticket
{
	private UserId _customer;
	private List&amp;lt;ProductId&amp;gt; _products;
	private UserId _assignedAgent;
	private List&amp;lt;Message&amp;gt; _messages;
	...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;티켓과 관련된 고객과 제품의 모음, 그리고 할당된 에이전트는 &lt;b&gt;애그리게이트에 속하지 않아 ID로 참조된다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 애그리게이트를 참조할 때 ID로 참조하는 이유는 이 같은 객체가 애그리게이트 경계에 속하지 않음을 명확히 하고, &lt;b&gt;각 애그리게이트가 자신의 트랜잭션 경계를 갖게 보장하기 위함이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티가 애그리게이트에 속하는지 판단하는 방법은 우선 비즈니스 로직 내에 궁극적으로 일관된 데이터를 다루는 상황이 되면 시스템의 상태를 손상시킬 수 있는지 여부를 판단한 후, 그 비즈니스 로직이 애그리게이트에 있는지 여부를 조사하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;애그리게이트 루트&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 봤듯이, 애그리게이트의 상태는 커맨드 중 하나를 실행해서만 수정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 6-5처럼 애그리게이트가 엔티티의 계층 구조를 대표하기 때문에 &lt;b&gt;그중 하나만&lt;/b&gt; 애그리게이트의 퍼블릭 인터페이스, 즉 &lt;b&gt;애그리게이트 루트로 지정돼야&lt;/b&gt; 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;237&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x1QfJ/dJMcac9BQFd/k9bJPWIOyRleULNKqTXcQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x1QfJ/dJMcac9BQFd/k9bJPWIOyRleULNKqTXcQ1/img.png&quot; data-alt=&quot;그림 6-5. 애그리게이트 루트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x1QfJ/dJMcac9BQFd/k9bJPWIOyRleULNKqTXcQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx1QfJ%2FdJMcac9BQFd%2Fk9bJPWIOyRleULNKqTXcQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;560&quot; height=&quot;237&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;237&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 6-5. 애그리게이트 루트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ticket 애그리게이트에서 발췌한 다음의 예를 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103825739&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Ticket
{
	...
	List&amp;lt;Message&amp;gt; _messages;
	...
	
	public void Execute(AcknowledgeMessage cmd)
	{
		var message = _messages.Where(x = &amp;gt; x.id == cmd.id).First();
		message.WasRead = true;
	}
	...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트는 특정 메시지의 읽음 상태를 수정할 수 있는 커멘드를 노출한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 애그리게이트 루트인 Ticket을 통해서만 접근할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트 루트의 퍼블릭 인터페이스 외에도 외부에서 애그리게이트와 커뮤니케이션할 수 있는 다른 메커니즘이 있는데, 바로 &lt;b&gt;도메인 이벤트다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;도메인 이벤트&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;도메인 이벤트&lt;/b&gt;는 비즈니스 도메인에서 일어나는 &lt;b&gt;중요한 이벤트를 설명하는 메시지다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;티켓이 할당됨&lt;/li&gt;
&lt;li&gt;티켓이 상부에 보고됨&lt;/li&gt;
&lt;li&gt;메시지가 수신됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 이벤트는 이미 발생된 것이기 때문에 과거형으로 명명한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 이벤트의 목적은 비즈니스 도메인에서 &lt;b&gt;일어난 일을 설명&lt;/b&gt;하고, &lt;b&gt;이벤트와 관련된 모든 필요한 데이터를 제공&lt;/b&gt;하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1768103856467&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	&quot;ticket-id&quot;: &quot;asdjflsaikdjflasv0asrfawefasdf&quot;,
	&quot;event-id&quot;: 146,
	&quot;event-type&quot;: &quot;ticket-escalated&quot;,
	&quot;escalation-reason&quot;: &quot;missed-sla&quot;,
	&quot;escalation-time&quot;: 12363322

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 이벤트의 이름이 비즈니스 도메인에서 일어난 일을 간결하고 정확하게 반영해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 이벤트는 애그리게이트의 퍼블릭 인터페이스의 일부다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애그리게이트는 &lt;b&gt;자신의 도메인 이벤트를 발행&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 6-6처럼 다른 프로세스, 애그리게이트, 심지어 외부 시스템도 이 도메인 이벤트를 구독하고, 이벤트에 반응하는 자신만의 로직을 실행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;9.png&quot; data-origin-width=&quot;476&quot; data-origin-height=&quot;181&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eoMzeK/dJMcadHswzI/HsO9yFiyr9mAc3euWkpnA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eoMzeK/dJMcadHswzI/HsO9yFiyr9mAc3euWkpnA0/img.png&quot; data-alt=&quot;그림 6-6. 도메인 이벤트의 게시 흐름&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eoMzeK/dJMcadHswzI/HsO9yFiyr9mAc3euWkpnA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeoMzeK%2FdJMcadHswzI%2FHsO9yFiyr9mAc3euWkpnA0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;476&quot; height=&quot;181&quot; data-filename=&quot;9.png&quot; data-origin-width=&quot;476&quot; data-origin-height=&quot;181&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 6-6. 도메인 이벤트의 게시 흐름&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 이벤트의 예는 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768103896936&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Ticket
{
	...
	private List&amp;lt;DomainEvent&amp;gt; _domainEvents;
	
	...
	
	public void Execute(RequestEscalation cmd)
	{
		if (!this.IsEscalated &amp;amp;&amp;amp; this.remainingTimePercentage &amp;lt;= 0)
		{
			this.IsEscalated = true;
			var escalatedEvent = new TicketEscalated(_id, cmd.Reason);
			_domainEvents.Append(escalatedEvent);
		}
	
	}
...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;유비쿼터스 언어&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로, 애그리게이트는 유비쿼터스 언어를 사용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;도메인 서비스&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언젠가는 애그리게이트도 밸류 오브젝트에도 속하지 않거나 복수의 애그리게이트에 관련된 비즈니스 로직을 다루게 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 도메인 주도 설계에서는 &lt;b&gt;도메인 서비스로&lt;/b&gt; 로직을 구현할 것을 제안한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 서비스는 비즈니스 로직을 구현한 &lt;b&gt;상태가 없는 객체&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 경우 이런 로직은 어떤 계산이나 분석을 수행하기 위한 &lt;b&gt;다양한 시스템의 호출의 조율을&lt;/b&gt; 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;티켓 애그리게이트 예제로 돌아가 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;티켓은 제한된 시간 내에 고객에게 솔루션을 제공해야 하는데, 이 시간은 이에전트 소속 부서의 우선순위별 SLA 관련 정책, 이에전트의 스케줄에 종속된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 예제를 살펴보자.&lt;/p&gt;
&lt;pre id=&quot;code_1768103935689&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ResponseTimeFramecalculationService
{
	...
	
	public ResponseTimeframe CalculateAgentResponseDeadline(Userid agentId,
		Priority priority, bool escalated, DateTime startTime)
		{
			var policy = _departmentRepository.GetDepartmentPolicy(agentId);
			var maxProcTime = policy.GetMaxresponseTimeFor(priority);
			
			if (escalated) {
				maxProcTime = maxProcTime * policy.EscalationFactor;
			}
			
			var shifts = _departmentRepository.GetUpcomingShifts(agentId,
				startTime, startTime.Add(policy.MaxAgentResponseTime));
				
			return CalculateTargetTime(maxProcTime, shifts);
		
		}
	...

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 서비스는 여러 애그리게이트의 작업을 쉽게 조율할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 한 개의 데이터베이스 트랜잭션에서 한 개의 애그리게이트 인스턴스만 수정할 수 있다고 했던 애그리게이트 패턴의 한계를 명심해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[결론]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 모델 패턴은 복잡한 비즈니스 로직을 다루는데 목적이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에는 세 개의 구성요소가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;밸류 오브젝트&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이것은 값만으로 식별되는 비즈니스 도메인의 개념이기 때문에 명시적인 ID 필드가 필요없다.&lt;/li&gt;
&lt;li&gt;필드 중 하나가 변경되면 의미상 새로운 값을 생성하므로 불변이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;애그리게이트&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션 경계를 공유하는 엔티티의 계층이다.&lt;/li&gt;
&lt;li&gt;애그리게이트의 경계에 속하는 모든 데이터는 비즈니스 로직의 구현을 통해 강력한 일관성을 제공한다.&lt;/li&gt;
&lt;li&gt;애그리게이트의 상태와 내부 객체는 애그리게이트의 커맨드를 실행하여 퍼블릭 인터페이스를 통해서만 수정 될 수 있다.&lt;/li&gt;
&lt;li&gt;애그리게이트는 트랜잭션의 경계 역할을 한다. 즉, 내부 객체를 포함한 모든 데이터는 원자적인 단일 트랜잭션으로 데이터베이스에 커밋되어야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;도메인 서비스&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;도메인 서비스란 도메인 모델에서 애그리게이트 또는 밸류 오브젝트에 속하지 않는 비즈니스 로직을 담는 상태가 없는 객체다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 도메인 모델 구성요소들은 경계 내의 밸류 오브젝트와 애그리게이트를 감싸서 비즈니스 로직의 복잡성을 다룬다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-end=&quot;1752&quot; data-start=&quot;1699&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;✅ Chapter 5~6 요약 섹션&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-end=&quot;1780&quot; data-start=&quot;1754&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;핵심 포인트 (Key Takeaways)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2012&quot; data-start=&quot;1781&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1878&quot; data-start=&quot;1781&quot;&gt;비즈니스 로직은 소프트웨어의 핵심이며, 하위 도메인의 중요도/복잡도에 따라 구현 방식이 달라져야 함&lt;/li&gt;
&lt;li data-end=&quot;1965&quot; data-start=&quot;1879&quot;&gt;복잡도가 낮은 로직은 단순하게(예: Transaction Script), 복잡도가 높은 로직은 모델 중심으로(도메인 모델) 접근해야 유지보수가 쉬움&lt;/li&gt;
&lt;li data-end=&quot;2012&quot; data-start=&quot;1966&quot;&gt;&amp;ldquo;아키텍처를 멋있게&amp;rdquo;보다 더 중요한 건 &lt;b&gt;도메인의 성격에 맞는 전략 선택&lt;/b&gt;임&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;2042&quot; data-start=&quot;2014&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;실무 연결 포인트 (How to apply)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2217&quot; data-start=&quot;2043&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2109&quot; data-start=&quot;2043&quot;&gt;Supporting domain인데 도메인 모델을 과하게 적용하고 있다면 &amp;rarr; 비용 과다(설계 과잉) 가능성 체크&lt;/li&gt;
&lt;li data-end=&quot;2170&quot; data-start=&quot;2110&quot;&gt;Core domain에서 if-else 절차로만 로직이 늘어나고 있다면 &amp;rarr; &lt;b&gt;도메인 모델 전환 신호&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;2217&quot; data-start=&quot;2171&quot;&gt;&amp;ldquo;패턴 선택 기준&amp;rdquo;을 팀 내 합의로 문서화(규칙이 없으면 로직이 무작위로 커짐)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;2231&quot; data-start=&quot;2219&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;한 줄 인사이트&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-end=&quot;2278&quot; data-start=&quot;2232&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2278&quot; data-start=&quot;2234&quot; data-ke-size=&quot;size16&quot;&gt;좋은 설계는 &amp;lsquo;정답 패턴&amp;rsquo;이 아니라 &lt;b&gt;도메인별 최적 전략 선택&lt;/b&gt;에서 나온다.&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>Book Notes</category>
      <category>ddd</category>
      <category>it</category>
      <category>개발</category>
      <category>개발서적</category>
      <category>개발자</category>
      <category>도메인주도설계</category>
      <category>도메인주도설계첫걸음</category>
      <category>필독서</category>
      <author>feel2</author>
      <guid isPermaLink="true">https://feel2.tistory.com/157</guid>
      <comments>https://feel2.tistory.com/157#entry157comment</comments>
      <pubDate>Sun, 11 Jan 2026 12:59:54 +0900</pubDate>
    </item>
    <item>
      <title>[개발서적] 도메인 주도 설계 첫걸음 1부(ch3~4) 요약 (2)</title>
      <link>https://feel2.tistory.com/156</link>
      <description>&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Ch3. 도메인 복잡성 관리&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트의 성공을 보장하려면 소프트웨어 엔지니어로부터 도메인 전문가에 이르기까지 모든 이해관계자가 의사소통에 사용할 수 있는 &lt;b&gt;유비쿼터스 언어를 개발하는 것&lt;/b&gt;이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리의 목표는 유비쿼터스 언어를 사용하여 소프트웨어 설계의 의사결정을 내리는 것이기 때문에 &lt;b&gt;언어는 명확하고 일관성이 있어야 한다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 같은 비즈니스 도메인이어도 도메인 전문가마다 서로 다른 모델을 사용할 수 있다. 예제를 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[일관성 없는 모델]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2장의 텔레마케팅 회사의 예를 보자. 회사의 마케팅 부서는 온라인 광고를 통해 리드(lead)를 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영업 부서는 잠재고객이 제품이나 서비스를 구매하도록 유도하는 역할을 하며, 이것이 그림 3-1에 나와 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;875&quot; data-origin-height=&quot;247&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d30WoS/dJMcahb2Y6E/xZ8ngekk6jIDIOU1YwGguk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d30WoS/dJMcahb2Y6E/xZ8ngekk6jIDIOU1YwGguk/img.png&quot; data-alt=&quot;그림 3-1. 비즈니스 도메인 예시: 텔레마케팅 회사&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d30WoS/dJMcahb2Y6E/xZ8ngekk6jIDIOU1YwGguk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd30WoS%2FdJMcahb2Y6E%2FxZ8ngekk6jIDIOU1YwGguk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;875&quot; height=&quot;247&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;875&quot; data-origin-height=&quot;247&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 3-1. 비즈니스 도메인 예시: 텔레마케팅 회사&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 전문가의 언어를 살펴보면 특이한 점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리드(lead)라는 용어가 마케팅과 영업 부서에서 &lt;b&gt;서로 다른 의미로 사용한다&lt;/b&gt;.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;마케팅 부서&lt;/b&gt;: 누군가가 제품 중 하나에 관심이 있다는 알림, 잠재고객의 연락처 정보를 수신하는 이벤트를 리드로 간주함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;영업 부서&lt;/b&gt;: 영업 프로세스의 전체 수명주기, 리드는 단순한 이벤트가 아니라 장기적으로 진행되는 과정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;텔레마케팅 회사의 경우 유비쿼터스 언어를 어떻게 공식화할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제에 대한 전통적인 솔루션은 &lt;b&gt;모든 종류의 문제에 사용할 수 있는 단일 모델을 설계&lt;/b&gt;하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 ERD를 설계하더라도 너무 복잡하면 관리가 어려워 진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;9.png&quot; data-origin-width=&quot;936&quot; data-origin-height=&quot;493&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5y71v/dJMcacBO4Yd/SHMxCjq59QD69Uv5XkPqnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5y71v/dJMcacBO4Yd/SHMxCjq59QD69Uv5XkPqnk/img.png&quot; data-alt=&quot;그림 3-2. 전사적 엔티티 관계 다이어그램&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5y71v/dJMcacBO4Yd/SHMxCjq59QD69Uv5XkPqnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5y71v%2FdJMcacBO4Yd%2FSHMxCjq59QD69Uv5XkPqnk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;936&quot; height=&quot;493&quot; data-filename=&quot;9.png&quot; data-origin-width=&quot;936&quot; data-origin-height=&quot;493&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 3-2. 전사적 엔티티 관계 다이어그램&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 다른 솔루션은 &amp;lsquo;마케팅 리드&amp;rsquo;, &amp;lsquo;영업 리드&amp;rsquo;와 같이 문맥상 정의에 문제가 있는 용어 앞에 접두사를 추가하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 이 방식도 그렇게 적합하지는 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 문제를 해결하기 위해 도메인 주도 설계 패턴 중 하나인 &lt;b&gt;바운디드 컨텍스트&lt;/b&gt;라는 주제를 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[바운디드 컨텍스트란 무엇인가?]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 주도 설계에서 솔루션은 간단하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유비쿼터스 언어를 여러 개의 작은 언어로 나눈 다음, 각 언어를 적용할 수 있는 명시적인 &lt;b&gt;바운디드 컨텍스트(bounded context)에 할당하면 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞의 예에서 마케팅과 영업이라는 두가지 바운디드 컨텍스트를 식별할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 3-3에서 보듯이 &amp;lsquo;&lt;b&gt;리드&lt;/b&gt;&amp;rsquo;라는 용어는 &lt;b&gt;두 가지 바운디드 컨텍스트에 모두 존재한다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;10.png&quot; data-origin-width=&quot;936&quot; data-origin-height=&quot;394&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Fmg8U/dJMcahXrL5S/MbQKUXYPHMT9rbqeHil251/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Fmg8U/dJMcahXrL5S/MbQKUXYPHMT9rbqeHil251/img.png&quot; data-alt=&quot;그림 3-3. 유비쿼터스 언어를 바운디드 컨텍스트로분할하여 인관성이 없는 문제를 해결&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Fmg8U/dJMcahXrL5S/MbQKUXYPHMT9rbqeHil251/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFmg8U%2FdJMcahXrL5S%2FMbQKUXYPHMT9rbqeHil251%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;936&quot; height=&quot;394&quot; data-filename=&quot;10.png&quot; data-origin-width=&quot;936&quot; data-origin-height=&quot;394&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 3-3. 유비쿼터스 언어를 바운디드 컨텍스트로분할하여 인관성이 없는 문제를 해결&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 의미에서 용어 충돌과 암시적 컨텍스트는 적당한 규모의 모든 비즈니스에 내재된 부분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트 패턴을 사용하면 &lt;b&gt;컨텍스트를 명시적이고&lt;/b&gt;, 중요한 비즈니스 도메인의 요소로 &lt;b&gt;모델링 가능하다.&lt;/b&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;모델 경계&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모델&lt;/b&gt;은 실제 세계의 복사본이 아니라 &lt;b&gt;복잡한 시스템을 이해하는데 도움을 주기 위해&lt;/b&gt; 구조화한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델은 모델의 경계(바운디드 컨텍스트)를 정의하는 것이 모델링 프로세스의 &lt;b&gt;본질적인 부분&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 바운디드 컨텍스트의 유비쿼터스 언어는 다른 바운디드 컨테긋트 범위와는 완전히 관련이 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트는 유비쿼터스 언어의 &lt;b&gt;일관성이 유지되는 경계&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;정제된 유비쿼터스 언어&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유비쿼터스 언어는 &lt;b&gt;바운디드 컨텍스트 경계 안에서만&lt;/b&gt; 보편적으로 적용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 유비쿼터스 언어는 바운디드 컨텍스트에 포함된 &lt;b&gt;모델을 설명하는데만&lt;/b&gt; 집중한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;바운디드 컨텍스트 범위&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스 도메인을 모델링하기 위해 우리는 모델을 분리하고, 각 세분화된 모델을 적용 가능한 컨텍스트(바운디드 컨텍스트)를 엄격하게 정의해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 그림 3-4와 같이 모델을 더 작은 바운디드 컨텍스트로 분해할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;11.png&quot; data-origin-width=&quot;936&quot; data-origin-height=&quot;394&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blm6Kh/dJMcaiWiIvH/yhn832ZnrbfIVaz4qzzytK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blm6Kh/dJMcaiWiIvH/yhn832ZnrbfIVaz4qzzytK/img.png&quot; data-alt=&quot;그림 3-4. 더 작은 바운디드 컨텍스트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blm6Kh/dJMcaiWiIvH/yhn832ZnrbfIVaz4qzzytK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fblm6Kh%2FdJMcaiWiIvH%2Fyhn832ZnrbfIVaz4qzzytK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;936&quot; height=&quot;394&quot; data-filename=&quot;11.png&quot; data-origin-width=&quot;936&quot; data-origin-height=&quot;394&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 3-4. 더 작은 바운디드 컨텍스트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유비쿼터스 언어의 범위(바운디드 컨텍스트)를 정의하는 것은 &lt;b&gt;전략적인 설계 의사결정이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경계는 비즈니스 도메인의 고유한 컨텍스트에 따라 넓힐 수도 있고, 세분화하여 좁힐 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트는 상황에 따라 커질수도, 작아질수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 모델을 유용하게 유지하고, 바운디드 컨텍스트의 크기를 &lt;b&gt;비즈니스 요구사항과 조직의 제약사항에 맞춰라&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한가지 주의할 점은 응집된 기능을 여러 바운디드 컨텍스트로 분할하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 비효율적인 분해를 피하기 위해 &lt;b&gt;하위 도메인을 찾고&lt;/b&gt;, 같은 데이터에서 작동하는 &lt;b&gt;응집된 유스케이스의 집합을 식별&lt;/b&gt;하되, 그것을 &lt;b&gt;여러 개의 바운디드 컨텍스트로 분해하지 마라.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[바운디드 컨텍스트 대 하위 도메인]&lt;/b&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;하위 도메인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기업의 비즈니스 전략을 이해하려면 &lt;b&gt;비즈니스 도메인을 분석해야&lt;/b&gt; 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 주도 설계 방법론에 따르면 분석 단계에는 다양한 하위 도메인(핵심, 지원, 일반)을 식별하는 작업이 포함된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그것이 바로 조직이 일하고 경쟁 전략을 계획하는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 엔지니어로서 우리는 &lt;b&gt;요구사항을 정의하지 않는다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 하위 도메인을 식별하기 위한 &lt;b&gt;비즈니스 도메인을 분석한다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;바운디드 컨텍스트&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면에 바운디드 컨텍스트는 &lt;b&gt;소프트웨어 엔지니어에 의해&lt;/b&gt; 설계된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 비즈니스 도메인을 더 작고 관리 가능한 문제 도메인으로 어떻게 나눌지 정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;하위 도메인과 바운디드 컨텍스트 사이의 상호작용&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비현식적이지만, 이론적으로 단일 모델이 전체 비즈니스 도메인에 적용될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 3-5와 같이 소규모 시스템의 경우 그렇다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;12.png&quot; data-origin-width=&quot;627&quot; data-origin-height=&quot;343&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DVIUU/dJMcacu29kQ/TcYlklekUwFp6yp0EPEip0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DVIUU/dJMcacu29kQ/TcYlklekUwFp6yp0EPEip0/img.png&quot; data-alt=&quot;그림 3-5. 모놀리식 바운디드 컨텍스트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DVIUU/dJMcacu29kQ/TcYlklekUwFp6yp0EPEip0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDVIUU%2FdJMcacu29kQ%2FTcYlklekUwFp6yp0EPEip0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;627&quot; height=&quot;343&quot; data-filename=&quot;12.png&quot; data-origin-width=&quot;627&quot; data-origin-height=&quot;343&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 3-5. 모놀리식 바운디드 컨텍스트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델이 충돌하면 3-6과 같이 도메인 전문가의 모델을 따라 시스템을 바운디드 컨텍스트로 분해할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;13.png&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d0yNNI/dJMcabiCfCV/jY7IuvxGX3xLdiLBOs5W01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d0yNNI/dJMcabiCfCV/jY7IuvxGX3xLdiLBOs5W01/img.png&quot; data-alt=&quot;그림 3-6. 유비쿼터스 언어의 일관성에 따라 나눈 바운디드 컨텍스트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d0yNNI/dJMcabiCfCV/jY7IuvxGX3xLdiLBOs5W01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd0yNNI%2FdJMcabiCfCV%2FjY7IuvxGX3xLdiLBOs5W01%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;695&quot; height=&quot;321&quot; data-filename=&quot;13.png&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 3-6. 유비쿼터스 언어의 일관성에 따라 나눈 바운디드 컨텍스트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델이 여전히 크고 유지보수가 어려운 경우 더 작은 바운디드 컨텍스트로 분해할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 각 하위 도메인에 대한 바운디드 컨텍스트로 나눌 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;14.png&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dhBWep/dJMcagRKvW8/1aiIgf2ygP1mnmzoyjeKTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dhBWep/dJMcagRKvW8/1aiIgf2ygP1mnmzoyjeKTK/img.png&quot; data-alt=&quot;그림 3-7. 하위 도메인 경계에 맞춰 나눈 바운디드 컨텍스트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dhBWep/dJMcagRKvW8/1aiIgf2ygP1mnmzoyjeKTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdhBWep%2FdJMcagRKvW8%2F1aiIgf2ygP1mnmzoyjeKTK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;695&quot; height=&quot;252&quot; data-filename=&quot;14.png&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 3-7. 하위 도메인 경계에 맞춰 나눈 바운디드 컨텍스트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어느 쪽이든 이것은 설계에 대한 의사결정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요한 것은 하위 도메인은 &lt;b&gt;발견하고&lt;/b&gt; 바운디드 컨텍스트는 &lt;b&gt;설계한다는 점이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 하위 도메인은 비즈니스 전략에 의해 정의된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 바운디드 컨텍스트는 소프트웨어 엔지니어가 &lt;b&gt;특정 문제를 해결하기 위해&lt;/b&gt; 설계한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[경계]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트 패턴은 &lt;b&gt;물리적 경계&lt;/b&gt;와 &lt;b&gt;소유권 경계&lt;/b&gt;를 규정하기 위한 도메인 주도 설계 도구다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;물리적 경계&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트는 모델 경계뿐만 아니라 이를 구현하는 &lt;b&gt;시스템의 물리적 경계 역할&lt;/b&gt;도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 바운디드 컨텍스트는 &lt;b&gt;개별 서비스/프로젝트로 구현돼야&lt;/b&gt; 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 구현, 진화, 버전 관리를 각각의 다른 바운디드 컨텍스트와 &lt;b&gt;독립적으로&lt;/b&gt; 해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트 간의 명확한 물리적 경계를 통해, 각 바운디드 컨텍스트를 요구사항에 &lt;b&gt;가장 적합한 기술 스택으로 구현할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 논의한 바와 같이 바운디드 컨텍스트는 여러 하위 도메인을 포함할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 경우 바운디드 컨텍스트는 &lt;b&gt;물리적 경계&lt;/b&gt;고, 하위 도메인은 &lt;b&gt;논리적 경계&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;소유권 경계&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀 간의 작업 분배는 바운디드 컨텍스트 패턴을 사용하여 내릴 수 있는 또 다른 &lt;b&gt;전략적 의사결정이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트는 &lt;b&gt;한 팀에서만&lt;/b&gt; 구현, 발전, 유지 관리를 해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 각각의 팀은 서로 다른 바운디드 컨텍스트로 분리된 시스템과 연동하기 위해서는 &lt;b&gt;통신 프로토콜을 정의해야 한다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트는 한 팀이 여러 개 소유할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;15.png&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BUXVa/dJMcafSRcax/kWbZgk8kfQStO66Fa6s0Ok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BUXVa/dJMcafSRcax/kWbZgk8kfQStO66Fa6s0Ok/img.png&quot; data-alt=&quot;그림 3-8. 하나의 팀은 여러 바운디드 컨텍스트를 소유할 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BUXVa/dJMcafSRcax/kWbZgk8kfQStO66Fa6s0Ok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBUXVa%2FdJMcafSRcax%2FkWbZgk8kfQStO66Fa6s0Ok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;695&quot; height=&quot;424&quot; data-filename=&quot;15.png&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;424&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 3-8. 하나의 팀은 여러 바운디드 컨텍스트를 소유할 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[실생활의 바운디드 컨텍스트]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 엔지니어는 도메인 전문가가 다양한 비즈니스 엔티티와 프로세스에 대해 어떻게 생각하는지 항상 의식해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;시맨틱 도메인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 주도 설계의 바운디드 컨텍스트는 시&lt;b&gt;멘틱 도메인의 사전적 개념에 기반&lt;/b&gt;한다고 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;시맨틱 도메인(semantic domain)&lt;/b&gt;은 &lt;b&gt;의미 영역&lt;/b&gt;과 해당 의미를 전달하기 위해 사용하는 &lt;b&gt;단어 영역&lt;/b&gt;으로 구분한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 모니터, 포트, 프로세서라는 단어는 소프트웨어와 하드웨어 엔지니어링 시맨틱 도메인에서 서로 다른 의미를 갖는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;과학&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과학의 경우 모든 경우에 들어맞는 과학적 이론은 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 이론은 다른 맥락 안에서 유용하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 뉴턴의 운동 법칙에 따르면 공간과 시간은 절대적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아인슈타인의 상대성 이론에서는 공간과 시간은 더 이상 절대적이지 않고 관찰자에 따라 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 모델이 모순되는 것처럼 보이지만 둘 다 &lt;b&gt;적절한 (바운디드) 컨텍스트에서 유용하다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[결론]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 전문가의 멘탈 모델에 내재된 충돌을 발견할 때마다 유비쿼터스 언어를 여러개 바운디드 컨텍스트로 분해해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 도메인이 발견되면 바운디드 컨텍스트도 설계한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인을 바운디드 컨텍스트로 나누는 것은 &lt;b&gt;전략적 설계의 의사결정이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트는 &lt;b&gt;시스템을 서비스, 하위 시스템 등의 물리적 구성요소로 분해한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 바운디드 컨텍스트의 &lt;b&gt;수명주기는 서로 독립적&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Ch4. 바운디드 컨텍스트 연동&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트 패턴은 유비쿼터스 언어의 일관성을 유지할 뿐만 아니라 &lt;b&gt;모델링도 가능하게&lt;/b&gt; 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델의 목적, 즉 &lt;b&gt;경계를 명시하지 않고는&lt;/b&gt; 모델을 구축할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경계가 언어의 책임을 구분 짓는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트는 서로 독립적으로 발전할 수는 있지만, &lt;b&gt;상호작용해야 한다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트 사이에는 항상 접점이 있는데, 이를 &lt;b&gt;컨트랙트(contract)&lt;/b&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨트랙트의 필요성은 바운디드 컨텍스트의 모델과 언어의 차이에서 비롯된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 컨트렉트는 하나 이상의 당사자에게 영향을 끼치므로 서로 조율해서 컨트랙트를 정의해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[협력형 패턴 그룹]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;협력형(cooperation) 그룹의 패턴은 &lt;b&gt;소통이 잘 되는 팀에서 구현된&lt;/b&gt; 바운디드 컨텍스트와 관련이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴이 적합한 요건은 팀의 커뮤니케이션과 협업의 수준이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;파트너십 패턴&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파트너십(partnership) 모델에서 바운디드 컨텍스트 간의 연동은 &lt;b&gt;애드훅(ad-hoc) 방식으로&lt;/b&gt; 조정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 팀은 다른 팀에게 API의 변경을 알리고 다른 팀은 충돌 없이 이를 받아들인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;16.png&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;184&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsqADg/dJMcagc9qRP/sfBJkBz2jFoYy4bkvnO9Rk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsqADg/dJMcagc9qRP/sfBJkBz2jFoYy4bkvnO9Rk/img.png&quot; data-alt=&quot;그림 4-1. 파트너십 모델&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsqADg/dJMcagc9qRP/sfBJkBz2jFoYy4bkvnO9Rk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsqADg%2FdJMcagc9qRP%2FsfBJkBz2jFoYy4bkvnO9Rk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;649&quot; height=&quot;184&quot; data-filename=&quot;16.png&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;184&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 4-1. 파트너십 모델&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 연동의 조정은 &lt;b&gt;양방향에서 한다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;양 팀은 서로 다른 언어를 사용할 수도 있으며, 적절한 솔루션을 택할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연동의 문제는 &lt;b&gt;양 팀 모두 협력하여&lt;/b&gt; 해결한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 패턴은 동기화와 커뮤니케이션의 어려움 때문에 지리적으로 떨어져 있는 팀에게는 적합하지 않을 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;공유 커널 패턴&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트가 모델의 경계임에도 불구하고, 여전히 하위 도메인의 동일 모델 혹은 그 일부가 여러 다른 바운디드 컨텍스트에서 구현되는 경우가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공유 커널(shared kernel)과 같은 모델은 &lt;b&gt;모든 바운디드 컨텍스트의 필요에 따라&lt;/b&gt; 설계된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자의 권한을 관리하는 모델을 내부에서 개발해 사용하는 기업 시스템을 예로 들어보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 사용자는 권한을 직접 부여받거나 소속된 단위 조직에서 상속받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 바운디드 콘텍스트는 권한 모델을 수정할 수 있고, 이 변경은 이 모델을 사용하는 모든 다른 바운디드 컨텍스트에 영향을 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;17.png&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4MS4n/dJMcadm8pyB/ExbDg5BrSkki5VU3QAORx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4MS4n/dJMcadm8pyB/ExbDg5BrSkki5VU3QAORx1/img.png&quot; data-alt=&quot;그림 4-2. 공유 커널&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4MS4n/dJMcadm8pyB/ExbDg5BrSkki5VU3QAORx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4MS4n%2FdJMcadm8pyB%2FExbDg5BrSkki5VU3QAORx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;649&quot; height=&quot;228&quot; data-filename=&quot;17.png&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;228&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 4-2. 공유 커널&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;공유 범위&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공유 커널은 바운디드 컨텍스트 간에 제공될 의도가 있는 &lt;b&gt;연동 관련 컨트랙트와 자료구조만으로&lt;/b&gt; 구성하는 것이 이상적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;구현&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공유 커널은 소스코드의 모든 변경이 이를 사용하는 모든 바운디드 컨텍스트에 즉시 반영되도록 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 방식이든 공유 커널에 대한 변경이 생길 때마다 영항을 받는 모든 바운디드 컨텍스트와 연동 테스트를 추가해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;공유 커널을 사용해야 하는 경우&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공유 커널 패턴의 적용 여부를 결정하는 가장 중요한 기준은 &lt;b&gt;중복 비용과 조율 비용의 비율&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴은 &lt;b&gt;중복 비용이 조율 비용보다 클 경우&lt;/b&gt;에만 적용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;변경이 잦을수록&lt;/b&gt; 통합 비용이 높아진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러므로 자연스럽게 공유 커널은 &lt;b&gt;핵심 하위 도메인처럼 많이 변하는 하위 도메인&lt;/b&gt;에 적용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공유 커널을 사용하는 데는 명분이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 지리적인 제약이나 조직의 정치적 문제로 커뮤니케이션 또는 협업이 어려워서 파트너십 패턴을 구현하기 어려울 때를 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 다른 예로는 레거시 시스템을 점진적으로 현대화하는 경우다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국, 공유 커널은 &lt;b&gt;동일 팀에서 소유하고 구현한 바운디드 컨텍스트를 연동하는 경우&lt;/b&gt;에 잘 맞는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[사용자-제공자 패턴 그룹]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;협업 패턴 중에 두번째로 살펴 볼 그룹은 사용자-제공자(customer-supplier) 패턴 그룹이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 4-3에서는 제공자는 사용자에게 &lt;b&gt;서비스를 제공한다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스 제공자는 &amp;lsquo;업스트림&amp;rsquo;이고, 고객 또는 사용자는 &amp;lsquo;다운스트림&amp;rsquo;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;18.png&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;257&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxTdd5/dJMcafSRcb9/y7QAmyKKGFmli2Y3QJgXgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxTdd5/dJMcafSRcb9/y7QAmyKKGFmli2Y3QJgXgK/img.png&quot; data-alt=&quot;그림 4-3. 사용자-제공자 관계&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxTdd5/dJMcafSRcb9/y7QAmyKKGFmli2Y3QJgXgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxTdd5%2FdJMcafSRcb9%2Fy7QAmyKKGFmli2Y3QJgXgK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;649&quot; height=&quot;257&quot; data-filename=&quot;18.png&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;257&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 4-3. 사용자-제공자 관계&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;협력 그룹의 경우와는 다르게 양 팀은 서로 &lt;b&gt;독립적으로&lt;/b&gt; 성공할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 대부분의 경우 업스트림 또는 다운스트림의 팀이 연동 컨트랙트를 주도하는 &lt;b&gt;권력의 불균형이&lt;/b&gt; 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;순응주의자 패턴&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;힘의 균형이 서비스를 제공하는 &lt;b&gt;업스트림에&lt;/b&gt; 있는 경우다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자의 요구를 지원할 동기가 없는 경우가 그렇다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;19.png&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;184&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Bo9n7/dJMcab3YDYj/LtS8yVa7kVqjDXVb0NPiY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Bo9n7/dJMcab3YDYj/LtS8yVa7kVqjDXVb0NPiY1/img.png&quot; data-alt=&quot;그림 4-4. 순응주의자 관계&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Bo9n7/dJMcab3YDYj/LtS8yVa7kVqjDXVb0NPiY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBo9n7%2FdJMcab3YDYj%2FLtS8yVa7kVqjDXVb0NPiY1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;649&quot; height=&quot;184&quot; data-filename=&quot;19.png&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;184&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 4-4. 순응주의자 관계&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업스트림 팀이 노출한 컨트랙트가 예를 들어 &lt;b&gt;산업 표준&lt;/b&gt;이거나 &lt;b&gt;잘 구축된 모델&lt;/b&gt; 또는 다운스트림 팀의 요건에 충분하다면 다운스트림 팀이 자율성의 일부를 포기할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;충돌 방지 계층 패턴&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순응주의자 패턴에서 힘의 균형은 업스트림 서비스에 치우쳐 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 다운스트림 서비스가 이에 순응하지 않을 경우 충돌 방지 계층을 통해 스스로의 필요에 맞게 가공할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20.png&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;237&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ekCIUK/dJMcafrL5gU/T41BeR2C8hw1PlYA4HK531/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ekCIUK/dJMcafrL5gU/T41BeR2C8hw1PlYA4HK531/img.png&quot; data-alt=&quot;그림 4-5. 충돌 방지 계층을 통한 연동&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ekCIUK/dJMcafrL5gU/T41BeR2C8hw1PlYA4HK531/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FekCIUK%2FdJMcafrL5gU%2FT41BeR2C8hw1PlYA4HK531%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;649&quot; height=&quot;237&quot; data-filename=&quot;20.png&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;237&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 4-5. 충돌 방지 계층을 통한 연동&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;충돌 방지 계층(ACL: anticorruption layer)&lt;/b&gt; 패턴은 제공자의 모델을 따르는 것을 원치 않거나 순응에 필요한 노력이 가치가 없는 경우를 다룬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같은 경우 이에 해당할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다운스트림 바운드디 컨텍스트가 핵심 하위 도메인을 포함할 경우&lt;/li&gt;
&lt;li&gt;업스트림 모델이 사용자의 요건에 비효율적이거나 불편한 경우&lt;/li&gt;
&lt;li&gt;제공자가 컨트렉트를 자주 변경하는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;오픈 호스트 서비스 패턴&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴은 &lt;b&gt;힘이 사용자 측에 있는 경우를&lt;/b&gt; 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제공자는 사용자를 보호하고 가능한 최고의 서비스를 제공하는데 관심이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현 모델의 변경으로부터 사용자를 보호하기 위해 업스트림 제공자는 &lt;b&gt;퍼블릭 인터페이스와 구현 모델을 분리&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 외부에 제공되는 퍼블릭 모델과 그 내부 구현을 다른 속도로 발전시킬 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;21.png&quot; data-origin-width=&quot;567&quot; data-origin-height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QCyX6/dJMcafefrJ2/PTsRLGSxSdKUW88PsJZntk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QCyX6/dJMcafefrJ2/PTsRLGSxSdKUW88PsJZntk/img.png&quot; data-alt=&quot;그림 4-6. 오픈 호스트 서비스를 통한 연동&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QCyX6/dJMcafefrJ2/PTsRLGSxSdKUW88PsJZntk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQCyX6%2FdJMcafefrJ2%2FPTsRLGSxSdKUW88PsJZntk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;567&quot; height=&quot;196&quot; data-filename=&quot;21.png&quot; data-origin-width=&quot;567&quot; data-origin-height=&quot;196&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 4-6. 오픈 호스트 서비스를 통한 연동&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림에서 제공자의 퍼블릭 인터페이스는 자신의 유비쿼터스 언어를 따르는 대신, &lt;b&gt;연동 지향 언어(integration-oriented language)를 통해&lt;/b&gt; 프로토콜을 노출하려 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 퍼블릭 프로토콜을 &lt;b&gt;공표된 언어(published language)&lt;/b&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한편, 오픈 호스트 서비스(OHS) 패턴은 충돌 방지 계층 패턴의 반대다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 사용자 대신 &lt;b&gt;제공자&lt;/b&gt;가 &lt;b&gt;내부 모델 번역을 구현&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 연동 모델을 분리하면 업스트림 바운디드 컨텍스트는 이미 공표된 언어의 여러 버전을 동시에 노출할 수 있어서 사용자가 점진적으로새로운 버전으로 이관할 수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;22.png&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;311&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTW5jF/dJMcacohnMl/sogccHPhUwMq5fsxFHDA91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTW5jF/dJMcacohnMl/sogccHPhUwMq5fsxFHDA91/img.png&quot; data-alt=&quot;그림 4-7. 여러 버전의 공표된 언어를 노출하는 오픈 호스트 서비스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTW5jF/dJMcacohnMl/sogccHPhUwMq5fsxFHDA91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTW5jF%2FdJMcacohnMl%2FsogccHPhUwMq5fsxFHDA91%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;572&quot; height=&quot;311&quot; data-filename=&quot;22.png&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;311&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 4-7. 여러 버전의 공표된 언어를 노출하는 오픈 호스트 서비스&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[분리형 노선]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 살펴볼 협업 옵션은 &lt;b&gt;전혀 협력하지 않는 것이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;분리형 노선(separated ways) 패턴&lt;/b&gt;에는 팀에 헙업 의지가 없거나 협업할 수 없는 경우와 같이 다양한 이유가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;커뮤니케이션 이슈&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;협업을 회피하는 일반적인 이유는 조직의 규모와 내부 정치 요인으로 인한 커뮤니케이션의 어려움 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 경우 각자의 길을 가는 것이 더 비용 효과적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;일반 하위 도메인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중복된 하위 도메인의 특성도 협업 없이 분리된 길을 가야할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 &lt;b&gt;로깅 프레임워크&lt;/b&gt;가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;모델의 차이&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델이 너무 다르다면 순응주의자 관계가 불가능하고, 충돌 방지 계층 구현하는 것이 더 비용이 클 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[컨텍스트 맵]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템의 바운디드 컨텍스트 간의 연동 패턴을 분석하면 다음과 같은 컨텍스트 맵을 그릴 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;23.png&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;339&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cT9WwH/dJMcaiaXR8Y/NUVT1Gr9YbpvgRlK7UvIjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cT9WwH/dJMcaiaXR8Y/NUVT1Gr9YbpvgRlK7UvIjK/img.png&quot; data-alt=&quot;그림 4-8. 컨텍스트 맵&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cT9WwH/dJMcaiaXR8Y/NUVT1Gr9YbpvgRlK7UvIjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcT9WwH%2FdJMcaiaXR8Y%2FNUVT1Gr9YbpvgRlK7UvIjK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;572&quot; height=&quot;339&quot; data-filename=&quot;23.png&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;339&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 4-8. 컨텍스트 맵&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨텍스트 맵은 시&lt;b&gt;스템의 바운디드 컨텍스트와의 연동을 시각적으로 표현&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨텍스트 맵은 다음과 같은 전략적 통찰력을 제공한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;거시적 설계관점:&lt;/b&gt; 시스템의 구성요소나 구현하는 모델의 개요를 제공한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커뮤니케이션 패턴:&lt;/b&gt; 어떤 팀이 협력하고, 충돌 방지 계층과 분리형 노선 패턴과 같은 연동 패턴의 선호도를 보여준다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;조직적 문제&lt;/b&gt;: 조직적 문제에 대한 통찰력을 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;유지보수&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨텍스트 맵은 &lt;b&gt;프로젝트 초기부터 도입해서&lt;/b&gt; 새로운 바운디드 컨텍스트와 기존 요소에 대한 수정을 반영하는 것이 이상적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨텍스트 맵은 여러 팀이 작업한 정보가 담겨 있기 때문에 &lt;b&gt;같이 유지보수하는&lt;/b&gt; 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;한계&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨텍스트 맵을 작성하는 것은 &lt;b&gt;어려운 일이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 하위 도메인에 걸친 시스템의 바운디드 컨텍스트에는 여러 연동 패턴이 있을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;24.png&quot; data-origin-width=&quot;859&quot; data-origin-height=&quot;339&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bARl88/dJMcacIA5b2/PjRha7zoFhhg42yxiowV51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bARl88/dJMcacIA5b2/PjRha7zoFhhg42yxiowV51/img.png&quot; data-alt=&quot;그림 4-9. 복잡한 컨텍스트 맵&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bARl88/dJMcacIA5b2/PjRha7zoFhhg42yxiowV51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbARl88%2FdJMcacIA5b2%2FPjRha7zoFhhg42yxiowV51%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;859&quot; height=&quot;339&quot; data-filename=&quot;24.png&quot; data-origin-width=&quot;859&quot; data-origin-height=&quot;339&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 4-9. 복잡한 컨텍스트 맵&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[결론]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바운디드 컨텍스트는 서로 독립적이지 않다. 서로 상호작용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음의 패턴은 바운디드 컨텍스트가 연동하는 다양한 방법이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;파트너십&lt;/b&gt;: 바운디드 컨텍스트는 애드훅 방식으로 지원한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공유 커널:&lt;/b&gt; 두개 이상의 바운디드 컨텍스트가 참여하는 모든 컨텍스트를 공유하는 제한적으로 겹쳐서 공유한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;순응주의자&lt;/b&gt;: 사용자는 서비스 제공자의 모델을 순응한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;충돌 방지 계층:&lt;/b&gt; 사용자는 서비스 제공자의 모델을 사용자의 요건에 맞게 번역한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;오픈 호스트 서비스&lt;/b&gt;: 서비스 제공자는 사용자의 요건에 최적화된 모델인 공표된 언어를 구현한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;분리형 노선&lt;/b&gt;: 특정 기능을 중복으로 두는 것이 더 저렴한 경우다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-end=&quot;1028&quot; data-start=&quot;975&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;✅ Chapter 3~4 요약 섹션&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-end=&quot;1056&quot; data-start=&quot;1030&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;핵심 포인트 (Key Takeaways)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1431&quot; data-start=&quot;1057&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1169&quot; data-start=&quot;1057&quot;&gt;복잡한 도메인일수록 이해관계자 모두가 공유하는 &lt;b&gt;유비쿼터스 언어(Ubiquitous Language)&lt;/b&gt; 가 핵심 자산이 됨&lt;/li&gt;
&lt;li data-end=&quot;1261&quot; data-start=&quot;1170&quot;&gt;같은 비즈니스라도 사람마다 모델이 다를 수 있고, 이를 그대로 섞으면 설계가 혼란스러워짐&lt;/li&gt;
&lt;li data-end=&quot;1381&quot; data-start=&quot;1262&quot;&gt;이 문제를 해결하는 방법이 바로 &lt;b&gt;Bounded Context(모델의 경계)&lt;/b&gt; 이며, 경계 안에서는 언어/모델의 일관성이 보장되어야 함&lt;/li&gt;
&lt;li data-end=&quot;1431&quot; data-start=&quot;1382&quot;&gt;복잡성 관리는 &amp;ldquo;더 많은 클래스/패턴&amp;rdquo;이 아니라, &lt;b&gt;경계와 언어 정리&lt;/b&gt;에서 시작됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;1461&quot; data-start=&quot;1433&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;실무 연결 포인트 (How to apply)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1643&quot; data-start=&quot;1462&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1523&quot; data-start=&quot;1462&quot;&gt;PR/리뷰에서 &amp;ldquo;이 용어가 우리 도메인에서 어떤 의미인가?&amp;rdquo;가 애매하면 &amp;rarr; 언어부터 정리(용어집/정의)&lt;/li&gt;
&lt;li data-end=&quot;1590&quot; data-start=&quot;1524&quot;&gt;팀 간/파트 간 충돌하는 모델이 보이면 &amp;rarr; 모델을 통합하려 하지 말고 &lt;b&gt;Bounded Context로 분리&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1643&quot; data-start=&quot;1591&quot;&gt;도메인 용어를 DTO/엔티티/DB 필드 네이밍에 일관되게 반영하여 커뮤니케이션 비용을 줄임&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;1657&quot; data-start=&quot;1645&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;한 줄 인사이트&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-end=&quot;1692&quot; data-start=&quot;1658&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1692&quot; data-start=&quot;1660&quot; data-ke-size=&quot;size16&quot;&gt;복잡성은 코드가 아니라, &lt;b&gt;언어가 섞일 때 폭발한다.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>Book Notes</category>
      <category>ddd</category>
      <category>it</category>
      <category>개발</category>
      <category>개발서적</category>
      <category>개발자</category>
      <category>도메인주도설계</category>
      <category>도메인주도설계첫걸음</category>
      <category>필독서</category>
      <author>feel2</author>
      <guid isPermaLink="true">https://feel2.tistory.com/156</guid>
      <comments>https://feel2.tistory.com/156#entry156comment</comments>
      <pubDate>Sat, 10 Jan 2026 16:06:44 +0900</pubDate>
    </item>
    <item>
      <title>[개발서적] 도메인 주도 설계 첫걸음 1부(ch1~2) 요약 (1)</title>
      <link>https://feel2.tistory.com/155</link>
      <description>&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Ch1. 비즈니스 도메인 분석하기&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;도메인 주도 설계 수업 시간에 이 내용을 가르치면 학생들이 &amp;ldquo;우리가 이것을 알아야 하나요?&amp;rdquo;라고 이야기한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정답은 &amp;ldquo;그렇다&amp;rdquo;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;효과적인 솔루션을 설계하고 구축하기 위해서는 그것의 바탕이 되는 &lt;b&gt;문제를 이해해야&lt;/b&gt; 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[비즈니스 도메인이란?]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스 도메인이란 &lt;b&gt;회사가 고객에게 제공하는 서비스&lt;/b&gt;를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;패덱스는 배송 서비스를 제공한다.&lt;/li&gt;
&lt;li&gt;스타벅스는 커피로 가장 잘 알려져 있다.&lt;/li&gt;
&lt;li&gt;월마트는 가장 널리 알려진 소매업체 중 하나다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기업은 여러 비즈니스 도메인을 운영할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 아마존은 소매와 클라우드 서비스를 모두 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우버는 차량 공유 회사이면서 음식 배달 및 자전거 공유 서비스도 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사는 비즈니스 도메인을 자주 변경할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[하위 도메인이란?]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스 도메인의 목표를 달성하기 위해서는 기업은 여러 가지 &lt;b&gt;하위 도메인(subdomain)&lt;/b&gt;을 운영해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 도메인은 비즈니스 활동의 &lt;b&gt;세분화된 영역이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 회사의 하위 도메인은 고객에게 제공하는 서비스 단위로 &lt;b&gt;비즈니스 도메인을&lt;/b&gt; 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 하위 도메인으로는 회사가 성공하기 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 도메인은 전체 시스템에서 하나의 구성요소일 뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 하위 도메인은 회사의 비즈니스 도메인에서 &lt;b&gt;목표를 달성하기 위해 서로 상호작용해야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 스타벅스는 커피를 만드는 일 외에 좋은 위치의 부동산을 구매하거나 임대하고, 직원을 고용하고, 재정을 관리해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 하위 도메인 중 어느 것도 자체적으로 수익을 낼 수는 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;하위 도메인의 유형&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 시스템이 다양한 아키텍처 구성요소(데이터베이스, 프론트엔드, 백엔드, 기타 구성요소)로 이뤄진 것처럼, 하위 도메인은 서로 다른 전략적 비즈니스 가치를 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 주도 설계에서 하위 도메인은 &lt;b&gt;핵심, 일반, 지원의 세 가지 유형&lt;/b&gt;으로 구분된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;핵심 하위 도메인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심 하위 도메인(core subdomain)&lt;/b&gt;은 &lt;b&gt;회사가 경쟁업체와 다르게 수행하고 있는 것&lt;/b&gt;을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가령 새로운 제품이나 서비스를 발명하거나 기존 프로세스를 최적화하여 비용을 줄이는 것이 그렇다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우버의 경우, 처음에는 승차 공유 서비스를 제공했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경쟁업체가 그것을 따라잡으면 우버는 그에 대응해 핵심 비즈니스를 최적화하고 발전시킬 방법을 찾았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, &lt;b&gt;같은 방향으로 향하는 손님을 매칭해서 비용을 절감&lt;/b&gt;할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우버의 핵심 하위 도메인은 수익에 영향을 미친다. 우버는 이렇게 경쟁사로부터 차별화했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고객에게 더 좋은 서비스를 제공하고 수익성을 극대화하는 전략이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 예로 구글의 검색 알고리즘을 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글의 광고 플랫폼이 구글 수익의 대부분을 차지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글 애즈(Google Ads)는 하위 도메인이 아니라, 하위 도메인이 있는 별도의 비즈니스 도메인이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 구글 검색과 알고리즘은 어떤가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글 검색 엔진은 유료 서비스는 아니지만, 구글 애즈를 위한 가장 큰 플랫폼이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘에 버그가 생기면 광고 비즈니스 수익에 큰 타격을 주기 때문에 알고리즘이 핵심 알고리즘이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;복잡성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현하기 쉬운 핵심 하위 도메인은 일시적인 경쟁 우위만을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 핵심 하위 도메인은 &lt;b&gt;자연스럽게 복잡해진다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사의 핵심 비즈니스는 &lt;b&gt;높은 진입장벽이&lt;/b&gt; 있어야 한다. 그래야 경쟁사가 모방하거나 복제하기 어려워진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;경쟁 우위의 원천&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 하위 도메인이 반드시 기술이 들어가야 하는 것은 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사의 경쟁 우위는 다양한 원천에서 나올 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 온라인으로 제품을 판매하는 보석 제조업체를 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;온라인 쇼핑몰&lt;/b&gt;은 중요하지만 핵심 하위 도메인은 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;보석 디자인&lt;/b&gt;이 이 회사의 핵심 하위 도메인이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 복잡한 예로, 수동 사기 탐지를 전문으로 하는 회사를 상상해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 회사는 분석가가 의심스러운 문서를 검토하고 잠재적인 사기 사례를 파악할 수 있도록 훈련시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가령 분석가가 이용하는 소프트웨어 시스템을 개발하고 있다고 하자. 이것은 핵심 하위 도메인일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아니다. 핵심 하위 도메인은 &lt;b&gt;분석가가 수행하는 작업&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;일반 하위 도메인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 하위 도메인(&lt;b&gt;generic subdomain&lt;/b&gt;)은 &lt;b&gt;모든 회사가 같은 방식으로&lt;/b&gt; 수행하는 비즈니스 활동을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 하위 도메인과 마찬가지로 일반 하위 도메인은 일반적으로 구현이 복잡하고 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 일반 하위 도메인은 &lt;b&gt;회사에 경쟁력을 제공하지는 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 대부분의 시스템은 사용자를 인증하고 권한을 부여한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 전용 인증 메커니즘을 개발하는 대신 기존에 만들어진 솔루션을 사용하는 것이 더 합리적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;온라인에서 보석을 판매하는 업체로 돌아가보면, 보석 디자인은 핵심 하위 도메인이지만, 온라인 쇼핑몰은 일반 하위 도메인이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;지원 하위 도메인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름에서 알 수 있듯이 지원 하위 도메인(supporting subdomain)은 회사의 &lt;b&gt;비즈니스를 지원하는 활동&lt;/b&gt;을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 핵심 하위 도메인과 달리 지원 하위 도메인은 &lt;b&gt;어떠한 경쟁 우위도 제공하지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지원 하위 도메인의 차별되는 특징은 솔루션의 비즈니스 로직의 복잡성이다. 지원 하위 도메인은 간단하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지원 하위 도메인의 비즈니스 로직은 대부분 데이터 입력 화면과 ETL(extract, transform, load) 작업과 유사하다. 이는 소위 말하는 CRUD(create, read, update, delete)와 유사하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;하위 도메인 비교&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 세 가지 유형의 하위 도메인의 차이점을 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;경쟁 우위&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심 하위 도메인만이&lt;/b&gt; 회사에 경쟁 우위를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 하위 도메인은 경쟁사와 차별화를 가지기 위한 회사의 전략이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정의에 따르면 일반 하위 도메인은 경쟁 우위의 원천이 될 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지원 하위 도메인은 진입장벽이 낮고, 경쟁 우위도 제공할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사가 해결할 수 있는 문제가 더 복잡할수록 더 많은 비즈니스 가치를 제공할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 복잡한 문제를 해결하면 비즈니스를 더욱 최적화하거나, 더 낮은 운영 비용으로 경쟁 우위를 얻을 수 있다.&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;b&gt;복잡성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기술적인 관점에서 보면 하위 도메인의 유형에 따라 복잡성의 수준이 다르기 때문에 조직의 하위 도메인을 식별하는 것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어를 설계할 때 우리는 &lt;b&gt;비즈니스 요구사항의 복잡성을 수용할 수 있는&lt;/b&gt; 도구를 선택해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지원 하위 도메인의 비즈니스 로직은 &lt;b&gt;간단하다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 기본적인 ETL 작업과 CRUD 인터페이스이며, 비즈니스 로직이 명확하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력의 유효성을 검증하거나, 다른 구조의 데이터로 변환하는 것 이상의 로직을 벗어나지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 하위 도메인은 &lt;b&gt;훨씬 더 복잡하다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 사람들이 이미 이러한 문제를 해결하는 데 시간과 노력을 투자한 데는 그럴 만한 이유가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 암호화 알고리즘이나 인증 메커니즘을 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지식 가용성 관점에서 일반 하위 도메인은 &amp;lsquo;알려진 미지&amp;rsquo;다. 이것은 여러분이 &amp;lsquo;모른다는 사실&amp;rsquo;을 알고 있는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 업계에서 인정하는 모범 사례를 사용하거나 전문 컨설턴트를 고용하여 맞춤형 솔루션을 설계할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 하위 도메인은 &lt;b&gt;복잡하다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사의 수익성이 좌우되게 때문에 경쟁업체가 최대한 &lt;b&gt;모방하기 어려워야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 회사는 전략적으로 핵심 하위 도메인으로 복잡한 문제를 해결하려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때때로 핵심 하위 도메인과 지원 하위 도메인을 구별하는게 어려울 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 &lt;b&gt;복잡성은&lt;/b&gt; 도메인을 구별하는 유용한 지침이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 도메인을 부업으로 전환할 수 있는지 물어보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기꺼이 비용을 지불할 수 있는가? 그렇다면 이것은 &lt;b&gt;핵심 하위 도메인이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지원 하위 도메인과 일반 하위 도메인을 구별하는 것도 비슷하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 솔루션을 연동하는 것보다 자체 솔루션을 구현하는 것이 더 간단하고 저렴한가? 그렇다면 &lt;b&gt;지원 하위 도메인이다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;1688&quot; data-origin-height=&quot;1168&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qwwyC/dJMcahpBgPQ/RGJuk2A4VTH33qiLslEUVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qwwyC/dJMcahpBgPQ/RGJuk2A4VTH33qiLslEUVk/img.png&quot; data-alt=&quot;그림 1-1. 세 가지 유형의 하위 도메인의 비즈니스 차별화 및 비즈니스 로직 복잡성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qwwyC/dJMcahpBgPQ/RGJuk2A4VTH33qiLslEUVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqwwyC%2FdJMcahpBgPQ%2FRGJuk2A4VTH33qiLslEUVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1688&quot; height=&quot;1168&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;1688&quot; data-origin-height=&quot;1168&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 1-1. 세 가지 유형의 하위 도메인의 비즈니스 차별화 및 비즈니스 로직 복잡성&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그림 1-1의 차트는 비즈니스 차별화와 비즈니스 로직 복잡성 측면에서 세 가지 유형의 하위 도메인 간의 상호작용을 나타낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 알 수 있는 것은&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기능을 자체적으로 구현하는 것보다 일반적인 솔루션 연동이 더 간단하거나 저렴하다? &amp;rarr; &lt;b&gt;일반 하위 도메인&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;자체 구현이 간단하고 저렴하다? &amp;rarr; &lt;b&gt;지원 하위 도메인&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;변동성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 언급했듯이 핵심 하위 도메인은 &lt;b&gt;자주 변경될 수 있다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한번의 시도로 문제가 해결될 수 있다면 경쟁자들도 빠르게 따라잡을 수 있기 때문에 아마도 경쟁 우위에서 좋은 위치는 아닐 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 최적화된 솔루션을 찾아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 핵심 하위 도메인에 대한 개선 작업은 지속적으로 혁신하고 발전해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 하위 도메인과 달리 지원 하위 도메인은 &lt;b&gt;자주 변경되지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 술루션이 있음에도 일반 하위 도메인은 &lt;b&gt;시간이 지남에 따라 변경될 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;솔루션 전략&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 하위 도메인은 업계에서 기업이 다른 경쟁사와 &lt;b&gt;경쟁할 수 있는 능력을 제공한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 핵심 하위 도메인은 비즈니스가 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 핵심 하위 도메인은 &lt;b&gt;사내에서 구현되어야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 하위 도메인의 요구사항은 자주, 지속적으로 변경될 것으로 예상되어 솔루션은 &lt;b&gt;유지보수가 가능하고 쉽게 개선될 수 있어야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 핵심 하위 도메인은 &lt;b&gt;가장 진보된 엔지니어링 기술로 구현되어야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 하위 도메인은 어렵지만 이미 문제가 해결되었기에 이미 만들어진 &lt;b&gt;제품을 구입하거나 오픈소스 솔루션을 채택하는 것이&lt;/b&gt; 비용 면에서 더 효율적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지원 하위 도메인의 구현은 비즈니스 로직이 단순하고 변경의 빈도가 적기 때문에 적당히 진행하기 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 가지 유형의 하위 도메인의 차이점을 표 1-1에 정리했다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;1891&quot; data-origin-height=&quot;461&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3sOa9/dJMcafFjtDR/SpfueS6eX95DNlK3TGlJlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3sOa9/dJMcafFjtDR/SpfueS6eX95DNlK3TGlJlk/img.png&quot; data-alt=&quot;표 1-1. 세 가지 하위 도메인 유형의 차이점&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3sOa9/dJMcafFjtDR/SpfueS6eX95DNlK3TGlJlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3sOa9%2FdJMcafFjtDR%2FSpfueS6eX95DNlK3TGlJlk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1891&quot; height=&quot;461&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;1891&quot; data-origin-height=&quot;461&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;표 1-1. 세 가지 하위 도메인 유형의 차이점&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;하위 도메인 경계 식별&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 도메인과 해당 유형을 식별하면 소프트웨어 솔루션을 구축할 때 설계와 관련된 의사결정에 상당한 도움이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 실제로 해당 경계를 어떻게 식별할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 도메인과 그 유형은 기업의 비즈니스 전략에 따라 정의되며, 이는 동일한 분야에서 다른 회사와 경쟁하기 위해 &lt;b&gt;자신을 차별화하는 방법이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대다수의 소프트웨어 프로젝트에서 하위 도메인은 어떤 식으로든 &lt;b&gt;&amp;lsquo;이미 존재&amp;rsquo;한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;하위 도메인 정제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크게 나눈 하위 도메인은 좋은 출발점이지만, 문제는 &lt;b&gt;세부 사항에 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스 기능의 복잡한 내용에 숨겨진 중요한 정보를 놓치지 않아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고객 서비스 부서를 예로 들어보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부적인 업무를 조사하면 전형적인 고객 서비스 부서가 헬프 데스크 시스템, 교대 근무 관리 및 일정, 전화 시스템 등과 같이 좀 더 세분화되어 있음을 알 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;핵심 하위 도메인&lt;/b&gt; - 상담 사례 라우팅&lt;/li&gt;
&lt;li&gt;&lt;b&gt;일반 하위 도메인&lt;/b&gt; - 헬프 데스크, 전화 시스템&lt;/li&gt;
&lt;li&gt;&lt;b&gt;지원 하위 도메인&lt;/b&gt; - 교대 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 고객 상담을 라우팅 하는 경우, 과거에 비슷한 상담 사례를 성공적으로 처리한 상담원에게 상담을 전달할 수 있는 &lt;b&gt;독창적인 알고리즘을 개발할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 라우팅 알고리즘을 통해 경쟁업체보다 &lt;b&gt;더 나은 고객 서비스를 제공할 수 있게 되므로&lt;/b&gt; 라우팅 알고리즘이 핵심 하위 도메인으로 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;1682&quot; data-origin-height=&quot;636&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buN8XS/dJMcahwlYAU/3qAN9G6rqu3iq0aEpweaBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buN8XS/dJMcahwlYAU/3qAN9G6rqu3iq0aEpweaBK/img.png&quot; data-alt=&quot;그림 1-2. 일반 하위 도메인의 내부 업무를 의문을 가지고 분석하여 더욱 세분화된 핵심 하위 도메인, 지원 하위 도메인, 일반 하위 도메인으로 나눈 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buN8XS/dJMcahwlYAU/3qAN9G6rqu3iq0aEpweaBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuN8XS%2FdJMcahwlYAU%2F3qAN9G6rqu3iq0aEpweaBK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1682&quot; height=&quot;636&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;1682&quot; data-origin-height=&quot;636&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 1-2. 일반 하위 도메인의 내부 업무를 의문을 가지고 분석하여 더욱 세분화된 핵심 하위 도메인, 지원 하위 도메인, 일반 하위 도메인으로 나눈 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;응집된 유스케이스를 하위 도메인으로&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기술적인 관점에서 하위 도메인은 상호 연관되고 응집된 &lt;b&gt;유스케이스의 집합과 유사하다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 유스케이스 집합에서는 보통 동일한 행위자(actor), 비즈니스 엔티티(business entity)를 포함하고 모두 밀접하게 관련된 &lt;b&gt;데이터의 집합을 다룬다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 1-3에 표시된 신용카드 결제 게이트웨이의 유스케이스 다이어그램을 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 유스케이스는 작업 중인 데이터 및 관련된 행위자와 밀접하게 연관되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 모든 유스케이스는 신용카드 결제 하위 도메인을 형성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;1832&quot; data-origin-height=&quot;908&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEOZJD/dJMb99LQzC8/EYdXKwVioQAFSoHo5qpy7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEOZJD/dJMb99LQzC8/EYdXKwVioQAFSoHo5qpy7K/img.png&quot; data-alt=&quot;그림 1-3. 신용카드 결제 하위 도메인의 유스케이스 다이어그램&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEOZJD/dJMb99LQzC8/EYdXKwVioQAFSoHo5qpy7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEOZJD%2FdJMb99LQzC8%2FEYdXKwVioQAFSoHo5qpy7K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1832&quot; height=&quot;908&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;1832&quot; data-origin-height=&quot;908&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 1-3. 신용카드 결제 하위 도메인의 유스케이스 다이어그램&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 도메인의 경계를 식별하기 위해 온 신경을 곤두세워 노력해야 할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 하위 도메인에는 &lt;b&gt;이러한 노력이 필요하다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 하위 도메인은 가장 중요하고, 변동성이 있고, 복잡하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 가능한 한 많이 졍제하는 것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;핵심에 집중&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 도메인은 소프트웨어 설계 의사결정을 내리는 프로세스의 어려움을 쉽게 해결하도록 돕는 도구다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 조직에는 경쟁 우위를 제공하지만, &lt;b&gt;소프트웨어와는 아무 관련이 없는 비즈니스 기능이 꽤나 많다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 도메인을 찾을 때 소프트웨어와 관련되지 않은 비즈니스 기능을 식별하고, 그 자체로 인정하며, &lt;b&gt;작업 중인 소프트웨어 시스템과 관련된 비지니스에 집중하는 것&lt;/b&gt;이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[도메인 분석 예제]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 도메인의 개념을 실제로 적용해서 여러 전략적 설계 의사결정을 하는데 활용하는 방법을 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Gigmaster와 BusVNext라는 가상의 두 회사가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Gigmaster&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GigMaster는 티켓 판매 및 유통 회사다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모바일 앱은 사용자의 음악 라이브러리, 스트리밍 서비스 계정, 소셜 미디어 프로필을 분석하여 사용자가 관심을 가질 만한 주변의 공연 정보를 찾아낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GigMaster는 사용자의 개인 정보에 민감하여 모두 암호화 해서 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 회사의 추천 알고리즘은 익명 데이터만 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앱의 추천 기능을 개선하기 위해 새로운 모듈이 구현되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GigMaster를 통해 티켓을 구매하지 않더라도 사용자가 과거에 참석한 공연 정보를 기록할 수 있다.&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;b&gt;비즈니스 도메인과 하위 도메인&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Gigmaster의 비즈니스 도메인은 &lt;b&gt;티켓 판매이며,&lt;/b&gt; 이것이 고객에게 제공하는 서비스다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Gigmaster의 주요 경쟁 우위는 추천 엔진이다. 또한 회사는 사용자의 개인정보를 중요하게 생각하며 익명 데이터에 대해서만 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명시적으로 언급하지 않았지만 모바일 앱의 사용자 경험도 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 핵심 도메인은&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;추천 엔진&lt;/li&gt;
&lt;li&gt;데이터 익명화&lt;/li&gt;
&lt;li&gt;모바일 앱&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 하위 도메인은&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;암호화 - 모든 데이터 암호화&lt;/li&gt;
&lt;li&gt;회계 - 회사가 영업을 하고 있기 때문에&lt;/li&gt;
&lt;li&gt;정산 - 고객에게 청구&lt;/li&gt;
&lt;li&gt;인증 및 권한 부여 - 사용자 식별&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지원 하위 도메인은&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;음악 스트리밍 서비스와 연동&lt;/li&gt;
&lt;li&gt;소셜 네트워크와 연동&lt;/li&gt;
&lt;li&gt;참석 공연 모듈&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로 볼 수 있겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;설계 의사결정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작동 중인 하위 도메인과 해당 유형 간의 차이점을 알면 이미 몇 가지 전략적인 설계 의사결정을 내릴 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;추천 엔진, 데이터 익명화, 모바일 앱은 가장 진보된 엔지니어링 도구와 기술을 사용하여 &lt;b&gt;사내에서 구현돼야 한다&lt;/b&gt;. 이러한 모듈은 가장 자주 변경된다.&lt;/li&gt;
&lt;li&gt;데이터 암호화, 회계, 정산, 인증에는 사용 또는 오픈소스 솔루션을 사용해야 한다.&lt;/li&gt;
&lt;li&gt;스트리밍 서비스, 소셜 네트워크와의 연동과 참석한 공연을 위한 모듈 개발은 하청할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;BusVNext&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BusVNext는 대중교통 회사다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고객에게 택시를 잡는 것처럼 쉽게 버스를 타는 경험을 제공하는 것이 목표다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BusVNext의 고객은 모바일 앱을 통해 승차권을 예매할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예정된 출발 시간에 가까운 버스의 경로에 즉시 조정해서 지정된 출발 시간에 고객을 픽업한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사의 주요 과제는 라우팅 알고리즘을 구현하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 요구사항은 &amp;lsquo;외판원 문제(Traveling Salesman Problem)&amp;rsquo;의 변형이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라우팅 로직은 계속 조정되고 최적화된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 통계에 따르면 탑승이 취소된 주된 이유는 버스가 도착하기까지 오랜 시간을 기다려야 하기 떄문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 하차가 지연되더라도 빠른 픽억을 우선시하는 라우팅 알고리즘을 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;비즈니스 도메인과 하위 도메인&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BusVNext는 고객에게 최적화된 버스 승차 서비스를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스 도메인은 &lt;b&gt;대중교통이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BusVNext의 주요 경쟁 우위는 다양한 비즈니스 목표를 우선시하면서, 동시에 복잡한 문제의 해결을 시도하는 라우팅 알고리즘이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 새로운 통찰력을 얻기 위해 지속적인 분석이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 핵심 하위 도메인은&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;라우팅&lt;/li&gt;
&lt;li&gt;분석&lt;/li&gt;
&lt;li&gt;모바일 앱 사용자 경험&lt;/li&gt;
&lt;li&gt;차량 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 하위 도메인은&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;교통 상황&lt;/li&gt;
&lt;li&gt;회계&lt;/li&gt;
&lt;li&gt;청구&lt;/li&gt;
&lt;li&gt;권한 부여&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지원 하위 도메인은&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로모션&lt;/li&gt;
&lt;li&gt;할인 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등이 되겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;설계 의사결정&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;라우팅 알고리즘, 데이터 분석, 차량 관리, 앱 사용성은 가장 정교한 기술 도구와 패턴을 사용하여 사내에서 개발해야 한다.&lt;/li&gt;
&lt;li&gt;판촉 관리 모듈의 구현은 외부에 위탁할 수 있다.&lt;/li&gt;
&lt;li&gt;교통 상황 식별, 사용자 권한 관리, 재무 및 거래 기록 관리는 외부 서비스 제공 업체에 맡길 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[도메인 전문가는 어떤 사람인가?]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 비즈니스 도메인과 하위 도메인에 대해 명확하게 이해했으니 다음 장에서 자주 사용할 또 다른 용어인 DDD 용어인 도메인 전문가(domain expoert)에 대해 살펴보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 전문가란 우리가 모델링하고 코드로 구현할 &lt;b&gt;비즈니스의 모든 복장성을 알고 있는 주제 전문가&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 전문가는 &lt;b&gt;비즈니스를 대표한다.&lt;/b&gt; 또한 일반적으로 요구사항을 제시하는 사람 또는 소프트웨어 최종 사용자이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 온라인 광고 대행사의 경우, 도메인 전문가는 캠페인 관리자, 미디어 구매자, 분석가, 그리고 기타 비즈니스 이해관계자가 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[결론]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 하위 도메인&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;흥미로운 문제들, 기업이 경쟁자로부터 차별화하고 경쟁 우위를 얻는 활동이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 하위 도메인&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해결된 문제들. 이것은 모든 회사가 같은 방식으로 하고 있는 일이다. 여기에는 &lt;b&gt;혁신이 필요하지 않다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;사내 솔루션을 개발하는 것보다 기존 솔루션을 사용하는 것이 더 비용 효과적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지원 하위 도메인&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;분명한 해결책이 있는 문제들. 사내에서 구현해야 할 활동이지만 경쟁 우위를 제공하지는 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;Ch2.&lt;span&gt; 도메인 지식 찾아내기&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&amp;ldquo;운영환경에 배포되는 것은 도메인 전문가의 지식이 아니라 개발자의 이해 혹은 오해다.&amp;rdquo; - 알베르토 브랜돌리니(Alberto Brandolini)&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1장에서는 비즈니스 도메인을 탐색하기 시작해서 기업의 비즈니스 도메인 또는 활동 영역을 식별하는 방법과 식별된 도메인에서 경쟁 전략을 분석하는 방법, 즉 비즈니스 하위 도메인의 경계와 유형을 식별하는 방법을 배웠다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 장에서는 효과적인 커뮤니케이션과 지식 공유를 위한 도메인 주도 설계 도구인 유비쿼터스 언어를 배우고, 비즈니스 도메인의 복잡성을 이해하며, 비즈니스 로직을 소프트웨어 모델로 만들고 구현하는데 이를 활용해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[비즈니스 문제]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 개발하는 소프트웨어 시스템은 &lt;b&gt;비즈니스 문제를 해결하는 솔루션이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 언급한 문제는, 비즈니스 도메인의 컨텍스트에서 &lt;b&gt;광범위하다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스 문제는&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;워크플로우와 프로세스 최적화&lt;/li&gt;
&lt;li&gt;수작업 최소화&lt;/li&gt;
&lt;li&gt;자원 관리&lt;/li&gt;
&lt;li&gt;의사결정 지원&lt;/li&gt;
&lt;li&gt;데이터 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등과 관련한 과제일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 도메인은 세분화된 문제 도메인(&lt;b&gt;problem domain&lt;/b&gt;)으로 &lt;b&gt;특정 비즈니스 기능에 대한 솔루션을 제공&lt;/b&gt;하는 것이 목적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[도메인 지식 찾아내기]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;효과적인 소프트웨어 솔루션을 설계하려면 적어도 &lt;b&gt;기본적인 비즈니스 도메인 지식이&lt;/b&gt; 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 지식은 도메인 전문가의 몫이고, 우리는 될 필요도 없고, 될 수도 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 중요한 것인 &lt;b&gt;도메인 전문가를 이해하고 그들이 쓰는 동일한 비즈니스 용어를 사용하는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;효과적인 소프트웨어는 도메인 전문가가 문제를 생각하는 방식, 즉 &lt;b&gt;멘탈 모델을 모방해야&lt;/b&gt; 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스 문제와 요구사항 이면에 있는 이유에 대한 이해가 없다면, 솔루션은 비즈니스 요구사항을 소스코드로 &lt;b&gt;&amp;lsquo;번역&amp;rsquo;&lt;/b&gt;한 것에 불과하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알베르토 브랜돌리니는 소프트웨어 개발은 &lt;b&gt;배우는 과정&lt;/b&gt;이고, 작동하는 코드는 &lt;b&gt;그 부산물&lt;/b&gt;이라고 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 프로젝트의 성공은 도메인 전문가와 소프트웨어 엔지니어 간의 &lt;b&gt;효과적인 지식 공유&lt;/b&gt;에 달렸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제를 해결하려면, 문제를 이해해야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 도메인 전문가와 소프트웨어 엔지니어 간의 효과적인 지식 공유에는 &lt;b&gt;효과적인 커뮤니케이션이 필요하다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[커뮤니케이션]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거의 모든 소프트웨어 프로젝트에는 도메인 전문가, 프로젝트 소유자, 엔지니어, UI와 UX 디자이너, 프로젝트 매니저, 테스터, 분석가 등 다양한 역할의 이해관계자의 &lt;b&gt;협업이 필요하다고&lt;/b&gt; 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트와 연관된 모든 것에 대한 합의와 일치는 &lt;b&gt;프로젝트의 성공에 필수다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 프로젝트가 실패하는 이유에 대한 연구에서 &lt;b&gt;효과적인 커뮤니케이션&lt;/b&gt;이 지식 공유와 프로젝트 성공에 필수라는 것을 밝혀냈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 2-1에서는 일반적인 커뮤니케이션의 모습을 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;1832&quot; data-origin-height=&quot;786&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ualBs/dJMcaajHntI/XKTNyCojXMbwgV5yhrqpvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ualBs/dJMcaajHntI/XKTNyCojXMbwgV5yhrqpvk/img.png&quot; data-alt=&quot;그림 2-1 소프트웨어 프로젝트에서의 지식 공유 흐름&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ualBs/dJMcaajHntI/XKTNyCojXMbwgV5yhrqpvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FualBs%2FdJMcaajHntI%2FXKTNyCojXMbwgV5yhrqpvk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1832&quot; height=&quot;786&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;1832&quot; data-origin-height=&quot;786&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 2-1 소프트웨어 프로젝트에서의 지식 공유 흐름&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전형적인 소프트웨어 개발 생애주기에서 도메인 지식은 분석 모델(analysis model)로 알려진 &lt;b&gt;엔지니어 친화적인 형태로 &amp;lsquo;변환&amp;rsquo;된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분석 모델은 도메인 지식 이면에 존재하는 비즈니스 도메인에 기반하기보다는 &lt;b&gt;시스템 요구사항을 설명한 것&lt;/b&gt;에 지나지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의도는 좋을지 모르지만, 이런 식의 중재는 지식을 공유하는데 해를 끼친다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국에는 전달 과정에서 &lt;b&gt;손실이 일어난다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흔히 그렇듯이, 문서화된 커뮤니케이션은 최신 정보를 담아내지 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 &lt;b&gt;소스코드가&lt;/b&gt; 프로젝트를 유지관리할 소프트웨어 엔지니어에게까지도 도메인 지식을 전달하는데 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;1654&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chenqp/dJMcafyxrDB/agpKjMyzkDOTelKwkaLAkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chenqp/dJMcafyxrDB/agpKjMyzkDOTelKwkaLAkK/img.png&quot; data-alt=&quot;그림 2-2. 모델 변환&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chenqp/dJMcafyxrDB/agpKjMyzkDOTelKwkaLAkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fchenqp%2FdJMcafyxrDB%2FagpKjMyzkDOTelKwkaLAkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1654&quot; height=&quot;540&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;1654&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 2-2. 모델 변환&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 2-2는 도메인 지식을 코드로 구현하는데 필요한 다양한 &amp;lsquo;변환&amp;rsquo;을 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 소프트웨어 개발 과정은 우리나라로 치면 가족오락관에 &amp;lsquo;고요속의 외침&amp;rsquo;과 비슷한 면이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메시지를 전달하면서 종종 &lt;b&gt;왜곡된 상태로 데이터가 전달&lt;/b&gt;된다는 의미다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 경우든 이런 경우 소프트웨어 프로젝트는 실패한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 같은 문제를 해결하기 위해 더 나은 전달 방식이 있는데, &lt;b&gt;유비쿼터스 언어&lt;/b&gt;가 바로 그것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[유비쿼터스 언어란 무엇인가?]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유비쿼터스 언어를 사용하는 것은 &lt;b&gt;도메인 주도 설계의 초석이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이디어는 간단하다. 참가자들이 효과적으로 소통하기 위해 &lt;b&gt;같은 언어를 사용하는 것이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;굉장히 상식적으로 들리지만, 볼테르(Voltaire)는 이렇게 말했다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;우리가 말하는 상식은 실제로 일반적이지 않다(Common sense is not so common)&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전통적인 소프트웨어 개발 생애주기에서 변환이 어떻게 일어나는지 정리해보면 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;도메인 지식 &amp;rarr; 분석 모델 &amp;rarr; 요구사항 &amp;rarr; 시스템 설계 &amp;rarr; 소스코드&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면에 도메인 주도 설계에서는 이같이 도메인 지식을 계속해서 변환하는 대신, &lt;b&gt;단일화된 언어 체계&lt;/b&gt;를 세우고자 하는데, 그것이 &lt;b&gt;유비쿼터스 언어&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트와 관련된 모든 이해관계자는 비즈니스 도메인을 설명할 때 유비쿼터스 언어를 사용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 중요한 것은 도메인 전문가가 유비쿼터스 언어를 사용해 비즈니스 도메인을 추론하는데 편안해야 한다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[비즈니스 언어]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유비쿼터스 언어는 &lt;b&gt;비즈니스 언어&lt;/b&gt;라는 점을 강조하고 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 기술 용어는 빼고 &lt;b&gt;비즈니스 도메인에 관련된 용어&lt;/b&gt;로만 구성해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유비쿼터스 언어는 &lt;b&gt;도메인 전문가의 이해&lt;/b&gt;와 &lt;b&gt;비즈니스 도메인에 대한 멘탈 모델을 쉽게 이해할 수 있는 관점&lt;/b&gt;으로 표현하는 것을 목표로 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;시나리오&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;광고 캠페인 관리 시스템을 만들고 있다고 가정해보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;광고 캠페인은 다양한 창의적인 자료를 전시할 수 있다.&lt;/li&gt;
&lt;li&gt;캠페인은 최소한 하나의 광고 할당이 활성화되어야 게시된다.&lt;/li&gt;
&lt;li&gt;판매 커미션은 거래가 승인된 후에 회계 처리된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 문장은 &lt;b&gt;비즈니스 언어&lt;/b&gt;로 작성됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 다음 문장은 철저히 기술적이어서 유비쿼터스 언어의 개념에 맞지 않는다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;광고의 아이프레임(iframe)은 HTML 파일을 표시한다.&lt;/li&gt;
&lt;li&gt;캠페인은 &amp;lsquo;활성-할당(active-placement)&amp;rsquo; 테이블에 하나의 연관 레코드가 있어야 한다.&lt;/li&gt;
&lt;li&gt;판매 커미션은 거래(transaction) 테이블과 판매-승인(approved-sales) 테이블의 연관 레코드에 근거하여 처리된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후자의 문장은 순수하게 기술적이어서 도메인 전문가가 이해하기 쉽지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자가 이렇게 기술적인 관점으로 바라보는데만 익숙한 경우, 결국 비즈니스 로직을 완전히 이해하지 못해 효과적으로 솔루션을 구현하는 능력이 제한될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;일관성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유비쿼터스 언어는 &lt;b&gt;반드시 정확하고 일관성이 있어야 한다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가정할 필요가 없어야 하고, 비즈니스 도메인의 로직을 명료하게 표현해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;모호한 용어&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 비즈니스 도메인에서는 &lt;b&gt;정책(policy)&lt;/b&gt; 이라는 용어가 규제 규칙 또는 보험 계약과 같은 여러 의미를 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정확한 의미는 맥락에 따라 사람 간의 상호작용을 통해서만 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 소프트웨어는 모호성에 잘 대처하지 못해, &amp;lsquo;정책&amp;rsquo;이라는 객체(entity)를 코드로 모델링하기가 어려울 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유비쿼터스 언어는 용어마다 &lt;b&gt;단일 의미를 갖게 하기 때문에&lt;/b&gt; &amp;lsquo;정책&amp;rsquo;의 경우 &amp;lsquo;규제 규칙&amp;rsquo;과 &amp;lsquo;보험 계약&amp;rsquo;의 두 용어를 사용하여 명확한 모델을 만들어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;동의어&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유비쿼터스 언어에서 두 용어는 &lt;b&gt;서로 바꿔 사용할 수 없다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, &amp;lsquo;사용자&amp;rsquo;라는 용어는 수많은 시스템에서 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 도메인 전문가의 언어로 신중하게 설명하면 &amp;lsquo;&lt;b&gt;사용자&lt;/b&gt;&amp;rsquo;, &amp;lsquo;&lt;b&gt;방문자&lt;/b&gt;&amp;rsquo;, &amp;lsquo;&lt;b&gt;관리자&lt;/b&gt;&amp;rsquo;, &amp;lsquo;&lt;b&gt;계정&lt;/b&gt;&amp;rsquo; 등의 다른 용어가 혼용된다는 것을 발견할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 컨텍스트 안에서 &lt;b&gt;각각의 용어를 사용하는 것이&lt;/b&gt; 바람직하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[비즈니스 도메인 모델]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 모델링 관점에서 유비쿼터스 언어를 살펴보자.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;모델이란 무엇인가?&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델이란 사물이나 현상에서 의도한 관점만 강조하고 다른 측면은 무시하며 간략히 표현한 것이다. 즉, 특정 용도를 마음에 둔 추상화된 결과다. - 레베카 워프스-브록(Rebeca Wirfs-Brock)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델은 실세계의 복제가 아니라 &lt;b&gt;우리가 실제 시스템을 이해하는데 도움을 주는&lt;/b&gt; 인간의 창조물이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델을 잘 설명하는 예시 중 하나가 지도다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 2-3의 예시와 같이 길 안내 지도, 지형도, 세계 지도, 지하철 노선도 등 모든 지도는 일종의 모델이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;1750&quot; data-origin-height=&quot;1026&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWqGP9/dJMcadtUkD9/BmmchtnM7lamMYI3F6zlkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWqGP9/dJMcadtUkD9/BmmchtnM7lamMYI3F6zlkk/img.png&quot; data-alt=&quot;그림 2-3. 도로, 표준 시간대, 항해 항법, 지형, 항공 항법, 지하철 노선 등 다양한 형태의 지도는 지구의 다양한 모델이다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWqGP9/dJMcadtUkD9/BmmchtnM7lamMYI3F6zlkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWqGP9%2FdJMcadtUkD9%2FBmmchtnM7lamMYI3F6zlkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1750&quot; height=&quot;1026&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;1750&quot; data-origin-height=&quot;1026&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그림 2-3. 도로, 표준 시간대, 항해 항법, 지형, 항공 항법, 지하철 노선 등 다양한 형태의 지도는 지구의 다양한 모델이다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 지도는 특정 목적을 지원하는데 충분한 자료만 담고 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;효과적인 모델링&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 모델에는 목적이 있고, 효과적인 모델은 &lt;b&gt;그 목적을 달성하는데 필요한 세부사항&lt;/b&gt;만 포함한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 이 점이 중요하다. 즉, 유용한 모델은 실세계의 복사본이 아니라 &lt;b&gt;문제를 해결하려는 의도&lt;/b&gt;가 있으며, &lt;b&gt;그 목적에 필요한 정보만 제공&lt;/b&gt;해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델은 본질적으로 &lt;b&gt;추상화의 결과&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에츠허르 데이크스트라는 자신의 논문 &amp;ldquo;겸손한 프로그래머&amp;rdquo;에서 추상화의 목적은 모호함이 아니라 절대적으로정확할 수 있는 &lt;b&gt;새로운 의미론적 수준(semantic level)을 만드는 것&lt;/b&gt;이라고 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;비즈니스 도메인 모델링&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유비쿼터스 언어를 발전시키는 것은 사실상 &lt;b&gt;비즈니스 도메인 모델을 구축하는 셈&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델은 관련된 비즈니스 엔티티(business entity)와 그것의 행동, 인과 관계, 불변성 등을 반영해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유비쿼터스 언어는 도메인의 모든 가능한 상세 정보를 포함하는 게 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신, 모델은 필요한 시스템을 구현하는 데, 즉 소프트웨어가 해결하고자 하는 &lt;b&gt;특정 문제를 해결하는데 필요한 만큼의 비즈니스 도메인 관점을 포함하면 된다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, 엔지니어링 팀과 도메인 전문가의 효과적인 커뮤니케이션은 필수다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스 도메인이 복잡할수록 커뮤니케이션의 중요성은 커진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스 도메인의 이해를 확인할 유일한 방법은 도메인 전문가가 이해할 수 있는 &lt;b&gt;비즈니스 언어(유비쿼터스 언어)로 대화하는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;지속적인 노력&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유비쿼터스 언어를 정형화(formulation)하라면 언어의 소유자인 &lt;b&gt;도메인 전문가와의 상호작용이 중요하다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 이해관계자는 모든 프로젝트와 관련된 커뮤니케이션에 유비쿼터스 언어를 지속적으로 사용해서 지식 공유를 확산하고 비즈니스 도메인에 대한 공유된 이해를 강화해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 중요한 점은 유비쿼터스 언어르 발전시키는 것이 &lt;b&gt;진행형이라는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지속해서 검증하고 발전시켜야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모두가 이 언어를 &lt;b&gt;일상적으로 사용하면&lt;/b&gt; 비즈니스 도메인에 대한 통찰을 얻을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;도구&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유비쿼터스 언어를 수집하고 관리하는 과정을 돕는 도구와 기술이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 위키는 유비쿼터스 언어를 수집하고 관리하는 용어집(glossary)으로 사용될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 용어집은 비즈니스 도메인의 용어에 대한 정보를 얻을 수 있는 &lt;b&gt;거점 역할&lt;/b&gt;을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 다 함께 용어집을 유지보수하는 것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유비쿼터스 언어가 변경되면 모든 팀원이 수정할 수 있게 독려해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 용어집을 유지보수하는 것의 장점이 명백함에도 불구하고, 여기에는 본질적 한계가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;용어집은 엔티티의 이름, 과정, 역할 등의 &amp;lsquo;명사(noun)&amp;rsquo;에만 효과적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명사가 중요하긴 하지만, 행동(behavior)을 포착하는 것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행동은 규칙, 가정, 그리고 불변성을 가진 &lt;b&gt;실제 비즈니스 로직이다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러므로 용어집은 &lt;b&gt;유스케이스&lt;/b&gt; 또는 &lt;b&gt;거킨 테스트&lt;/b&gt;처럼 &lt;b&gt;행동을 포착하는데&lt;/b&gt; 적합한 다른 도구와 함께 사용하는 것이 가장 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거킨 테스트(Gherkin language)로 작성된 자동화 테스트는 유비쿼터스 언어를 포착하기에 좋은 언어일 뿐 아니라 도메인 전문가와 소프트웨어 엔지니어의 간극을 메우는 보조 도구로서의 역할을 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거킨 언어로 작성된 다음 예제 테스트를 살펴보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Scenario&lt;/b&gt;: 에이전트에게 새로운 지원 케이스에 대해 알린다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Given&lt;/b&gt;: 빈센트 줄스는 다음 내용을 담은 새로운 지원 케이스를 제출한다:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;ldquo;나는 AWS Infinidash를 설정하는데 도움이 필요하다.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;When&lt;/b&gt;: 티켓이 울프 씨에게 할당된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Then:&lt;/b&gt; 에이전트는 새로운 티켓에 대해 알림을 받는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거킨 기반의 테스트 스위트를 관리하는 것은 때때로 어려운 일이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 복잡한 비즈니스 도메인인 경우 확실히 가치가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 유비쿼터스 언어의 용어의 사용을 검증할 수 있는 정적 코드 분석 도구도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 도구 중 주목할만한 예는 NDepend다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 도구가 유용하긴 하지만, 일상적인 상호작용에서 사용하는 것보다는 못하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;도전과제&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이론상으로 유비쿼터스 언어를 발전시키는 것이 간단한 과정 같지만 실제로는 그렇지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 지식을 수집하는 신뢰할만한 유일한 방법은 &lt;b&gt;도메인 전문가와 대화를 해보는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 기법에 경험이 쌓이면 단순히 존재하는 지식을 발견하는 것뿐만 아니라 도메인 전문가와 협럭해서 모델을 함께 만들어가는 것이 자주 포함되는 사실을 알게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 비즈니스 도메인의 특성에 대해 질문하면 종종 숨어있던 충돌과 공백을 찾아내 명확하게 할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 특히 핵심 하위 도메인의 경우에 일반적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 과정은 도메인 전문가가 자신의 영역을 더 잘 이해하도록 돕는 상호보완적인 배움의 과정이기도 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[결론]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;효과적인 커뮤니케이션과 지식 공유는 성공적인 소프트웨어 프로젝트에 필수다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 엔지니어가 소프트웨어 솔루션을 설계하고 개발하기 위해서는 반드시 비즈니스 도메인을 이해해야 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-end=&quot;207&quot; data-start=&quot;154&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;✅ Chapter 1~2 요약 섹션&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-end=&quot;235&quot; data-start=&quot;209&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;핵심 포인트 (Key Takeaways)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;663&quot; data-start=&quot;236&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;328&quot; data-start=&quot;236&quot;&gt;도메인 주도 설계의 출발점은 &amp;ldquo;기술&amp;rdquo;이 아니라 &lt;b&gt;비즈니스 문제를 정확히 이해하는 것&lt;/b&gt;임&lt;/li&gt;
&lt;li data-end=&quot;438&quot; data-start=&quot;329&quot;&gt;비즈니스 도메인은 여러 &lt;b&gt;하위 도메인(subdomain)&lt;/b&gt; 으로 구성되며, 이 구조를 먼저 식별해야 설계 방향이 잡힘&lt;/li&gt;
&lt;li data-end=&quot;569&quot; data-start=&quot;439&quot;&gt;하위 도메인은 &lt;b&gt;핵심(Core) / 일반(Generic) / 지원(Supporting)&lt;/b&gt; 으로 나뉘고, 각 유형마다 투자해야 하는 설계/기술 레벨이 달라짐&lt;/li&gt;
&lt;li data-end=&quot;663&quot; data-start=&quot;570&quot;&gt;&amp;ldquo;무엇이 핵심인가?&amp;rdquo;를 구분하는 능력이 결국 &lt;b&gt;조직의 우선순위(리소스 배분)를 결정&lt;/b&gt;한다&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;693&quot; data-start=&quot;665&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;실무 연결 포인트 (How to apply)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;891&quot; data-start=&quot;694&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;789&quot; data-start=&quot;694&quot;&gt;기능 개발 전 &amp;ldquo;이 기능이 속한 하위 도메인은 무엇인가?&amp;rdquo;를 먼저 분류해보고,&lt;br /&gt;Core라면 유지보수성과 확장성이 높은 구조(DDD/클린아키텍처)를 적극 적용&lt;/li&gt;
&lt;li data-end=&quot;837&quot; data-start=&quot;790&quot;&gt;Generic(인증/권한 등)은 &lt;b&gt;직접 구현보다 검증된 솔루션&lt;/b&gt; 우선 검토&lt;/li&gt;
&lt;li data-end=&quot;891&quot; data-start=&quot;838&quot;&gt;Supporting(단순 CRUD/관리 기능)은 과한 설계를 피하고 &amp;ldquo;빠르고 명확하게&amp;rdquo; 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;905&quot; data-start=&quot;893&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;한 줄 인사이트&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-end=&quot;968&quot; data-start=&quot;906&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;968&quot; data-start=&quot;908&quot; data-ke-size=&quot;size16&quot;&gt;DDD는 &amp;lsquo;도메인을 잘 모델링하는 기술&amp;rsquo;이 아니라, &lt;b&gt;어디에 엔지니어링을 집중할지 결정하는 프레임&lt;/b&gt;이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Book Notes</category>
      <category>ddd</category>
      <category>it</category>
      <category>개발</category>
      <category>개발서적</category>
      <category>개발자</category>
      <category>도메인주도설계</category>
      <category>도메인주도설계첫걸음</category>
      <category>필독서</category>
      <author>feel2</author>
      <guid isPermaLink="true">https://feel2.tistory.com/155</guid>
      <comments>https://feel2.tistory.com/155#entry155comment</comments>
      <pubDate>Sat, 10 Jan 2026 15:50:47 +0900</pubDate>
    </item>
  </channel>
</rss>