领域驱动设计(一)

171 阅读4分钟

一、背景

领域驱动设计(DDD)到底为什么会出现,它改变了传统的软件开发模式的什么东西,为什么沉寂了一段时间后现在又流行起来了。在三层架构模式里,Controller接收请求,把请求委托给Service处理,基本上Service负责事务、业务逻辑和服务编排,而数据库操作交由DAO层负责。使用数据库表模式对现实世界进行建模,通过代码生成工具生成与表一一对应的Entity,这些Entity只有属性没有方法。这种建模方式,无法反映现实世界的真实情况,而软件开发也只是事务脚本式开发,很难说是面向对象开发。

DDD的出现,我觉得解决了两个问题,其一是通过面向对象建模范式建模,改变了上述的贫血的模型。其二是作为方法论,倡导模型与代码实现绑定,当模型改变时,代码需要及时做出修改,当代码的修改影响了模型,那么模型也需要继续调整,以便让团队及时得到反馈。

二、模型和深层模型

在说模型之前,先说说“领域”。在“领域驱动设计”中,可能我们会对“领域”这个概念感到困惑,到底指的是什么。“领域”本身就有多重含义,比如,“电商”领域,“金融”领域,此时“领域”表示的是一个行业。又比如,在电商系统里,有“订单”领域,有“物流”领域,此时代表的是一个系统或子系统。

模型,反映了系统的现实世界,在DDD里,推行的是模型驱动开发(Model Driven Design),而DDD的难点也是建模。在Evens DDD里货运模型,如下:

9505B2BF-63C4-4D68-A25D-2CA8071D741A.png

这虽然是一个简单的模型,但是一个货运系统,可能就是从这个简单模型迭代出来的。模型只有通过不断的迭代和重构,可能在某一次重构时,才得到一个深层模型。深层模型,是最能反映的业务领域的。

领域可以分为核心子域、通用子域、支撑子域。核心子域是我们最有价值的系统,通用子域可能会是权限、部门等,支撑子域比如对零售商领域来说,电商系统是核心域,物流系统可能是支撑子域。

三、通用语言

通用语言,是大家约定俗成的概念表述,其中会包含行业术语,比如对购物车来说,“在订单结算时,需要把所有优惠券叠加起来结算”,这里的表述,本身就是通用语言,它也会反映出购物车的一些业务规则。

通用语言本身需要不断修正和理解,后期还需要维护,可能在开发过程中,我们发现了一种新的表述,而这种表述就需要添加到通用语言里。这里可能不禁会问一下,那通用语言是文档吗。可以用文档作为通用语言,如果没有文档,那么代码注释也可以作为通用语言,文档和代码注释都需要及时维护。

四、消化知识

知识,是指领域知识,说白了,就是业务知识,作为研发人员,对领域知识的学习是必须的。可以从领域专家(有经验的研发、产品、业务)学习,也可以继续买一些领域相关的书籍自学。消化知识的目的,就是为了更好地建模。在Evens DDD里提到,应该让核心研发人员负责核心域的开发,对研发人员来说,消化知识也意味着需要对领域知识有一定的兴趣。

五、模型与实现绑定

我们的目标是用代码实现模型,如果代码偏离了模型,那么代码就没有什么存在的意义,虽然还能工作。它们之间有绑定关系,是因为研发本身需要参与到建模工作中,而建模人员,也需要参与到开发中,这两者也会让模型和实现的做到统一。一旦建模和实现分离,很有可能建出来的模型难以实现,研发人员自己就实现了一个新的模型,这样模型就没有任何意义。

模型驱动设计,本质就是把建模和设计统一起来,而不是分成建模阶段,设计阶段。

六、DDD知识体系

除了上述的背景,按Evens DDD,可以划分为战术设计和战略设计部分,但核心还是模型驱动设计。推行DDD很难(悲观者的味道),主要是因为建模需要花费很多时间,而模型的重构也需要很多时间,在现在的互联网公司,恨不得今天提需求,今天上线,很难给研发人员时间去消化知识和建模。这种情况,就很难不适用面向数据库开发。

那为什么还要去学和去推行呢。

我觉得主要是DDD改变了我们的思考方式。