首页 编程语言 领域驱动设计,让程序员心中有码(六)

领域驱动设计,让程序员心中有码(六)

领域驱动设计-聚合,一种极简的思维模式

引言

    作为IT技术产业飞速发展的产物,软件工程学已经成为当今时代非常重要的一个学科。作为一名资深的软件开发从业者,我们需要学习的东西实际上已经远远超出了原本在大学教育阶段所接受的知识深度和广度,领域驱动设计更是如此。当然必须承认的是大学阶段开了很多扇窗,直到今天才深刻体会那些平时看起来毫不起眼的学科(如图论、概率论、高等代数),实际上对软件领域的影响已经远远超出了我们的想象,例如,如果想做AI,没有扎实的数学和图论基础,显然只能成为工具的使用者,而非技术专家。

     有许多读者提到,笔者的内容缺乏实际例子,在具体阅读时,很难形成带入感。主要是因为领域驱动设计思想本身体系庞大,细节非常多,这需要在日常学习之余多加思考,细细的品味知识中的奥妙,笔者也是按照同样的思路来指导自己的学习过程的。坦率而言,要把这些概念的名词都记住,显然很容易,但是要理解这些名词的具体含义以及实际应用场景,却需要更多的思考,这也同样是软件工程博大精深的奥妙所在。

领域生命周期的复杂性是如何影响设计的

      我们都清楚领域驱动设计,作为应对复杂情形下的软件工程思路,实际上受到了传统软件思维的广泛影响,例如之前提到的实体和值对象、以及服务和包(模块)实际上在非领域驱动设计中同样普遍存在。但是聚合和聚合根的思想,应该属于领域驱动设计中独特的知识点,进一步加强这个知识点的认识,将有助于我们更好的进行聚合设计,从而更好的设计一个符合实际应用场景的应用系统。        

      在上一篇文章中,我们了解到,领域驱动的五个基本部分(关联,实体,值对象,服务和模块),他们是构成软件体系的最基础元素。在一个简单的软件系统中,往往只需使用这些元素的简单组合即可完成单个模块功能的开发,而且显然速度非常迅速。但是我们也将同样面对一些对象,他们具有更长的生命周期,也许有相当一部分时间,是通过复杂的数据持久化处理机制、甚至是跨数据源、跨服务来完成,这意味着不是单纯的依靠一块内存空间来度过的。它们与其他对象有着复杂的依赖关系,在它们漫长的生命周期中,会根据不同场景的规则、经历许多次状态的变化。对于这些对象的操作,稍不留心,就会导致代码间的耦合度急剧提升,甚至成为软件系统中最难以维护的代码块,这实际上偏离了模型驱动设计的理想轨道,成为经验设计史上的一大典型问题。

       领域驱动设计认为,这种复杂过程的操作对模型驱动设计带来的影响主要包括以下两个方面:   

        1、维护对象间,在整个生命周期中的完整性:对象依赖不同的数据源或存储机制或内存单元时,完整性将难以保障。

        2、陷入管理生命周期复杂性造成的困境中。同上,要维护这套具有复杂体系的模型结果,本身成为一个问题。

聚合,让设计简化

       领域驱动设计思想针对这两种场景,设计了聚合(Aggregate)对象来解决这个问题,并使用工厂对象和仓储对象来对生命周期进行管理,由于时间和篇幅的关系,我这一篇先介绍聚合对象和聚合根,下一篇在介绍工厂对象和仓储对象。

        实际上我们很容易就设计出一个具有复杂关系的对象,例如,Person对象,实际上可能关联了地址和工作等不同的实体或者值对象,如果要对数据进行删除,可能倾向于直接删除Person对象,而保留其他对象;或者删除Person对象时,同时删除地址对象。但是这两种方式都并非非常合理的策略,在于方式一,会在数据库中形成冗余数据,不利于后期数据的维护管理;而后者则可能导致依赖于地址的其他Person出现异常。

        即使是再简单的场景,遇到并发访问时,也会存在问题。由于不同的用户对系统中的数据的访问是随机分布的,意味着有可能会造成多个用户同时修改相互依赖的对象,进而造成系统可用性的急剧下降。

        因此,在具有复杂关联的模型中,要想保证数据更改的一致性是很困难的。不仅互不关联的对象需要遵守一定的规则,而且紧密关联的对象间操作同样也存在规则。经常使用的一种方式可能是事务锁,但是设计谨慎的锁机制,固然可以解决这个问题,但是可能导致用户间的操作不可控,系统变得不可用。事实上数据库层面的行锁和表锁,也是为了解决这些问题提供的思路,但是这种方案实际上分散了人们对于模型的注意力,使得系统流程的设计过程本身就相当臃肿。这也是古老的系统用户体验不佳的一个主要原因。    

        领域驱动设计认为,表面上看是对数据操作层面的技术问题,但是它的根源依然是由于模型的设计依然是基于实体关系模型的设计,而缺乏明确定义的边界。认为通过一个合理的模型的设计,可以是模型更加理解,并且使设计过程更易于沟通。当模型被修改时,它也将引导我们对实现进行修改。

        这种模式,就是聚合模式(Aggregate)。这种来源于制造业体系中的模型,简单但严格,但是可以提供新的思路。

        领域驱动设计中,认为实现这个聚合模型,应当包含以下要素:

        1、通过一个顶层抽象来封装模型中的引用。使用Aggregate对象,实现一组相关对象的集合,作为数据修改的单元。

        2、每个Aggreate对象具有一个根和边界。边界,用以定义Aggreate内部都有什么。而根是Aggregate对外暴露的特定实体。对Aggregate而言,外部对象只可以引用根,而边界内部的对象则可以相互引用。

        3、除根之外的所有实体,在Aggregate内部都有唯一标识,但外部对象只能看到根实体而无法看到其他实体。

        对Aggregate的操作,应该按照一定的规则,确保数据变化时,能够保持一致性。而任何跨越Aggregate的规则,则不要求每时每刻都保持最新状态,跨越通过事件处理、批处理或者其他更新机制,使依赖项在规定的时间内得到解决。但是在Aggregate内部,规则必须得到满足。

        这意味着,对于这个Aggregate的操作,必须应用更加具体的规则,包括但不限定于以下内容。

        1、聚合根Entity,具有全局标识,代表整个Aggregate对外提供服务,并最终负责检查规则。

        2、边界内的对象具有本地标识,但仅限于Aggregate内部保持唯一性。

        3Aggregate外部的对象不能引用除根Entity之外的其他内部对象。根可以将内部对象的引用传递给外部对象,但是外部对象只能使用,而不能保持引用更不能操作。这也意味着,根可以将值对象的副本传递给外部对象,因为它只是一个属性值,而不是一个完整的生命周期对象。

        4、只有Aggregate的对象才能通过数据库查询直接完成,而其他对象应该在创建后,通过根的对象遍历关联来发现。

        5Aggregate内部对象,可以引用外部的Aggregate根对象的引用(不能反过来)

        6、删除操作,应该一次性删除Aggregate边界内的所有对象。

        7、对Aggregate内部任何对象的操作,必须保证上述规则都得到满足。

总结

  Aggregate对象实际上是通过划分一个界限清晰的范围,确保在Aggregate对象的生命周期内,对范围内对象每个阶段的操作都满足规定规则。

  对Aggregate对象的定义和分析是一件非常细致的工作,我们应该根据实际应用场景,将实体和值对象分别聚集到Aggregate中,定义好边界和根后,通过根Entity来控制对边界内部其他对象的访问。只允许外部对象引用根,并在一次操作中,临时引用内部成员。但不能通过根来修改内部对象,这种设计有利于Aggregate内部的对象满足规则,也能保证它本身能够作为一个整体满足规则。而对Aggregate对象上的操作,是通过下一篇提到的Factory和Repository来实现的,它们分别在不同的阶段,实现了对象转化的复杂性封装。

站心网

领域驱动设计-聚合,一种极简的思维模式引言 作为IT技术产业飞速发展的产物,软件工程学已经成为当今时代非..

为您推荐

程序员职业发展与技能要求

程序员是从事计算机程序开发、维护和优化的专业人员。他们通过编写代码,设计软件系统,解决技术问题,推动技术创新。以下是程序员的一些关键信息:核心技能编程语言:掌握如Python、Java、C++、JavaScript等语言。..

程序员离职时删除代码注释算违法吗?

程序员离职前删除代码注释是否违法,取决于多个因素,包括雇佣合同、公司规定、法律条款以及删除行为的动机。以下是几个关键分析点:1. 合同与公司规定劳动合同或保密协议:如果合同或公司规定明确要求代码的完整性..

创造型职业程序员的无奈

编程是为数不多的一种既能满足个人爱好,又能赚钱的职业之一。烹饪是另一个这样的例子。在一般情况下,大多数职业要么不可能让你待在家里(例如医生和电工),要么你没有兴趣在家里做(例如清洁)。同样的,大多数好..

程序员副业探索之电商

目录一、小程序化妆品1.1 小程序准备(营业执照&微信支付&小程序appId)1.2 小程序开发二、拼多多电商三、跨境电商四、总结在腾讯广告工作期间,我主要负责小程序电商与广告业务,见证了互联网电商行业的剧变,特别..

谈程序员如何做好业务

前言技术能做两种事情,通过技术实现业务和通过技术支持技术。我们大部分时候做的是前者,养活我们的大部分也是业务。 近两个月,作为项目负责人角色从0到1经历了新项目的几个版本迭代,跨入了部分新领域,也有一定..

程序员增加收入的几种方法

在这个互联网飞速发展的社会,学会如何make money很重要。咱们是个俗人,赚钱才是社会生存的头等大事。这不是高山流水的世界,而是能力创造财富,对于程序员来说,更是如此。作为程序员,我们有更多挣钱的姿势,注意..

程序员跳槽到对手公司,被前老板设计陷害

这件事发生在2007年,我就职的第一家公司。今天把它整理写出来,希望它对程序员有一个警醒的作用。永远要记住,程序员的世界除了有代码,还有被套路。资深工程师的苦恼第一天到公司,是浩子带着我办理了入职手续。浩..

程序员如何提一个好问题

提出好的问题是在编写软件时的一个非常重要的技能。这么多年来我对此也算略有小成。这里有一些我用着觉得很棒的指导方针!开始我实际上是那种总是会问出愚蠢问题或“不好”问题的大信徒。我一直在问人们一些愚蠢并且..

我是李玉宝,我是个程序员!

听说今天我的名字很火,那我也来凑个热闹。在2015年的时候,我做过一次人生总结,当时写了:为了理想,我放弃了一切! 转眼到了2019年,说说最近一年多的一些事情吧!做的好的!坚持把权限管理框架OpenAuth.Net做了..

程序员失业日记1:工作五年,交接半天

最近发现越来越多的小伙伴被公司裁员,有的是因为公司业绩不景气被裁员,有的是因为压力太大离职。很多公司都在裁人、减员。找工作也比之前难。刚好去年我也被上家裁员了,正好做一个系列的日志,希望能帮到在找工作..

改善程序员生活质量的 3+10 习惯

一封离职邮件2017年的一天,代码伴随着手指极具节奏感地输出在IDE上,突然某Chrome插件弹出一封邮件提示:“今天是我在ThoughtWorks的最后一天”。遇到这种离职邮件,我都会点进去,一来看看是否是自己曾经共事的小..

倾听程序员的心声真的很重要

说到开发产品,没有人比程序员更了解产品。程序员知道产品的优点、缺陷、用途和潜在用途。说起这些,程序员了如指掌,如数家珍。在这个似乎无所不在的数字时代,倾听程序员必须要说的内容非常重要,而且也许比以往任..

助力程序员成功的几个好习惯

老实说,如果你google搜索“程序员的好习惯”这方面的内容,那么就会有很多大同小异的文章映入你的眼帘。但是今天我想从一个略有不同的角度来探讨这个主题。不是关于如何更擅长编程,而是如何使程序员更有市场竞争力..

倔强的程序员

对于程序员来说,大多数人公司都有技术和管理两条发展路线,通常在同一家公司,管理路线的发展可能性,要相对广阔一些;但是技术路线也有技术路线的好处,比如相对而言更依赖于硬实力,因而工作机会丰富。我相信有不..

程序员如何在当今就业市场中让自己脱颖而出

俗话说,钱不是万能的,但没有钱是万万不能的。可见钱对于生活的重要性。不管你从事什么职业,实现财务自由才能让你无所畏惧地应对挑战。但是还有一点是值得开发人员所关注的:如何脱颖而出与众不同。毫无疑问,软件..

领域驱动设计,让程序员心中有码(七)

-设计原则和设计模式,互联网开发者们共同的追求 前言多年来,笔者一直从事传统软件企业的软件开发和项目管理工作。笔者发现在众多的传统软件企业中,评判优秀开发者的标准往往是技能的熟练程度,基本上都是以梭代码..

如何成为一名成功的程序员

编程是一个仅靠兴趣仍不足以抵达成功彼岸的领域。你必须充满激情,并且持之以恒地不断汲取更多有关编程的知识。只是对编程感兴趣还不足以功成名就——众所周知,我们工作起来像疯子。编程是一个没有极限的职业,所以..

写作路上的这些小成绩,铸就了一个不平庸的程序员

01 好的写作平台可以加速我们的成长“路漫漫其修远兮,吾将上下而求索”,在写作这条漫漫长路上,我已经求索了将近5年的时间;在这5年时间里,有过兴奋,有过迷茫,但幸好,我未曾放弃。2014年的4月初,我在ITeye(..

程序员如何讲清楚技术方案

最近在评审技术方案,和代码review的时候,遇到刚入行的同学们,很多都讲不清楚技术方案。具体表现是:上来不说需求,直接说算法实现。台下一头雾水,根本不知道设计方案是否合理。描述完需求后,又直接看代码,看表..

排除万难,我终于入了程序员的坑

“恭喜你,成功的避过了所有的正确答案,选择了错误答案”。没错,我是一个数学专业的普通大学生,排除万难,我终于还是入了程序员的坑。1. 生活爆锤了我一顿我是一个平凡的人,人生也一直都是平淡且稀里糊涂的!像..

发表回复

返回顶部