[{"data":1,"prerenderedAt":406},["ShallowReactive",2],{"blog-ddd-complex-business":3},{"id":4,"title":5,"body":6,"category":391,"date":392,"description":382,"extension":393,"meta":394,"navigation":395,"path":396,"seo":397,"series":398,"seriesOrder":399,"stem":400,"tags":401,"__hash__":405},"blog\u002Fblog\u002Fddd-complex-business.md","DDD 实战（一）：DDD 到底在解决什么问题",{"type":7,"value":8,"toc":381},"minimark",[9,13,28,46,49,57,62,65,84,87,90,97,100,104,107,110,127,130,133,140,147,154,160,164,172,180,183,189,195,201,204,208,211,240,243,246,269,272,275,292,295,299,302,308,317,323,329,335,339,342,366,372,375],[10,11,5],"h1",{"id":12},"ddd-实战一ddd-到底在解决什么问题",[14,15,16],"blockquote",{},[17,18,19,20,27],"p",{},"推荐 ",[21,22,26],"a",{"href":23,"rel":24},"https:\u002F\u002Fbewild.ai?code=BYZDOTME",[25],"nofollow","BeWild"," 代充 Codex ，工作猛猛提效。",[17,29,30,31,35,36,35,39,35,42,45],{},"很多人第一次接触 DDD，会先看到一堆名词：限界上下文、核心域、聚合根、领域服务、仓储、领域事件。再往后看，往往又会看到一套目录结构：",[32,33,34],"code",{},"domain","、",[32,37,38],{},"application",[32,40,41],{},"infrastructure",[32,43,44],{},"interfaces","。",[17,47,48],{},"于是 DDD 很容易被误解成一种“高级分层架构”：只要把代码放进这些目录，把数据库表映射成实体，再把 service 改名叫 application service，好像就完成了 DDD。",[17,50,51,52,56],{},"这其实把问题看反了。DDD 首先不是目录规范，而是一套",[53,54,55],"strong",{},"管理业务复杂度的方法","。目录结构只是模型边界落到代码里的结果。",[58,59,61],"h2",{"id":60},"_1-复杂业务不是功能多而是变化多","1. 复杂业务不是功能多，而是变化多",[17,63,64],{},"业务复杂度不等于页面多、接口多、表多。一个后台管理系统可能有上百张表，但如果所有功能都是简单增删改查，它并不复杂。真正复杂的是这些情况：",[66,67,68,72,75,78,81],"ul",{},[69,70,71],"li",{},"同一个词在不同场景里含义不同。",[69,73,74],{},"一个业务动作会牵动多个模块，且每个模块有自己的规则。",[69,76,77],{},"规则经常变化，而且变化点不集中。",[69,79,80],{},"不同团队对同一对象有不同理解。",[69,82,83],{},"数据一致性、权限、审计、通知、搜索、开放接口同时参与同一个流程。",[17,85,86],{},"拿协同办公 IM 来说，“用户”这个词就不稳定。",[17,88,89],{},"在登录场景里，用户是账号、凭证、设备、登录会话。在组织通讯录里，用户是某个企业下的成员。在外部联系人里，用户可能是客户、好友、供应商。在群聊里，用户又是群成员、群主、管理员、普通成员或被禁言成员。",[17,91,92,93,96],{},"如果整个系统都共享一个 ",[32,94,95],{},"User"," 模型，短期看起来很省事，长期就会出现一个越来越大的“用户中心”。所有模块都往里面加字段、加规则、加判断，最后谁都不敢改。",[17,98,99],{},"DDD 要解决的第一类问题，就是让不同业务语境拥有自己的模型，而不是强迫全系统共享一个万能模型。",[58,101,103],{"id":102},"_2-普通三层架构为什么会失效","2. 普通三层架构为什么会失效",[17,105,106],{},"经典三层架构通常分为 Controller、Service、DAO。对于简单业务，这种分层很有效：入口、业务逻辑、数据访问各司其职。",[17,108,109],{},"但业务复杂之后，三层架构经常演变成这样：",[66,111,112,115,118,121,124],{},[69,113,114],{},"Controller 只负责转发请求。",[69,116,117],{},"DAO 只负责读写数据库。",[69,119,120],{},"所有业务规则都堆到 Service。",[69,122,123],{},"Service 之间互相调用，互相知道对方的数据结构。",[69,125,126],{},"数据库表结构逐渐变成事实上的业务模型。",[17,128,129],{},"这种结构最大的问题，不是代码不够优雅，而是业务知识没有稳定的位置。一个规则到底属于账号、组织、关系、群组还是消息，没人能说清楚。只要需求来了，就在最顺手的 Service 里补一个判断。",[17,131,132],{},"几年之后，系统会出现三种典型症状。",[17,134,135,136,139],{},"第一，",[53,137,138],{},"模型失血","。实体只是数据库字段的搬运对象，业务规则散落在各种 service、handler、util 里。代码里有对象，但没有业务模型。",[17,141,142,143,146],{},"第二，",[53,144,145],{},"边界失焦","。账号模块可以改好友关系，群聊模块可以改成员资料，消息模块可以直接查组织表。调用链越来越短，耦合越来越深。",[17,148,149,150,153],{},"第三，",[53,151,152],{},"语言断裂","。产品、业务、测试、开发说的都是“用户”“群”“联系人”，但每个人心里的含义不一样。需求评审时看似达成一致，落到代码里才发现理解完全不同。",[17,155,156,157],{},"DDD 不是为了替代三层架构，而是为了补上三层架构没有回答的问题：",[53,158,159],{},"业务概念如何建模，模型边界如何确定，变化如何被限制在局部。",[58,161,163],{"id":162},"_3-ddd-的核心模型语言和边界","3. DDD 的核心：模型、语言和边界",[17,165,166,167],{},"Microsoft 的微服务领域分析文档强调，服务边界没有机械的标准答案，需要从业务域、需求、架构特征和目标中推导；它也把 DDD 分成战略设计和战术设计两部分。战略设计关注大系统结构，战术设计关注实体、聚合、领域服务等模型模式。",[21,168,171],{"href":169,"rel":170},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Farchitecture\u002Fmicroservices\u002Fmodel\u002Fdomain-analysis",[25],"Microsoft: Domain analysis for microservices",[17,173,174,175],{},"Martin Fowler 在解释 Bounded Context 时，也强调模型只有在某个上下文边界内才有明确含义，同一个术语在不同上下文里可以对应不同模型。",[21,176,179],{"href":177,"rel":178},"https:\u002F\u002Fmartinfowler.com\u002Fbliki\u002FBoundedContext.html",[25],"Martin Fowler: Bounded Context",[17,181,182],{},"这两点正好说明 DDD 的核心不是“把项目分成几层”，而是三件事。",[17,184,135,185,188],{},[53,186,187],{},"建立统一语言","。开发、产品、业务专家要围绕同一套业务词汇沟通。这个语言不只写在文档里，也要进入代码。",[17,190,142,191,194],{},[53,192,193],{},"识别模型边界","。同一个现实对象，在不同业务上下文里可以有不同模型。账号、组织成员、好友、群成员不必强行合并成同一个大对象。",[17,196,149,197,200],{},[53,198,199],{},"保护业务规则","。重要规则应该沉淀在领域模型里，而不是散落在接口层和数据库访问层。",[17,202,203],{},"DDD 的价值不在于让代码看起来更“架构化”，而在于让业务规则有稳定表达，让变化有明确落点。",[58,205,207],{"id":206},"_4-用协同办公-im-看-ddd-的必要性","4. 用协同办公 IM 看 DDD 的必要性",[17,209,210],{},"协同办公 IM 是一个非常适合讲 DDD 的业务场景。它看起来是“聊天软件”，实际上覆盖了很多不同业务域：",[66,212,213,216,219,222,225,228,231,234,237],{},[69,214,215],{},"账号、认证、设备、安全策略。",[69,217,218],{},"企业、部门、成员、角色、通讯录。",[69,220,221],{},"好友、联系人、外部联系人、黑名单。",[69,223,224],{},"单聊、群聊、群成员、群治理。",[69,226,227],{},"消息、已读未读、撤回、转发、引用、附件。",[69,229,230],{},"通知、离线推送、站内提醒。",[69,232,233],{},"工作台、审批、日程、任务、文档。",[69,235,236],{},"开放平台、机器人、Webhook、事件订阅。",[69,238,239],{},"搜索、审计、风控、合规。",[17,241,242],{},"如果只按技术分层组织这些能力，系统很容易变成“一个 IM 大服务 + 一堆辅助模块”。早期开发会很快，但业务持续演进后，几个问题会越来越突出。",[17,244,245],{},"比如“从企业组织中移除一个成员”这件事，至少会影响：",[66,247,248,251,254,257,260,263,266],{},[69,249,250],{},"登录权限是否立即失效。",[69,252,253],{},"通讯录是否还能搜索到这个人。",[69,255,256],{},"历史消息是否保留。",[69,258,259],{},"群成员身份是否移除。",[69,261,262],{},"文档权限是否回收。",[69,264,265],{},"机器人和开放平台事件是否通知。",[69,267,268],{},"审计日志是否记录。",[17,270,271],{},"这些动作不应该由一个超级 Service 同步完成。更合理的方式，是让组织上下文发布“成员离职”或“成员移除”事件，由消息、群组、文档、搜索、开放平台、审计等上下文分别响应。",[17,273,274],{},"这里就自然引出了 DDD 的几个关键问题：",[66,276,277,280,283,286,289],{},[69,278,279],{},"哪些模型应该属于同一个限界上下文？",[69,281,282],{},"哪些操作必须在一个聚合内强一致？",[69,284,285],{},"哪些动作可以通过领域事件最终一致？",[69,287,288],{},"哪些能力是核心域，哪些是支撑域，哪些是通用域？",[69,290,291],{},"当前系统应该是模块化单体，还是拆成多个服务？",[17,293,294],{},"这些问题没有标准答案，但必须有清晰的推理过程。",[58,296,298],{"id":297},"_5-ddd-不是什么","5. DDD 不是什么",[17,300,301],{},"为了避免走偏，先把几个常见误解说清楚。",[17,303,304,307],{},[53,305,306],{},"DDD 不是微服务。"," 微服务可以以 DDD 作为边界识别方法，但 DDD 不要求一开始就拆服务。很多系统更适合先做模块化单体，把领域边界在代码里立住，再按演进压力拆部署。",[17,309,310,313,314,316],{},[53,311,312],{},"DDD 不是贫血模型加目录结构。"," 如果 ",[32,315,34],{}," 目录里只有字段和 getter\u002Fsetter，业务规则仍然写在 application service 里，那只是换了文件夹。",[17,318,319,322],{},[53,320,321],{},"DDD 不是数据库建模。"," 聚合边界不是外键关系，聚合根不是主表对象。聚合关注的是业务一致性边界，不是表结构层级。",[17,324,325,328],{},[53,326,327],{},"DDD 不是越细越好。"," 边界切得太粗会耦合，切得太细会增加协作成本。DDD 追求的是当前业务阶段下足够清晰、足够可演进的模型。",[17,330,331,334],{},[53,332,333],{},"DDD 不是一次性设计。"," 业务演进几年后，今天合理的边界可能会变得别扭。领域模型需要持续复盘和重构。",[58,336,338],{"id":337},"_6-这个系列会怎么展开","6. 这个系列会怎么展开",[17,340,341],{},"这个系列采用一条从认知到落地的路线：",[343,344,345,348,351,354,357,360,363],"ol",{},[69,346,347],{},"先讲 DDD 解决什么问题。",[69,349,350],{},"再讲战略设计：领域、子域、核心域、支撑域、通用域、限界上下文。",[69,352,353],{},"再讲战术设计：实体、值对象、聚合根、领域服务、领域事件。",[69,355,356],{},"然后基于钉钉、飞书\u002FLark 等公开产品和开放平台能力，推导协同办公 IM 的业务域地图。",[69,358,359],{},"接着专门讨论账号、组织、关系、群组这些最容易争议的边界。",[69,361,362],{},"再讨论消息、通知、搜索、开放平台这些跨域协作能力。",[69,364,365],{},"最后落到部署模块和 Go 项目代码组织。",[17,367,368,369],{},"我的基本观点是：",[53,370,371],{},"DDD 的严格性不在于找到唯一标准答案，而在于能够说清楚为什么这样建模、代价是什么、什么时候需要推翻它。",[17,373,374],{},"这也是程序员真正敢在项目中实践 DDD 的前提。",[17,376,377],{},[21,378,380],{"href":379},"\u002Fblog\u002F","返回博客列表",{"title":382,"searchDepth":383,"depth":383,"links":384},"",2,[385,386,387,388,389,390],{"id":60,"depth":383,"text":61},{"id":102,"depth":383,"text":103},{"id":162,"depth":383,"text":163},{"id":206,"depth":383,"text":207},{"id":297,"depth":383,"text":298},{"id":337,"depth":383,"text":338},"架构设计","2026-06-24","md",{},true,"\u002Fblog\u002Fddd-complex-business",{"title":5,"description":382},"DDD 实战",1,"blog\u002Fddd-complex-business",[402,403,391,404],"DDD","领域驱动设计","复杂业务","Te-cbOKEj9bdTGReS6XL2YfNT4mz0T5krWgqbk4fXZY",1784193099137]