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

1、易于腐化的软件设计

犹记得刚刚参加工做时,是地图厂商四维图新集团旗下的一家子公司,主要从事规划测绘相关软件研发的公司。当时个人项目是为勘测设计院提供相对应的应用软件,对地理信息和规划相关的图纸信息,几乎已经专业水平。事实上,规划设计大概和软件设计相似,有规划的设计、或无规划的设计,形成的结果几乎是天壤之别。程序员

咱们或许很容易就能设想到一个毫无规划设计的城市,纵横交错的路网、杂乱无章式的建筑布局、各类凌乱的棚户区设计,刚好象征着软件设计的无序性,也刚好体现了软件企业在经费不足、组织缺少管理、开发者能力不足、软件随时随地想改就改时的行业现状,只能说这样的软件是最能符合当时实际劳动生产力水平的产品。数据库

巴西棚户区

如图一所示,巴西棚户区,层层叠叠、风格迥异、密密麻麻,若是做为一个外人贸然来到这样的地方,大概很容易迷失期间、更不用说充斥在棚户区的各种毒品和黑社会。杂乱无章的建筑和街区,就像代码中错综复杂的调用链;而借助贫民区搞事的黑社会就像是代码中的异味或者bug,表面上看起来如此平静、与世无争、可是你永远也不知道啥时候会来一冷枪。编程

不要觉得离咱们很远,咱们其实轻易就能写出这样的软件工程项目。不必定是“大泥球”系统,也有可能只是一些看似简单的业务系统,但内部代码逻辑,可能会复杂到使人窒息的程度。也许那个时候有个别开发者也许会试图靠本身的能力来改变局面,可是每每也会碍于屎山太大,难如下咽。架构

大概只有最顶级的规划设计师、耗费足够多的资源,才能将这样的软件系统进行整改。然而,即使如此,若是之后没有持续维护的手段、更好的设计、仅靠老程序员或个别架构师、盲目相信将单体服务拆分红微服务,几乎不太可能实现软件将来的可持续发展。框架

一个良好的软件产品的一辈子、或许实际上是一家企业一辈子的真实写照。微服务

在特定组织架构下,缺少技术基因的组织有时候期待技术变革,却会开启新的泥坑。而那些渴望靠技术改变一切的技术专家,虽然拥有某些大厂微服务式架构、以及架构改造的经验,他们也试图经过本身的努力,为企业业务腾飞助力。而在他们过去的经验中,每每相信组织遇到的问题,用微服务必定能解决问题。而后大肆扩招,一年内从几我的的规模、扩招到数百人的规模,将原来的系统从单体服务、改良成为微服务。可是靠单枪匹马根本无力拯救大势,没有更好的业务拆分策略,就只能按照数据库的表名关系实现了最简单的拆分。架构改造并不是每次都会百试百灵,有时甚至连原来的需求都包不住,毕竟只能看到用户界面层外观上的表面逻辑,而隐藏在业务中的那数十万行代码,哪怕包含了企业最有价值的经验财富,也因为代码过于混乱,最终抛弃在源代码管理器中,堪称化神奇为腐朽。布局

2、易于腐化的面向过程开发

老系统改造也好、新系统开发也好,毫无疑问,咱们最容易相信的实际上是老程序员经验,而程序员们掌控系统的方式,就是靠数据库建模来驱动软件开发的古老模式,并且几乎都是面向过程式的代码,这些代码的流程几乎如出一辙,只需简单的按照步骤,一步步套模式,轻易就能学会。学习

一、查看用户界面,定义须要绑定到界面的模型和层级结构。设计

二、设计数据库,无论什么类型的项目,先根据客户提供的业务表单、将其转化成实体关系(ER图)、而后创建对应的代码模型。有可能使用专业软件设计ER图,也有可能会使用Navicat软件设计ER图。3d

三、设计接口,而后把数据拼凑成用户界面层所需的对象。

四、代码层次结构为传统的三层架构,严格按照用户界面层、业务逻辑层、数据访问层进行设计,有时候会引入依赖注入框架,实现不一样层次间的解耦。

可是有时候程序员不会严格区分须要编写的代码,到底是属于哪一个层次应该囊括的内容。因而毫无疑问,若是代码是为了实现用户界面上某些数据绑定操做,代码就往用户界面层写;或者代码是为了实现从数据库中抽取某些复杂数据、并构形成知足用户表现层逻辑的查询对象,那么就能够看到数据访问层代码中那些臃肿的SQL语句或查询方法。

正如“罗马不是一天建成的”,屎山也一样如此。这样的写法在代码刚刚编写之初并无问题,只是随着业务变化、时间的积累、程序员的水平、方法重构、新技术新组件的引入,代码将成为屎山。

这时,高级程序员们的价值,就在于他如何可以在屎山中快速找到bug、并解决问题的能力,这大概是一种不能复用、不可再生的能力,由于永远有让人看不懂的垃圾代码,并且每家企业都有本身的特色,不一样企业间每每不能循环利用。我一位朋友常常吐槽,他感受本身的价值就是守住公司那份拥有8年历史的古老代码,以便其余程序员在进行代码修改时,不会引起莫名其妙的bug让系统没法运转。

3、过程式开发和事务脚本模式

在现代软件工程学的教科书中,都会指出面向对象是解决软件复杂性的方法,但实际上掌握这种方法的开发者并很少。因为开发者广泛缺少抽象化思惟,因此面向数据库、面向过程式的编程习惯可以成为业界主流,并不是时代的倒退,而仅仅只是在短时间效率和长期维护性上,被迫作出的艰难选择。

假设咱们设计出的符合三层架构的系统结构图简化后,以下图所示:

咱们来看看这种数据库建模的开发流程中的输出成果:

一、会定义两种对象,分别是是面向UI层的模型(DTO)和数据实体(Entity)。在领域驱动设计中,将这两种称为所谓贫血模型,贫血模型,只有赋值器Set和取值器Get,(在Java里面会使用POJO 这个名词来定义)。贫血模型是为了做为保存状态或传递对象而存在,他并不是按照实际用例场景对某类具体事务的抽象、也没有与对象相关的行为。

二、定义数据访问层来实现数据的持久化、或者从持久层实现数据的建立过程。数据访问层存在的目的是为了构建上述贫血模型对象,这种访问机制被成为“事务脚本”。事务脚本与对象行为割裂,并且容易致使异味产生。

三、与用户行为相关的操做割裂的存放在不一样层。有的可能放在用户界面层、有的可能放在数据访问层、有的可能放在业务逻辑层,形成了领域知识的丢失。

四、用户界面层使用接口做为外观或者一种行为、开发者会使用本身独立的风格习惯来定义这种行为,就容易形成术语和规则不统一,也会为后期产品的维护迭代形成问题。

五、如今的软件设计,每每要求输出一份高保真的原型图、也会按照敏捷项目管理的流程对这份原型图创建持续更新的机制,确保原型图是需求的具体表达,可是产品语言并不是统一语言,也许产品语言具备业务含义,可是因为不能指导开发者进行接口、类、持久层的设计,形成了代码与需求的割裂。在张逸老师的《领域驱动战术实践》提到他曾经使用dimension和metric两种不一样的对象来定义一个维度对象,为代码形成了没必要要的麻烦。我也曾经在一个项目,遇到过产品术语未能澄清,致使开发中使用style和theme两种大相径庭的定义来定义与“风格”相关术语,为代码引入了没必要要的纠结。

4、领域驱动设计是什么?

领域驱动设计引入了如下概念,可是咱们无需在这篇文章中深入理解这些概念的具体含义,咱们只需知道,有这个东西。当咱们开始按照领域驱动设计的方法设计一个系统时,按照前人整理的领域驱动的sample,每每就会将概念融汇贯通,达到更好的理解效果。

一、统一语言:定义好产品原型,须要创建统一语言。这是一种在内部和外部都能使用的规范化用语,包括UML、适当的图、一致性的描述、以及专业术语和术语对应的英文描述。

二、实体:在领域中能够经过标识进行惟一值定位的对象。

三、值对象:在领域中,从其余领域或某个实体中分离出只包含某些特定属性的对象。因为不具有惟一性特征,每每无需用于数据持久化。

四、聚合、聚合根:将具备相关性的对象聚合在一块儿,并以聚合根的形式统一对外提供访问方法和属性字段成员。

五、限界上下文:领域包含核心领域、子域和通用子域,而限界上下文则是一个具体业务的流程。每一个限界上下文独立于其余限界上下文而存在,独立演进、功能完备。限界上下文的识别充满技术含量。

六、领域服务:包括仓储服务和工厂服务,前者负责实现对象与数据库的操做过程、封装了一系列数据库操做的方法;后者则侧重于对象的建立过程。我的认为从三层架构演进到领域驱动架构过程当中,仓储服务是最接近于数据访问层的逻辑,也是让大部分领域驱动架构最终又回归到三层架构的一种通病。从对数据访问层中抽出对象、行为、数据访问,是战术设计的关键步骤。

领域驱动设计引入了一堆新的架构形式,包括经典的四层架构、EDA(事件驱动架构)、CQRS架构(命令查询职责分离)。而因为Evans的原书没有过度讨论如何识别领域,后来又有许多大佬在他的基础上进行了完善,提出了许多方法,包括名词、形容词、动词建模法、事件风暴、四色建模等方法,限于篇幅,且听下回分解。

领域驱动的结构

5、思惟的转变,才是最大的困难

领域驱动设计,或许是解决这些问题的一剂良方,但也或许是开启了暗黑世界的大门。

概念晦涩难懂、程序员们不肯意开始思惟变革、技术上可能存在不预期的坑、均可能让新方法的实践陷入一滩烂泥。还有许多人觉得本身看懂了领域驱动设计(包括笔者),在往项目中运用时,老是有意无心的会被过程式代码的思惟定式控制,让架构回退到三层架构。

因为微服务架构的兴起,让复杂系统的开发维护成为你们广泛关心的问题,使得Eric Evans于十五年前提出的这套理论,在今天绽开出了新的光芒。固然领域驱动设计仅仅只是众多面向对象编程的一种实践,经过领域驱动设计将UML等方法灵活的运用其中,经过打破原有数据库关系建模给代码形成的桎梏,让开发者可以真正的实现面向对象编程。

然而思惟模式的转换并不是易事,从过程式代码中,抽离出与对象有关的行为,远比理解这几个概念要复杂,这须要大量经验的积累。

领域的复杂性
毋庸置疑,数据库建模驱动软件开发具备速度快、学习成本低的显著特色,在许多项目中,能在短时间内能够给开发者带来许多便利;而应用领域驱动设计,则能够在更长的维护周期内,给软件维护带来实质性好处。

两种不一样类型的开发模式,根据企业实际出发进行选择,还只是开始,但能真正运用好领域驱动设计或者UML、面向对象设计这种软件工程的美学思惟来改造咱们的系统,让系统绽开出更加璀璨的光芒,这才是软件设计的乐趣所在。

如何画马


本文版权归原做者和博客园共同拥有。做品采用知识共享署名-非商业性使用-相同方式共享4.0 国际许可协议进行许可。 本文来自: 溪源 | 长沙.NET技术社区。阅读更多精彩好文,欢迎关注长沙.NET技术社区公众号【DotNET技术圈】。 首发于溪源的我的博客www.techq.xyz

相关文章
相关标签/搜索