领域模型在交流中扮演的角色

2021-11-15 From 张逸说 By 张逸

实际上领域模型是搭建现实模型需求问题解决方案的桥梁。领域模型领域概念尤其是统一语言的可视化表现,在Eric写作《领域驱动设计》一书的时代,领域模型多数以UML来表达。

这里要注意一个历史问题。在Eric写作该书的时代,正是UML与逆向工程大行其道的时代。当时有很多人都在倡导运用建模工具如Rational Rose来建模,进而利用图形化的模型生成代码。这个思想在当时人们的心中会是未来编程的一个主流发展方向,也有很多人在朝着这个方向努力,随之也催生了诸多建模工具的诞生,UML得到大量的普及,甚至差点成为了软件设计的唯一标准。这也是Eric倡导模型驱动设计的一个历史背景,至少我认为他在写书时是收到这个思想影响的。最终,这种设计思想并没有得以实现,人们低估了编程的复杂度,高估了模型的重要性。所以,Eric的书是有历史局限性的。尽信书不如无书,这是阅读他的书要注意的。书中讲的一些实践,未必都对。

但是,Eric的领域驱动设计是一个方法学,是开放的,也是逐步演进的。事实上,已经有很多人站在Eric的肩膀上,提出了很多切合实际,也吻合软件行业发展趋势的实践与模式,作为领域驱动设计的补充。例如领域事件六边形架构以及CQRS等。Eric自己也认可这种演进。

回到模型上来。我认为领域模型就是对领域概念的抽象,你说的超载10%其实就是业务规则,所以可以抽象为一个领域概念,在与领域专家进行交流时,可以通过领域模型的这个领域概念来表达,而不是直接使用代码。

设计模型则是对领域模型的一种技术呈现,乃至于是从技术角度的一种精化与演进,例如通过引入设计原则与模式,可以实现领域模型对象更好的职责分配,通过抽象实现解耦,定义更加合理的封装。这时,设计模型要取决于你的编程范式,如采用面向对象还是函数式编程。同样以超载规则为例,面向对象范式的设计模型就是抽象的服务接口,函数式就是一个函数。如果规则需要组合,前者就利用继承或委派,后者就用组合子。

代码模型设计模型的具体实现,它是遵循设计模型来实现的,采用不同的语言和框架,也会有区别。例如,有的语言可以非常方便地定义值对象,如Scala的Case Class,就是值对象的语法糖。

整体来看,领域模型是团队与领域专家交流所用,设计模型是团队的设计人员交流的工具,代码模型自然为程序服务。这三个模型之间的关系如下图所示:

随着时间的推移,这三种模型可能会出现不同步的问题。Eric在书中讲解模型驱动设计时也提到了这个问题。如上图所示,领域模型为指导设计模型设计模型领域模型的实现,而随着设计模型的演进,我们又需要这种变更体现在领域模型中,保证模型领域的真实表达。至于代码模型,一方面是遵循设计模型进行代码的实现,同时还应该尽力保障代码模型要表达领域概念,这不仅仅是从代码可读性的角度来考虑,也牵涉到代码对领域逻辑的呈现。这也是为什么在DDD的编程实践中,我们为什么希望避免贫血模型,希望避免使用无法表达领域行为的get和set方法的原因。

倘若要在代码模型中体现领域模型,一种更好的做法是使用DSL,即领域特定语言。但DSL的实现其实是一个相对漫长的积累过程,不同语言的领域表达能力也不相同。所以DSL主要还是用在一些相对复杂但又相对稳定专业的行业中,例如通信和金融行业,就有DSL的开发需求。当然,即使不去做一套DSL,我们也可以借鉴DSL的思想,例如通过Fluent Interface之类的实践改进代码的表达能力。

还有一种做法就是利用BDD编写验收测试,形成活文档(Live Document)。BDD框架如Cucumber、Robot Framework、RSpec其实就是一种DSL,通过这些框架可以编写符合自然语言规范的测试用例,形成一个中规格(Specification),这些测试用例又是能够运行的代码,这就相当于搭建了代码与需求规格的桥梁。不过,这种活文档只能应用在测试保障上,它可以帮助我们建立一种更好的交流机制,但并不能取代设计模型和代码模型

本文来源:张逸说,转载请注明出处!

来源地址:https://zhangyi.xyz/role-of-domain-model-in-communication/

发表感想

© 2016 - 2022 chengxuzhixin.com All Rights Reserved.

浙ICP备2021034854号-1    浙公网安备 33011002016107号