> DDD 实战1 - 基础代码模型
> DDD 实战2 - 集成限界上下文(Rest & DubboQ?/a>
> DDD 实战3 - 集成限界上下文(消息模式Q?br />> DDD 实战4 - 领域事g的设计与使用
> DDD 实战5 - 实体与值对?br />> DDD 实战6 - 聚合的设?br />> DDD 实战7 - 领域工厂与领域资源库
> DDD 实战8 - 领域服务与应用服?br />> DDD 实战9 - 架构设计
> DDD 实战10 - 战略设计
当h们要做一个Y件系l时Q一般L因ؓ(f)遇到了什么问题,然后希望通过一个Y件系l来解决?/p>
比如Q我是一家企业,然后我觉得我现在U下销售自q产品q不够,我希望能够在U上也能销售自q产品。所以,自然而然想到要做一个普通电(sh)商系l,用于实现在线销售自׃业品的目的?/p>
再比如,我是一家互联网公司Q公司有很多pȝ对外提供服务Q面向很多客L(fng)讑֤。但是最q由于各U原因,D服务l常出故障。所以,我们希望通过各种措施提高服务的质量和E_性。其中的一个措施就是希望能做一个灰度发布的q_Q这个^台可以提供灰度发布的服务。然后,当某个业务系l做了一些修改ƈ需要发布时Q可以用我们的灰度发布q_来非常方便的实现灰度发布的功能。比如在灰度发布q_上方便的定制允许哪些特定的客L(fng)才会(x)讉K新服务,哪些客户端l用老服务。灰度发布^台可以提供各U灰度的{略。有了这L(fng)灰度发布机制Q那即便pȝ的新逻辑有什么问题,受媄(jing)响的面也不会(x)很大Q在可控范围内。所以,如果公司里的所有对外提供服务的pȝ都接入了灰度q_Q那q些pȝ的发布环节就可以更加有保障了?/p>
MQ我们做M一个Y件系l,都是有原因的Q否则就没必要做q个pȝQ而这个原因就是我们遇到的问题。所以,通过问题Q我们就知道了我们需要一个什么样的系l,q个pȝ解决什么样的问题。最后,我们很自然的得Z一个目标,即知道了自己要什么。比如我要做一个论坛、一个博客系l、一个电(sh)商^台、一个灰度发布系l、一个IDE、一个分布式消息队列、一个通信框架Q等{?/p>
DDD的全UCؓ(f)Domain-driven DesignQ即领域驱动设计。下面我从领域、问题域、领域模型、设计、驱动这几个词语的含义和联系的角度去阐述DDD是如何融入到我们qx的Y件开发初期阶D늚。要理解什么是领域驱动设计Q首先要理解什么是领域Q什么是设计Q还有驱动是什么意思,什么驱动什么?/p>
前面我们已经清楚的知道我们现在要做一个什么样的系l,q个pȝ需要解决什么问题。我认ؓ(f)M一个系l都?x)属于某个特定的领域Q比如论坛是一个领域,只要你想做一个论坛,那这个论坛的核心业务是确定的Q比如都有用户发帖、回帖等核心基本功能。比如电(sh)商^台、普通电(sh)商系l,q种都属于网上电(sh)商领域,只要是这个领域的pȝQ那都有商品览、购物R、下单、减库存、付?gu)ƾ交易等核心环节。所以,同一个领域的pȝ都具有相同的核心业务Q因Z们要解决的问题的本质是类似的?/p>
因此Q我们可以推断出Q一个领域本质上可以理解为就是一个问题域Q只要是同一个领域,那问题域q同。所以,只要我们定了系l所属的领域Q那q个pȝ的核心业务,卌解决的关键问题、问题的范围边界基本确定了。通常我们_(d)要成Z个领域的专家Q必要在这个领域深入研I很多年才行。因为只有你研究了很多年Q你才会(x)遇到非常多的该领域的问题Q同时你解决q个领域中的问题的经验也非常丰富。很多时候,领域专家比技术专家更加吃香,比如金融领域的专家?/p>
DDD中的设计主要指领域模型的设计。ؓ(f)什么是领域模型的设计而不是架构设计或其他的什么设计呢Q因为DDD是一U基于模型驱动开发的软g开发思想Q强调领域模型是整个pȝ的核心,领域模型也是整个pȝ的核心h(hun)值所在。每一个领域,都有一个对应的领域模型Q领域模型能够很好的帮我们解军_杂的业务问题?/p>
从领域和代码实现的角度来理解Q领域模型绑定了领域和代码实玎ͼ保了最l的代码实现׃定是解决了领域中的核心问题的。因为:(x)1Q领域驱动领域模型设计;2Q领域模型驱动代码实现。我们只要保证领域模型的设计是正的Q就能确定领域模型可以解决领域中的核心问题;同理Q我们只要保证代码实现是严格按照领域模型的意图来落地的,那就能保证最后出来的代码能够解决领域的核心问题的。这个思\Q和传统的分析、设计、编码这几个阶段被割裂(q且每个阶段的物也不同Q的软g开发方法学形成鲜明的对比?/p>
上面其实已经提到了,是Q?Q领域驱动领域模型设计;2Q领域模型驱动代码实现。这个就和我们传l的数据库驱动开发的思\形成Ҏ(gu)了。DDD中,我们L以领域ؓ(f)边界Q分析领域中的核心问题(核心x点)Q然后设计对应的领域模型Q再通过领域模型驱动代码实现。而像数据库设计、持久化技术等q些都不是DDD的核心,而是外围的东ѝ?/p>
领域驱动设计QDDDQ告诉我们的最大h(hun)值我觉得是:(x)当我们要开发一个系l时Q应该尽量先把领域模型想清楚Q然后再开始动手编码,q样的系l后期才?x)很好维护。但是,很多目Q尤其是互联|项目,Z赶工Q都是一开始模型没x楚,一上来开始徏表写代码Q代码写的非常冗余,完全是过E是的思考方式,最后导致系l非帔R以维护。而且更糟p的是,出来hL要还的,前期的领域模型设计的不好Q不够抽象,如果你的pȝ?x)长期需要维护和适应业务变化Q那后面你一定会(x)遇到各种问题l护上的困难Q比如数据结构设计不合理Q代码到处冗余,改BUG到处引入新的BUGQ新人对q种代码上手困难Q等。而那时如果你再想重构模型Q那要付出的代h(hun)?x)比一开始重新开发还要大Q因Zq要考虑兼容历史的数据,数据q移Q如何^滑发布等各种头疼的问题。所以,导致我们最后天天加班?/p>
虽然Q我们都知道q个道理Q但是我也明白,人的?fn)惯很难改变的,大部分h都很难从面向q程式的惛_哪里写到哪里的思想转变为基于系l化的模型驱动的思维。我惻Iq或许是DDD很难在中国或国外行h的原因吧。但是,我想q不应该成ؓ(f)我们攑ּ学习(fn)DDD的原因,对吧Q?/p>
上面我们通过W一步,虽然我们明确了要做一个什么样的系l,该系l主要解决什么问题,但是ph们还无法开始进行实际的需求分析和模型设计Q我们还必须我们的问题q行拆分Q需求进行细化。有些时候,需求方Q即提出问题的hQ很可能自己不清楚具体想要什么。他只知道一个概念,一个大的目标。比如他只知道要做一个股交易系l,一个灰度发布系l,一个电(sh)商^収ͼ一个开发工P{。但是他不清楚这些系l应该具体做成什么样子。这个时候,我认为领域专家就非常重要了,DDD也非常强调领域专家的重要性。因为领域专家对q个领域非常了解Q对领域内的各种业务场景和各U业务规则也非常清楚QMQ对q个领域内的一切业务相关的知识都非怺解。所以,他们自然有能力表达出系l该做成什么样子。所以,要知道一个系l到底该做成什么样子,到底哪些是核心业务关注点Q只能靠沉淀(wn)领域内的各种知识Q别无他法。因此,假设你现在打做一个电(sh)商^収ͼ但是你对q个领域没什么了解,那你一定得先去了解下该领域内主的?sh)商q_Q比如淘宝、天猫、京东、亚马逊等。这个了解的q程是你沉淀(wn)领域知识的过E。如果你不了解,q你领域徏模的能力再强Q各U技术架构能力再Z是不上力。领域专家不是某个固定的角色Q而是某一cMhQ这cMh对这个领域非怺解。比如,一个开发h员也可以是一个领域专家。假设你在一个公司开发和l护一个系l已l好几年了,但是q个pȝ的品经理(PDQ可能已l换q好几Q了,q种情况下,我相信这几Q产品l理都没有比你更熟?zhn)q个领域?/p>
上面我们明白了,领域建模的基是要先理解领域,让自己成为领域专家。如果做Cq点Q我们就打好了坚实的基础了。但是,有时一个领域往往太复杂,涉及(qing)到的领域概念、业务规则、交互流E太多,D我们没办法直接针对这个大的领域进行领域徏模。所以,我们需要将领域q行拆分Q本质上是把大问题拆分为小问题Q然后各个击破的思\。然后既然把一个大的领域划分ؓ(f)了多个小的领域(子域Q,那最关键的就是要理清每个子域的边界;然后要搞清楚哪些子域是核心子域,哪些是非核心子域Q哪些是公共支撑子域Q然后,q要思考子域之间的联系是什么。那么,我们该如何划分子域呢Q我的个人看法是从业务相x的角度L考,也就是我们^时说的按业务功能为出发点q行划分。还是拿l典的电(sh)商系l来分析Q通常一个电(sh)商系l都?x)包含好几个大块Q比如:(x)
上面q些中心看v来很自然Q因为大家对?sh)子商务的这个领域都已经非常熟(zhn)了,所以都没什么疑问,好像很自然的样子。所以,领域划分是不是就是没什么挑战了呢?昄不是。之所以我们觉得子域划分很单,是因为我们对整个大领域非怺解了。如果我们遇C个冷门的领域Q就没办法这么容易的d分子域了。这需要我们先d力理解领域内的知识。所以,我个Z来不怿什么子域划分的技巧什么的东西Q因为我觉得q个工作没有M诀H可以用。当我们不了解一个东西的时候,如何L解它Q当我们Ҏ(gu)个领域有一定的熟?zhn)了,了解了领域内的相关业务的本质和关p,我们p然而然的能划分出合理的子域了。不qƈ不是所有的pȝ都需要划分子域的Q有些系l只是解决一个小问题Q这个问题不复杂Q可能只有一两个核心概念。所以,q种pȝ完全不需要再划分子域。但不是l对的,当一个领域,我们的关注点来多Q每个关注点我们x的信息越来越多的时候,我们?x)不pȝ去进一步的划分子域。比如,也许我们一开始将商品和商品的库存都放在商品中心里Q但是后来由于库存的l护来复杂,D揉在一起对我们的系l维护带来一定的困难Ӟ我们׃(x)考虑两者进行拆分,q个是所谓的业务垂直分割?/p>
通过上面的两步,我们了解了领域里的知识,也对领域q行了子域划分。但q样q不够,凭这些我们还无法q行后箋的领域模型设计。我们还必须再进一步细化每个子域,q一步明每个子域的核心x点,即需求细化。我觉得我们需要细化的斚w有以下几点:(x)
从上面这4个方面,我们从领域概c(din)业务规则、交互场景、业务流E等l度梳理了我们到底要什么,整理了整个系l应该具备的功能。这个工作我觉得是一个非常具有创造性和有难度的工作。我们一斚w?x)主观的定义我们惌什么;另一斚wQ我们还?x)思考我们要的东西的合理性。我认ؓ(f)q个是产品l理的工作,产品l理必须要负赯责,把他的品充分设计好Q从各个斚w去考虑Q如何设计一个品,才能更好的解决用L(fng)核心诉求Q即领域内的核心问题。如果对领域不够了解Q如果想不清楚用户到底要什么,如果思考问题不够全面,谈何设计Z个合理的产品呢?
关于领域概念的梳理,我觉得可以采用四色原型分析法Q这个分析法通过pȝ的方法,概念划分ؓ(f)不同的种c,Z同种cȝ概念标注不同的颜艌Ӏ然后将q些概念有机的组合v来,从而让我们可以清晰的分析出概念和概念之间的关系。有兴趣的同学可以在|上搜烦(ch)?a target="_blank" style="color: #1d58d1; text-decoration: none;">四色原型?/p>
注意Q上面我说的q四点,重点是梳理出我们要什么功能,而不是思考如何实现这些功能,如何实现是Y件设计h员的职责?/strong>
q部分内容,我想学习(fn)DDD的h都很熟?zhn)了。DDD原著中提Z很多实用的徏模工P(x)聚合、实体、值对象、工厂、仓储、领域服务、领域事件。我们可以用这些工P来设计每一个子域的领域模型。最l通过领域模型囑ְ设计沉淀(wn)下来。要使用q些工具Q首先就要理解每个工L(fng)含义和用场景。不要以为很单哦Q比如聚合的划分是一个非常具有艺术的zR同一个系l,不同的h设计出来的聚合是完全不同的。而且很有可能高手之间的最后设计出来的差别反而更大,实际上我认ؓ(f)是世界观的相互碰撞,呵呵。所以,要领域徏模,我觉得每个h都应该去学学哲学知识Q这有助于我们更好的认识世界Q更好的理解事物的本质?/p>
关于q些建模工具的概念和如何q用我就不多展开了,我博客里也有很多q方面的介绍。下面我再讲一下我认ؓ(f)比较重要的东西,比如到底该如何领域徏模?步骤应该是怎么L(fng)Q?/p>
通过上面我介l的l化子域的内容,现在再来谈该如何领域建模Q我觉得方便很多了。我的主要方法是Q?/p>
下图是我最q做个一个普通电(sh)商系l的商品中心的领域模型图Q给大家参考:(x)
需要特别注意的是,领域模型设计只是整个软g设计中的很小一部分。除了领域模型设计之外,要落C个系l,我们q有非常多的其他设计要做Q比如:(x)
{等。上面这些都需要我们^时的大量学习(fn)和积累。作Z个合格的开发h员或架构师,我觉得除了要?x)DDD领域驱动设计Q还要会(x)上面q么多的技术能力,实是非怸Ҏ(gu)的。所以,千万不要以ؓ(f)?x)DDD了就以ؓ(f)自己很牛|实际上你?x)的只是软g设计中的冰山一角而已?/p>
本文的重Ҏ(gu)Z我个人对DDD的一些理解,希望能整理出一些自己ȝ出来的一些感(zhn)和l验Qƈ分nl大家。我怿很多人已l看q太多DDD书上的东西,我L感觉书上的东西看似都?#8221;正规“Q很多时候我们读了之后很难消化,q理解了书里的内容Q当我们惌q用到实践中ӞL感觉无从下手。本文希望通过通俗易懂的文字,介绍了一部分我对DDD的学?fn)感?zhn)和实践心得Q希望能l大家一些启发和帮助?/p>