项目上的思考和感悟
在软件开发过程中,有很多人说,DDD不适合我们,我们要敏捷,要小步快跑,快速试错,项目很紧张,哪有时间设计等等,首先,DDD和敏捷不冲突,DDD侧重于软件设计建模方法,而敏捷侧重于项目开发过程。
其次,DDD不影响我们快速试错,我始终坚信一点,设计先行,很多人说不需要设计,但是从某种意义上来说,你的代码也是你的设计,不过是在战略和战术层面的区别,而且,前期的设计更利于后期的扩展维护。
DDD是一个抽象的概念,他告诉我们使用领域驱动的方式去设计你的软件,很多人觉得很抽象,很难去落地,其实,你错了,不管你是做什么样的业务,DDD中的意思思想,一些工具其实已经在我们的项目中使用了,只不过是我们之前不知道DDD对这些工具或者方法做过总结而已,抑或是其他软件设计的思想和DDD异曲同工。
接下来我将从一个实际项目中看看我们有哪些地方用到了DDD的方法或者有哪些思想类似的
业务场景
简单的电商系统,包含用户下单,商家上单,活动促销,流水结算,售后退款,物流信息等模块
前期设计
在我们前期设计中,我们可能没有那么复杂的功能,没有那么多的业务场景,那么我们可能会做一个单体应用,只包含用户下单,商家上单,售后退款比较少的功能,这个时候我们业务发展迅速,业务要求我们短期上线,这个时候,简单的设计已经满足了我们的业务场景,一个单体应用也足以支持业务运行
在这个前期设计中,我们可以说是没有太强领域的概念
扩展
在系统运行一段时间之后,业务开始加入活动促销模块,和商家的结算也要加入到公司统一的流水结算系统中,商家产品更加丰富,这个时候这个单体应用就很难扩展了,大量的模块耦合,系统牵一发动全身,开发人员苦不堪言
重构1
我们决定重新设计,首先我们决定拆分成几个模块,按照不同的功能,不同的业务,比如订单系统,商品系统,促销系统,结算系统等,每一个模块做成一个微服务,各个模块之前通过RPC或者消息解耦,这样一来我们系统层次更清晰,扩展更简单,每次开发流程更快捷
并且我们认识到,订单系统是一个很重要的模块,我们要提取处核心逻辑和功能,基于此,我们使用状态机的方式管理订单状态并通过消息将状态变更广播的方式传递给其他系统
在这次重构中,我们明确了很多独立的模块, 这个其实就是我们划分了限界上下文,并且定义了通用语言,比如订单系统就是一个限界上下文,订单,创建订单,支付等可以理解为这个限界上下文中的通用语言, 而各个服务之间的依赖关系(上下游)和交互方式(RPC或者是消息)则对应到了上下文映射和集成方式
我们业务识别出了核心域(订单子域),并确定了采用事件驱动的架构设计核心域
重构2
随着业务的迅速膨胀,订单模块开始出现压力,订单服务既要满足C端用户的创建和查询,也要满足B端系统的查询,还要满足其他各个业务系统的各种查询,真是压力越来越大,所以我们开始拆分订单模块,拆分成C订单查询模块,下单模块,退款模块,B端订单查询模块等,之所以我们要区分C和B查询,是因为C需要实时,而B可以接受较短的时延,所以C端我们使用查库的方式,B端使用搜索
在上述重构中我们运用到了CQRS的思想,查询和创建分离,B的搜索基于数据库的binglog事件,通过事件溯源的方式重建索引
可以看到上述一个简单的系统设计和演进中,有很多东西和DDD的战略建模是很契合的,比如我们可能没有意识到在做的事情其实很契合某一种方法论,那是因为我们平时缺乏理论的指导,很多时候都是前辈们经验的传授,所以,或多或少我们日常都是在使用DDD的思想,不管是微服务还是DDD,很多思想都是异曲同工的。 我们可能陌生的是DDD战术层面的工具使用,比如充血模型,我们很难适应将贫血模型改造成一个充满业务逻辑的充血模型,这对我们而言有点无所适从