在使用 DDD 的思想时,最让人迷惑的就是如何组织代码,也就是通常所说的系统架构的问题。在前面提到 DDD 可以很好地指导代码组织,其中举了两个例子,单体和微服务架构下 DDD 如何指导代码的组织方式。令人沮丧的是,大部分应用系统既不是完全的单体系统,也不是纯粹的微服务架构,而是出于某种中间状态。
无论我们使用单体、SOA、微服务、中台或者其他架构,都需要解决如何组织代码这个问题,DDD 并不是一个技术,而是指导我们组织代码的一种思想,这种思想也并不是凭空出现的。
就代码组织这个问题,看起来没有什么技术含量,但实际上非常重要,软件工程发展过程中出现过三次危机,软件危机泛指在计算机软件的开发和维护过程中所遇到的一系列严重问题,代码的组织和大规模协作是其重要的组成部分。
- 结构化程序设计解决了第一次软件危机。60年代~70年代计算机刚刚投入商业使用,主要的编程方式还是汇编语言在特定的机器上编写程序。当软件规模较小,基本上处于计算机科学家个人编码设计、使用的方式。随着软件规模扩大,复杂度增加,依赖特定机器、无结构化的编程方式无法应对软件的发展,带来了第一次软件危机。为了克服这个问题,业界提出了”软件工程“的概念,1972 年 C 语言的出现,解决了代码结构化、抽象性、可移植的问题。
- 面向对象解决了第二次软件危机。随着软件在商业中大规模使用,软件变得原来越复杂,即使结构化的 C 语言也无法满足业界对可维护性、可拓展性的需求。标志性的事件是 IBM 公司开发的 OS/360 系统失败,该系统有 4000 多个模块,约 100 万条指令,以及大量的 bug。面向对象的编程语言,Java、C#、C++ 出现,面向对象带来了更自然地代码组织方式,软件开发变得越像建筑业。
- 第三次软件危机。第三次软件危机还没有一个明确定义,通常来说就是互联网行业兴起,软件变得越来越复杂,需求越来越多变。软件开发从建筑业变成了服务业,需要随时响应变化,在软件行业表现为瀑布开发越来越不可行,敏捷开发越来越重要。从技术上表现为单机开发越来越不可行,分布式系统是必然的趋势。
每一次危机的解决,都是建立在前一次的基础之上的。面向对象是建立在结构化程序设计之上的,敏捷也是建立在瀑布之上的,而不是推翻前者。DDD 还停留在面向对象这个阶段,可以用来指导分布式系统设计,应对越来越复杂的应用系统,DDD 也不是面向对象思想的替代者。
DDD 的代码组织形式众说纷纭,并没有一个标准的代码架构。为什么会这样呢?实践中我们发现,不同公司、项目的业务背景不一致,架构不一致,架构的演化层次不一样(查看另外一篇文章《架构的演进》),标准的代码架构并不适合每一个公司。
当我们的系统架构从单体往 SOA、微服务、中台演变,无论名称如何变化,实际上都是分布式系统,只不过分布式的程度不一致而已。所以我们需要将问题拓展到分布式系统这个更大的概念上,再来谈 DDD 的代码组织形式才有意义。
我们看一下分布式系统下一个定义:
分布式系统是一组电脑,透过网络相互连接传递消息与通信后并协调它们的行为而形成的系统。——维基百科
从广义的分布式系统定义上来看,现在的互联网应用基本上没有不是分布式的了。分布式系统不是软件工程师主动选择的结构,而是业务逼得这样选择。阿里巴巴带动的去 IOE (去掉IBM的小型机、Oracle数据库、EMC存储设备,代之以自己在开源软件基础上开发的系统)就是一个很好的体现。
在这样的一个思维方式下,单体系统是只有一个计算节点的分布式系统,那么 DDD 在单体应用下的经验也可以应用起来。我没有找到一个专业术语描述分布式系统程度,这里请允许我创造一个新词,分布式级别。
分布式级别
为了解决业务上的问题,用户量大、业务规模大,当用户量增长到无法被容忍时,我们引入分库分表(分布式数据库)、垂直拆分业务(微服务)。
我们会将系统变得越来越复杂,然后不得不解决各种分布式系统下的新问题,业务上面临的问题被转移到技术上,从而业务才有可能持续性的发展。我们面临的问题不会消失,只会从一个地方转移到另外