我始终认为,Eric Evans的领域驱动设计是对软件设计领域的一次重新审视,是在面向对象语言大行其道时对数据建模的“拔乱反正”。Eric强调了模型的重要性,例如他在书中总结了模型在领域驱动设计中的作用包括:
- 模型和设计的核心互相影响
- 模型是团队所有成员使用的统一语言的中枢
- 模型是浓缩的知识
显然,模型在领域驱动设计中是设计的起点和关键。但是,该如何才能得到我们心目中能够准确表达业务需求的模型呢?我们需要认识到模型和领域模型是两个不同层次的概念。如前所述,模型还可以是数据模型或服务模型,这取决于我们观察现实世界业务需求的视角。因此,领域模型是以“领域”为关注核心的模型,是对领域知识严格的组织且有选择的抽象。
即便有了这个定义,却没有清晰地说明领域模型到底长什么样子。领域模型究竟是什么呢?是使用建模工具绘制出来的UML图?是通过编程语言实现的代码?或者干脆就是一个完整的书面设计文档?
我认为,UML图、代码与文档仅仅是表达领域模型的一种载体而已,如果绘制出来的UML图或者编写的代码与文档并没有传递领域知识,那就不是领域模型。因此,领域模型应该具备以下特征:
- 运用了统一语言来表达领域中的概念
- 蕴含了业务活动和规则等领域知识
- 对领域知识进行了适度的提炼和抽象
- 它的建立是一个迭代的演进的过程
- 能够有助于业务人员与技术人员的交流
既然如此,不管领域模型的表现形式,只要它正确地传递了领域知识,并有助于业务人员与技术人员的交流,就可以说是领域模型。这是一个更不容易犯错误的定义。它其实体现的是一种原则。
很可惜,这样高屋建瓴的原则并不能指导开发团队运用领域驱动设计。就好似软件设计有个核心原则是“高内聚低耦合”,然而知道这个原则并不能保证你设计出高内聚低耦合的方案。故而诸如这样打太极似的原则与模糊定义,并不能让开发团队满意,他们还是会执着地追问:领域模型到底是什么?
Eric并没有就此作出正面地解答,但是他在模型驱动设计中提到了模型与程序设计之间的关系:“模型驱动设计不再将分析模型和程序设计分离开,而是寻求一种能够满足这两方面需求的单一模型。”这句话说明分析模型和程序设计应该一起被放入到同一个模型中。这个单一模型应该就是“领域模型”。
他反复强调程序设计与程序实现应该忠实地反映领域模型。例如,他写道:“软件系统各个部分的设计应该忠实地反映领域模型,以便体现出这二者之间的明确对应关系。”同时,他还要求:“从模型中获取用于程序设计和基本职责分配的术语。让程序代码成为模型的表达。”
在我看来,设计对领域模型的反映,就是“设计模型”;代码对领域模型的表达,就是“实现模型”。分析模型、设计模型与实现模型在领域视角下,成为了领域模型中相互引用和参考的不可或缺的组成部分,它们分别代表了分析阶段、设计阶段与实现阶段进行建模的产物。
模型驱动设计非常强调模型的一致性,Eric Evans甚至认为“将分析、建模、设计和编程工作过度分离会对模型驱动设计产生不良影响。”这正是我将分析、设计和实现都统一到模型驱动设计中的原因。
我之所以清晰地将领域模型划分为这三个模型,主要是出于交流的目的。
在分析阶段,开发团队与领域专家一起工作,通过建立更加准确而简洁的分析模型,直观地传递着不同角色对业务知识的理解。
在设计阶段,必须基于分析模型对模型中的对象做出设计改进,考虑职责的合理分配与良好的协作,建立具有指导意义的设计模型。
在实现阶段,代码必须是设计模型的忠实表现,意味着它其实也忠实表现了分析模型蕴含的领域知识。
一言以蔽之,让分析模型服务于开发团队与领域专家,设计模型服务于软件设计人员,代码模型服务于程序员。这三个模型各司其职,各取所需。
在建模过程中,我们需要不断地从“统一语言”中汲取建模的营养,并通过“统一语言”来维护模型的一致性。当开发团队根据分析模型建立设计模型时,如果发现分析模型中的概念未能准确表达领域知识,又或者缺少了隐式概念,就需要调整分析模型,使得设计模型与分析模型保持一致。实现模型亦当如此。
显然,统一语言在领域模型驱动设计中,提供了一致的领域概念,使得模型在整个软件开发阶段保持了同步:
分析、设计与实现不是割裂开的三个阶段,而是一个迭代建模(Iteration Modeling)的过程。
在战略设计阶段,我们可以通过业务场景识别系统的限界上下文。在限界上下文中的语义相关与功能相关的用例可以作为分析建模的重要输入。这个阶段可以在系统的先启活动中完成,之后就进入到战术设计阶段。
战术设计以限界上下文为单位开始迭代,通过迭代中的用户故事逐步对分析模型进行细化,并引入设计模式获得设计模型后,就可以利用诸如测试驱动开发等实践进行编码实现,以求快速交付高价值的可运行的功能。
说明:迭代建模与本图参考了Scott W. Ambler敏捷建模的思想,参见链接:http://agilemodeling.com/essays/iterationModeling.htm
显然,这种迭代建模的方式是与迭代的增量开发是一脉相承的。它避免了在建模过程尤其是分析建模过程的分析瘫痪,也避免了在设计建模过程中的过度设计,同时还将通过增量快速地开发出新功能来及时获得反馈。获得的模型也随着增量开发而不断演化,并始终指导着设计与开发。
迭代建模使得建模活动成为迭代开发中不可缺少的一个重要环节,但整个活动却是轻量的,有效地促进了团队成员的交流,符合Kent Beck提出的核心价值观:沟通、简单和灵活。