你真的需要防腐层吗?DDD 系统间的7种关系梳理与实践

当提到系统间交互的时候,人们都会想到大名鼎鼎的防腐层,即用一个 Adaptor 进行系统间模型的转换,用来防止其他系统的模型变更对本系统造成影响。但是在实践这个模式的过程中,我们是否常常遇到如下问题:

  • 业务代码只有三行,模型转换代码却写了几十行
  • 为了给前端增加一个返回值,需要给整条链路上的每个模型增加一个属性,可链路上还会涉及好几个系统,一不小心漏加,还会导致 bug
  • 明明是类似的东西,在不同接口中却是不同的类,导致调用方没法统一处理。

这个时候,我们就应该仔细思考 “防腐层” 是否真的适合了。防腐层一词最早出现于 Evans 《领域驱动设计》,英文为 Anticorruption Layer,简称 ACL(下文中都会称之为 ACL),如果去翻阅原著,会发现 “防腐层" 只不过是 Evans 定义的九种系统间关系的一种,在设计系统间关系时,我们应该根据实际情况灵活选择,而不是生搬硬套 ACL 来处理所有的系统间关系。

DDD 的战略模式与战术模式:ACL 属于哪种?


毛爷爷曾说“战略上藐视敌人,战术上重视敌人”,战略一般是指比较大的规划,而战术更加偏向具体执行,在长津湖战役中,彭德怀将美军分割成四个部分分别击破的规划,就是战略,电影中第七穿插连在新兴里击退美军的过程就是战术。

战略与战术

具体到软件工程中,战略是指高层视角的系统与人员规划,可能涉及多团队的合作关系,往往由架构师拍板决策;而战术一般是具体的类和方法的设计,开发者一般有更大的话语权。

在《领域驱动设计》中,前三部分主要讲战术设计,最后一部分专门讲战略设计。

目录

ACL 这个词出现在 "战略设计" 部分。这可能违背大多数人的直觉,因为在日常工作中,我们常常不加思考地就引入一个 ACL,以为这就是一个简单的设计模式。其实两个系统间是否要引入 ACL,是架构师对于系统间关系深思熟虑的结果,并不是一个简单的代码层面的设计模式。

此处涉及到两个相关的 DDD 术语:“限界上下文”(Bounded Context)和“上下文映射图”(Context Map)。一个系统所管理的业务范围称之为“限界上下文”(Bounded Context),而且我们前文所说的 “系统间关系”,本质上就是两个 “限界上下文” 之间的关系,这种系统间关系在 DDD 中我们称之为 “上下文映射图”(Context Map),ACL 就是一种 “上下文映射图”。

7 种系统间关系


本节将根据耦合度从高到低逐一探讨这些关系。耦合度高有时并不是坏事,它能够让团队内部的系统更加内聚,而不是无法整合的碎块。我们应该根据具体情况进行选择。

因为系统间关系往往也是组织架构的反映,此处每种关系除了描述其相关的技术架构,本节也将描述其适用的组织架构。

共享内核(Shared Kernel)

系统间共享部分模型和相关逻辑,是最亲密的合作关系。

共享内核

当负责这两个系统的团队存在非常紧密的合作关系(甚至就是同一个团队),并且业务上十分相似时,共享内核就是一个不错的选择。在职责上,即使共享内核有专门的 owner,其任何修改都需要经过多方探讨,因为其中的任何模型更改都会深刻地影响这几个系统。

最典型的就是业务系统以及业务相关的批量导入导出系统,两者虽然因为技术原因(隔离消耗资源的任务)被划分成了两个系统,但是它们的模型理论上应该完全共享的(即共享内核),这样才能保证业务上的修改及时反映到导入导出中。试想如果这种场景还用 ACL 做隔离的话,每次业务系统修改,还需要同步在导入导出模型中做修改,这将是非常麻烦的。

客户-供应方(Customer-Supplier)

两个系统虽然相对独立发展,但是底层系统(Supplier, 供应方)愿意为上层系统(Customer, 客户)的需求负责,并且做对应的变更。这也是一种非常亲密的合作关系,只比共享内核弱一点。

因为两个系统在实现时会互相考虑对方,此时两者交互部分的模型会非常相似,相比共享内核,它只共享一些模型,不共享逻辑代码。

例如,智能办公的表单导出系统依赖表单搜索系统搜索需要导出的数据,表单搜索系统的维护者是同一个团队的开发者,他会接受导出相关的所有搜索需求,所以不需要在此基础上再进行任何封装,直接将表单搜索系统提供的 QueryCondition 模型作为导出任务模型的一个属性:

public class ExportJob {
    // 来自搜索系统的模型
    private QueryCondition queryCondition;
    // 其他属性
    private Long id;
    //...省略
}

遵奉者(Conformist)

两个系统完全独立发展,底层系统因为没有人力或者其他原因,不可能因为上层系统的需求做出任何变更。这与下文 ACL 适用的情况类似。

上层系统的模型设计与底层系统的模型严格地保持一致,虽然也是需要一个转换层转换,但是没有做任何“真正”的转换,最多只是简单的属性拷贝,这是和 ACL 的主要区别,ACL 会做更加复杂的转换。

例如,钉钉的外部 ISV(三方应用开发商)想要基于钉钉通讯录开发一款应用,因为这个三方应用所有功能都是基于钉钉通讯录,ISV 可以采取的最合适的方式就是定义一批和钉钉通讯录差不多的模型,这样才能最充分地利用通讯录已有功能,概念上的一致性也有助于和钉钉通讯录开发人员沟通。

防腐层(ACL)

ACL 对应的组织架构与遵奉者类似。

ACL 适合两种情况:

  • 同样的概念在两个系统中有不同的含义:“用户”概念在 IM 中就是消息发起接受方,但是在钉钉通讯录中却是指某个组织内的、含有职位,角色等信息的职员
  • 模型相差巨大:比如 excel 表格和钉钉文档中的表格

ACL 是指复杂的数据转换层,在转换数据时需要做概念上的翻译。

另谋它路(Separate Way)

“最好”的解耦方法就是完全另写一套代码。

这有点像 “拆中台” 的思路,研究了半天,发现依赖复杂的中台,还不如业务团队自己写一套简单的系统实现。

这已经不能算是系统间关系了,是 “完全没有关系” 的意思。

开放主机服务(Open Host Service)与发布语言(Published Language)

直接举例,底层服务开放一个 Http 接口(开放主机服务),允许以 json 的数据格式(发布语言)进行调用。

它们其实就是开放 RPC 调用。他们被单独列出来完全是因为 《领域驱动设计》这本书成书较早,互联网软件比较少,RPC 也没有特别规范的标准。在微服务时代,限界上下文的调用几乎都通过 RPC 进行,并且使用 Hsf, Dubbo 等 RPC 框架将发布语言封装在最底层。这也是我将本条放在最后一个的原因。

总结


软件工程追求的终极目标就是 “高内聚,低耦合”,翻译成两个正面的指标就是内聚和解耦:

  • 共享内核:内聚度最高,解耦最差
  • ACL:内聚度最低,解耦最强
解耦和内聚

这张图恰恰反映了软件工程没有银弹的道理,通过梳理系统间关系,合理的控制系统的内聚与耦合程度,才是项目架构的难点所在。

ACL 被滥用的原因在于开发者将自己写的一小部分代码像“伊甸园”一样保护起来,这是比较简单的处理方式,但是如果要梳理如何和现有业务与系统结合,却要付出大量精力。这就导致系统过度“解耦”,以至于同一个团队维护的业务系统却给调用方一种支离破碎的感觉

因此是否引入 ACL 要根据两个系统当前情况和未来规划决定,如果满足:

  • 同一个团队维护
  • 属于同一个业务
  • 模型差别不大

其中的一到两条。此时可以考虑暂时不引入 ACL,而是采用共享内核,或者客户-供应商来处理系统间关系。

但是这条定律也只能作为参考,还是需要结合现实中对于内聚与解耦的需求决定,毕竟软件工程中唯一的定律就是没有定律。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容