天天看点

DDD(Domain Driven Design) 领域驱动设计从理论到实践 二

… 接上文

领域驱动设计解决了什么问题呢?

​     回归本节正题,我们将通过讨论DDD解决开发常见问题上进一步介绍领域驱动设计的特点。回溯前面所提出的软件开发时经常遇到的问题。

​ 问题1:开发人员对业务需求理解不正确

​ 问题2:业务人员或产品人员对需求描述不清晰

​     对于这两个问题大概是软件开发领域最常见的问题,通常情况下管理者非常希望开发人员和产品人员通过有效沟通来解决这个问题。但是,事与愿违,事实上这个问题在任何开发领域都是存在的,或大或小而已。

​     领域驱动设计方法中强调产品人员和开发人员通过建立**领域通用语言(Ubiquitous Language)**来对业务需求、用户案例、业务单元和业务实体等要素进行精确定义和描述。这个领域语言并不是产品人员定义的,也不是开发人员定义的,而是双方经过大量商讨和沟通共同商定的,确保双方都能够准确理解其中的含义。领域语言还可以为未来需求改变、功能增加时充当一个统一的描述框架。

​ 问题3:需求经常变化,使开发人员不堪重负。

​     需求变化通常是由开始定义需求时对于某些业务细节考虑的不清楚亦或是业务环境变化导致增加了新的功能需求。由于领域语言是由产品人员和开发人员共同头脑风暴产生的,所以很显然会对前者有缓解作用。

​     而对于新增功能需求,DDD思想中比较重视面向对象分析和良构设计模式的使用。笔者这里无意探讨面向过程、面向对象、函数编程的优劣,但面向对象和设计模式确实强调如何更好的应对变化。例如设计模式中的开闭原则,对修改封闭且对扩展开放;对于增加新的功能和应对变化,面向对象分析和设计模式确实可以起到很好地简化问题的作用。

​ 问题4:新的开发人员无法接手,或者周期很长

​     有了定义清晰的领域统一语言和良好地面向对象分析和设计模式、良构的代码结构和风格,新的研发人员的接手工作将会变得简单。

​ 问题5:产品的长期迭代演进困难,在此过程中,经常发现产品的技术选型和架构问题

​     软件产品一般来说是长期服务于业务的,随着时间的推移,业务需求出现变化是非常正常的。这一点也符合软件开发的基本要素之一:应对变化。而产品迭代困难的主要原因多是因为初期设计问题和不规范、混乱的代码造成的。

​     DDD的架构设计强调所有的技术选型和架构都应该依赖于领域模型和业务抽象,因为技术本身是服务于业务的,没有理由业务被以前的技术选型绑架。这一点和传统的设计思维是有区别的,笔者会在后续文章中深入探讨这一点。

​     还有,我们在软件设计过程中除了需要考虑未来什么最有可能变化以外,还需要思索什么是不变的。因为商业实体的业务需求有变化是一个常态,但其业务本质是不会变的。例如一个电商从卖具体的商品增加了卖线上的某种服务;在新的需求中,物流子域不需要了,但实际上业务本质并没有变,用户登录验证子域仍然需要,支付子域也依然需要。所以,DDD在设计中要综合考虑变化的和不变的,将其本质业务逻辑沉淀到产品层或者平台层,合理封装其需要变化的地方。如果能够非常合理地加以规划,那么产品地迭代更新将会容易许多。

DDD适用于所有场景吗

​     答案当然是否定的。没有任何一种方法论可以适用于所有场景,架构师和管理者通常在做权衡以得到适合自己应用场景的解决方案。DDD相对适合于业务场景非常复杂的情况,而对业务需求较为简单的情况采用DDD是得不偿失的。因为进行领域驱动设计通常需要专业的业务人员和精通面向对象分析、设计模式的高级研发工程师的共同努力。对于业务复杂的情况,这种投入会被证明是值得的;但是如果业务比较简单,投入产出比就差强人意了。

DDD所面临的挑战
  • 为创建领域通用语言腾出时间和精力
  • 持续地将领域专家进入项目
  • 改变开发者对领域的思考方式

到现在为止,我们得到了这个

那么,从DDD的视角上看,领域模型的组成要素都有什么呢?见下图:

DDD(Domain Driven Design) 领域驱动设计从理论到实践 二

    图中所涉及的元素,诸如实体(Entity)、值对象(Value Object)、领域服务(Service)、聚合(Aggregate)等等都是DDD中定义的系统抽象。现在先请读者有一个大概印象和感觉,在本系列文章的第四节:领域驱动设计的基本概念中笔者将会详细介绍。

    实际上,好的领域驱动设计能缓解软件开发过程中的很多问题,在后续文章中将会一一阐述。笔者认为其重要的方面有两个:面对变化和重用。

​     其实,评定诸如DDD这种软件设计方法论的优劣无非是通过两个方面:

  1. 是否能够开发出高质量的软件。
  2. 是否能够节约成本。

    其中,第一条的影响因素太多了。我们尝试以成本的角度来审视 DDD 的作用:

    软件系统的成本可以表示为:

    ​ c o s t t o t a l = c o s t d e v e l o p m e n t + c o s t m a i n t a i n cost_{total}=cost_{development}+cost_{maintain} costtotal​=costdevelopment​+costmaintain​

    ​ c o s t d e v e l o p m e n t = c o s t a n a l y s i s + c o s t u n d e r s t a n d i n g + c o s t d e s i g n + c o s t c o d i n g + c o s t t e s t cost_{development} = cost_{analysis}+cost_{understanding}+cost_{design}+cost_{coding}+cost_{test} costdevelopment​=costanalysis​+costunderstanding​+costdesign​+costcoding​+costtest​

    ​ c o s t m a i n t a i n = c o s t u n d e r s t a n d i n g + c o s t c h a n g e + c o s t t e s t + c o s t d e p l o y cost_{maintain}=cost_{understanding}+cost_{change}+cost_{test}+cost_{deploy} costmaintain​=costunderstanding​+costchange​+costtest​+costdeploy​

    这种表达并非绝对精确,但应该也捕捉到了研发成本的主要组成部分。

    • c o s t u n d e r s t a n d i n g cost_{understanding} costunderstanding​ 在开发和维护阶段都存在,DDD领域通用语言的建立将在一定程度上增加理解的准确性从而降低成本。
    • c o s t a n a l y s i s cost_{analysis} costanalysis​ 和 c o s t d e s i g n cost_{design} costdesign​ 之间往往存在缝隙。无数经验告诉我们,需求分析和设计模型之间存在断层,这导致系统实现与功能需求是不完全匹配的。DDD的设计方法论就是架起从需求到设计之间的桥梁。
    • c o s t c h a n g e cost_{change} costchange​ , c o s t t e s t cost_{test} costtest​ , DDD注重良好的设计模式构建可重用、易于扩展的领域模型;子域的划分有效的分割了问题单元,这些对于应对变化和独立单元测试都有助推作用。

未完,待续…

DDD(Domain Driven Design) 领域驱动设计从理论到实践 一

DDD(Domain Driven Design) 领域驱动设计从理论到实践 二

DDD(Domain Driven Design) 领域驱动设计从理论到实践 三

DDD(Domain Driven Design) 领域驱动设计从理论到实践 四

DDD(Domain Driven Design) 领域驱动设计从理论到实践 五

DDD(Domain Driven Design) 领域驱动设计从理论到实践 六

DDD(Domain Driven Design) 领域驱动设计从理论到实践 七

DDD(Domain Driven Design) 领域驱动设计从理论到实践 八

DDD(Domain Driven Design) 领域驱动设计从理论到实践 九

继续阅读