不要脸的数据模型

作者: IT长弓 | 来源:发表于2018-03-26 16:02 被阅读711次

    在上一篇文章《不要脸的业务构件》中,谈到了建筑师冯果川在一席中的演讲《我今天讲的所有建筑都是不要脸的建筑》,说中国的公共建筑都是庞然大物,前面有一个超尺度的广场,是为了留出足够的距离让你欣赏他正面的脸面,这种要脸的建筑以大块的空间,阻碍了和人、和自然之间的顺畅交流,空间层次单一而呆板。

    而冯果川他们的设计,把大块的地块切碎,让人能够走进去,设计成不要脸的建筑,把整体的单一建筑分割成可以随意布置的多个小的建筑,不仅丰富了内外的层次和变化,而且也便于和人、和自然的交流。

    在上一篇文章中,把要脸的业务构件拆分成了更小单位的不要脸的构件,不仅可以灵活提供给外部调用者,而且精细化的、标准化的构件切分,也为以后工业化、自动化生产业务构件打下了良好的基础。

    上篇文章的最后,提到了可能由于设计不合理,把不应该属于该构件的对象放进了该构件中,该构件也许应该拆分为多个构件,这个问题的根本原因实际上是在模型设计时带来的。

    1.要脸的物理模型图

    曾经见过一个系统的物理模型PDM,按住Ctrl+鼠标滚轮往下滚了半天,才看到了全貌,而且每滚一次,鼠标的进度条圆圈要转几圈图才能出来。下面这张图已经缩小到最小了,据说有几百上千张表。这张模型就像一座大山,要看清全貌,真的得后退一个上海科技馆前面的广场的距离才行。要找到一张表,如果不用搜索,恐怕很难找到。这样的物理模型设计把所有的表都集中在一起,看似统一管理了,实质上却很难维护,维护这种PDM的同学可真算得上是勇攀珠峰的英雄啊!

    某系统的物理模型图

    2.要不要对象模型?

    对很多研发来说,对象模型完全是多余的,一张PDM在手,实现系统需求分分钟就有。

    我也曾经是这类研发人员中的“佼佼者”。拿到需求,读上几遍,总共需要几张表,哪些表是怎么关联的,一张基本完整的PDM,就已然浮现在脑海了。然后再根据表去设计对应的对象,加上增删改查对应的功能,一个需求就算完成了。

    甚至跟客户、同事间的交流、培训,全靠一张PDM图。有的PDM的表之间连一根线都没有,感觉交流起来确实是无法下嘴啊。

    经过一段时间的刻苦学习SID和领域建模技术,特别是做完一版产品管理的模型建模,尤其是输出文档需要对每个概念进行精确定义之后,深刻体会到了通过对象模型进行领域建模的好处,两个对象之间的关系连线到底应该是用什么类型的线、线两边的数量到底是0还是1还是N,都体现了问题领域的需求本质,通过概念模型去和别人交流时,当时怎么设计的、为什么要这么设计、可以满足那些业务场景,都能够说得头头是道。

    参与人对象模型图 

    3.要脸的对象模型

    因此,对象模型是个好东西,希望大家都能拥有。

    但设计对象模型时,也会将概念模型设计成一个庞大的、要脸的对象模型图。

    上面那张庞大的物理模型,如果不采取什么优化的设计策略的话,要画成对应的对象模型图,一样也会很庞大。

    又比如下面这张客户的概念模型图:

    客户对象模型图

    这张图只描述了部分主要的对象,其他对象以及对象的子对象再往下的关系没有在此进一步描述,如果全部描述出来的话,这张图就很庞大了。

    对象图并不仅仅是我们了解和交流业务需求的,更重要的是应用系统的实现应该基于对象图,否则设计和实现就脱离了,实现的系统必然失真,偏离了需求,最后做成了客户不需要的系统。

    设计的数据模型是怎样的 实现之后的系统是在这样的

    上篇文章中说,我们需要构建不要脸的构件,不需要一个庞然大物,因此业务构件的来源——对象图,也就需要拆分为不要脸的对象图。

    这就涉及到领域设计的问题。

    4.如何设计不要脸的模型

    说到领域建模,当然离不开DDD,即领域驱动设计(Domain Driven Design)的方法, 是Eric Evans在他的同名经典著作中提出来的。

    Vaughn Vernon在《Implementing Domain-Driven Design》中说,从广义上讲,领域是一个组织所做的事情以及其中所包含的一切,商业机构通常会确定一个市场,然后在这个市场中销售产品和服务,每个组织都有他自己的业务范围和做事方式,这个业务范围以及在其中所进行的活动就是领域。

    4.1领域拆分为子域

    Vaughn Vernon说,由于领域模型包含了领域这个词,我们可能会认为应该为整个系统创建一个单一的、内聚的、全功能的模型,但这并不是DDD的目标。恰恰相反,在DDD中,一个领域被分成若干子域,领域模型在限界上下文中完成开发。

    SID将一个电信运营商的支撑系统分成了以下领域:

    SID划分的领域

    4.2将子域内散列的对象进行聚合

    前面所讲的客户模型概念图,看上去挺合理的,客户拥有账户、订单、合同、地址等信息,这些信息都是属于特定客户的,离开客户这些都不可能存在。

    但是作为CRM系统,也就是客户关系管理系统,有多少对象又不属于客户呢?难道和客户相关的所有对象都必须在这一张图里面描述清楚吗?那这张概念模型图又将是难以维护的、要脸的、庞然大物了。

    因此,我们需要把整个子域的设计图进行拆分,拆分到更小的粒度。

    将大的领域拆分为很多小的子域后,子域内包含了很多用来表达业务对象的实体或者值对象,很多对象或值对象可以聚合在一起,来完成一个业务目的,这就是聚合(Aggregate)。聚合中有一个核心业务对象,叫做聚合根。聚合根通过禁止外部对象保持对其成员的引用来保证聚合内所做更改的一致性。

    下图是SID客户领域内的聚合,包括了客户、客户订单、客户问题、客户交互、客户账单等。

    SID 客户子域的聚合

    4.3聚合的粒度合适吗?

    下图是SID的客户聚合的对象图。

    SID 客户聚合对象图

    可以看到,客户账户是客户聚合的部分。

    按照DDD的原则,聚合根通过禁止外部对象保持对其成员的引用来保证聚合内所做更改的一致性。

    那么客户账户是否具有独立的业务能力呢?客户账户信息和客户信息是否必须保证一致性呢?客户是否只是定位账户和在对账户进行操作时需要作为校验规则使用的一个关键因素呢?这些问题的答案决定了我们是否需要把账户从客户聚合中独立出来作为一个单独的聚合来处理。

    我们分析和讨论了电信运营商的业务场景,认为维护客户账户信息和维护客户信息,是可以分离的,账户具备很多独立的业务能力,每次对账户操作时,并不需要把客户对象装载出来再进行账户的操作,因此客户账户应该可以独立成一个单独的聚合。

    你看,我们又成功地拆分了一个聚合,也即拆分了一个业务构件,把一张小脸改成了不要脸。

    4.4公共领域的对象是独立的聚合吗?

    我们在业务建模的过程中,就公共部分到底是不是独立的业务构件,讨论了很多次,争吵了很多次,最后暂时不认为是独立聚合的意见占了上风。

    但看看SID的领域和聚合图,公共部分显然是九大领域中的一个,包含了很多聚合。

    公共业务对象子域的聚合

    事实上,在实践过程中,我们也发现,这些公共部分如果独立出来作为单独的构件,会具有更高的可复用性、可维护性和可扩展性。

    5.结束语

    我们从一张要脸的、庞大的物理模型图开始,引出了我们不仅需要对象模型,而且需要设计不要脸的、粒度合适的领域对象模型。

    通过把领域拆分为多个子域、子域内的散列对象以聚合根为中心形成聚合、公共部分单独抽象成聚合等多种技术手段,把领域的一张庞大的对象图拆分为不要脸的、多领域多聚合的对象图。

    以拆分后的细粒度的对象图为基础,实现不要脸的业务构件就很容易了,有了这些被拆分的业务构件,再根据业务需求,挑选合适的业务构件,组装成一个个满足客户需求的端到端业务场景,这些业务场景就组成了一个应用。

    由于不要脸的业务构件的细粒度、高内聚、低耦合,因此可以灵活组装以满足不同应用的需求。

    相关文章

      网友评论

        本文标题:不要脸的数据模型

        本文链接:https://www.haomeiwen.com/subject/vesrcftx.html