在进行业务架构设计时,我们需要进行业务域的划分。能否划分出合理、稳定、可持续发展的业务域对于未来平台的发展可谓至关重要。当然,对于一些急于试错的项目、DEMO性质的项目、或者进度优先或者是一锤子买卖的项目而言,可以忽略本文。

接下来,我会介绍一下域是如何被识别出来的,以及如何评价域划分的合理性。

Step 1:用户需求场景分析,识别出业务全景Use Case

在进行域划分前,我们第一步要做的是要进行用户需求场景分析。本文不会展开介绍具体如何去做场景分析,有兴趣的同学可以参考《UML用户指南(第2版)(修订版)》需求分析与系统设计(原书第3版)

简单来说,我们经过对一个业务过程总是可以识别出有哪些人、角色会参与到业务过程的相关活动中。我们使用UML建模方法。一般我们会用Use Case图进行表达,Use Case图会包含这些元素:

  • Actor: 常见的翻译包括“参与者、执行者、主角”等等。
  • Use Case: 在不展现一个系统或子系统内部结构的情况下,对系统或子系统的某个连贯的功能单元的定义和描述。

其中Use Case还会包含这些信息:名称、简单描述、关系、活动图和状态图、前置条件、后置条件等等。以一个简单的用户账号管理为例,我们绘制的整体Use Case图如下:

Step 2:分析模型鲁棒图,识别出业务场景中所有的实体对象

鲁棒图 —— 是需求设计过程中使用的一种方法(鲁棒性分析),通过鲁棒分析法可以让设计人员更清晰、全面了解需求。它通常使用在需求分析后及需求设计前做软件架构分析之用,它主要注重于功能需求的设计分析工作。需求规格说明书为其输入信息,设计模型为其输出信息。它是从功能需求向设计方案过渡的第一步,重点是识别组成软件系统的高级职责模块、规划模块之间的关系。

鲁棒图包含三种图形:边界、控制、实体,三个图形如下:

  • 边界——起与外界交互的作用,它只能与控制对象和执行者有关系
  • 控制——对业务控制、流程控制的作用,它能与边界对象和实体对象有关系
  • 实体——业务元素的存储对象,与领域模型中的对象有良好的关系。它只能与控制对象有关系

我们在对之前识别出的每个Use Case,都可以绘制一份鲁棒图。通过绘制鲁棒图,我们可以定义出该场景的涉及到的边界类、控制类以及这些控制类会加工/处理哪些实体对象。我们以邮箱注册账号这个Case为例,我们可以简单的绘制出鲁棒图如下:

通过对所有的Use Case的依次分析,我们必然可以分析出所有的实体对象。

Step 3:领域划分,将所有识别出的实体对象进行分类

接下来,我们通过对所有实体对象进行分类,就可以完成域划分了。比如,主订单、子订单对象可以归类到交易域;买家、卖家对象可以归类到会员域。

当然,最终所有的对象是归类到十个域还是二十个域,从理论上看,可以看做一次排列组合过程。只是,我们往往可以根据以往的经验、业务知识,做一个初始的域划分(但不见得是靠谱的)。因此,我们可以认为一个域实际上是一个或多个实体对象的信息集合,并对所管理的实体对象的生命周期进行管理。

  • 一个域管理一个或多个实体对象
  • 一个实体对象被一个域进行管理

如果出现一个实体对象被多个域进行管理,那么相关域的职责实际上就是存在冲突,存在耦合,相互影响。

Step 4:评估域划分合理性,并进行优化

我们在经过Step 3之后,往往可以得到一个或多个域划分的方案(或者组合)。那么,如何进行评估哪种划分方案更加合理呢?其实判定原则非常简单,就是看域划分是否符合“高内聚、低耦合”原则。这个道理相信大家都能理解,但问题是如何进行定量的评估?这里介绍一个实用简单的方法:

我们需要再回到Step 1中得到的Use Case全景图。这时,我们需要再将每个Use Case依次画时序图。在这个时序图上,生命周期线是按照“域”这个维度来看。如下示例:

在绘制过程中,我们可以看域与域之间的调用是否过于频繁?甚至是反复调用不同的域服务?如果存在这种情况,就意味着这两个域之间存在比较严重的耦合。这往往通过直观就能有个大致的判断。如果要从定量角度来分析,可以参考代码圈复杂度的度量算法,我们也可以设定一个“域依赖度”算法,来衡量域与域之间的依赖度。对于依赖度比较高的几个域,我们可以采用:1)域合并 2)域拆分 3)提取第三方域做依赖倒置等降低耦合。

通过将所有的Use Case(至少是最关键的一级Case)绘制完时序图后,我们基本上就可以得到一个经过平衡考量后合理的域划分。

域划分一个不合理的案例

比如,在交易下单系统中,目前还有一个域叫做限购域。按照过往的业务背景知识,大家很容易接受这个域。觉得很合理啊,下单时有各种各样的限购情况。可是,当我们将所有的限购场景使用鲁棒图绘制时就发现,这些限购场景涉及到的对象如下:

  • 按买家维度做限购:比如按照买家的信用级别等进行限购管理(更新买家信息,如打标等),涉及的对象是买家对象。买家对象应该是由“会员域”去管理啊。
  • 按商品维度做限购:比如,给特定商品打一些标,这样能对这类商品进行区域限购。涉及的对象是商品对象。商品对象应该是由“商品域”去管理啊。
  • 按曾经是否享受过特价优惠做限购(比如半年内买过特价商品,半年内不能再买)。这个涉及到的对象有买家和订单等信息。

很显然,限购这个域是按照“场景”维度进行提取的,而不是根据“对象”进行汇聚产生的。这么划分,会产生的一个问题是,“场景”是不可枚举的、易变的。今年有10个应用场景,明年随着市场的发展,可能又有20个应用场景。如果,按照“场景”维度去做域划分,就会导致按照这种方式划分的域,是不稳定的!