领域驱动设计(四) - 战略设计 - 【2/2】核心域提取和模型能力设计

news2024/10/5 13:39:11

模型的复杂性必须通过重构和知识的消化才能把关键的领域、最有价值的部分(core domain)、优先级提取出来。让团队而把主要精力放在core domain上而不要为无关的细节分散注意力,这有益于:

  • 帮助团队成员掌握系统的总体设计以便更好的协调工作;
  • 找到一个具有适度规模的核心模型并把它添加到通用语言中,从而促进沟通;
  • 专注于模型中最有价值的那部分;
  • 指导外包、现成组件的使用以及任务委派;
  • 指导重构;

精炼的目的是为核心域减负把模型设计的更明显,精炼的前提是对模型理解的深入,深层次的理解通过必须通过连续的重构得到(不能纸上谈兵),然后才有可能向深层模型和柔性设计推进。

在选择重构目标时,不能哪痛治哪,要观察一下根源问题是否涉及core domain或其与core domain的关系,如果确实涉及,那么重构它。重构的过程就是把core domain更好的提取出来,完善对core的隔离,并把支持性的子领域提炼成通用子领域。下图是精炼的通用策略:

一、核心域提炼

1.1、核心域的定义

什么是核心域?技术复杂有门槛==核心域,答案显然不是。但是事实是无论前期认知如何统一,实施时都可能陷入技术复杂==核心域这个道路上来,在落地的过程中高级的开发人员往往会分配到基础技术设施(复杂而且绝对有必要把它们做好)和通用问题的解决上,领域的核心往往是由初级开发人员来完成包括DB表的设计,这种恶性循环的结果会导致真正的业务资产被忽略,反正有可能沉淀下很多与业务无关的技术组件。

上述现象的产生不是个例,解决上述问题的对策不是把系统的所有部分精细化有针对性的安排工作,而是要分出优先级,梳理出模型的真正核心并根据核心来向外扩展功能,制定一个明确的整体设计视图,让团队所有成员都要理解项目中最关键的部分。这些关键的部分就称为core domain。

提炼core domain不容易,但做出决策并不难。对core domain的选择取决于看问题的角度。core domain的提炼是一种积累的过程,落地时这部分必须要自研,必要时可以请一些专家来培训。

领域分类:

  • 核心域:唯一的、定义明确的领导模型是业务中最重要的部分,是核心竞争力的体现;在系统建议时对核心域要有资源倾向性;
  • 支撑子域:核心域的成功离不开它,但它又不是业务的核心部分,在系统建设时一般提供定制开发,架构设计时需要考虑其可替换性;
  • 通用子域:指通用功能,一般来讲市场上已经有很多成熟的产品了,在系统建设时往往倾向于采购;

1.1.1、领域前景说明domain vision statement,阐明价值主张

前景说明是一份文档,主要描述的是如何为企业带来价值。为团队提供了统一的方向,通俗来讲,就是一份阶段性的认知合同,设计者要先想明白,然后写一份core domain的简短描述以及它将会创建的价值,也就是”价值主张”。展示出领域模型是如何 实现和均衡各方利益的。这价描述要尽量精简。尽早把它写出来,等到获得新的理解后再修改它。

1.1.2、突出核心highlighted core,改善沟通指导决策过程

尽管团队成员可能大体上知道核心领域是由什么构成的,但core domain到底包含哪些元素,不同的人会有不同的理解,甚至同一个人在不同的时间也会有不同的理解。如果我们总是要不断过滤模型以便识别出关键部分,那么就会分散本应该投入到设计上的精力,而且这还需要广泛的模型知识。

因此有必要编写一份补充文档,用于描述core domain及core元素之间的主要交互过程。它可以作为一个指标器用来指示模型改变的重要程序。当模型或代码的修改影响到精炼文档时,需要与团队其他成员一起协商。当对精炼文档做出修改时,需要立即通知所有团队成员,而且要把新版本的文档分发给他们。

1.2、精炼策略

1.2.1、通用子领域generic subdomain,从定制到组件化的过渡

实际上,在软件开发过程中大部分模型都需要自研很少集成商业产品,但是模型中包含的大量一般原则和专门的细节并不是主要关注点,而只是起到支持作用。这些部分有可能很重要,但它们不是核心部分,很大可能性还会混淆core,因此是有必要把内聚的子领域识别出来,分离到单独一个单独子域中。

分离后,除低优先级在core domain之下,同时把分离出的子领域发布出去,使其成为一个专门的通用子领域,抽离核心开发人员到core domain开发上,只在有必要的时候才在支持性的子领域中投入工作。

注意通用不等于可以重用,通用子领域的设计必须严格地限定在通用概念的范围之内。专用的概念要么属于core,要么属于更专业的子领域。不应该属于通用子领域。

1.2.2、内聚机制cohesive mechanism,解决复杂计算掩盖了模型表达的问题

计算服务有时会很复杂,当对业务模型做大量计算时就有可能把模型概念掩盖。此时我们要做的并不是改变算法,而需要从模型上下手分析,把概念上的cohesive mechanism分离到一个单独的轻量级框架中,用intentetion-revealing interface来分开这个框架的功能,从而把解决方案的复杂性转移给了框架,这些被分离出来的机制承担起了支持的任务,从而留下了一个更小的,表达更清楚的core domain。

这种框架应该专注于计算,避免模型的概念。通常我们要分离core和mechanism,二者的职责应该分离,避免产生耦合,限制将来的改进,也会使模型复杂化。子领域和内聚机制都是为core domain减负,但前者是以一个描述问题的模型作为基础,后者与模型没有关系专注于计算(模型提出问题,cohesive mechanism解决问题)。有一种例外情况是计算本身就是core domain,此时算法要做严格的封装。

1.2.3、隔离核心segreated core,解决core内的耦合

模型中的元素可能有一部分属于core domain,而另一部分起支持作用。核心元素可能与一般元素紧密耦合在一起。core的概念内聚性可能不是很强,看上去也不明显,这种混乱性和耦合关系抑制了core的分离。设计人员如果无法清晰地看到最重要的关系,就会开出一个脆弱的设计。

虽然通过把generic subdomain分离出来可以从领域中清除一些干扰性的细节,使core变的更清楚,但识别和澄清所有这些子领域是很困难的,而且有些工作看起来并不值得去做,最重要的core domain仍然与剩下的那些元素纠缠在一起。

此时可以从只从代码结构上对模型进行重构,把核心概念从支持性元素(包括定义得不清楚的那些元素)中分离出来,并增强core的内聚性,同时减少它与其它代码的耦合。把所有通用元素或支持性元素提取到其他对象中并把这些对象放到其他的包中,即使这会把一些紧密耦合的元素分开;

1.2.4、抽象核心abstract core,解决子域的复杂引用

当不同的子领域之间有大量交互时,一般会有两种解决方案:1、在模型间创建很多引用;2、创建一个中间层间接地实现这些交互。但这样就会使模型变得难懂。此时可以设计一个抽象模型,使之能够表达出重要组件之间的大部分交互,把模型中最基本的概念识别出来,并分离到不同的类、抽象类和接口中。把这个完整的抽象模型放到它自己的mudule中,而专用的、详细的实现类则留在由子领域定义的module中。从而解决复杂交互的问题,在抽象时要注意:

  • 注意抽象出的通用语言可理解,并且一定要符合业务专家的心智模型;
  • 建立抽象体系模型使差异化定义在层级上,防止以实现体现差异化的情况发生;
  • 防止实现类时解决非核心问题时会产生大量的代码的问题;

二、大比例设计

在大型系统中,如果由于缺少一种全局性的原则而使团队成员无法根据元素在模型中的角色来解释这些元素,那么开发人员就会产生局限性,过多的预先规定的假设又会使项目变得束缚,而且会极大地限制应用程序中某些特定部分的开发人员/设计人员的能力。很快,开发人员就会为适应结构而不得不在应用程序的开发上妥协,要么完全推翻要么回到老路上来。

大比例结构是一种语言,可以用它从大局上讨论和理解系统,起到即能指导设计、又能指导理解的作用,大比例语言也是对精炼的一种补充。在实施时应该允许这种概念上的大比例结构随着应用程序一起演变,甚至可以变成一种完全不同的结构风格。有些设计决策和模型决策必须在掌握了详细知识之后才能确定。不要为了追求设计的完整性而勉强去使用一种结构,而应该找到能够最精简地解决所出现问题的方案后再进行决策。

2.1、设计模式

2.1.1、系统隐喻system metaphor,用类比来描述系统

软件设计往往非常抽象且难于掌握,开发人员和用户都需要一些切实可行的方式来理解系统并共享系统的一个整体视图。当概念理解起来非常困难时,一个具体的类比正好符合团队成员对系统的想像,并能够引导他们向着一个有用的方向进行思考时,就应该把这个类比用作一种大比例结构。围绕这个隐喻来组织设计,并把它吸收到ubiquitous language中。隐喻即能促进系统的交流,又能指导系统的开发。它可以增加系统不同部分之间的一致性,甚至可以跨越不同的限界上下文。

隐喻并不是一定存在的,它其实是对ubiquitous language的一种补充。

2.1.2、职责分层responsibility layer,用分层来描述系统

如果每个对象的职责都是手工分配的,将没有统一的指导原则和一致性,也无法把领域作为一个整体来处理。为了保持模型的一致性,有必要在职责分配上实施一定的结构化控制。最简单的就是分层,在实现时,层的数量要适中经验值是最好不要超过4层。

层的特征

  • 场景描述:层应该能表达出领域的基本实现和优先级;
  • 概念依赖性:较高层应该依赖较低层,而低层应该独立于较高层;
  • 伸缩性:不同的层必须具有不同的变化频率和原因;

层的分类

  • 能力层:我们能做什么;
  • 作业层:我们正在做什么有时也会和潜能层合并成一个层;
  • 决策层:应该采取什么行动或制定什么策略,类似于智能路由;
  • 策略层:为决策支持层提供了规则和目标,类似策略模式;
  • 承诺层:我们承诺了什么,一般表示协议;

2.1.3、知识级别knowledge level,开放能力,组件配置化

当需要让用户对模型的一部分有所控制,而模型又必须满足更大的一组规则时,可以利用知识级别来处理这种情况,它可以使系统具有可配置的行为。这种配置可以在启动或运行时进行修改。系统的规则不能过于灵活。这种分离出去的部分同样也需要一个模型的支撑。

如果在一个应用程序中,entity的角色和它们之间的关系在不同的情况下有很大的变化,那么复杂性会显著增加。在这种情况下,无论是一般的模型还是高度定制的模型,都无法满足用户的需求。为了兼顾各种不同的情形,对象需要引用其他的类型,或者需要具务一些在不同情况下包括不同使用方式的属性。具有相同数据和行为的类可能会大量增加,而这些类的唯一作用只是为了满足不同的组装规则。

因此,创建一组不同的对象,用它们来描述和约束基本模型的结构和行为。把这些对象分为两个级别,一个是非常具体的,另一个则提供了一些可供用户定制的规则和知识。知识级别是在同一层次上分离的,并不是分层的上下级关系。

2.1.4、可插入组件pluggable component framework

当很多应用需要进行互操作时,如果所有应用程序都基于相同的一些抽象,但它们是独立设计的,那么在多个context之间的转换会限制它们的集成。各个团队之间如果不能紧密协作,就会导致重复和分裂进而增加开发和安装的成本,交互也会难于实现。

因此,通用的作法是封装成单独的组件,插入到一个中央的hub上,这个hub支持组件所需的所有协议,并且知道如何与它们所提供的接口进行对话。从接口和交互中提炼出一个Abstract core,并创建一个框架,这个框架要允许这些接口的各种不同实现被自由替换。无论是什么应用程序,只要它严格地通过abs core的接口进行操作,就允许它使用这些组件。这种模式最大的问题是难以使用、编码限制、扩展性差。一般只有要成功集成多个专门的应用后再采用这种结构。


End,后续笔者将持续更新与战术设计相关的知识细节。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/752264.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于多场景的考虑虑热网网损的太阳能消纳能力评估研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

微信小程序使用字体图标——链接引入

目录 1.下载字体图标 1.选择需要的图标加入购物车添加到项目 2.查看项目 3.生成在线链接 4.复制生成的链接 等下放到iconfont.json中​编辑 2.引入链接 1.下载 2.生成iconfont.json文件 3. 在iconfont.json中 放入生成的链接 4.需要重新编译小程序之后在终端执行 5…

二维码识别 OCR 原理及如何应用于物流和仓储管理中

摘要 在传统的物流和仓储管理中,人工操作容易出现错误和低效率。然而,随着二维码技术的普及和二维码识别OCR接口的应用,物流和仓储管理实现了更高水平的自动化和智能化。通过扫描和解码二维码,物流和仓储管理系统可以实现货物跟踪…

yapi的部署和安装

安装Node.js环境 wget https://nodejs.org/dist/v14.15.4/node-v14.15.4-linux-x64.tar.xz 或者直接浏览器下载传输到服务器上。 https://nodejs.org/zh-cn/download/tar -xvf node-v14.15.4-linux-x64.tar.xz 太高版本不行,install会报错。16开头的。 配置环境…

使用cpolar内网穿透,将Tomcat网页发布到公共互联网

文章目录 前言1.本地Tomcat网页搭建1.1 Tomcat安装1.2 配置环境变量1.3 环境配置1.4 Tomcat运行测试1.5 Cpolar安装和注册 2.本地网页发布2.1.Cpolar云端设置2.2 Cpolar本地设置 3.公网访问测试4.结语 前言 Tomcat作为一个轻量级的服务器,不仅名字很有趣&#xff0…

前端JavaScript入门-day07

(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 深入对象 创建对象三种方式 1. 利用对象字面量创建对象 2. 利用 new Object 创建对象 3. 利用构造函数创建对…

Java阶段五Day06

Java阶段五Day06 文章目录 Java阶段五Day06问题解析阶段性架构图 Dubbo组件远程调用RPC概括DubboDubbo调用案例调用业务选择和dubbo角色环境准备dubbo远程调用原理 问题解析 阶段性架构图 这个架构图,由于nacos的功能,可以实现服务治理(服务…

精确长延时电路/数字式长延时电路设计

精确长延时电路 该电路由CD4060组成定时器的时基电路,由电路产生的定时时基脉冲,通过内部分频器分频后输出时基信号。在通过外设的分频电路分频,取得所需要的定时控制时间。 一、电路工作原理 电路原理如图13 所示。 通电后,时…

MySQL在Centos 7环境安装

说明: 1.安装与卸载中,用户全部切换成为root,一旦安装,普通用户都能使用。 2.初期练习,mysql不进行用户管理,全部使用root进行,尽快适应mysql语句,后面学了用户管理,在考…

Unity UnityWebRequest使用http与web服务器通讯

一、搭建客户端与服务器http通讯 1.在Nodejs中文官网Node.js 中文网 (nodejs.com.cn),下载并安装Nodejs 2.在项目文件夹下新建WebServer文件夹,打开CMD窗口,在WebServer文件夹路径下安装express 3.在WebServer文件夹中新建main.js文件&#…

【UE4 塔防游戏系列】03-创建第一个敌人

步骤 1. 新建一个父类为“Chararcter”类,作为所有敌人的总类,命名为“TotalEnemyCategory” 以“TotalEnemyCategory”为父类创建子蓝图类,命名为“Enemy1” 2. 新建一个动画蓝图 选择目标骨骼为“Skeleton_Crossbowman_Skel” &#xff0c…

Stable Diffusion - After Detailer 插件 脸部和手部 重绘算法与应用

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/131699857 After Detailer 是一个用于 Stable Diffusion Webui 的扩展插件,可以自动检测、遮盖和修复图片中的人脸、手部或全身&#…

Latex 合并单元格 (合并同列的两行不居中问题)

Excel转latex 即使设置了居中,在latex也会不居中 删除上面这个

音频播放器Web页面集成(基于HTML5)

音频播放器是云点播Web播放器的重要补充,主要应用于音频为主的业务场景,基于HTML5实现PC/移动端兼容,并深度融合了视频云业务,如支持加密播放等,为用户提供简单、快速、安全、稳定的播放服务。 基础功能 支持播放上传…

冒泡排序模拟实现qsort()函数

冒泡排序模拟实现qsort函数 前言1. 分析2. 解决一,如何接受不同数据3. 解决二,如何实现不同数据的比较4. 解决三,如何实现不同数据交换5. 模拟bubble_sort()函数排序整型所有代码实现6. 结构体排序实现7. 结尾 前言 要…

将字符串转为类名

使用globals函数将字符串转为类名 如下: class Data:def __init__(self):self.name kellydef hello(self):print(hello)#直接使用字符串报错 res Data().hello() #res Data.hello()res1 globals()[Data]().hello()#通过字符串获取变量数据(变为类中…

【ACM】—蓝桥杯大一暑期集训Day1

🚀欢迎来到本文🚀 🍉个人简介:陈童学哦,目前专攻C/C、Python、Java等方向,一个正在慢慢前行的普通人。 🏀系列专栏:陈童学的日记 💡其他专栏:CSTL、蓝桥杯&am…

怎样优雅地增删查改(五):按组织架构查询

文章目录 原理实现应用测试 之前我们实现了Employee,Alarm管理模块以及通用查询应用层。 Employee的集合查询业务,是通过重写CreateFilteredQueryAsync方法,来实现按组织架构查询的过滤条件。 我们将这段逻辑代码提取到通用查询应用层中&…

【前后缀GCD】ABC125 C

C - GCD on Blackboard (atcoder.jp) 题意: 思路: 这道题,多看看样例大概就出来了 由样例可知,换成的数可以是其他N-1个数的gcd,这样对答案的贡献也没有影响 所以直接去枚举换的是什么数就行 因此怎么去快速求其他…

对于 Spring MVC 了解? SpringMVC 的执行流程?SpringMVC 的核心是什么?请求的流程是怎么处理的?控制反转怎么实现的?

对于 Spring MVC 了解? 之前 Model1 和 Model2 这两个没有 Spring MVC 的时代。 Model1 时代 : 整个 Web 应用几乎全部用 JSP 页面组成,只用少量的 JavaBean 来处理数据库连接、访问等操作。 JSP 既是控制层又是表现层,存在很多问题,如①将…