前两篇本座依次讲了DDD的上层设计和下层设计,或者叫战略设计和战术设计。今天来讲实践,其实之前小编写的一篇【大数据】事件驱动的微服务架构一定程度上也是DDD的一个现实案例。对于程序员来说,软件设计是学习业务领域的过程,代码只是附带产物。在程序员和领域专家沟通时,通常会使用用例图、行为图、序列图或ER图来表示对象之间的逻辑关系。
确实,如上一讲所提到的,每一个功能域的模型设计需要领域专家和技术人员不断碰撞出火花,而这个火花是理解子域中的每一个事件(Event)。如果群体讨论可以成为头脑风暴,那基于领域事件的头脑风暴也可称之为事件风暴(Event Storming),通过事件风暴的方法可以快速分析复杂业务领域,完成领域建模的目标。在活动中,团队先通过头脑风暴的形式罗列出领域中的所有的领域事件,整合之后形成最终的领域事件集合,然后对于每一个事件,标注出导致该事件的命令,然后再为每个事件标注出命令发起方的角色,命令可以是用户发起的,也可以是第三方系统调用或者是定时器触发等。最后对事件进行分类这里出聚合根以及有界上下文。
事件风暴的参与人员主要就是上述所讲的业务领域专家与技术人员,预期产出是经过分类的事件的相关属性(包括触发动作Command,统计方式Aggregate,用户角色User Role,视图View、处理规则Policy等等),在事件风暴的时候用便利贴的形式贴在讨论版上。
这些对象通过事件关联在一起,比如网购的领域模型可以拆解为用户“浏览商品”事件-->“购买商品”事件-->“确认订单”事件-->“物流”事件,每个事件有各自的关联触发动作、用户角色分配、统计方式、视图、处理规则等等。然后根据事件的相关性形成子域模型,例如上述事件可以组成为“商品目录”、“订单”和“配送”三个子域,也就是网购领域的DDD下沉设计,然后每个子域中的各个事件和相关对象就形成了各个子域的微服务架构。
其实在很多互联网公司我们都可以看到DDD的事件风暴,国外的GAFA和国内的BAT,在考虑共享复用和用户故事的时候,都会整版整版地讨论事件流和事件地图。
接下来进入代码层面的讲述,捋清事件逻辑后,代码就是水到渠成的事,以上面网购中的物流领域为例,某商家策略是购买一定数量的产品后可以免运费,对于未满足数量要求的订单,邮费可以有普邮和EMS的选择。
我们来看下面一串代码,如果放在大学编程课上,这段代码会是一个满分作品,逻辑清晰,思维缜密。但作为领域驱动设计的代码而言,它让非技术人员摸不着头脑,没有表述功能。
首先,红色部分,这些数字的含义是什么;橙色部分,重复的代码段;绿色部分,BigDecimal对应的原始类型是什么;蓝色部分,公类私类对象错误;紫色部分,i即时作为常用参量,对非技术人员不具备可读性。
此外这段代码还有很多数字不明的地方(就是因为直接使用了数字,导致复用性和可读性都很低),例如:
下面我们来看下在DDD中干净,可读性强的通用语言代码是怎样的。
这段代码几乎无需多做解释,就通俗易懂哪怕是跟业务人员交流,而且把参数定义全部抛到前端提供了“类中台”层的能力接口。其实很多开发人员并不是做不到代码的通俗易复用,只是在很多时候,由于开发工期的要求,没有考虑到业务逻辑在多场景下的通用性,甚至有种腹黑的说法是“代码乱到只有自己看得懂才是公司不可替代的人才”。呵呵~
总结下,大到城市规划,小到代码规范,我们都可以用领域驱动的方法论来设计。其重心在于:
战略着眼,战术着手:合理高效的拆分领域是成功的关键;
抓大放小,突出优势:找出公司自身与同业的竞争优势,倾力这些核心子域;
业务驱动,超脱技术:不要将商业问题归咎于技术能力,C++解决不了的问题Python同样解决不了。
规范引领,统筹建设:尽快形成企业内部的技术规范,提高业务复用能力。