闲扯DDD

建模

客观世界时刻处在变化中,因此稳定的模型理论上是不存在的,建模者应去洞察变化从而对模型施加预期变量,让模型的向后兼容好。
在《大象会跳舞--Thinking in UML》有对“投影(projection)”的精彩论述,当时很受启发,加上个人日常实践的感受我概括下“在尽可能多的场景中从不同角度观察客体,每个角度的一次观察就是一个投影,会发现:1)既有客体是有多个投影,2)也有多个客体投影重叠。投影是第一层抽象,产出物就是驱动业务活动的业务实体,从此刻我们开始逐渐远离现实,进入架空再构建的抽象世界”。

DDD和领域建模

很多人将DDD等同领域建模,其实很不准确。领域建模是门完整的方法论,应包括对现实的分析,从现实中去提炼问题,再去解决问题,这是一个建模者应当具备的能力。
DDD在这上面是含糊的,把这一工作推向了领域专家,专家带来领域知识、分享知识,再引导系统设计,建立领域模型,实际上这还是传统的软件工程思维,因为需求和现实之间经过了加工,开发者认识的需求是和现实断层的。

真实需求

建模中的大多数不确定性都指向的是对真实需求的捕捉,这种不确定最后带来的就是交付后和用户预期的差距。①也许专家对需求做了真实表达,但是开发者因为缺少现实映射,理解出现偏差。②又也许专家有很强的业务背景,但对已有系统实现细节的认知偏差,导致他(她)的观察角度出现偏差,从而得到错误的分析结果。
事实上有时候真实需求是什么连客户也许都没意识到,客户的表达往往会偏向细节,很多细节背后往往是同一件事情,但是在需求整理上可能就变成两条,这就回到了上文说的多角度观察发现他们是同一投影,而得到什么样的投影是基于观察角度的,而观察角度一定是对已有系统实现有精准理解后得出的,否则实施成本就会很大,甚至无法实施。
所以作为对实现细节最理解的开发者是应该参与最早期的需求捕捉和分析过程的--①保证对需求和现实的联系;②保证建模过程中的观察角度和既有系统是一个夹角。

DDD是系统实施实践的方法论

  1. 主张限界上下文之间语义集成,限界上下文可以理解成一个思考的边界,进入特定限界后就应及时切换思考上下文。随着认知程度加深以及事实变换,限界上下文可能会分类也可能会合并。与之相应的在架构实践上也提出了依赖倒置、六边形、消息集成等等。
    因为限界上下文的表达不一,在开发协作时当前限界(A)和另一限界(B)有集成时,应该提出自己对B的主张,在A中对B做有限理解,再通过适配关系将获取到的B的某个方面适配成A中有限理解的B'。这会带来两个好处:
  • 在A开发过程中,涉及到任何限界集成,先定义自己需要的B’是什么,保证逻辑和实现的分离,后面再去找B’的实现,在此之前的开发过程B'实现完全可以是个Mock实现。
  • 因为逻辑和实现的分离,业务对外部变化是钝感的,当B发生变化时,调整的是适配而不是业务核心代码。
  1. 主张oo充血表达,这点其实是整个业界的反思结论。
  • oo的有行为表达可读性更好,无论从代码向纸面模型的回溯还是从纸面模型向代码的映射都更容易。
  • 其他内聚、强协议等优点就不逐一说明了。
  1. 主张最终一致性而不是强事务,最终一致性实际是个业务容忍度问题:
  • 如果业务可以短期容忍差异,那么通过消息反复投递配合系统监控,再加上必要的人肉及时介入保证一定周期内发现和解决问题就行。
  • 如果完全无法容忍差异,那么强事务是必不可少,当然DDD也给了另一种实现思路“按对象Snapshot回滚”,这同时也可以完美解决跨域事务,但代码实现代价过大。

避免刻舟求剑和形而上

DDD和领域建模就是器和术的关系,没有术只有器难免会刻舟求剑,失去现实和模型的联想,模型的持续演进变得可能,迭代几代后就进入重构周期。同时没有器光研究术也难免会形而上,比较普遍的现象就是一大篇领域分析的论述后直接得出数据库表结构,看上去没问题,实际上此后从代码到文档的联想变得非常困难,这也是日后代码变得无法维护的源头。

上一篇:LINUX下解决netstat查看TIME_WAIT状态过多问题


下一篇:手机淘宝性能优化