By Experience 的三个层次 -- 领域驱动设计的经验之谈

这真的是一篇经验之谈,是谈经验的,是我在去年DDD大会的演讲主题,现在整理出来和大家分享。
以下是一个电商场景的简化版事件风暴,这可能需要我们有一些事件风暴的背景。我把一些非关键的事件用省略号代替了,只留下了一些关键的事件。我们从左往右,从上往下看。可以看到这里我们有5个事件。当我们提交订单时,发生了一个事件,这个事件叫做“订单已创建”。当我们支付成功后,发生了“订单已支付”的事件,然后当快递小哥上门揽收了包裹后,发生了“物流单已创建”的事件,当客户签收后,发生了“物流单已确认收货”的事件,最后当客户点解收货时,发生了“订单已完成”的事件。这5个事件一般来说是按照这个时间顺序发生的。

我们接下来的讨论都是基于这个事件风暴的上下文。从这个事件风暴中,我们看到这里反复提到了两个概念,就是订单与物流单。

那我们怎么去划分聚合呢?

接下来,我们进入By Experience的第一层次。我把它叫做感觉,第一个层次,凭经验,就是凭感觉。
这时有位架构师A说:

按照他的说法,凭他的感觉,订单与物流单之间就会有两个聚合,一个订单聚合,一个物流单聚合,这是第一层次。

接下来是第二层次,我把它叫做规则。
这个时候,有另外一位架构师B,他说:

他把经验总结提炼成了一个规则,这个规则就是根据比较两个概念的生命周期的长短来划分聚合。生命周期长的称为聚合。
按照他总结的规则,对之前的事件风暴进行分析,得出订单的生命周期确实是比物流单的生命周期要长,而且整个物流单的生命周期都被订单的生命周期涵盖,所以这里只有一个聚合,就是订单聚合,而物流单只是作为订单聚合内部的一个实体存在。


这是第二个层次,规则。
好,接下来我们来到第三个层次-人,这是最玄乎的一个层次。
这个时候,有一位业务专家说话了,他说:

按照他的意思,虽然订单的生命周期涵盖了物流单的生命周期,但是因为物流系统是外包的,客户拿着物流单号是可以直接跑到外部的物流系统查询物流状态的。如果按照第二层次的划分方法,物流单只是作为订单聚合内部的一个实体的话,显然不能支持这个业务场景。
这个时候又要把两者拆分成两个不同的聚合了。

那到这里我们的聚合划分之旅就结束了吗?感觉结果又回到了原地啊,跟第一个层次凭感觉一样啊?
我们说并不是结束。整个DDD的架构建模过程,是一个螺旋上升,螺旋前进的过程,这个过程的一头是协作,另一头是演进,良好无间的协作推进架构的持续不断地演进,使得我们的最优解不断逼近完美解。注意这里说的是逼近,而不是达到。因为完美解永远都达不到。

经过这三个层次之后,到了反思的时候了。我们如何把控DDD建模或者是架构设计过程中的经验与非经验因素呢?

以上这句话来自一次真实的客户现场的对话,当时客户问我你能不能总结一些DDD的规则,到时候他们按照这些规则就可以自己实施DDD了, 我就帮他们总结了一些,包括前面的第二个层次里面提到的按照生命周期长短来划分聚合。但是最后我补上了这么一句话。
这句话里面的一端是经验,另一端是规则,就是把一些经验总结提炼成了让所有人都可以操作的规则。
这里的两端,表面上,一端是经验,另一端是规则。

实际上,背后蕴含着的是人和机器两种因素,规则一端对应的是机器,经验一端对应的人,而人代表的是一种不确定的因素,如果我们可以把所有的经验都总结成规则,那就不需要架构师了,完全可以让机器按照规则来把架构输出出来了。但这个是不可能的,要那样我们都失业了,怎么可能呢?我们永远无法完全去除掉人的因素,就像刚才的例子,你永远不会知道会不会有第四位,第五位,第六位领域专家跳出来说他脑子里面只有他自己知道的的东西。这是一种unknown-unknown的情况,只有被告知或观测了,才会坍缩。

相反的是,我认为架构设计中的闪光点,最点睛的一笔,恰恰就是因为有人这种不确定型的因素存在。这里的机器和人,其实更深层次的意思是代表着你追求的究竟是一个技术品,还是一个艺术品。就像建筑学,构建能住人的房子是容易的,它只是一个技术品,构建富有美学涵义的建筑物是困难的,需要建筑师付出心血。软件系统架构设计也一样,如果完全通过机器根据规则推导输出出来的架构,顶多算是一个技术品,而糅合了人的经验,灵感,智慧等因素而得出的架构,才说得上是艺术品。

保持对一个美的架构的追求,我想这是我们作为一名架构师存在的意义所在。
版权声明: 本文为 InfoQ 作者【Winfield】的原创文章。
原文链接:【http://xie.infoq.cn/article/6e82d2fbfb354ede4d049a6ac】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论