第12课:领域模型

对于我们所从事的软件开发行业来说,如果有什么东西像是经济一样永恒,那么无疑就是领域(domain)了。在计算机发展的最初岁月,它主要是用来完成一些计算密集型的工作,例如核试验、天气预报中的庞大的计算工作。后来人们发现计算机很适合用来模拟人类世界很多领域中所存在的业务逻辑,把人们从繁重的重复性人工处理中解放出来,去做更有创造力和乐趣的工作。特别是在20世纪80年代以苹果电脑和IBM PC为代表的个人电脑的出现后,计算机迅速普及到了各行各业。

计算机之所以很有用,是因为通过使用计算机软件能够解决人们所从事的某个领域的问题。然而,假如软件的开发人员并没有深入理解软件所处的领域,软件就无法很好地解决该领域的问题,其实用价值就会大打折扣。因此对于业务软件的开发人员,应该时常提醒自己的一句话是:“笨蛋,问题是领域”。深入理解领域的开发人员,即使使用过时技术所开发出来的软件,也远远好过完全不理解领域的开发人员,使用最时髦技术所开发出来的软件。

遗憾的是,这个很明显的道理,在软件开发人员中并没有被普遍接受。在很多兴趣驱动的开发人员看来,深入理解领域中的业务逻辑,是一件枯燥乏味的事情。他首先会考虑:“我要在这个项目中使用苹果公司新推出的Swift编程语言,在服务器端要使用Hadoop,最好再尝试一下深度学习方面的技术”,然后就一头扎进这些时髦和高大上的技术之中。三个月后,你去问他需要解决的领域中的真实问题是什么,他还是一脸茫然。

哥们,别王顾左右而言他,作为软件开发人员,很可能你也有这样的倾向。实话实说,在大约十年前,笔者也曾经是这样一位兴趣驱动的开发人员。当然,责任并不是完全在我身上。IT行业,尤其是软件开发行业,是一个非常喜欢炒作新概念的行业。新的编程语言、新的开发框架层出不穷,让开发人员疲于跟随。以有涯之人生,去追随无涯的技术变迁,实在是一件很痛苦的事情。

如何跳出这样的恶性循环,获得人生的解脱呢?我们需要有某种方法论的指导。幸运的是,这种方法论已经有了,那就是领域驱动设计——DDD。DDD就是我们做业务软件开发的指路明灯。它指导我们专注于最重要的问题——领域,并且为如何设计好的领域模型,以便更好地解决领域问题提出了很多具体的做法。


l1.png


我们把三层架构等除了领域驱动之外的架构方式都可以归纳为以数据为中心的架构方式,在图中是黑色的粗实线;

领域驱动设计在图中是绿色的粗实线。

  • 当软件在开发初期,以数据驱动的架构方式非常容易上手,但是随着业务的增长和项目的推进,软件开发和维护难度急剧升高。

  • 领域驱动设计则在项目初期就处在一个比较难以上手的位置,但是随着业务的增长和项目的推进,软件开发和维护难度平滑上升。

这幅图形象的解释了领域驱动设计和传统的软件架构模式两者在软件开发过程中解决复杂性之间的差异。

领域驱动设计的核心是什么?

顾名思义,领域驱动设计的核心是领域模型,这一方法论可以通俗的理解为先找到业务中的领域模型,以领域模型为中心驱动项目的开发。而领域模型的设计精髓在于面向对象分析,在于对事物的抽象能力,一个领域驱动架构师必然是一个面向对象分析的大师。

在面向对象编程中讲究封装,讲究设计低耦合,高内聚的类。而对于一个软件工程来讲,仅仅只靠类的设计是不够的,我们需要把紧密联系在一起的业务设计为一个领域模型,让领域模型内部隐藏一些细节,这样一来领域模型和领域模型之间的关系就会变得简单。这一思想有效的降低了复杂的业务之间千丝万缕的耦合关系。


下图是“领域模型”:领域和领域之间只存在大粒度的接口和交互:


l2.png


正如本文通篇所说,领域驱动设计讲究的是领域模型的分析和对事物的抽象,从来没有提起过数据如何存取这个话题,言下之意在领域驱动设计中,我们不关心过数据如何存取,怎么样写linq效率高,使用懒加载还是include,这些实现细节会将你带入传统的三层架构模式中。

在领域驱动设计中要先设计领域模型,接着写Domain逻辑,至于数据库,仅仅是用来存储数据的工具。使用database first那不叫领域驱动设计,很明显你先设计的表结构,所以应该叫数据库驱动设计更为准确。更不要引入数据库独有的技术,例如触发器,存储过程等。数据库除了存储数据外,其余一切逻辑都是Domain逻辑。


话虽这样说,但是既然你在使用关系数据库,有人就会免不了跟你提起性能怎么优化这样的话题。这也是传统ORM+关系数据库实现领域驱动设计的硬伤,特别是当你的领域模型Scope设计过大,意味着Repository中的操作每次都要关联一堆表出来,特别是有人设计数据喜欢遵守第N范式这种基本就没辙了(没有贬低遵守这些范式的意思,只是这样设计的数据库+ORM会产生较多关联,相对应的设计为表结构冗余设计,有利于ORM提升性能),不得不说到了最后由于数据库的存储性能问题,我们又一次将数据库纳入到了考虑范围。

解决这一问题的方案是CQRS架构, Query端各种缓存和Nosql,顺便把搜索引擎也用上,让你的软件飞奔起来。这一架构解耦了数据库操作,你基本没有机会跟数据库打交道并且还解决了数据存储的性能问题


l3.jpg


这一进化过程也解开了一些人的疑虑,为什么从刚开始写代码就开始学习各种设计模式,但是从来没有机会使用过?因为你所写的代码无时无刻不耦合着数据库这一“毒瘤”,而数据库操作作为一种实现细节掺杂在你的代码中,所以领域驱动设计为此而生,你准备好了吗?