有没有一种感觉,网上谈论DDD理论的文章一抓一大把,但是真正谈落地的文章却寥寥无几?基于DDD的开发框架也只有零零星星的那么几个,更别说基于DDD实现的开源项目了。
我经历了几家公司,大公司、小公司、创业公司都待过;也咨询过朋友所在的公司,有成功上市的创业公司、有互联网大厂;面试时也和面试者聊过公司项目。使用DDD的项目一只手都数得过来。
即使是使用了DDD的项目,也是打了各种折扣。像我目前公司里一个项目组使用了DDD,但整体结构比较混乱。之前面试时,一位面试者所参与的项目使用了DDD,在设计时设计了各种领域、子域、核心域、支撑域,但是在落地时做了各种阉割,使得设计与实现出现了割裂。
那为什么DDD这么难落地呢?个人总结了两个问题:
何谓复杂
软件界的金玉良言有很多,其中有一句大家应该都很熟悉了:「没有银弹」!
DDD的开山之作是Eric Evans的《领域驱动设计》,这本书早在2003年就出版了,但是出版后一直不温不火。一直到近几年,借着微服务的东风,DDD才再次进入大家的视野。
我不知道你有没有读过Evans的这本书,我是在2013年左右购买的这本书,不过直到2016年我才真正的读完此书。在此之前,我一直对DDD的理解是错误的,所以,如果你没有读过这本书的话,还是建议你读一读。顺便看一看这本书的副标题—软件核心复杂性应对之道。
DDD是应对软件复杂度的方法!也就是说,DDD不是银弹,它是针对复杂软件的解决方案,不是所有软件的解决方案!所以,如果你开发的软件并不复杂,那完全就不需要使用DDD。如果你强行使用了DDD,你会发现,你自己把软件给复杂化了。具体怎么复杂化了,我们下文讨论。这就是我们为什么要进行软件设计、技术选型的原因,没有完美的方案,只有合适的方案。
那么,问题来了,我们如何定义软件的复杂度呢?或者换个更针对性的问题:当软件复杂到何种程度时,才需要使用DDD?有没有一套标准来确定呢?Evans没有给出答案,后人好像也没有给出答案。
软件复杂度的计算有计算方法和公式,但是复杂到哪种程度需要使用DDD,目前没有一个确定的标准,也无法计算出这个标准,下面给出原因。
而我自己的答案是,不到迫不得已,能不用DDD就不用DDD。因为使用DDD的隐性成本很高,在你没有把握保证引入DDD所带来的收益能cover住这些成本时,就不要引入DDD。
成本
DDD的引入会带来很多的隐性成本,包括但不限于:
我们来具体讨论,引入DDD后,首先增加的就是「学习成本」。因为DDD里有一堆的概念,比如:领域、子域、核心域、支撑域、通用域、实体、值对象、聚合、聚合根、领域事件等等等等。不仅仅需要架构师、设计人员理解这些概念,项目组的所有成员都需要理解这些概念。
同时项目组内需要在各个领域内定义一套统一的词汇表,方便沟通使用。虽然,这对项目来说,长期是有益的,但是短期内不仅增加了「学习成本」,还增加了「沟通成本」和「管理成本」。想一想,你在做传统三层软件开发时,需要理解这么多的概念吗?是不是只需要了解一下框架的大体结构就可以上手开发了?
学习内容增加了,实际就是对人员的要求提高了。对人员要求的提高,实际就会导致「人力成本」的增加,本来可能只需要招聘初级开发人员,现在可能至少需要招聘中级开发人员,才能适应开发工作。
同时,新招聘的人员还需要进行相应的培训、学习和理解对应的领域词汇,才能参与到项目中,这又增加了「培训成本」。而由于这些成本的增加,又变相的增加了「人力成本」,因为人员流动所产生的项目风险增加了。
对于「管理成本」来说,上面的各种成本的增加都会增加「管理成本」,但是「管理成本」增加最多的地方在于设计沟通以及代码管理。我先举一个之前看到过的例子,你体会一下!大意是,国内引入了某品牌汽车的生产线,生产线上有一个标准操作「某个螺丝需要拧三圈再退回半圈」,理论上这是要严格执行的,但是,在国内生产线上的很多工人最后会偷偷将回半圈的操作给省略了,直接拧两圈半。这个问题肉眼根本无法察觉,但是导致的问题就是同样的车型,国产车的某些部位明显比进口车故障和维修率高。
假设你是一线工人,你会偷懒吗?我感觉我大概率会!
为什么螺丝要在拧紧后,再松半圈呢?因为,螺丝在拧紧后,为了防止松动,应额外施加一个预紧力。但是,螺丝在拧紧后处于弹性形变中,尤其是在高温和震动载荷的情况下。长期这样持续压力会产生蠕变,螺丝塑性变形后,其e度会大幅下降甚至失效。退回半圈是让弹性形变恢复一些,同时消除预紧力,以后螺丝在持续压力的变形还是在弹性形变之中,产生塑性应变和失效的几率大幅降低,使螺丝能保持持续高强度的压力,而直接拧两圈半是达不到这样的效果的。
DDD所面临的场景类似。DDD所推荐的框架结构,较传统三层框架结构要复杂不少,相应的开发人员要编写的代码也相对多了一些。且不像编写事务脚本那样,DDD代码中包含了很多的设计,如果一线开发人员不理解你的设计,和你来确认,你每次都要解释一遍,沟通成本就增加了。开发人员来和你沟通,这还是理想情况。如果向上面一样,开发人员不理解设计,也不来沟通,直接以自己的方式去实现了,这就可能导致代码的腐化以及设计的腐化。
我的实践
基于上面的原因,我在项目中没有完全推行DDD,而是部分实践了DDD。当然,如果你能解决上面这些问题,并且确定引入DDD后所带来的收益是能cover住这些成本的,可以去实践DDD,同时也欢迎分享分享实践经验。
我目前的项目使用的是微服务架构,结合DDD与微服务的做法是:
即架构层面采用了DDD进行战略设计,而在代码实现层面则融合了传统事务脚本开发与面向对象开发。
这样做带来了几点好处:
首先,DDD的复杂性被限制在了架构层面,这样只需要架构相关人员掌握DDD即可,而对一线开发人员没有提出特别的要求。通过对复杂度的范围限制,可以有效的控制上面所提到的各类成本。
具体到各个微服务层面,根据各个微服务的业务复杂度,可以选择是直接使用事务脚本,还是使用面向对象编程。我在项目中分别使用了事务脚本和Bob大叔所推荐的简洁架构设计。
通过这样的划分,既按照各个服务的实际复杂度进行了相对合理的设计,也划分了人员职责:
同时也规划了开发人员的一个大致成长路线:
总结
本文是个人对DDD的一些实践感悟,纯属个人的观点和实践,有不同意见欢迎探讨。
限 时 特 惠: 本站每日持续更新海量各大内部创业教程,一年会员只需98元,全站资源免费下载 点击查看详情
站 长 微 信: lzxmw777