[{"data":1,"prerenderedAt":645},["ShallowReactive",2],{"article-\u002Farticles\u002Fddd-subdomains-bounded-context":3},{"id":4,"title":5,"body":6,"date":629,"description":630,"excerpt":631,"extension":632,"meta":633,"navigation":634,"path":635,"seo":636,"stem":637,"tags":638,"__hash__":644},"articles\u002Farticles\u002Fddd-subdomains-bounded-context.md","怎麼劃分 Domain？找出子域、分辨核心／支撐／通用，再對應到限界上下文",{"type":7,"value":8,"toc":609},"minimark",[9,23,46,50,117,123,127,130,135,138,162,166,173,179,182,186,189,197,201,215,222,226,232,282,286,293,307,314,317,343,350,353,367,370,374,381,401,407,414,417,429,432,435,461,464,510,514,521,600,603,606],[10,11,12,17,18,22],"p",{},[13,14,16],"a",{"href":15},"\u002Farticles\u002Fddd-overview-strategic-tactical","DDD 概論"," 裡簡單介紹了子域和限界上下文，",[13,19,21],{"href":20},"\u002Farticles\u002Fdomain-storytelling","Domain Storytelling"," 那篇也從故事裡找出了「搜尋、帶看、斡旋」三個候選邊界。但真的要替整個系統劃分時，還有幾個問題要回答：",[24,25,26,34,40],"ol",{},[27,28,29,33],"li",{},[30,31,32],"strong",{},"子域要怎麼找？"," 只靠一個故事不夠，整個業務要從哪些角度看？",[27,35,36,39],{},[30,37,38],{},"怎麼判斷是核心、支撐還是通用？"," 每個人都覺得自己負責的是核心",[27,41,42,45],{},[30,43,44],{},"子域和限界上下文是一對一嗎？"," 系統要照子域切嗎？",[47,48,49],"h2",{"id":49},"先分清楚三個名詞",[51,52,53,72],"table",{},[54,55,56],"thead",{},[57,58,59,63,66,69],"tr",{},[60,61,62],"th",{},"名詞",[60,64,65],{},"屬於",[60,67,68],{},"說明",[60,70,71],{},"房仲的例子",[73,74,75,90,103],"tbody",{},[57,76,77,81,84,87],{},[78,79,80],"td",{},"領域（Domain）",[78,82,83],{},"問題空間",[78,85,86],{},"公司從事的整個業務",[78,88,89],{},"房屋仲介",[57,91,92,95,97,100],{},[78,93,94],{},"子域（Subdomain）",[78,96,83],{},[78,98,99],{},"業務中相對獨立的一塊能力",[78,101,102],{},"物件刊登、物件媒合、帶看、斡旋成交、佣金業績",[57,104,105,108,111,114],{},[78,106,107],{},"限界上下文（Bounded Context）",[78,109,110],{},"解法空間",[78,112,113],{},"一個模型與它的語言有效的範圍，是系統的切法",[78,115,116],{},"刊登上下文、搜尋上下文、成交上下文",[10,118,119,122],{},[30,120,121],{},"子域是「發現」的，限界上下文是「設計」的。"," 子域在寫任何程式之前就存在：就算公司全部用紙本作業，「帶看」這件事還是存在；限界上下文則是我們決定怎麼用軟體去解決它。",[47,124,126],{"id":125},"第一步找出子域","第一步：找出子域",[10,128,129],{},"沒有一個公式能直接算出子域，但有幾個角度可以交叉比對：",[131,132,134],"h3",{"id":133},"_1-從業務能力出發","1. 從業務能力出發",[10,136,137],{},"問「公司做哪些事？」，用「動詞＋名詞」列出業務能力，而不是列出系統功能或資料表：",[139,140,141,144,147,150,153,156,159],"ul",{},[27,142,143],{},"開發委託：說服屋主簽下委託",[27,145,146],{},"刊登物件：把物件資訊、照片放上網站",[27,148,149],{},"媒合買方：讓買方找到適合的物件",[27,151,152],{},"安排帶看：協調買方、屋主、經紀人的時間",[27,154,155],{},"斡旋議價：在買賣雙方之間協商價格",[27,157,158],{},"簽約交屋：簽訂買賣契約、交屋",[27,160,161],{},"計算佣金與業績：服務費怎麼拆給經紀人與分店",[131,163,165],{"id":164},"_2-從流程中的關鍵事件切","2. 從流程中的關鍵事件切",[10,167,168,169,172],{},"跑過 Event Storming 或畫過粗粒度的領域故事後，時間軸上會有幾個",[30,170,171],{},"關鍵事件（Pivotal Event）","，它們是業務階段的分界：",[174,175,176],"blockquote",{},[10,177,178],{},"委託已簽訂 → 物件已上架 → 帶看已完成 → 斡旋已接受 → 買賣契約已簽訂 → 已交屋",[10,180,181],{},"兩個關鍵事件之間的那一段，通常就是一個子域的候選。",[131,183,185],{"id":184},"_3-從語言的變化","3. 從語言的變化",[10,187,188],{},"同一個詞意思開始不一樣的地方，就是邊界：",[139,190,191,194],{},[27,192,193],{},"刊登時的「物件」是一則廣告，在意的是照片好不好看、文案吸不吸引人",[27,195,196],{},"成交時的「物件」是一個交易標的，在意的是權狀、地號、有沒有抵押",[131,198,200],{"id":199},"_4-從組織與變化頻率","4. 從組織與變化頻率",[139,202,203,209],{},[27,204,205,208],{},[30,206,207],{},"誰負責？"," 刊登歸行銷、斡旋歸店長、佣金歸財務，不同部門的需求很少會同時改到",[27,210,211,214],{},[30,212,213],{},"多常改？"," 搜尋與推薦幾乎每個月都在調整，佣金規則一年才改一次",[10,216,217,218,221],{},"這四個角度得出的結果通常不會完全一致，",[30,219,220],{},"不一致的地方就是要拿去和領域專家討論的地方","。",[47,223,225],{"id":224},"第二步分類","第二步：分類",[10,227,228,229],{},"找出子域後，下一步是決定每一塊值得投資多少。分類的關鍵問題只有一個：",[30,230,231],{},"這一塊做得比對手好，客戶會因此選擇我們嗎？",[51,233,234,247],{},[54,235,236],{},[57,237,238,241,244],{},[60,239,240],{},"類型",[60,242,243],{},"判斷問題",[60,245,246],{},"策略",[73,248,249,260,271],{},[57,250,251,254,257],{},[78,252,253],{},"核心子域（Core）",[78,255,256],{},"做得好會讓客戶選我們、做不好會失去客戶",[78,258,259],{},"自己做，放最好的人，用完整的 DDD 設計，持續投資",[57,261,262,265,268],{},[78,263,264],{},"支撐子域（Supporting）",[78,266,267],{},"業務需要、買不到現成的，但做得再好客戶也不會在意",[78,269,270],{},"自己做但做簡單，可以外包，不需要複雜的設計",[57,272,273,276,279],{},[78,274,275],{},"通用子域（Generic）",[78,277,278],{},"每家公司都有一樣的問題，市場上有成熟方案",[78,280,281],{},"買現成的、用開源或雲端服務，不要自己寫",[131,283,285],{"id":284},"用-core-domain-chart-畫出來","用 Core Domain Chart 畫出來",[10,287,288,289,292],{},"只用文字分類容易流於主觀，可以用 Nick Tune 提出的 ",[30,290,291],{},"Core Domain Chart","，把每個子域放在兩個維度上：",[139,294,295,301],{},[27,296,297,300],{},[30,298,299],{},"橫軸：模型複雜度","，業務規則有多複雜、多難做對",[27,302,303,306],{},[30,304,305],{},"縱軸：業務差異化","，對競爭優勢的影響有多大",[10,308,309],{},[310,311],"img",{"alt":312,"src":313},"房仲業務的 Core Domain Chart：橫軸是模型複雜度，縱軸是業務差異化。上半部差異化高的區域是核心子域，物件媒合與推薦位在右上角，複雜度和差異化都最高，斡旋成交流程也在核心區；下半部差異化低，左下是支撐子域，包含物件刊登、帶看排程、佣金與業績；右下是通用子域，複雜但不帶來差異化，包含會員與登入、地圖與地理資訊、金流，這些應該買現成方案。右側說明各區的投資策略","\u002Fimages\u002Farticles\u002Fddd-core-domain-chart.svg",[10,315,316],{},"圖的讀法：",[139,318,319,325,331,337],{},[27,320,321,324],{},[30,322,323],{},"右上（核心）","：複雜又能帶來差異，是最值得投資的地方。物件媒合做得好，買方更快找到房子，經紀人的帶看成交率也更高",[27,326,327,330],{},[30,328,329],{},"左下（支撐）","：簡單、不帶來差異，自己做但用最簡單的方式做。帶看排程只要能約時間、會提醒就夠了",[27,332,333,336],{},[30,334,335],{},"右下（通用）","：很複雜，但做得好也不會讓客戶選我們。金流、身分驗證自己寫很容易出錯，應該買現成的",[27,338,339,342],{},[30,340,341],{},"左上","：簡單但有差異化，可能是一個剛出現的機會，或是很快會被對手模仿的功能",[10,344,345,346,349],{},"佣金與業績是個有趣的例子：規則其實不簡單（專任／一般委託的比例不同、跨店合作要拆帳），但它不影響客戶的選擇，所以是支撐子域。",[30,347,348],{},"複雜不等於核心","，這是分類時最常見的誤判。",[131,351,352],{"id":352},"分類不是永久的",[139,354,355,361],{},[27,356,357,360],{},[30,358,359],{},"公司策略決定核心","：同樣是房仲，主打「經紀人服務品質」的公司，帶看體驗可能就是核心；主打「線上找房」的公司，核心是搜尋和推薦",[27,362,363,366],{},[30,364,365],{},"核心會變成通用","：十年前地圖找房是差異化，現在每個房屋網站都有，加上地圖服務越來越成熟，它就變成通用子域了",[10,368,369],{},"所以分類的結果要寫下來，並且定期（例如每半年）重新檢視一次。",[47,371,373],{"id":372},"第三步對應到限界上下文","第三步：對應到限界上下文",[10,375,376,377,380],{},"理想上，",[30,378,379],{},"一個子域對應一個限界上下文","，邊界最清楚。但實際上常見幾種情況：",[139,382,383,389,395],{},[27,384,385,388],{},[30,386,387],{},"一個子域、多個上下文","：物件媒合包含「搜尋」和「推薦」，兩者的模型不同（搜尋要的是篩選條件，推薦要的是瀏覽紀錄和相似度），可以切成兩個上下文",[27,390,391,394],{},[30,392,393],{},"多個子域、一個上下文","：舊系統常常一個大系統包辦刊登、帶看、成交。短期內不一定要拆，但要知道它涵蓋了哪些子域，新功能盡量不要再往裡面塞",[27,396,397,400],{},[30,398,399],{},"通用子域變成外部服務","：金流直接用第三方，在自己這邊加一層防腐層，把對方的格式轉成自己的模型",[10,402,403],{},[310,404],{"alt":405,"src":406},"子域與限界上下文的對應：上方是問題空間的子域，物件刊登與帶看排程是支撐子域，物件媒合與斡旋成交是核心子域，金流是通用子域；下方是解法空間的限界上下文，物件刊登對應刊登上下文，物件媒合拆成搜尋與推薦兩個上下文，帶看排程對應帶看上下文，斡旋成交對應成交上下文，金流對應外部金流服務。每個上下文裡的「物件」模型都不同：刊登上下文是標題、照片、文案，搜尋上下文是座標、價格、坪數，推薦上下文是瀏覽紀錄與相似物件，帶看上下文只存物件 Id 與時段，成交上下文是權狀、地號與所有權人。刊登上下文透過「物件已上架」事件以公開語言通知搜尋與推薦，成交上下文透過防腐層串接外部金流服務","\u002Fimages\u002Farticles\u002Fddd-subdomain-to-context.svg",[10,408,409,410,413],{},"注意帶看上下文的「物件」只有 Id：帶看只需要知道是哪一間、地址在哪，不需要照片或權狀。",[30,411,412],{},"每個上下文只保留自己需要的部分","，這正是限界上下文的意義。",[10,415,416],{},"上下文之間的關係（上下文映射）也要一起決定：",[139,418,419,426],{},[27,420,421,422],{},"刊登 → 搜尋、推薦：刊登上下文發布「物件已上架」、「物件已改價」事件，用統一格式給多個下游（開放主機服務／公開語言），搜尋端再依事件更新自己的索引，做法類似 ",[13,423,425],{"href":424},"\u002Farticles\u002Fcqrs-elasticsearch-read-model","CQRS 的讀取模型",[27,427,428],{},"成交 → 外部金流：用防腐層把金流服務的欄位與狀態碼轉成成交上下文的模型，換金流商時只需要改這一層",[47,430,431],{"id":431},"邊界切錯的徵兆",[10,433,434],{},"切完之後，可以用這些問題檢查：",[139,436,437,443,449,455],{},[27,438,439,442],{},[30,440,441],{},"一個需求要同時改好幾個上下文？"," 偶爾發生是正常的，經常發生代表相關的規則被切開了",[27,444,445,448],{},[30,446,447],{},"上下文之間一直同步呼叫？"," 完成一件事要 A 呼叫 B、B 再呼叫 C，任何一個掛掉整個流程就失敗，代表它們其實是同一件事",[27,450,451,454],{},[30,452,453],{},"一個上下文需要兩個團隊一起改？"," 限界上下文最好由一個團隊負責，否則每次修改都要協調",[27,456,457,460],{},[30,458,459],{},"同一個上下文裡，同一個詞有兩種意思？"," 代表裡面其實有兩個模型，應該再切開",[10,462,463],{},"幾種常見的錯誤切法：",[51,465,466,476],{},[54,467,468],{},[57,469,470,473],{},[60,471,472],{},"切法",[60,474,475],{},"問題",[73,477,478,486,494,502],{},[57,479,480,483],{},[78,481,482],{},"依資料表切：物件服務、會員服務、訂單服務",[78,484,485],{},"每個業務流程都要跨好幾個服務，「物件服務」又變回所有人共用的大模型",[57,487,488,491],{},[78,489,490],{},"依技術層切：前端團隊、API 團隊、資料庫團隊",[78,492,493],{},"任何功能都要三個團隊排程，沒有人對完整的業務負責",[57,495,496,499],{},[78,497,498],{},"切得太細：每個聚合一個服務",[78,500,501],{},"服務之間的呼叫和資料同步成本超過拆分的好處",[57,503,504,507],{},[78,505,506],{},"照組織圖切，但組織本身就不合理",[78,508,509],{},"康威定律會把組織的問題複製到系統裡，有時候要調整的是團隊分工",[47,511,513],{"id":512},"不同類型不同做法","不同類型，不同做法",[10,515,516,517,520],{},"分類的目的是",[30,518,519],{},"把力氣花在對的地方","，不同類型的子域，架構和開發方式可以完全不同：",[51,522,523,538],{},[54,524,525],{},[57,526,527,529,532,535],{},[60,528],{},[60,530,531],{},"核心子域",[60,533,534],{},"支撐子域",[60,536,537],{},"通用子域",[73,539,540,554,572,586],{},[57,541,542,545,548,551],{},[78,543,544],{},"設計方式",[78,546,547],{},"完整的戰術設計：聚合、值物件、領域事件",[78,549,550],{},"簡單的分層或 Transaction Script，CRUD 也可以",[78,552,553],{},"不自己設計，整合現成方案",[57,555,556,559,566,569],{},[78,557,558],{},"架構",[78,560,561,565],{},[13,562,564],{"href":563},"\u002Farticles\u002Fhexagonal-architecture-dotnet","六角形架構","，隔離業務與技術",[78,567,568],{},"能動、好維護就好",[78,570,571],{},"用防腐層包起來",[57,573,574,577,580,583],{},[78,575,576],{},"測試",[78,578,579],{},"業務規則要有完整的單元測試",[78,581,582],{},"主要流程的整合測試",[78,584,585],{},"測試整合的那一層",[57,587,588,591,594,597],{},[78,589,590],{},"人力",[78,592,593],{},"最資深、最懂業務的人",[78,595,596],{},"新人、外包都可以",[78,598,599],{},"少量人力負責整合",[10,601,602],{},"「全部都用完整的 DDD」和「全部都不用」一樣不好。用在核心子域，才能得到 DDD 最大的回報。",[47,604,605],{"id":605},"一句話總結",[10,607,608],{},"子域是從業務能力、關鍵事件、語言變化與組織分工中「發現」出來的，用「做得好會不會讓客戶選我們」與模型複雜度把它們分成核心、支撐、通用；限界上下文則是我們「設計」的系統切法，理想上和子域一對一，但可以視模型差異再拆或暫時合併，每個上下文只保留自己需要的模型，最後把最多的心力放在核心子域。",{"title":610,"searchDepth":611,"depth":611,"links":612},"",2,[613,614,621,625,626,627,628],{"id":49,"depth":611,"text":49},{"id":125,"depth":611,"text":126,"children":615},[616,618,619,620],{"id":133,"depth":617,"text":134},3,{"id":164,"depth":617,"text":165},{"id":184,"depth":617,"text":185},{"id":199,"depth":617,"text":200},{"id":224,"depth":611,"text":225,"children":622},[623,624],{"id":284,"depth":617,"text":285},{"id":352,"depth":617,"text":352},{"id":372,"depth":611,"text":373},{"id":431,"depth":611,"text":431},{"id":512,"depth":611,"text":513},{"id":605,"depth":611,"text":605},"2024-04-30","DDD 概論 裡簡單介紹了子域和限界上下文，Domain Storytelling 那篇也從故事裡找出了「搜尋、帶看、斡旋」三個候選邊界。但真的要替整個系統劃分時，還有幾個問題要回答：",null,"md",{},true,"\u002Farticles\u002Fddd-subdomains-bounded-context",{"title":5,"description":630},"articles\u002Fddd-subdomains-bounded-context",[639,640,641,642,643],"DDD","領域驅動設計","架構設計","系統設計","微服務","la84EVeNZ0qtKX0H9GDJd5eCDOTztgSnb7xdGfj3na4",1792959150387]