领域驱动设计和母亲的铁皮盒子

那个铁皮盒子原本是装丹麦曲奇的。蓝绿色,盖子上的小女孩图案磨得只剩下一双眼睛,看得人心里发毛。我妈在上世纪八十年代末把它清空,从此它就成了一份编外档案室。

我小时候一直以为盒子里全是钱。因为它锁在父母房间那个五斗柜的最底层,被几件旧毛衣压着,像一个不太成功的藏宝点。直到今年春天我妈住院,让我回家找她的医保卡,我才第二次——或者说第一次认真地——把它打开。

里面没有藏宝图。有的是:1978年我爸在苏北农场的工分记录、我三岁时的疫苗本、1992年房屋集资款的收据、十几张不同年代的公交月票,还有我小学三年级一张只考了58分的数学卷子。卷子上用圆珠笔写着“下次要细心”——那是我妈的笔迹,不是老师的。

我坐在她床边翻了整整一下午。不是感动。是一种很奇怪的错位感。我做了十一年软件,每天在系统里给字段建模、划分聚合边界、跟产品经理吵“这个属性到底属于订单还是属于用户”,结果我妈用一个铁皮盒子,早就在做同样的事。

两张几乎一样的收据

真正让我愣住的,是盒子里的一叠医疗收据。

我妈把其中几张用回形针别在一起,跟另外一叠用橡皮筋扎着的分开放。我拿起来比对了一下——都是药店打印的小票,格式一模一样,金额差不多,时间跨度也没超过两个月。

老式铁皮点心盒装满旧票据照片
老式铁皮点心盒装满旧票据照片

“这为什么分开?”我问她。那时候她已经出院回家了,靠在沙发上剥毛豆。

“你看嘛。”她头也没抬,“那边几张是我自己买降压药的,这边几张是给你外婆买的。你外婆那时候还没办慢病卡,全都是自费。自费的不能和报销的放一起,不然以后说起来搞不清楚。”

我说,不都是药吗?

她抬头看了我一眼,那种“你这孩子怎么这么迟钝”的眼神。“药是同一个药。账是两笔账。”

我没有再追问。但脑子里有什么东西咔嗒响了一声。

那段时间我正好在做一个很痛苦的项目。一个保险核心系统,二十多年的代码,经历了至少四轮重构,每一轮都留下了大量“临时方案”。业务方说“保单”的时候,指的是客户签的那份保险合同;技术方说“保单”的时候,指的是数据库里那张主表;运营说“保单”的时候,可能只关心它有没有缴费、有没有到期。同一个词,三个意思。

我们尝试过建一个“统一保单模型”,包含所有可能的字段。结果是那张表有将近两百个列,一半以上常年是空的。改一个字段,两个模块报错,三个报表变样,四个接口超时。谁也说不清楚哪个字段是给谁用的。

后来我们请了一位外部顾问,他推荐了领域驱动设计。核心思路不复杂——别一开始就想着“统一”,先把业务切成不同的边界。在每一个边界里面,语言是一致的;跨边界的时候,做明确的翻译。别让所有人都用同一本词典,除非你确定他们真的在说同一件事。

我当时觉得这个道理很新。现在看着我妈的回形针和橡皮筋,我觉得自己像个笑话。

我妈的限界上下文

我妈没有读过埃文斯那本书。她初中都没读完。但她区分那些收据的逻辑,和领域驱动设计里“限界上下文”的思路,本质上是一回事。

她没有试图建一个“大一统”的账本。她分了几个小的独立单元——我的医疗记录一个信封、我爸单位的事一个信封、人情往来一个笔记本、家里的水电煤一个铁夹子。每个单元内部的规则不一样:医疗的按时间排,水电煤按缴费渠道分,人情往来按对方的家庭记。

有一次我试图帮她把这些东西全部扫描进电脑,按统一的分类标准归档。我建了一套命名规则,什么“年份-类型-金额-备注”,自认为非常科学。她看了一眼,说:“这样我找不到。”

“怎么会找不到?你搜关键词就行。”

“我要找的东西,有时候不是关键词能搜出来的。”她说得很含糊,但我大概懂了。她要找的,是某个具体时刻的记忆——比如1998年那次搬家到底交了多少押金,比如我外婆最后一次住院是什么时候。这些信息在不同的“上下文”里,意义完全不同。在医疗那个文件夹里,它是一笔费用;在家庭记忆那个盒子里,它是一个时间刻度。

我们的“统一分类体系”抹掉了这种差异。正如我们那个两百列的保单表,抹掉了业务部门之间的语义差异。

我们的系统曾经像一间没有墙壁的屋子

有一个细节我记得很清楚。

项目刚开始的时候,我们确实试图跟业务部门“统一语言”。每天早上九点半,会议室的投影仪开着,白板上画着模型图,一群人在争“客户”到底包不包括投保人。

软件工程师在白板上绘制领域模型草图
软件工程师在白板上绘制领域模型草图

争了两个星期,没有结论。

后来顾问说了一句话:“你们不需要统一。你们需要承认,他们在不同的地方,说的本来就是不一样的东西。承认它,然后给每个地方一个名字。”

这句话我现在都记得。因为当时所有人——包括我——都沉默了好几秒钟。不是因为震惊,是因为大家其实早就知道。只是没人愿意说出口。承认“同一个公司里不同部门用同一个词指不同的事”,在很多团队里,等于承认沟通失败。

我们把系统重新划分了上下文。承保一个、理赔一个、客服一个、对账一个。每个上下文里,有自己的一套模型、自己的一套语言。跨上下文调用的时候,通过明确的接口做转换。不完美。但至少我们知道了,哪一堵墙立在哪里,门开在哪里。

有一个同事说,这不就跟老小区一样嘛。每栋楼有自己的门禁,但楼和楼之间有路连着。以前我们想做的事,是把所有单元打通成一个大通间。结果就是没有一面墙能挂东西。

盒子底下的那张收据

我把铁皮盒子里的东西整理完之后,在盒底最下面发现了一张很薄的纸片。是我出生那年的住院费收据。1982年,南京市妇幼保健院。金额是十四块六毛。

手写的字迹已经洇开了,但数字还能辨认。我妈说她当时不太舍得用这张纸夹在别的东西里,怕折坏了,就一直放在最底下。“反正也不报账。”她说,“就记着你是在这儿来到我们家的。”

这张收据不属于任何“上下文”。它不参与报销、不用于核对、不构成任何业务逻辑。它只是存在在那里。我把它翻过来,背面有一行铅笔字:“七斤二两,哭声很大。”

我后来想,如果我们做的系统里,也能容得下这样一张“不参与任何流程”的记录,那可能比任何花哨的架构图都难。但也许,那才是真正重要的东西。

说不清楚但确实存在

我现在的项目仍然有问题。边界划分不是一劳永逸的,语言在变,业务在变,团队在换人。每隔几个月,就会有新的词语冒出来,或者说旧词语被赋予了新的意思。

但我不再那么焦虑了。因为我慢慢意识到,领域驱动设计与其说是一种技术方案,不如说是一种承认。承认人的认知是局部的,承认同一件事在不同人眼里本来就是不同的事,承认试图用一套模型解释一切,是一种傲慢。

我妈的铁皮盒子至今没有数字化。我给她买过一个扫描仪,她用了几次就搁下了。“有些东西还是得用手翻。”她说。

我不知道该怎么反驳她。因为在软件系统里,我做的事情——划分边界、定义语言、维护模型——最终不也是为了让某些东西可以被理解、可以被找到、可以在需要的时候被重新读一遍吗?

那张住院费收据现在还在盒子最底下。我偶尔会拿出来看一眼。十四块六毛。七斤二两。哭声很大。这些数字和描述,不在任何流程里,不被任何系统引用,但它是整个盒子里最沉的一张纸。

也许好的系统设计也是这样。不是把所有东西都管起来,而是知道哪些东西应该被放在最底下,让它安安静静地待着,不被任何上下文打扰。

作者|fawen

排版|fawen

审核|满满

免责声明:市场有风险,选择需谨慎!此文仅供参考,不作买卖依据。如有侵权请联系删除。
文章名称:领域驱动设计和母亲的铁皮盒子
文章链接:https://m.lfdjt.com/info_23_31315.html