架构进阶之路:复杂业务开发与领域驱动设计
以下是在现公司,给成员做分享的资料。业务案例来自:。作者:张建飞,进行了重新整理。
一 业务开发职责
1.1 开发=CVS?

1.2 为什么会这样?
1、业务所限。非供应链、交易、金融等复杂业务领域,简单业务需求偏多
2、个人原因。接受需求时,只考虑局部实现,不考虑整体业务。
设计时还没有达到要求,只局限于当前需求实现这一最低要求;无法从更高一层的角度看待问题。如果当前级别的需求都存在很大的疏漏,那么到了复杂业务场景,真的有能力能够让人放心交给你来做吗?

1.3 业务真的简单吗?

上图是当前业务系统中的信息流投放与CRM交互过程。这只是CRM中的很小一部分,目前做了多家供应商支持,不同的回调码、消息结构;而且目前支持了组合,各种分支逻辑会更复杂。加上各种风控限制,供应商的稳定性问题,整体看起来,我们的业务也没有那么简单。
1.4 复杂业务场景下的设计开发
如何定义“复杂”?

1.5 基于经验的一些解决方法

二 业务案例与分析实战
2.1 背景

2.2 商品的生命周期

2.3 关键业务节点——上架

提问:从这张图,能看到哪些信息?
2.4 实现思路?
拆分:一个大service => check1(), check2(),…,createNo(), publish(),……
问题:流程如何管理?
是否需要引入流程引擎(工作流引擎):已有 or 自研的流程引擎,or 依赖于数据库配置的流程处理。 但过早考虑这些是否合理?
2.5 回归核心问题

2.6 总结
当问题被清楚地结构化分解之后,我们就可以很明确地通过简单的组合等手段实现业务流程。在保证实现的基础之上,再考虑工具或设计模式来提升灵活性和可扩展性。
2.7 过程分解后的两个问题
2.8 怎么做?
举个例子,在上架过程中,有一个校验是检查库存的,其中对于组合商品(CombineBackOffer)其库存的处理会和普通商品不一样。原来的代码写法:

引入领域模型:


使用模型的表达要清晰易懂很多,而且也不需要做关于组合商品的判断了,因为我们在系统中引入了更加贴近现实的对象模型(CombineBackOffer 继承 BackOffer),通过对象的多态可以消除我们代码中的大部分的 if-else。
三 复杂业务开发方法总结
3.1 总结:过程分解+对象模型 上下结合
所谓上下结合,是指我们要结合自上而下的过程分解和自下而上的对象建模,螺旋式的构建我们的应用系统。这是一个动态的过程,两个步骤可以交替进行、也可以同时进行。
这两个步骤是相辅相成的,上面的分析可以帮助我们更好的理清模型之间的关系,而使用模型表达可以提升我们代码的复用度和业务语义表达能力。

四 领域驱动设计初探
4.1 领域驱动设计的一些基础概念

领域:本质上是一种边界划分,领域词语中的“域”也是边界的意思。
领域设计= 边界 + 设计。要求:具备领域知识、总结和概括能力、达成共同认知。


领域模型的基础是对象模型,对象是由属性和方法组成的。识别贫血模型有一个重要的指标是:模型自身需要处理的业务逻辑是否外漏。
如果模型本身没有需要处理的业务逻辑,只包含属性那么他不应该称为贫血模型。
如果模型自身需要处理业务逻辑但是没有处理,而是由调用者来处理本属于模型本身的业务逻辑时就应该称之为贫血模型。
在处理表单数据校验时,通常使用的是外部校验方式
领域设计不是一件简单事情,首先你得有这个领域的知识,然后还有一套你对这个领域知识总结和概括,甚至摸清了领域中的逻辑关系,一般人不一定掌握得好,大概只有多年业务专家才会有这个本事,或者多年来一直在开发某个业务系统,直至公司人员组织结构都按照业务领域划分成不同部门了,比如电商公司有订单组、仓库组、支付组和货运组,这种带有业务性质的组织部门其实已经代表了大家的共同领域认识。
4.2 领域驱动实践历程
哪些能力应该放在 Domain 层,是不是按照DDD传统的做法,将所有的业务都收拢到 Domain 上,这样做合理吗?这并不是一个可以很容易说清楚的问题。因为在现实业务中,很多的功能都是用例特有的,如果盲目的使用 Domain 收拢业务并不见得能带来多大的益处。相反,这种收拢会导致 Domain 层的膨胀过厚,反而会影响复用性和表达能力。
所以,我们考虑逐步地进行能力下沉的方式,即不强求一次就能设计出 Domain 的能力,也不强制要求把所有的业务功能都放到 Domain 层,而是采用实用主义的态度,即只对那些需要在多个场景中需要被复用的能力进行抽象下沉,而不需要复用的,就暂时放在 App 层的 Use Case 里就好了。
通过实践,发现这种循序渐进的能力下沉策略,应该是一种更符合实际、更敏捷的方法。因为我们承认模型不是一次性设计出来的,而是迭代演化出来的。
4.3 能力下沉过程

五 开发的选择:技术 or 业务
很多业务技术同学的困惑,也是我之前的困惑:即业务技术到底是在做业务,还是做技术?业务技术的技术性体现在哪里?
通过上面的案例,我们可以看到业务所面临的复杂性并不亚于底层技术,要想写好业务代码也不是一件容易的事情。业务技术和底层技术人员唯一的区别是他们所面临的问题域不一样。
业务技术面对的问题域变化更多、面对的人更加庞杂。而底层技术面对的问题域更加稳定、但对技术的要求更加深。比如,如果你需要去开发 Pandora,你就要对 Class Loader 有更加深入的了解才行。
但是不管是业务技术还是底层技术人员,有一些思维和能力都是共通的。比如,分解问题的能力,抽象思维,结构化思维等等。这些,都需要我们在日常的工作生活中不断的加深思考,沉淀能力。