
1.4 领域驱动设计的应用场景
DDD是一套应付复杂性的分析设计方法,这个方法本身有一套范式,因此只要这套范式的使用效果相对于复杂性而言是合算的,成本不会高于收益,那么就可以使用DDD,它适合任何有一定复杂性的行业。
那么,如何衡量复杂性呢?从日常生活角度看,如果做一件事需要考虑全面,那么就可能有些复杂,如不但要把事情做好,还要考虑安全性、便利性,这些因素混合到一起就有了复杂性。举一个例子,和金钱有关的系统都应该比较复杂,财务系统、银行系统、金融系统、股票系统等都属于比较复杂的项目,因为金钱对于人来说很重要,金钱的往来流动不能出错,安全性需要考虑,但是过分强调安全又不方便,如银行网站为了提高安全性,登录时需要一个USB硬件加密器,无法和支付宝、微信支付的便利相提并论。但是后两者在安全性上也有一定漏洞,特别是数据完整性和一致性方面确实存在问题。
对于用户支付这个上下文,从DDD来看是一个支付聚合,无论使用多么复杂的分布式技术,都不能破坏这个聚合,这个聚合保证了所有相关子对象的更新一致性,如果不是从这个角度去设计并保证,随着时间推移和系统复杂性的提高,这种数据完整性就很难保证了。
通过DDD划分边界,突出聚合,保证数据一致性和完整性,将其放在整个系统的最高位置,这也是对重视资金安全性的充分体现,因此,金融、财务等系统是非常适合应用DDD的。DDD不但用于跟踪资金流,还能用于跟踪物流、资源流等随着时间变化的复杂应用场景。Martin Fowler认为软件系统本身就是一种跟踪系统,人们之所以依赖软件系统,是相信它的可靠性、完整性和安全性,软件公司帮助他们实现这样的系统时,千万别辜负他们的这些期待,过分沉湎于技术细节而失去了方向。
1.4.1 哪些应用不适合?
首先,传统的CRUD系统不适合使用DDD。能够使用CRUD完成的系统大部分是简单系统,当然,如果在新增或修改时,对输入的数据需要验证,保证企业自身的业务规则,那么就该考虑使用DDD了。
其次,演示系统或教学案例系统也不适合使用DDD。演示教程侧重于演示具体技术的使用,和业务无关,当然也不能完全脱离业务,所以使用关系数据库操作来代表业务操作更合适,很多人就是从这些演示教程一步步进入编程生涯的。业务问题基本都是转化为数据库表结构来实现的,也就是通过纯数据结构来完成,这样的系统如果再使用DDD重构就比较困难了,因为业务规则、模型核心都体现在数据表结构中,即使这些表结构设计不合理,考虑到大量历史遗留数据,也很难进行范式转换。
那么,DDD一定适合新系统吗?也不一定。对业务需求的认识是通过不同的设计开发迭代完成的,一般情况下,1.0版本是对需求摸索的初步映像和结果,是切入系统的起点,1.0版本系统基本能让软件运行起来,满足客户的要求,如果这时客户提出更大的变动要求,那么2.0版本就可能适合使用DDD进行灵活性、复杂性的升级了。
1.4.2 适合微服务架构
前面是从应用类型的复杂性角度判断是否适合使用DDD,也可以从架构角度判断。当前企业应用主要以SOA和微服务架构为主,这些架构主要偏重技术实现,将业务使用“服务”或“微服务”一个词语替代,服务内部是什么却被一言蔽之。服务代表业务,内部是业务逻辑,只要使用服务模型,SOA和微服务架构就能实现很多好处,实际上,业务才是编程的核心。
例如,有一个系统是存储文档的数据库,它对外通过服务暴露了用于文档存储和查询的API(也就是CRUD基础操作),但是很快有新的需求,需要更复杂的搜索功能,设计人员认为将此搜索功能添加到现有文档的CRUD API中违背微服务原则,因为“搜索”和“CRUD”属于不同类型的服务,另外搜索使用的数据库也不是普通关系数据库,可能是一个NoSQL,因此他们决定创建新服务实现搜索功能。注意,这只是从“搜索”和“CRUD”是两个不同动作、活动,或者说不同的动词类型角度将两者区分为不同的服务类型,但是仅仅根据动词的不同进行分类还不够。
设计人员会创建一个包含搜索索引的搜索API,该索引基本上是CRUD主数据库中数据的副本。两者数据需要同步,但是数据同步需要特别的并发机制或事务机制,如果没有就可能出现时而同步、时而不同步的情况。
切入该系统的视角并没有从领域模型入手,而是直接从动词入手,当然,也没有通过动词表象寻找背后的上下文规则或数据结构,结果,数据设计被忽视了,最后数据的完整性或一致性得不到保证。
这个案例说明:虽然使用了微服务架构,但是如果不考虑DDD,同样会遭遇和以前大泥球的单体系统一样的问题。