蚂蚁金服对研发高要求的领域建模能力是指什么?

5,357 阅读14分钟

0 前言

最近,由于工作需要,我接触了网商银行的一个项目。项目里对应的业务模型设计,是我工作这三年来见过的所有模型里最复杂的。于是,利用五一这个短暂的假期,我温习了一遍领域建模相关的知识,对于领域模型的设计,有了一些额外的思考。

在领域界有一本书 《Domain-Driven Design》,是Eric编写的,这本书在Goodreads上的评分是4.15分(相当高)。书中有这样的一段话:

“软件开发人员几乎总是专注于技术,把技术作为自己能力的展示和成功的度量......当领域很复杂时,这是一项艰巨的任务,要求高水平技术人员的共同努力。开发人员必须钻研领域以获取业务知识。他们必须磨砺其建模技巧,并精通领域设计。“

书中所强调的领域设计的能力,是对技术人员综合能力评估的一种体现。在我看来,这是属于在软件工程这个方向中,T-1级别的能力。而所谓的领域建模,是一种通过日常不断实践,来强化开发人员思维,逼迫开发人员进入深度思考的过程,并通过在这个过程中的不断锤炼,可以使得开发人员形成结构化思考方式的方法论。

但是,需要注意的是,领域模型本身的定义,在不同的方法论和流派中,是有一些区别的。领域建模的方法也有多种。不过,求同存异,没有对错之分。

在本文,我主要是写一写我对于领域建模的理解,以及介绍一些基础的领域模型知识。算是对这个五一长假以及过去几年工作经验的一个总结。也会简单提提,如何将领域建模的思路,与我们的日常生活结合起来思考。希望能对各位有所帮助。

ok, start with why.

1 领域模型

1.1 领域模型是什么

在why之前,我们先插入一个what,介绍一下领域模型的基本概念。

领域模型是对领域内的概念累或现实世界中对象的可视化表示。又称概念模型、领域对象模型、分析对象模型。它专注于分析问题领域本身,发掘重要的业务领域概念,并建立业务领域概念之间的关系。 ———摘自度娘

这么解释看着有点迷糊,简单地说,领域模型,是用来描述事物本身的一个模型。它关注事物的特征,事物之间的联系。由于在日常业务开发中,所面临的场景是多样化的,所以可能同一个事物,在建模过程中,我们所获取的特征是不一样的。例如某人A,他是员工,是程序员,是男人,也是父亲。在特定的场景下,我们只提取指定的特征即可。

领域模型之间的联系,我们要怎么理解呢?

以上面这位某人A为例,本次我们所要提取的特征,是父亲。父亲与母亲,丈夫与配偶,关系是1对1的。也就是一夫一妻制。父亲与孩子,关系是1对N的,一位父亲,可以有一个孩子,也可以有多个孩子。母亲与孩子的关系,也是1对N的。所以这一家三口之间的联系,可以简单用这张图来表示:

当然领域模型的图形化还有很多种方式,例如UML类图、状态及图、时许图等,这边就不一一介绍。

1.2 为什么要学习领域模型

“基础设施决定上层建筑” —— 马克思。

老祖宗教导我们,万丈高楼平地起,告诉我们建高楼,要深地基。倘若把一个软件比喻成一栋高楼,那么领域模型,就可以理解为高楼地下的基础设施。

从架构上来说,领域模型是处于应用架构的最底层,上图的Domain层,这一层涵盖了模型治理、流程抽象、流程治理等方面的知识。我们可以很清楚地看到,如果领域模型没有把控好,那么就相当于大楼地基没有打好,带来的后续建筑或是维护成本之高,是难以想象的。

Problem space 与 Solution space,是一套通用的问题分析解决方法论。如果我们以Problem space 与 Solution space来理解的话,领域模型所做的事情,是处于Problem space阶段的,而Solution space 对应的则是系统模型。

领域模型与系统模型之间,我们要如何区分呢。

很简单,领域模型专注的还是事物本身,是高度抽象的。到了系统模型,就是到了具体的设计阶段。还是以上面的某人A为例,他有三个孩子,那么我们在设计阶段,要去怎么建立系统模型呢?可以有以下这三种方案:

  • 父亲表里有多个孩子字段,孩子1、孩子2、孩子3,用于保存孩子的信息
  • 父亲和孩子是两张独立的表,通过外键关联
  • 通过字符串的格式存储,例如搞个大json串,放在父亲的表里

这是三种不同的实现方案,但是在领域模型层面,依旧是父亲与孩子,是1对N

所以,我们是通过领域模型,进而推导出系统模型,设计出对应的解决方案的。如果领域模型初期建模有比较大的问题,可能就会导致开发人员做很多的无用功。

但是我们为什么要按照这种流程来做开发呢,语言有面向过程和面向对象之分,我们可以对应到开发流程上,也可以理解有面向过程和面向对象(模型)之分。前期不做分析与设计,脑海中有个初步的实现思路,直接操起键盘一把梭,岂不是很畅快?而且从物理学的角度来看,系统的演变,随着时间推移,混乱度总是不断增加的(熵增),难道说领域模型可以做到熵减这种反科学的能力么?

让我们来回忆一下这两个场景,看看你是否遇到过:

1、接到PD的需求,大概看了一眼,操起键盘一把梭,梭了一阶段以后,发现了某个环节存在问题,可能是PD的需求有不足,也可能是你实现方案存在局限性,找PD撕逼讨论过后,发现需求入口侧得不到解决。就只好推翻已有结果,从头再来。或者是写出一坨非常恶心人的代码,告诉自己后面有空再重构。

2、应用上线运行了一段时间后,PD想做个小优化,过来找你讨论。你发现虽然是个小优化,却有大的改动。原因是你之前设计方案,不能够很好的支持这次变更,或者说没有很好地和PD需求连接起来。结果导致代码越改越乱,难以维护。

当然,这么做,可能PD看到你为了她的小改动天天加班,心里过意不去,左一杯奶茶右一杯果汁,接触得多了,一段职场姻缘就此开始。

如果我们选择使用领域建模,这种自上而下的设计,能彻底解决上面的这两个问题么?

答案应该是不能的,要解决上面的两个问题,除了开发自身建模能力的提升之外,系统的设计能力、PD对于模型的理解能力,以及PD和RD之间的沟通有效性,都是值得考量的因素。但是,通过领域建模,我们至少可以保证代码的实现与层级结构是相对科学稳定的,符合业内规范的。在领域建模的过程中划分清楚域的边界,对于后续的系统稳定性提升、依赖区分、业务逻辑清晰性,都是有很大的帮助的。(领域建模能力在蚂蚁金服的某BU,是作为应用架构高P的考核标准之一

所以做好领域建模,不止是提升开发人员的综合素质能力,也是设计出可以低成本维护的可持续发展的稳定系统的必备要素。而领域模型到系统模型这一设计指导方针,可以帮助我们降低软件设计与现实需求的差异性。

1.3 如何进行领域建模

进行领域建模的方式是有多种的。需要注意的一点在于,领域建模不是纯粹的技术,不是简单学习后就能设计出完美的模型。设计出好的模型,需要依赖于大量的经验和思考。下面介绍给出一些常见的分析方法,然后我们选择一个比较有趣的方法进行深入介绍。

常见分析方法

  • 用例分析法
  • DDD(Domain-Driven Design)
  • DoDAF
  • 四色建模法(Java Modeling In Color With UML)
  • 飞马模型(蚂蚁金服内部)

例子

我们以用例分析法为例,这是最常见也是最简单的分析方法。

用例描述:金牛发布了一篇文章。

这个用例似乎有点太简单的,从主谓宾的角度来看,主语是金牛,谓语是发布,宾语是文章。

在这里我们补充一个点,领域模型是一个模型,模型本身是有属性的。例如上面的某人A例子,他是一个人,那么就会有年龄、性别、身高等属性。

为了引入属性这个概念,我们给上面的用例描述加上定语。

用例描述:金牛发布了一篇领域建模相关的文章。

主语:金牛,名词,可抽象为领域模型;
谓语:发布,动词,可抽象为模型关系;
定语:领域建模相关,形容词,可抽象为模型属性;
宾语:文章,名词,可抽象为领域模型;

当然,实际的用例描述会比上面这个复杂得多,具体的语与用途也会有更多映射关系,例如我们除了可以将定语抽象成宾语的属性外,还可以将其抽象成宾语的关联模型。

这时候我们根据上面这个简单的用例描述,就可以抽象出一个简单的领域模型,如图:

整个流程是很清晰易懂的。我们来抽象一下具体的步骤:

  • 收集用例描述集合
    • 一系列需求文字描述的用例集合
  • 寻找概念
    • 对用例描述进行语言分析,识别名词
  • 添加模型关联
    • 名词之间存在语义联系,则往往存在模型关联,例如上面的发布,联系了金牛和文章两个名词
  • 属性完善
    • 形容词完善,例如上面的领域建模相关,如果文章存在标签属性,那么它的值在我们这个用例里就是领域建模。

简单的步骤就是这四个,然而实际的工程中领域建模,远远比这个复杂。例如还存在子域划分、模型组合等手段。

接下来我们来看一个比较有趣的例子,内容来自于 《Object-Oriented Analysis from Textual Specifications》 论文,中文翻译为《基于文本规范的面向对象分析》,文章所讲的内容,是如何通过自然语言处理技术,从语义和句法的角度分析用例描述,进而通过程序提取出领域模型。

用例描述:

the Static Requirements are: Vendors may be sales employees or companies. Sales employees receive a basic wage and a commission, whereas companies only receive a commission. Each order corresponds to one vendor only, and each vendor has made at least one order, which is identified by an order number. One basic wage may be paid to several sales employees. The same commission may be paid to several sales employees and companies.

the Dynamic Requirements are: A monthly payment is made to vendors. When a vendor makes a sale, he/she reports the order to the system. The system then confirms the order to the customer, and orders are delivered to customers weekly.

分为static requirements 和 dynamic requirements,静态需求与动态需求。人工翻译一下,大意内容是:

静态需求: 供应商可能是销售人员或者公司。销售人员收取基本工资和佣金,而公司只收取佣金。每个订单只对应一个供应商,且每个供应商已经至少制造了一个订单。订单由订单号进行标识。一份基本工资可以支付给几个销售人员。同样的佣金可以支付给几个销售人员和公司。

动态需求: 每个月向供应商付款,当供应商进行销售时,他会向系统报告订单。然后系统确认订单给客户。订单每周完成对客户的交付。

这个例子会比一开始举例的发布文章复杂一点,我们还是用回上面的简单四个步骤。标记出以下名词:vendor, order, sales employee, company, order number, basic wage, commission.

这些名词,有一些是主语,有一些是宾语。我们再结合动词,能初步画出这样一张图

有些名词,可以作为另一部分名词的属性。例如销售人员与基本工资。基本工资可以作为销售人员的属性。文中写到提取这类属性,可以通过分析模型中的聚合与二元关联的关系。可以得到接下来这张图:

2 领域建模与日常生活

学会领域建模,只对开发人员有帮助么?

其实不是的,领域建模,本质是工程的高度抽象。如果我们把生活当成一个项目来看待,那么我们也可以对生活进行领域建模。又或者,我们遇到了一些问题,或者想去做成一件事情,那在这过程中,领域建模的能力可以帮到我们什么?

以解决一个问题,我们需要考虑哪些因素? 问题、目标、现状、方案

高度抽象出这四个模型,然后我们对其进行建模。如果方案可行,那么这个 问题-目标-现状-方案 的领域模型可以叫做什么?

我们可以理解为这是我们的处事模型,或者称之为原则。

软件工程教会了我们工程化的思维,领域建模训练了我们高度抽象的能力。

从大学毕业后,我懵懵懂懂感觉到了这些知识与技能对于我日常生活的帮助,也初步有了模型化的概念。以至于在毕业后一两年,我和友人交谈的时候,经常扯到模型这个词语。直到后面,我看了Ray Dalio《Principles》(中文名《原则》) 后才明白,原来这就是所谓的处事模型 ——— 原则。

通过领域建模,得到日常生活的原则,这对于我们有什么好处呢?

举个例子,我们将人脑的记忆部分比喻成磁盘。你遇到了一个问题,解决了一个问题,你告诉自己重复的错误不能再犯,于是你把这件事情记录了起来。过了一段时间,你遇到了一个类似的问题,又重复了上面的步骤,将这件事情记录到了磁盘里。

这么做有什么不好的地方呢,随着时间的推移,你的记忆里会塞满了各种各样实例化后的犯错经历,等你想回忆某一件事的时候,你需要到磁盘里去扫描得这个数据,那估计得费一阵子功夫。再加上人脑是有记忆曲线的,早期的犯错经历,可能很快就被数据淘汰掉了。

但是如果在早期就有了抽象的思维,你会发现随着时间推移,你所需要建立的“原则”越来越少,已有的原则会越来越完善。

所以说学会领域建模,有助于提升自己的抽象能力。有助于自己,to be a better man