上一篇文章《软件设计不是CRUD(10):低耦合模块设计理论——业务抽象:从需求中提取业务维度》本专题详细讲解了业务抽象的一个重要步骤:提取业务维度。本篇文章内容主要讲解在提取业务维度后,如何对应用程序中初步划分的各个功能模块进行分层规划。
1、为什么要进行模块分层
需要注意的是,在对应用程序的需求进行业务维度提取时,设计人员实际上还没有,也无法对应用程序最终如何划分功能模块进行明确。这是因为提取业务维度这件事情并不以划分模块为前提,而只是业务抽象设计的第一个工作。提取业务维度所需要的业务边界,也只是从设计人员对业务理解的角度出发、从设计人员经验角度出发的大致划分。
对应用系统中初步划分的功能模块进行分层规划,将形成对初步划分的功能模块进行调整和验证的依据,以便形成更准确的模块划分和模块边界。所谓调整就是将凭直觉、凭经验进行初步划分的模块按照分层原则进行再拆分、再合并、再添加甚至进行删除。所谓验证,就是验证这些完成分层的模块是否能匹配原始的需求、是否能匹配未来可能变化的需求点。
模块分层也是保证模块间低耦合强度的前提,是明确模块间调用关系的前提。注意,这里描述的因果关系:因为满足了模块分层的基本原则,所以才能保证模块间低耦合强度。而不是一些读者理解的:因为保证了模块间的低耦合强度,所以模块自然就进行了分层。这个因果关系存在的本质原因是模块间的依赖关系可以在从设计层面上出发,不受原始业务需求限制,随意地进行依赖倒转。
2、模块分层的基本原则
以下是基于模块分层原则,完成规划的应用程序功能模块分层示意图:
注意:上图中所描述的各个“分层区域”不存在特定意义,只是为了便于读者对模块分层后的效果进行理解而进行的一种归纳。可以看到进行了有效的模块分层规划后,所有模块间的依赖都是单向的,并且处于同一分层区域上的两个(或多个)模块很少存在依赖关系。
原始需求对模块的分层规划具有指导性作用,但并不起决定性作用。因为模块设计和原始需求通过业务抽象进行了设计隔离。具体的效果表现为:虽然原始需求的描述中,要求A模块工作过程中需要调用B模块的功能(例如:原始需求是,出库业务完成后会调用订单模块,将当前出库单对应的订单状态变为“已完成”),但是进行模块分层规划后,B模块所处分层完全可能在A模块所处分层之上(订单模块在出库模块之上)。模块分层的主要原则有:
- 变化风险越大的模块,分层位置越靠上
- 模块间的依赖关系一定是单向的,且一定不存在循环依赖
- 下层模块“看不到”上层模块
- 上层模块可以调用、扩展下层模块的功能
2.1、业务屈服度和业务变化风险
2.1.1、业务屈服度
业务屈服度是指当一个既有功能模块的需求变化达到何种程度后,功能模块的代码就必须进行修改,否则该功能模块就不再能满足业务要求。这种“不再能满足业务要求”的变化可以由业务维度发生变化导致,也可以由功能模块的控制逻辑发生改变导致。所以也可以对以上描述做如下理解:
功能模块A之所以叫做功能模块A,是因为具有X,Y,Z这三个业务维度,并有一个固定的控制逻辑将这三个业务维度联系起来,构成一个完整的工作过程。当功能模块的业务维度需要新增,且已存在的业务维度和新的业务维度无法进行合并时;又或者当目前的控制逻辑需要做出过大调整,不能再按照原来的顺序将业务维度联系起来时,需求变化的程度就超过了功能模块可以适应变化的最大设计强度,