接上文:《软件设计不是CRUD(12):低耦合模块设计理论——业务抽象:模块分层操作》
进行模型抽象是基于业务抽象的设计思想,从原始需求到模块设计落地的第三个重要步骤。之前的文章已经提到,模块是一组模型和行为的集合。 模型定义了模块的业务面,行为则驱动模块产生数据变化。进行模型抽象的工作本质就是确认“怎样最小信息量模型就是可以定义业务的模型”,其工作目标是依据已经分析得到的模块业务维度和模块分层规划,确定业务维度应归属的业务主体,以及业务维度在业务主体的体现方式。
1、模型抽象方式
模型抽象工作针对的粒度是已经明确模块归属的业务主体,也就是说每一个业务主体都需要设计它的抽象模型。有了抽象模型后,再对业务主体对应的业务行为进行抽象,形成抽象行为。在这个过程中,设计模式的运用将会给设计人员很多高效率的帮助。模型抽象的方式可以概括为,将为业务主体设计一个“最小的信息集合”,使得业务主体能用最小的信息集合刚好适配最大的业务变化。这些信息囊括了表达业务主体唯一性的信息、表达业务维度的信息、建立最小关联的信息以及参与控制逻辑工作的信息。
1.1、哪些关键信息必须包括在抽象模型中
1.1.1、确立业务主体唯一性的信息
这个原则主要是为了保证控制逻辑能够精确到每一条具体的业务信息,来控制业务逻辑的处理过程。如果业务主体按照租户编号 + 业务编号就能在未来运行的系统中找到这个业务主体下唯一一条业务信息,那么最小的业务主体的模型就应该包括租户编号、业务编号这两个信息;如果业务主体仅仅可以按照订单业务编号确定唯一性,那么最小的业务主体模型,就可以只包括订单业务编号。
注意,在抽象模型中描述业务主体唯一性的信息,应该是从业务角度能够说明唯一性的信息而非从技术角度能够说明唯一性的信息。这句话如何理解呢?以订单业务主体举例:利用关系型数据库的保存数据信息时,我们会为订单业务主体的基本信息设定一个id值,这个id值只是从技术层面上标识信息的唯一性,并没有任何业务意义。而从需求层面上看或者说,从业务层面上看,订单基本信息的数据唯一性是由租户 + 订单业务编号确定的;订单类型信息,从业务层面上能够说明其业务唯一性的,是订单类型编号/英文名。
另外需要注意,技术性质的ID信息并不适用于所有的具体落地形式,诸如一些非关系型数据库和较新的关系型数据库/数仓形式,都没有说一定需要一个纯技术性质的id编号,才能保存数据——实际上我们最常使用的MySQL数据,也没有说一定需要一个id作为数据表的主键才能保存数据,这完全都是技术实施过程中,人们约定俗成的方式。
1.1.2、代表模块中业务维度的信息
实际上在抽象模型中表达的业务维度信息,就是为这个模块将要设计落地的控制逻辑准备的必要信息(本专题后续讲解抽象行为时,会进行详控制逻辑设计的详细说明)。无论是前期分析得到的主要业务维度还是次要业务维度,都应该在抽象模型中进行表达。
例如前文示例中,有一个关于优惠券模块的业务维度分析。在那个示例中,我们根据原始需求提取到一个“优惠券使用门槛”的次要业务维度。具体来说是,优惠券可能存在多种不同的使用门槛,诸如“原始购买数量满X元”才能用券、“原始购买金额满X元”才能用券等等。不同的优惠券使用门槛填写的信息、具体的判定过程可能完全不一样,但无论怎样变化,抽象后的优惠券模型肯定是需要以某种方式记录当前优惠券使用的哪种门槛信息的(如果没有设定门槛,最多就是这个记录的信息没有具体的值)。
抽象后的模型记录的业务维度信息,必须是在控制逻辑执行过程中,能够唯一找到具体的业务维度信息的值。例如如果“优惠券使用门槛”是按照“门槛类型”区分不同的实现,那么抽象后的优惠券中就需要记录这个“门槛类型”值。
1.1.3、模型内的各业务主体的关联信息
能够在抽象模型中进行表达的关联信息是有前提的,就是关联信息涉及的两个或者多个业务主体,都是在同一个功能模块中进行维护。这主要是因为在同一个功能模块中进行维护的业务主体往往具有较高的内聚性,需要构成一个信息整体向外提供服务,这就使得这些业务主体的关联信息,必须在抽象后的模型中通过某种方式进行表达。例如,预算模块中的预算大类和预算项目之间的关联信息,订单类型和订单信息之间的关联信息。
实际上模型内各个业务主体的关联信息往往和模型内代表业务维度的信息具有较高的重合度,这主要是因为在模型内维护多个业务主体的情况下,这些业务主体基本上会都围绕一个更主要的业务主体对业务结构进行整体描述,而前者就有因为本身就是业务维度所以独立成一个业务主体的情况。例如,我们多次用来举例的费用模块,其中包括两个业务主体:费用科目和费用信息,其中费用科目本来就作为一个业务维度存在(不同费用科目,所填写的费用信息是有区别的)。
1.1.4、必须参与控制逻辑处理的信息,无论其是否有业务性
抽象后的模型中需要记录参与控制逻辑的信息,这些信息可能不存在任何业务性质,其主要服务于控制逻辑的执行过程。例如在各种“优惠政策门槛”的具体实现中,控制逻辑允许设定优先级或者默认值,当两种或者多种具体的“优惠政策门槛”存在冲突时,就以优先级更高的或者有默认标记的“门槛”作为判定依据。这种设定的优先级或者默认值,是没有具体的业务意义的,只是为了帮助控制逻辑能够在出现多义性时,决定控制逻辑流向。诸如,优先级、默认值、排序号等信息,基本都是为了匹配这样的场景。
注意:需要参与控制逻辑执行过程,且又具有较强业务性的情况,在实际工作中并不多见(或者说基本没有)。原因是模型中越是具有业务特性的信息,越不可能参与控制逻辑的处理——除非控制逻辑设计有问题;因为控制逻辑本身并不会参与任何带有业务性质的处理过程,而只是驱动各个既有的业务逻辑节点按照固定的(或者动态排定的)顺序进行工作。
抽象模型是指“最小具备哪些信息,业务模型就可以称之为业务模型”。再这样的要求下,只有为了确定业务信息唯一性、记录业务间关联性、帮助控制逻辑记录业务维度、判断执行流程的信息,可以作为放入抽象模型中的备选项。
1.2、哪些信息不应包括在抽象模型中
-
具有特定业务性质的,且不参与控制逻辑处理的信息
具体的业务信息不应该出现在抽象模型中。再具体、再重要的业务信息也只是服务于一种或者几种具体的业务实现,抽象的模型中加入这些具体的业务信息,将影响业务逻辑变化的灵活性——下一种实现中,可能都不再使用任何当前觉得重要的业务信息。诸如:收货地址、收货人、费用说明、使用的优惠券信息、要求送达日期、是否支持退货等等这样的业务信息,都属于抽象模型下的一种或者几种具体模型实现中应该具备的信息。
如果设计者根据工作经验、系统实际应用场景,非常确认某种具体的业务信息无论什么情况下都会存在,那么可能就需要思考一个问题:这个信息是否属于描述业务信息唯一性的信息?是否属于描述业务维度的信息?是否属于对逻辑执行过程进行干预的信息?请仔细思考,往往设计者会发现,以上问题的答案大概率有一个或者多个可以得到肯定的答案。
-
不同模块间业务主体的关联信息
不同模块间的业务主体关联信息,不应该放入抽象模型中,这主要是因为这个关联信息都只存在于某种或某几种具体的业务场景下,例如订单信息和预算信息的关联,显然只会出现在某些具体的订单类型下。所以这种关联并不是所有业务模型都需要具有的关联信息。这是从需求分析的角度看,从模块设计的角度看,如果将这种模块间的关联信息放置在抽象模型中,势必会出现“一个模块的所有实现都必须依赖另一个模块”的情况,即使前者并不需要,这显然增加了两个模块的依赖强度不利于前者后续的实现扩展。
-
为了方便查询、方便显示、简化代码过程的冗余信息文章来源:https://www.toymoban.com/news/detail-837049.html
在模块的设计落地过程中,为了提高查询信息的利用率、降低模块的维护成本,设计人员经常在保证数据一致性的前提下,为业务模型的某种落地方式(例如数据库方式)加入冗余信息。这是一个常规做法,但是也仅适用于业务模块的某一种具体实现。冗余信息不应该出现在抽象模型中,原因和上一个列举项目的原因一致:这些信息并不适用于所有扩展的业务场景,也不服务于控制逻辑的工作过程。文章来源地址https://www.toymoban.com/news/detail-837049.html
到了这里,关于软件设计不是CRUD(13):低耦合模块设计理论——业务抽象:抽象模型的操作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!