本系列的第一篇博文抛砖引玉,大谈领域驱动设计的优点,这里笔者仍是但愿以客观的态度,谈谈领域驱动设计的缺点及其不适合使用的场景,以让读者能够有选择性的使用领域驱动设计。程序员
咱们知道,没有最好,只有最合适,设计也是同样。所以,所谓设计,就是以你和你的团队的知识、经验和智慧,全面充分的考虑各类内外因素后,在大家的设计方案中做出合理的选择的过程。而这些影响大家选择的因素主要有:canvas
-
技术框架的特征和约束(若是你的项目决定使用C语言进行开发,那么首先在设计方法上,就须要使用面向过程而非面向对象的设计方法)。
-
时间的压力和约束(你永远不可能告诉你的老板,给我10年时间,我和个人团队将为你设计出世界上最优秀的软件)。
-
你的团队的能力、经验、性格、价值观等因素的约束(你不能指望一个长期从事遗留系统维护项目或大部分红员是缺少经验的高校毕业生的团队能很好的按照你的设计意图去实现你的高度抽象的优秀设计,同时你也别期望一帮家里经济条件不错,本着过来熬时间的家伙会乐意与你一块儿刻苦钻研、精益求精)。
-
你的系统的特征(若是你想把一个足够简单并且在能够预计的未来都不存在很大规模的需求变动的系统设计得很复杂,很精妙,具备很好的扩展性,但要为此付出巨大的时间、人力成本,这显然是一种不理智的过分设计(Over design))。
-
其余外在因素的约束(你的项目须要参与投标,你必须压缩人力、时间等以让你的项目成本成为巨大的竞争资本)。
固然,上述的考虑因素站在比较高的角度,一般是项目经理、架构师须要考虑的问题,但这当中你应该会获得一些启发。回到咱们的主题,咱们首先看看,领域驱动设计相对于传统的面向过程式的设计,有什么缺点:架构
- 复杂化:面向过程思惟之因此一直很受欢迎,是由于它很直观,很是符合大部分人的思惟习惯,大部分人拿到一个问题,一般都是会很直观的想第一步作什么、第二步作什么,若是怎样,应该怎样,不然怎样……,能够说,任何水平的程序员,都能很好的使用面向过程的方法进行设计和开发。同时,因为咱们教育水平的落后和总体IT环境的制约,能够这样说,真正掌握面向对象思惟和设计方法的程序员的比例很是低(虽然绝大部分都使用面向对象的语言和工具),而自己面向对象思惟要求人有很好的抽象思惟能力,由于你须要把一个复杂的系统一层层的抽象为简单的部分,须要把现实世界的事物(有些是可见的,但有些是不可见)合理的抽象为计算机世界的不一样元素。这些都不是一些很容易作的事情,要作得好,就更难。
- 团队的抗拒:若是你的团队(很大可能)大部分人都习惯于用很直观的面向过程的方式进行设计和开发,你须要推进你的团队转换思惟来采用面向对象的方式进行领域驱动设计,一般会遭到多数人的抗拒。由于人都是有惰性的,他们习惯安于现状,而改变是痛苦的,他们要付出额外的努力,须要进行学习,但以笔者的经验,至关一部分程序员,特别是有必定工做年限的程序员,他们从事IT工做都只是为了得到一份不错的报酬,所以他们的学习动力很是有限,并且,他们都至关自负,被说服的难度比较大。
- 管理、开发和维护的成本高:复杂度更高,意味着你须要花更多的时间进行设计,同时须要花出额外的时间进行必要的培训,并且须要有更完善的文档(设计文档,API文档,培训文档等)。领域驱动设计的抽象程度比较高,所以必需有良好的文档,不然,随着项目的不断迭代、升级和维护,它很容易由于后来者的误解而慢慢回归面向过程的设计,甚至会变得“四不象”,领域驱动设计的成本优点是随着时间的推移慢慢体现的(见下图),若是出现这种状况,全部前面付出的努力都会付诸东流。

系统的初始阶段,领域驱动设计须要付出更大的成本,但随着时间的推移,领域驱动设计的成本效益优点会逐步显现
框架
-
性能比较低:使用纯面向对象的方式进行领域驱动设计的程序,其系统开销一般要比面向过程设计的程序高,从而性能相对较低(关于具体的例子,后续的博文会说起)。
那么,假设咱们在时间、团队能力及各类资源都容许的状况下,是否就能够麻木的全盘使用领域驱动设计呢?正如本博文的标题同样,答案是否认的,咱们须要有选择性的使用。让咱们来看看一些指导性原则:工具
- 使用领域驱动设计,并不表明整个系统的方方面面都必须听从领域驱动设计的原则,须要根据实际状况,让适合的部分使用领域驱动设计,让不适合的部分使用面向过程的设计。
- 对于那些业务规则很是简单,一般只有增、删、改、查的简单操做,并且也不大可能发生大规模需求变动的模块,可让业务实体成为一个“贫血模型”,例如一些基础数据:系统参数、商品类型、国家、地址信息(注:对于这点,本人持保留态度,由于这些业务虽然很是简单,但既然选择了领取驱动设计,即便把这些业务实体设计为“充血模型”,即把极其简单的业务逻辑也封装在业务实体中,也并不比使用“贫血模型”成本高,而它却带来了统一设计风格的好处)。
- 对于查询操做,特别是复杂的查询操做,出于性能的考虑,能够用结构化查询逻辑一次性完成,并把这些逻辑封装在Repository(即技术上的DAO)中(这方面的具体例子,后面关于“查询通道”和“领域对象仓库”的博文会更具体的阐述)。咱们能够看到,对于一些业务视图,以及报表模块,很明显不适合使用面向对象的方式设计,由于这些“视图”和“报表”,本质上就不是业务实体。
- 一样出于性能的考虑,在业务实体的实现逻辑中,某些操做不适合过分偏执的使用面向对象方式。例如,在“订单”的“新增订单明细”(order.addOrderItem(orderItem))中,若是业务逻辑规定一张订单中包含优惠商品的明细数目不能超过20条,使用面向对象的方式,就须要把订单中的全部订单明细所有加载,而后逐个明细判断其对应的商品是否优惠商品,再统计出优惠商品的数目,这样很明显是低效率和高开销的,这里只须要使用Repository提供的一个统计方法,用一个结构化查询逻辑返回统计结果便可,而这就是非面向对象的方式。
本博文给有志于领域驱动设计的读者泼了一下冷水,提出一些“反模式”(Bitter),是为了让读者冷静一下,在领域驱动设计过程当中做出更灵活和更合理的选择。关于这方面的论述,笔者在这里浅尝则止,限于水平、经验和表达能力,不敢胡乱卖弄,建议读者能够参考阅读Martin Fowler的《Patterns of Enterprise Application Architecture》一书的相关观点。性能