戏说领域驱动设计(四)——本质论
所谓“读书破万卷,下笔如有神”,放到DDD上面确是个难题,仅这章的破题部分就难住了我,想要做到言简意赅但还不能口若悬河。虽自信本人面对指责应可作到宠辱不惊,但也不能依仗此而无赖的误导别人,所以本单的内容“我妄言之,您姑且听之”。
我有过这样的经验,读书的越多后面能攫取的有用的知识越少,也许从一本书中只能获取到一条有用的内容,可正是因为这一条内容会让自己瞬间悟道。2015年前我曾经读遍了市场上所有的DDD国内外相关书籍,也几乎读遍了能从网络上找到的各类问题。大方面都了解,可在日常工作中经常会因为一个小的细节让自己不得要领。因为这一小的瓶颈,无法上升到另外的一层台阶。所以我期望个人的一些经验能在您悟道的途中起到启发作用。
本章我会着重解释一下DDD的本质,也就是其到底在说些什么。这里面有个人的理解也有书上的理论,结合在一起,说一些白话,最重要的是掀起她那神秘的盖头。
一、DDD主要说明了什么
DDD分为两个部分:战略与战术。本质一点,这两点可指导您在业务与技术两方面应如何做来最小化需求变更导致的系统调整;再本质一点,DDD所达到的最终结果就是我们常常在面向对象中所说的:高内聚、低耦合。实际上,想要做到这两并不拘泥于是否使用了DDD,DDD之前也有许多上佳的实践可供使用。我们把目标进行反推:高内聚、低耦合的系统必然会让您的系统易维护、易扩展。易维护与扩展的系统必然是在设计之初就在业务方面与技术方面进行了思考与设计,这是起点,而DDD正好服务于这个起点。下图概括了DDD包含的内容,其实没您想像的复杂。
二、战略模式
1、子域
DDD的战略模型主要关注于“子域”与“限界上下文”,这两个都是DDD中的特有名词。用白话去说:“子域”是一种概念模型。再直白一点,假如您对比子域说明和实际的系统部署说明,会发现两者并不能一一对应。再比如,您以微服务架构落地一个OA系统,子服务可能包含“用户管理”、“签到管理”、“会议室管理”,这些是您可见的一个个的服务,也许还使用了不同的开发语言。而子域是虚的,是对一个大系统在业务上划小后人为的赋予每一个小业务的名称。仍然以OA系统为例,在系统未构建前将OA这个领域分成几个“中心”,比如“审批中心”、“员工中心”、“公文中心”,叫什么名是您自己定义的,是为了后面大家讨论的时候能明白彼此在说什么,这里的中心即为子域;放到落地阶段,“员工中心”搞不好会分成多个子系统比如“签到管理”、“绩效管理”,这些才是物理上可见的服务。
针对“子域”,此处您需要记住的是:1)子域是一种对领域的概念上的划分,是人为的主观行为,灵活性较高;2)子域的目的是把大的领域划小,使用分而治之的方法来简化业务设计时的复杂度;3)子域的划分是变化的,随着您对系统认识度的加深,会删除某些子域并增加新的进来,这不是您早期的划分有错,而是很自然的现象。子域的划分方式及相关细节会在下一章进行阐述。
2、限界上下文
“限界上下文(Bounded Context,为方便,后续文章中都将其简称为BC)”又是一个容易产生疑惑的名称。其重点是关注于系统的物理划分,在这里我给出的不严格定义是:限界上下文泛指系统中的模块、微服务架构中的子服务、单体中的“包(Java)”或“名称空间(C#)”。请拿出小本本记录下来:BC是对系统的一个物理划分,这里存在着可见的边界。实践中,建议明确子域后再进行BC设计,这种方式会让您的工作具备理论指导。
您可能会问:为什么叫限界上下文?这东西得分成两个词:限界,您的领域模型的活动范围是有界限的,不能像脱了缰的野马一样乱窜。那这个界限是什么或者说要将领域模型限制在哪里呢?答:“上下文”中!换成人话就是某个系统或某个业务场景。因此,系统设计之初“您需要画一个圈,将领域模型限制在这个圈内保证其不可串场,这个‘圈’即为限界上下文,实现时可以是一个单独的服务或‘包’或‘名称空间’”。引入BC的目的是为了达到“高内聚、低耦合”这个目标。想像一下:领域模型都在自身的圈子活动,互不干扰,后续有任何变更都不会超圈,这样的程序是否会更好维护?限界上下文的定义可以说是相当严谨的,但同时也比较晦涩。所以在非严格的场景下只需从朴素的角度理解即可。
另外,DDD还有一个词叫“通用语言”,简单来说就是大家在说一个东西的时候都能明白彼此所指的是什么。比如有个流行词叫“打卡”,如果您在和朋友聊工作考勤,这里的打卡代表的是员工到公司时的签到;如果您和朋友在聊某个比较火的景点或美食,这里的打卡代表着某人曾至此一游。因场景不同,同一个词就会有着不同的含义。这个场景有专业人士称其为“语境”,其实也就是“限界上下文”,所以BC又多了一层其它的作用:他给予了某个东西一个唯一的含义。实际上,“通用语言”是面向BC的,只有在BC内讨论才有意义。书上常说做DDD要有事件风暴,事件风暴的主要作用除了确认子域、BC、领域模型外,设定通用语言也是其主要的目的之一。
总结一下BC的概念:1)是系统的物理划分;2)应根据子域进行推导;3)限定了领域模型的边界;4)BC内,领域术语都有一个明确的含义(即通用语言)。
三、战术模式
战术模式对于技术人员来说就比较熟悉了,比如系统架构、领域模型、分层这类纯技术的内容,是DDD书籍中大讲特讲的部分。战术模式更多的聚焦于BC内,这方面的内容后续我们会进行细化说明。
复杂业务场景落地时,DDD尤其推荐使用面向对象或称之为对象驱动(ODD)的编程方式。实际上,DDD并不局限于面向对象,面向过程(经典三层模式)也会被经常用到。以个人的经验来看,两种方式使用的比例至多五五开,ODD使用率并不高,一般都在核心域内使用。Martin Fowler认为面向过程是一种“反模式”,我倒是觉得不存在正或反的概念,适合的最好。我们知道,一个研发团队应该以枣核形状为最佳,即存在着一大批的中等水平的工程师。ODD落地难度较大,开发缓慢,工作量也相对较多,应只在非常复杂的、多变的业务场景下使用。从管理角度来说,让整个团队无差别的使用面向对象编程也不太适合一般企业中的一般团队。
四、反思
有人会反驳说:DDD如果就是这点内容,为什么我看了半天看不懂,看懂了落地又如此之难。其实原因很简单:要构建优秀的系统,DDD指导仅仅是一方面。正常来说,系统分成内外两面,用户能看到的只有外面。虽然外面的工作量相对少也无法直接反映出架构的优秀度,但其是用户直接可见的,界面不好用、不好看,给人的印象就不好。再举个例子,做内容检索时一般会使用Elastic Search。在这个场景下面,DDD最多能在战略上给出指导,好不好用、快不快还在您的技术实现,这里面已经不是怎么建模能搞定的事情了。您要考虑的是有多少台服务器、如何配置等内容。
好的系统是由各类知识和各类人员汇聚而成,要包括优秀的UI设计师、项目经理、运维、测试;作为研发的您也需要对数据库、缓存、队列、所用框架和语言等有深入的了解,当然了,还要有一个端正的态度。这些都需要您在日常工作和学习中积累和反思。再实际一点,您简历上写精通DDD其实也说明不了什么,面试官一般都会从多个角度不同的技术上考核您,差一点就直接枪毙。所以,请您客观看待DDD,切莫神化,它就像您学习的如数据库、缓存、分布式系统等知识一样,是系统建设中的一个方面而非全部。