侧边栏壁纸
博主头像
极客魔方博主等级

远方不远,就在脚下

  • 累计撰写 12 篇文章
  • 累计创建 27 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

一个故事告诉你什么是 DDD,为什么要有 DDD

Rubik
2023-08-18 / 1 评论 / 1 点赞 / 23 阅读 / 7248 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2023-08-18,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

风靡全球 DDD

目前 DDD 在 B 端业务场景是很火的,因为 B 端业务场景的复杂度让很多开发都很挠头。微服务的出现降低了复杂度,但是降低的是应用层面的复杂度,而非业务场景的复杂度。

DDD 就是在微服务的基础上,全面降低复杂度的一个方法论,一种思想。

通过这种思想可以很快速的降低整个系统的复杂度,包括应用和业务。

支付系统开发小故事

有一个供应链公司,他们要开发一个支付系统。

人员介绍:

  • 开发人员:张三

  • 业务员:李四

  • 产品:王五

这天业务员李四和 A 企业商谈了关于支付系统中的一些能力。

A 企业要使用对公账户,使用支付宝平台进行支付。由该公司提供支付系统,A 企业进行支付。

经过王五和李四的深度沟通,制作了这个支付系统,开发人员是李四。

张三和王五确认,对公账户,支付宝平台。要不要考虑微信?王五说这点已经确认过了,A 企业根本不会用微信的,他们只用支付宝,你只做支付宝就行了。

然后张三开始开发,展示支付通道,A 企业点击之后,将企业及对公信息传入后台,后台保存支付信息之后,调用支付宝的平台进行支付。

很快就交付了,A 企业很满意,点击之后立刻就调用了支付宝的支付。

后来 A 企业发现支付宝的费率有点高了,他们发现银行卡的方式会更实惠一些。然后和李四沟通,咱这边为我们开通一个方式,我们要用银行卡的方式来结算。

A 企业是我们的大客户,根本不能得罪,李四满口答应,然后去找王五沟通,产品需要改一下,这块业务方需要增加一种支付方式,需要使用银行卡支付。王五说小问题,我只需要在支付的时候弹出一个弹窗,然后使用不同的平台去支付就行了。

然后王五去找张三,开始说本次需求。张三觉得没问题,于是在入参增加了一个参数,把支付宝相关的内容提出来一个方法,又新加了一个新的方法为银行卡的方法,然后判断支付方式为银行卡,则使用银行卡支付,为支付宝,则调用支付宝的方式。

很快开发完了,敏捷开发交付,赢得了业务方的好评,张三半夜都突然惊醒,我写的代码为何如此优秀?

很快这个支付系统在业内出名了,一些小公司也来合作,B 公司就是其中一个,他说我们只要银行卡,不用支付宝。C 说,我们需要用微信,能满足吗?李四说完全没问题,我们的开发很厉害的。

然后李四和王五开始沟通,王五在自己的产品上做了改动,如果是 A 公司,展示银行卡和支付宝,如果是 B 公司,展示银行卡,如果是 C 公司,展示银行卡支付宝和微信。

王五开始和张三确认需求,张三说小问题。于是张三对接了新的支付方式,微信平台。并且在支付方式枚举中增加了微信。然后在展示的位置中加入了判断,如果是 A,就展示 xx,b 展示 xx,c 展示 xxx。聪明的张三还做了一个数据字典,通过企业名称+支付方式来配置一个字典,不同的企业,展示不同的支付方式,这样来了新的企业,只需要配置一下,就能展示不同的。

如此高端的做法,又赢得了业务方的喝彩,张三如愿升职加薪。

到此,一个高端程序员的路已经几乎触顶了,没有一个新的模式,几乎很难上升。

此时来了新的需求,A 企业说,我们引入了新的业务,开启了零售模式,用户个人支付,需要使用支付宝和微信,并且是个人支付,没有企业信息。

最后需求到了张三这里,张三吐槽了几句,但也能做,于是张三就新开了一个个人结算接口,如果是企业支付则调用原来接口,如果是个人结算,则调用个人结算接口。

开发完后,测试开始提 bug,他说其他企业也会展示个人结算。产品说,个人结算只有 A 企业有,其他企业没有。然后张三在前端页面加了一个判断,如果是 A 企业,前端页面展示两个,如果不是,则只展示企业支付。

然后测试又提 bug 了,如果先将 A 企业的微信模式打开,然后再关闭不刷新页面,微信的入口还是打开的,实际是关闭状态,支付可以成功,但 A 企业是不允许微信支付的。后端没有做校验。

张三就开始在调用支付的时候,再加一个判断,判断当前是否为开启状态,没有开启则提示不允许这种方式。

原本巅峰的程序员,渐渐开始出现 bug 了。

听说这个支付系统还支持零售的个人支付,又有好几个企业前来合作。D 企业说我们也需要个人和企业支付。E 说我们只有零售业务,我们只展示个人支付。

张三要疯了,这都是什么需求,产品不能先设计好吗?产品怎么维护?虽然吐槽,还是做了,就在前端增加了判断,如果是 E 企业,就只展示个人,如果是 A 和 D,则展示全部,其他展示企业。又针对性的做了一些配置。

到这里,系统已经很难再改动了,业务稳定,系统支撑好多业务方,如果做了变动,会牵扯很大。

但此时,D 企业说,我们需要一种三方支付方式,能不能支持,如果支持可以额外给你们 80%的流量,否则你们只有 30%,我们大多数业务是需要三方支付的,我们没办法支付。

面对如此大业务量的诱惑,李四毅然决然的接了下来,今年可以加鸡腿了!

张三疯狂吐槽,这都是啥需求。如果是 D 企业,选择了某种支付方式,判断订单的类型,订单是自营单,则直接支付,订单是三方单,则调用该平台的三方支付能力。

除了 D 企业,其他企业是没有这种判断的,无法区分是否为自营。

没办法了,如果是银行卡支付,则判断是否为 D 企业。如果是 D 企业,则判断是否为自营,如果是自营,则调用银行卡支付。如果不是自营,则调用银行卡的三方支付能力。如果是支付宝 xxxx,就不赘述了。。。

开发很快,但很绝望。

很快开发完,D 说我们新接了一个业务,这个也属于自营。代码迭代中....

D 说这个属于三方。代码迭代中....

....

后来订单系统过来,说我们需要感知到支付的状态,支付成功我们订单状态要做变更。

张三再最外层定义一个状态来接收支付结果,是否成功。

在最后判断如果成功,告诉订单系统成功,否则告诉他失败。

迭代开发,支付能力已经一团乱麻,单个方法已经超过三百行。

张三已经在悄悄的打开 boss 了。

这时订单系统又过来说,我们需要知道支付失败的原因,网络问题?还是余额不足,信息错误等。他们都会返回对应的状态码,你根据这些来做下处理。

然后张三分别对微信支付,支付宝支付,银行卡支付三种情况,分别解析错误码,并定义一个对象来接收结果,分别接收支付结果及失败原因。

一切都是那么的巧合,这天测试在操作系统时,整好订单系统重启,然后支付就失败掉了,失败原因系统异常。

然后就给开发提了个 bug。张三要疯了,这不就是系统重启吗,你提 bug 干什么,别人的系统,我能做什么?

领导这时候说,问题发生在你这,你应该对这些做好容错,一个回传失败导致整个支付失败了,这合理吗?显然不合理。

张三无奈,没办法,砸着键盘把通知订单系统的能力做了异步。

然后测试找到了订单系统,告诉他我支付成功了,但是你们这状态没有变更。订单系统的人看了眼说支付系统没有回传状态,转手将 bug 指给了张三。

张三默默地查看日志,发现订单系统又重启了,导致推送失败。订单系统说你们得重推一下吧。

然后张三又增加了手动重发能力和重试。

....

再然后呢,其他系统也要通知,通知这个通知那个

每个都要加重试,加重推。

这一块内容实在太复杂了,一个人难以维护,老板又招来了一个高级开发,高级开发过来看了代码之后第二天辞职了。

然后老板就说,你们的支付系统为什么这么拉胯,狗不理系统吗?

老板说着,李四带着新的企业来了,一个大客户,他们也要分为三方和自营的,现有能力,直接接入就行啦。

张三说要开发,得把新的企业配置进去。然后张三在原本判断 D 企业的地方增加了 F 企业。

配置完了之后,测试说 A 企业的自营有问题,本该三方支付的,结果到了自营里面。张三排查之后发现,F 企业的自营判断逻辑和 D 企业的三方判断逻辑是一样的,订单编号的规则相同,导致判断错误。

于是张三生无可恋的在 D 的判断下面额外增加新的 F 判断,并写一套新的校验逻辑。

....

经过反复的迭代后,李四说我们的业务方越来越多,我们需要出一个数据大屏来看他们的使用情况。然后需要针对每一个企业的支付类型,支付方式等做一个数据。

张三又在每一次调用的时候,来判断本次的调用结果,然后保存到新的表中。

....

李四说在支付中,我需要看到这个企业,这种方式,有多少单,这种方式有多少单。

然后张三又和订单系统交互,统计订单量。

...

李四说我需要知道这个企业每天的订单量,每次下单后,结算了多少,没结算多少,失效多少,结算的金额是多少等。

我还需要账号的名字。

我还需要知道企业信息。

我还需要知道银行卡账号。

我还需要这个企业的支付耗时。

我还需要....

张三疯狂加逻辑,原本的支付系统,大部分已经被各种统计,埋点,通知,数据映射覆盖掉了。

还要面临着别人不停地说系统很拉胯。

....

终于张三背起了行囊,去了远方...

如果时间可以重来

支付系统 v1

客户:A 企业

需求:企业的支付宝类型支付

后端系统做法

  • 适配层:针对企业的支付宝类型的数据入参,将入参转为核心的支付信息对象,做基本数据的判断。

  • 核心领域能力:支付信息入库保存,调用支付,针对支付结果做处理,返回支付结果。

  • 核心领域子域:核心业务能力的整合

  • 支付信息入库:将信息保存到 mysql 数据库,将信息更新缓存....

  • 调用支付:根据支付类型,路由到支付宝的支付

  • 结果处理:更新支付状态,保存操作记录

  • 返回结果:将结果返回给调用方。

  • 基础设施:针对数据库的操作,mysql 的操作,支付宝的对接操作。封装为接口供外部调用。

支付系统 v2

客户:A 企业

需求:增加银行卡类型

后端系统改动点

  • 适配层增加针对企业的银行卡类型的数据入参,将入参转为核心的支付信息对象,做基本数据的判断。

  • 支付子域,增加拓展点模式,通过支付类型,路由到不同的支付中

  • 基础设施,对接银行卡支付,为支付子域中的银行卡支付提供支撑

  • 查询能力:针对 A 企业做设置,目前系统提供的支付方式为支付宝和银行卡。A 企业配置银行卡和支付宝两种方式。查询是返回这两种类型,前端根据返回结果展示不同的类型。

支付系统 v3

客户:A 企业,B 企业,C 企业

需求:增加微信类型

后端系统改动点:

  • 适配层增加企业的微信类型的数据入参,将入参转为核心的支付信息对象,做基本数据的判断。

  • 基础设施,对接微信支付,为支付子域中的微信支付提供支撑。

业务方配置

为 B 企业配置银行卡支付方式,C 企业全配置。

支付系统 v4

客户:A,B,C

需求:增加个人支付类型

后端改动点:

  • 查询能力中增加对支付类型的配置,增加个人支付和企业支付两种,可配置。

  • 适配层增加个人类型的银行卡,微信,支付宝三个接口。

  • 基础设施:之前调用银行卡微信支付宝时,拿固定的参数。现在通过对数据做充血模型,在领域对象中,根据不同的支付类型,来获取不同的支付信息。个人银行卡是姓名和银行卡号。企业银行卡则是账户名和账户号。映射到同一个模型中就是名字和账号。

  • 支付子领域路由中,做数据校验,判断支付方式该企业是否支持。

业务方配置

为 A 企业配置支付类型为个人和企业。其他的配置为企业支付。

支付系统 v5

客户:A,D

需求:增加自营的路由判断

后端改动点:

  • 支付子域路由升级:之前只针对支付方式来路由,现在还需要针对是否自营路由。

  • 订单号路由策略:通过订单号和企业 id 来路由不通的策略,在策略中判断是否为自营。提供默认策略为自营。

  • 基础设施:对接银行卡,微信,支付宝的三方支付能力。

业务方配置

为不同企业配置不同的支付类型

支付系统 v6

客户:D

需求:新的自营策略

后端改动点:

  • 订单号路由策略升级:引入计算引擎,所有企业配置化是否为自营单。比如通过订单号,如果以 xxx 开头,或者以 xxx 开头,或者以 xxx 开头,则为自营,否则为三方。所有企业拥有默认的计算引擎,默认全部为自营。

业务方配置

为需要特殊配置的企业配置计算引擎。

支付系统 v7

客户:其他系统

需求:通知其他系统状态

后端改动点:

  • 结果处理子域:增加事件通知机制,发送一个支付结果事件,采用异步事件通知

  • 基础设施:新增事件监听,支付有结果后,通知订单系统处理结果。

支付系统 v8

客户:其他系统

需求:增加稳定性,重试,补偿

后端改动点:

  • 监听事件做增强处理:将事件数据入库保存,做有状态的事件处理。引入重试框架,针对事件做重试。

  • 新的工具接口,通过事件 id,做事件重新触发能力。

支付系统 v9

客户:新的各种客户

需求:三方,自营,各种类型

后端改动点:

业务改动:

将新的客户配置不同的能力即可

支付系统 v10

客户:业务方

需求:各种奇葩的数据展示需求

后端改动:

  • 新做一个系统,来做 bi 类的事情,不要去污染支付系统

业务改动:

  • 去新的 bi 系统,做各种配置,你想要的全都有。

  • 给你整个世界

总结

通过比较,做到第九版的时候,就发现如此复杂的系统,竟然这么简单?

原来复杂的业务可以拆解和分散,原来新的业务接进来是可以不迭代系统完全业务就能做到的?

是的,ddd 正是这项能力的赋予者。ddd 让b 端业务系统,变得如此简单。

相信到这里,你已经基本明白了 ddd 解决的问题,和如何用 ddd 来解决问题。

ddd 是思想,并非一个框架。ddd 的框架更多的是用来吸收里面的精华,让自己对 ddd 思想有更深的认知,而并非去学习模仿框架。

否则将只得到一个型,而无法传神。

1

评论区