简单回忆

上一篇介绍了“精粹”,咱们学习了能够用于精粹的几种形式,比方 CORE DOMAIN 形式, GENERIC SUBDOMAIN 形式, DOMAIN VISION STATEMENT 形式等等。 运用这些形式让开发者们能够把留意力集 中到核心元素上,并把其他元素表明为支撑效果 。

但假如不贯彻某个宗旨来运用一些体系级的规划元素和形式的话,联系依然或许十分紊乱。本章节我将概要介绍几种大型结构办法,然后详细评论其中一种形式—— RESPONSIBILITY LAYER(责任层),经过这个示例来探索运用大型结构的意义。

杂乱体系面对的实在问题

布景

硅谷一家小规划公司签了一份为卫星通讯体系创立模拟器的合同。作业进展得很顺利,他们正在运用MODEL-DRIVEN DESIG来进行开发。为了弄清模型中的杂乱联系,他们现已把规划分化为一些在规划上便于管理的内聚MODULE,于是现在便有了的许多MODULE

问题

跟着越来越多的MODULE被创立,现在体系开发面对着这样一些问题,开发人员要想查找某个功用,应该到哪个MODULE中去查呢?假如有了一个新类,应该把它放在哪里?这些小软件包的实践意义是什么?它们又是怎么协同作业的呢?并且以后还要创立更多的MODULE

开发人员相互之间依然能够进行很好的沟通,并且也知道每天都要做什么作业,但项目领导者却不满意这种一知半解的情况。他们需求某种组织规划的办法,以便在项目进入到更杂乱的阶段时能够了解和掌控它

处理方案1.0

开发人员提出了不同的打包方案。有一些文档给出了体系的全貌,还有一些运用建模东西绘制的类图一一新视图能够用来指引开发人员找到正确的模块。但项目领导者对这些小花招并不满意。

缺陷

1)方案1.0能够用模型把模拟器的作业流程简单地描绘出来,也能够说清楚根底设施是怎么序列化数据的,以及电信技能层怎样保证数据的完整性和路由挑选。尽管模型包含了一切细节,可是却没有一条清楚的主线。范畴的一些重要概念丢掉了。这次丢掉的不是目标模型中的一两个类,而是整个模型的结构

处理方案2.0

经过一两周的细心考虑之后,开发人员有了思路。他们打算把规划放到一个结构中。整个模拟器将被看作由一系列层组成,这些层别离对应于通讯体系的各个方面。最下面的层用来表明物理根底设施,它具有将数据位从一个节点传送到另一个节点的根本才能。它的上面是封包路由层,与数据流定向有关的问题都被集中到这一层中。其他的层则表明其他概念层次的问题。这些层一同描绘了体系的大致情况。

依照新的结构来重构代码。为了不让MODULE跨过多个层,有必要对它们重新界说。在一些情况下,还需求重构目标责任,以便明晰地让每个目标只属于一个层。另一方面,藉由运用这些新思路的实践经历,概念层自身的界说也得到了精化。层、MODULE和目标一同演化,最终,整个规划都契合了这种分层结构的大体轮廓。

简单总结:将规划放到一个结构中。对整个体系重新分层,整个模拟器将被看作由一系列层组成,这些层别离对应于通讯体系的各个方面。一同依照新的结构来重构代码。

优点:

1)分层结构描绘了体系的大体轮廓,规划变得易于了解。人们根本上知道到哪里去寻觅某个特定功用。分工不同的开发人员所做的规划决议方案
能够大体上相互坚持一致。

问题定论

1)在一个大的体系中,假如由于缺少一种全局性的准则而使人们无法依据元素在形式(这些形式被运用于整个规划)中的人物来解说这些元素,那么开发人员就会陷入“只见树木,不见森林”的境地。

2)咱们需求了解各个部分在全体中的人物,而不必去深究细节。

由此事例引出大型结构这个概念

“大型结构”是一种言语,人们能够用它来从全局上评论和了解体系。它用一组高级概念或规矩(或两者兼有)来为整个体系的规划树立一种形式。这种组织准则既能辅导规划,又能协助了解规划。别的,它还能够和谐不同人员的作业,由于它供给了同享的全体视图,让人们知道各个部分在全体中的人物。

留意事项

大型结构能够被束缚在一个BOUNDED CONTEXT中,但一般是跨多个BOUNDED CONTEXT中。当团队规划较小并且模型也不太杂乱时,只需将模型分化为合理命名的MODULE,再进行必定程度的精粹,然后在开发人员之间进行非正式和谐,以上这些就足以使模型坚持杰出的组织结构了。不要强行套用大型结构。尽管大型结构能够节省项意图开发费用,但不恰当的结构会严峻阻止开发的进展。以下内容将探讨一些能成功构建这种规划结构的形式。

形式:EVOLVING ORDER (有序演化)

现状

许多开发人员都亲身经历过由于规划结构紊乱而产生的价值。为了避免紊乱,项目经过架构从各个方面对开发进行束缚。不管架构是面向技能的,仍是面向范畴的,假如其束缚了许多前期规划决议方案,那么跟着需求的改动和了解的深化,这些架构会变得束手束脚。

为了躲避紊乱,不得不做许多束缚,可是过多束缚,或许会产生如下问题:

一个没有任何规矩的随意规划会产生一些无法了解全体意义且很难维护的体系。但架构中早期的规划假设又会使项目变得束手束脚,并且会极大地束缚运用程序中某些特定部分的开发人员/规划人员的才能。很快,开发人员就会为适应结构而不得不在运用程序的开发上委曲求全,要么便是彻底推翻架构而又回到没有和谐的开发老路上来

问题并不在于辅导规矩自身应不应该存在,而在于这些规矩的严厉性和来历。假如这些用于操控规划的规矩确实契合开发环境,那么它们不但不会阻止开发,并且还会推动开发在健康的方向上行进,并且坚持开发的一致性。

处理方案

让这种概念上的大型结构跟着运用程序一同演化,乃至能够变成一种彻底不同的结构风格。不要依此过火束缚详细的规划和模型决议方案,这些决议方案和模型决议方案有必要在把握了详细常识之后才能确认。依据实践经历和范畴常识来挑选结构,并避免选用束缚过多的结构,如此能够降低折中的难度。真正适合范畴和需求的结构能够使细节的建模和规划变得更简单,由于它快速排除了许多选项。

定论

要想创立一种既为开发人员保存必要自在度一同又能保证开发作业不会陷入紊乱的结构绝非易事。尽管人们现已在软件体系的技能架构上投入了许多作业,但有关范畴层的结构化研讨还很少见。一些办法会损坏面向目标的范式,如那些按运用使命或按用例对范畴进行分化的办法。整个范畴的研讨还很贫瘠。
当发现一种大型结构能够显着使体系变得更明晰,而又没有对模型开发施加一些不天然的束缚时,就应该选用这种结构。

以下会介绍4中较为通用的大型结构形式,能够处理现阶段大型体系开发过程中普遍存在的问题

形式:SYSTEM METAPHOR (体系隐喻)

隐喻思维在软件开发(特别是模型)中是很普遍的。但极限编程中的“隐喻”却具有别的一种意义,它用一种特殊的隐喻办法来使整个体系的开发井然有序。

体系隐喻

SYSTEM METAPHOR(体系隐喻)是一种松懈的、易于了解的大型结构,它与目标范式是和谐的。由于体系隐喻仅仅对范畴的一种类比,因而不同模型能够用近似的办法来与它相关,这使得人们能够在多个BOUNDED CONTEXT中运用体系隐喻,从而有助于和谐各个BOUNDED CONTEXT之间的作业。

效果

SYSTEM METAPHOR应该既能促进体系的交流,又能辅导体系的开发。它能够添加体系不同部分之间的一致性,乃至能够跨过不同的BOUNDED CONTEXT。

留意事项

体系隐喻试一把双刃剑,并不适用于一切项目。且一切隐喻都不是彻底精确的,因而应不断检查隐喻是否过度或不恰当,当发现它起到阻止效果时,要随时准备抛弃它,不要为了用而用。

定论

当体系的一个详细类比正好契合团队成员对体系的想象,并且能够引导他们向着一个有用的方向进行考虑时,就应该把这个类比用作一种大型结构。“防火墙”便是一个类比,实在世界的防火墙能够防止火势从其他建筑蔓延到自身,而软件“防火墙”能够保护局域网免受来自外部网络的损坏

形式:RESPONSIBILITY LAYER (依照责任分层)(章节要点)

抛出观点

假如每个目标的责任都是人为分配的,将没有统一的辅导准则和一致性,也无法把范畴作为一个全体来处理。为了坚持大模型的一致,有必要在责任分配上实施必定的结构化操控。

暗示:按责任分层,对应章节标题

什么是层?

所谓的层,便是对体系进行划分,每个层的元素都知道或能够运用在它“下面”的那些层的服务,但却不知道它“上面”的层,并且与它上面的层坚持独立。

领域驱动设计(DDD)——大型结构

尽管这种自发的分层办法尽管使盯梢依赖性变得更简单,并且有时具有必定的直观意义,但它对模型的了解并没有多大的协助,也不能辅导建模决议方案。咱们需求一种具有更明晰意图的分层办法。

怎么进行有意义的分层?

在一个具有天然层次结构的模型中,能够环绕主要责任进行概念上的分层,这样能够把分层和责任驱动的规划这两个强有力的准则结合起来运用。这些责任有必要比分配给单个目标的责任广泛得多才行。
留意调查模型中的概念依赖性,以及范畴中不同部分的改动频率和改动的原因。假如在范畴中发现了天然的层次结构,就把它们转换为广泛的笼统责任。这些责任应该描绘体系的高层意图和规划。对模型进行重构,使得每个范畴目标、AGGREGATE和MODULE的责任都明晰地坐落一个责任层傍边。

为什么要分层?

这种明晰的责任分组能够进步模块化体系的可了解性,由于MODULE的责任会变得更易于解说。而高层次的责任与分层的结合为咱们(开发人员/范畴专家)供给了一种体系的组织准则

分层形式有一种变体最适合按责任来分层,咱们把这种变体称为RELAXED LAYERED SYSTEM(松懈分层体系)[Buschmann etal.1996,p.45],假如选用这种分层形式,某一层中的组件能够拜访任何比它低的层,而不限于只能拜访直接与它相邻的下一层。

上述内容过分笼统,咱们能够经过示例来深化了解

事例

以运送体系为例,以下是运送体系模型的一部分。此刻开发团队现已提炼出一个CORE DOMAIN,他们正在寻觅一个能表现整个体系的主题并且让大家一致认同的大型结构。

领域驱动设计(DDD)——大型结构

下图展示了在预订期间怎么运用模型来拟定一个货运线路。

领域驱动设计(DDD)——大型结构

团队成员调查到了一些天然的概念层次结构,比方评论运送时间表时,不需求涉及到货品。而评论货品的盯梢时,假如不知道它的运送信息,就很难进行盯梢。这里有很明晰的概念依赖性。团队分出了两个层:作业层和支撑这些作业的根底层(也称为才能层)。

领域驱动设计(DDD)——大型结构

公司的活动都被放到作业层中,最显着的作业目标是 Cargo ,它是公司大部分日常活动的焦点。Route Specification 是 Cargo 不可或缺的一部分,它规矩了运送需求,而 Itinerary 是运送方案,这些目标都以 Cargo 为聚合根。

才能层反响了公司在执行作业时所能运用的资源。为货轮拟定航程时间表时,需求考虑货轮的货运才能,因而 Transport Leg 是一个典型的例子。

把 Customer 目标放在哪里是一个略微杂乱一点决议方案。这家运送公司需求与客户坚持长期联系,由于大部分事务来自回头客。所以 Customer 应该属于才能层。假如是快递公司,客户或许仅仅临时目标,在包裹投递完成后就被遗忘了,此刻客户仅与作业相关,能够放在作业层。

尽管作业层与才能层的区别是这张图看上去很清楚了,但次第仍需求进一步细化。经过几个星期的试验后,团队发现 Router 并不是作业(方案)的一部分,它是用来协助修正方案的,因而界说了一个新的层,用来支撑决议方案(Decision Support)。

领域驱动设计(DDD)——大型结构


决议方案支撑层能够为用户供给用于拟定方案和决议方案的东西。Router 是一个 SERVICE,能协助挑选运送货品的最佳道路,因而属于决议方案支撑层。原先在 Transport Leg 中的 is preferred 特点是由于公司希望优先运用自己的货轮,当 Router 挑选最佳道路时会用到这个特点,因而它与才能层毫无联系,所以最终被重构到了 Route Bias Policy 中。


在屡次重构之后这个模型愈加契合大型结构了。


从事例中可得知,在挑选适宜的 RESPONSIBILITY LAYER 时,可从以下几个方面考量。

1)场景描绘

层应该能够表达出范畴的根本现实或优先级。挑选一种大比例结构与其说是一种技能决议方案,不如说是一种事务建模决议方案。层应该显示出事务的优先级。

2)概念依赖性

较高层概念的意义应该依赖较低层,而底层概念应该独立于较高的层。

3)CONCEPTUAL CONTOUR(概念轮廓)

假如不同层的目标有必要具有不同的变 化频率或原因,那么层应该能够容许它们之间的改动。

以下是常见的几种分层


1)才能层

咱们能够做什么?才能层不关怀咱们打算做什么,而关怀能够做什么。也称为潜能层。

2)作业层

咱们正在做什么?咱们运用这些潜能做了什么事情?像潜能层(才能层)相同,这个层也应该反映出现实情况,而不是咱们设想的情况。咱们希望在这个层中看到自己的作业和活动:咱们正在出售什么,而不是能够出售什么。

3)决议方案支撑层

应该选用什么举动或指定什么战略?这个层是用来作出剖析和拟定决议方案的。它依据来自较低层(比方潜能层或作业层)的信息进行剖析。决议方案支撑软件能够运用历史信息来自动寻觅适用于当时和未来作业的机会。 许多项目运用数据仓库技能完成决议方案支撑层,此刻决议方案支撑层实践上变成了一个共同的BOUNDED CONTEXT,并且与作业层软件具有一种CUSTOMER/SUPPLIER联系。

4)战略层

规矩和目标是什么?战略层能够和其他层运用同一种言语来编写,但他们有时候是运用规矩引擎来完成的。所以也能够考虑放到单独的 BOUNDED CONTEXT 中。

领域驱动设计(DDD)——大型结构


在金融服务或保险业中,潜能(才能)在很大程度上是由当时的运营情况决议的。 例如金融服务、保险等行业; 一家保险公司在考虑签保单承担理赔责任时,要依据当时事务的多样性来 判别是否有才能承担它所带来的危险。潜能(才能)层有或许会被合并到作业层 中,这样就会演化出一种不同的分层结构。

这些情况下经常出现的一个层是对客户所做出的许诺。

5)许诺层

咱们许诺了什么?这个层具有战略层的性质,由于它表述了一些辅导未来运营的目标;但它也有作业层的性质,由于许诺是作为后续事务活动的一部分而出现和改动的。

上述5个层尽管对许多企业体系都适用,但并不是一切范畴的概念都包括在这5个层中。咱们需求依据实践情况决议分层,层数过多将无法有效描绘范畴。

定论

在模型构建过程中,留意调查模型中的概念依赖性,以及范畴中不同部分的改动频率和改动的原因。假如在范畴中发现了天然的层次结构,就把它们转换为广泛的笼统责任。这些责任应该描绘体系的高层意图和规划。对模型进行重构,使得每个范畴目标、AGGREGATE和MODULE的责任都明晰地坐落一个责任层傍边。这样重构后模型就会愈加契合大型结构。

形式:KNOWLEDGE LEVEL (常识层级)

KNOWLEDGE LEVEL 是一组描绘了另一组目标应该有哪些行为的现象。它并不像其他剖析形式那样对范畴进行建模,而是用来结构模型的。

章节开头,大图阐明什么是KNOWLEDGE LEVEL

领域驱动设计(DDD)——大型结构

场景描绘


当咱们需求让用户对模型的一部分有所操控,而模型又有必要满意更 大的一组规矩时,能够运用KNOWLEDGE LEVEL(常识等级)来处理 这种情况。它能够使软件具有可配置的行为,其中实体中的人物和联系 有必要在装置时(乃至在运行时)进行修正。

当对体系进行修正或替换时,开发人员会发现,有一些功用的实在意义并不想他们看上去的那样。它们在不同情况下具有彻底不同的意义。假如不损坏这些相互叠加的意义,修正任何东西都是十分困难的。想要把数据迁移到一个“更适宜”的体系中,有必要要了解这些奇怪的部分,并对其进行编码。

看不懂/(ㄒoㄒ)/~~,经过事例深化了解

事例

以职工工资和退休金管理体系为例,职工分为小时工和受薪职工,小时工的退休金方案为固定代扣制(Defined Contribution),而受薪职工为固定获益制(Defined Benefit)。

领域驱动设计(DDD)——大型结构

领域驱动设计(DDD)——大型结构

领域驱动设计(DDD)——大型结构

在这个模型中,每个职工随意加入哪一种退休方案都能够,因而每位办公室行政人员都能够改动退休方案。管理层最终抛弃了这个模型,由于它没有反映出公司的战略。

办公室行政人员按小时付薪酬,且选用固定获益退休方案。这个战略暗示出job title(作业头衔)字段现在表明了一个重要的范畴概念。开发人员能够重构模型,用Employee Type(职工类型)把这个概念明晰显示出来,如图16-19和图16-20所示。

领域驱动设计(DDD)——大型结构

领域驱动设计(DDD)——大型结构

只需超级管理员才能修正 Employee Type 目标,并且只需公司战略改动时,他才能修正此目标。这些受束缚的目标让开发人员想到了 KNOWLEDGE LEVEL 形式,他尝试依照这种思想,重新组织了一下模型:

领域驱动设计(DDD)——大型结构

受束缚的目标都在 KNOWLEDGE LEVEL 中,能够自在修正的目标都在 Operational Level 中,区分得十分清楚。由于模型变得更明晰了,开发人员发现 Employee Type 能够被指定为 Retirement Plan 中的任何一种, 也能够被指定为两种工资类型中的任何一种。这里实践上隐含了一个 Payroll 的概念,它和 Employee Type 混在了一同。于是开发人员重构了模型:

领域驱动设计(DDD)——大型结构

经过事例得出定论

假如在一个运用程序中,ENTITY的人物和它们之间的联系在不同的情况下有很大改动,那么杂乱性会明显添加。这种情况下,不管是一般的模型仍是高度定制的模型,都无法满意用户的需求。为了统筹各种不同的景象,目标需求引用其他的类型,或者需求具备一些特点,用于在不同情况下选用不同运用办法。相当于在咱们模型中嵌入了另一个模型,效果是用来描绘咱们的模型。KNOWLEDGE LEVEL分离了模型的自我界说的功用,并明晰地表达了它的束缚。

KNOWLEDGE LEVEL 形式下,需求创立一组不同的目标,用他们来描绘和束缚根本模型的结构和行为。把这些目标分为两个“等级”,一个是十分详细的等级,另一个等级则供给了一些可供用户或者超级用户定制的规矩和常识。

相似和区别

KNOWLEDGE LEVEL 是 REFLECTION(反射)形式在范畴层中的一种运用。Java中有一些根本的反射机制,用于查询一个类的办法和特点等信息。

KNOWLEDGE LEVEL 看上去像是 RESPONSIBILITY LAYER 的一个特例,但现实并非如此。KNOWLEDGE LEVEL 中两个等级之间的依赖性是双向的,而在层次结构中,依赖是单向的。

KNOWLEDGE LEVEL具有两个很有用的特性。

1)首要,它重视的是运用范畴,这一点与人们所熟悉的REFLECTION形式的运用正好相反。

2)其次,它并不追求彻底的通用性。KNOWLEDGE LEVEL显得更简单,并且能够传达规划者的特别意图。

创立一组不同的目标,用它们来描绘和束缚根本模型的结构和行为。把这些目标分为两个“等级”,一个是十分详细的等级,另一个等级则供给了一些可供用户或超级用户定制的规矩和常识

形式:PLUGGABLE COMPONENT FRAMEWORK (可刺进式组件结构)

布景

当许多运用程序需求进行互操作时,假如一切运用程序都根据相同的一些笼统,但它们是独立规划的,那么在多个BOUNDEDCONTEXT之间的转换会束缚它们的集成。各个团队之间假如不能紧密地协作,就无法形成一个SHARED KERNEL。重复和割裂将会添加开发和装置的成本,并且互操作会变得很难完成。

处理方案

将它们的规划分化为组件,每个组件负责供给某些 类别的功用。一般一切组件都刺进到一个中央hub上,这个hub支撑组件 所需的一切协议,并且知道怎么与它们所供给的接口进行对话。还有其 他一些将组件连在一同的可行形式。对这些接口以及用于衔接它们的 hub的规划有必要要和谐,而组件内部的规划则能够更独立一些。

可刺进式组件结构的白话文解说

运用场景和要求

从接口和交互中提炼出一个 ABSTRACT CORE,并创立一个结构,这个结构需求允许这些接口的各种不同完成被自在替换。通用,不管是什么运用程序,只需它严厉的经过 ABSTRACT CORE 的接口进行操作,那么就能够允许它运用这些组件。

缺陷

1) 一个缺 点是它是一种十分难以运用的形式。它需求高精度的接口规划和一个非 常深化的模型,以便把一些必要的行为捕获到ABSTRACT CORE中。

2) 它只为运用程序供给了有限的挑选。假如一个运用程 序需求对CORE DOMAIN运用一种十分不同的方 法,那么可刺进式组 件结构将起到阻止效果。

结构应该有一种什么样的束缚

从十分宽松的SYSTEM METAPHOR到严厉的PLUGGABLE COMPONENT FRAMEWORK。当然,还有许多其他结构,并且,乃至在一个通用的结构形式中,在拟定规矩上也能够挑选多种不同的严厉程度。

咱们能够为每种不同的情况规划不同的事情机制,也能够让特殊层 中的目标在交互时恪守一种一致的形式。结构越严厉,一致性就越高, 规划也越简单了解。假如结构恰当的话,规矩将推动开发人员得出好的规划。不同的部分之间会更和谐。

另一方面,束缚也会束缚开发人员所需的灵活性。在异构体系中, 特别是当体系运用了不同的完成技能时,或许无法跨过不同的 BOUNDED CONTEXT来运用十分特殊的通讯路径。

因而必定要抑制,不要乱用结构和呆板地完成大比例结构。大比例 结构的最重要的奉献在于它具有概念上的一致性,并协助咱们更深化地 了解范畴。每条结构规矩都应该使开发变得更简单完成。

经过重构得到更适宜的结构

操控成本的一个要害是坚持一种简单、轻量级的结构。不要试图使结构八面玲珑。只需处理最主要的问题即可,其他问题能够留到后面一个一个地处理。开始最好挑选一种松懈的结构,如SYSTEM METAPHOR或几个RESPONSIBILITY LAYER。不管怎样,一种最小化的松懈结构能够起到轻量级的辅导效果,它有助于避免紊乱。

整个团队在新的开发和重构中有必要恪守结构。要做到这一点,整个团队有必要了解这种结构。有必要把术语和联系纳入到UBIQUITOUS LANGUAGE中。

对模型施加的另一项要害作业是继续精粹。这能够从各个方面减小修正结构的难度。

总结

本章,要点论述了大型结构体系中或许存在的一些实在问题,并别离给出了几个辅导准则进行加以改进。

形式:EVOLVING ORDER (有序演化):大型体系中的一些杂乱规矩和束缚,在初期不要束缚的太严厉,由于跟着需求的不断改动,这些严厉的规矩和束缚往往会束缚住开发人员的手脚,在初期能够略微宽松点,对规矩和束缚逐渐演进。

形式:SYSTEM METAPHOR (体系隐喻):有利于了解大型体系中的一些构件,需求把隐喻加到通用范畴言语内。

形式:RESPONSIBILITY LAYER (依照责任分层):对于杂乱体系,需求能经过责任划分出不同的层。分层的艺术能够要点看下示例。

形式:KNOWLEDGE LEVEL (常识等级):用来描绘另一组目标该有哪些行为,主要效果用来结构目标。结构的艺术需求要点消化下文中的示例

以下是各种大型结构和模型的联系、

领域驱动设计(DDD)——大型结构