- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
本文书接上回《反DDD模式之“复用”》,关注公众号(老肖想当外语大佬)获取信息:
最新文章更新; 。
DDD框架源码(.NET、Java双平台); 。
加群畅聊,建模分析、技术实现交流; 。
视频和直播在B站.
最近直播的时候,看到一条留言,问我是否有关于如何划分领域的文章,翻看了一下,发现关于这么重要的问题,居然没有专门、认真、细致地讲过。也难怪不少人说不接地气,整天搞些虚头巴脑的东西。但没有讲的原因,我还是要为自己辩解几句的,不是不想讲,也不是不能讲,而是我潜意识里觉得本质的东西讲明白了,这个问题就太简单,没必要讲.
当然,如果你是我的老粉丝,关注过我过往输出的内容,那么你也知道,早前也是有在我们FireUG社区的DDD公开课里专门讲这个话题(【DDD 领域驱动设计 | PART V:如何识别领域边界?】 https://b23.tv/sRqAC8O ).
时至今日,我自己对于软件工程的认知又经过了一轮迭代,重新来解读一下这个问题.
问:如何划分领域?
答:基于如下两条可以得出一个领域:
当你有一个需求,叫创建xxx时,那么这个xxx就是一个聚合根; 。
我们可以视作一个聚合根就是一个领域; 。
例如,一个系统中,需要创建一个用户,那么用户就是聚合根,用户就是一个领域,诸如此类的需求是非常容易识别的,我相信不论你的软件设计经验如何,都是可以基于这个规则来做出判断的.
当然你会说,我有一个需求是给用户创建收货地址,那么这个收货地址是不是聚合根呢?这就要看,你创建的是“收货地址”,还是“用户的收货地址”,如果你认为是“收货地址”,那么它就应该是聚合根,如果你认为是“用户的收货地址”,意味着这个需求,仅仅是给“用户的收货地址属性”添加新值.
又比如订单,你是认为是“创建订单”还是“用户的订单”呢?我想大部分人会直觉上选择“创建订单”,为什么会有这样的直觉?我想,你一定会得出一个答案,“订单”足够复杂.
那么这样看来,理解业务的标准是不是又变成了“复杂的就分开”这么一个不太好衡量的判断呢?不妨你把它反过来看,就有答案了,那就是“简单的就合并”.
还是前面的例子,还是收货地址,因为存在一个需求叫“创建收货地址”或者“创建用户的收货地址”,我分不清楚,没关系,我们就默认视作存在这个聚合根,存在“收货地址”这个领域。然后我们在考虑,这个领域独立存在对我们有没有好处,这个领域合并进“用户”领域,我们是否可以接受。如果我们有充分的把握说合并没有问题,那么就合并,否则,就让它成为一个领域,并保持边界明确.
也许,你会有疑问,为什么基于“创建xxx”需求来判断聚合根?核心逻辑就是这类需求,意味着xxx不可分割的整体,意味xxx就是最小的完整范围,相当于我们基于这类需求,识别出了系统内的“原子单元”,就像一片片乐高积木一样,不可再拆分.
在我看来,这样划分领域的方法的本质,就是我们先认为边界就在那里,凡是有创建xxx的需求,即存在一个领域,只是说我们经过思考,某些领域合并进去是比较确定复杂度是可以掌控的,那么我们才做出了合并领域的决定.
所以,与其说这是如何划分领域,不如说,这是思考什么时候合并领域.
如果你是跟随本系列文章一路阅读过来的话,一定知道,我对于软件设计的核心观点是:
DDD是一种价值观 。
保持边界明确是最重要的事 。
那么你就会发现,前面说的方法,是完全契合这个价值观的,我们首先明确出组成系统的一个个“原子单元”,识别出它们,然后再谨慎地进行合并,在没有把握的情况下,优先保持领域边界明确,避免它们之间的耦合.
而信奉这个价值观的依据则是我们对于复杂度的理解,这在前文也有详细讲解:
系统复杂度与元素的数量和元素的关系有关; 。
元素的关系对系统复杂度的影响远远大于元素的数量所产生的影响; 。
说到底,核心目的仍然是为了保持我们对系统复杂度的掌控,因此我们谨慎地为系统内的领域之间“建立耦合”.
那么,如果你和我一样,认同DDD是价值观,保持边界是最重要的事,我们完整的操作方法就是:
当你有一个需求,叫创建xxx时,那么这个xxx就是一个聚合根; 。
我们可以视作一个聚合根就是一个领域; 。
当我们非常大把握可以掌控一个领域合并后的复杂度时,可以考虑合并这两个领域; 。
以上就是我们团队日常分析需求、设计方案和建模的实际操作方法,如果你赞同或者有共鸣,也很期望您将文章分享给更多的朋友。如果你持有不同的观点和视角,也欢迎与我讨论,我相信,至少持续提升开发者幸福感这个方向,咱们是有共识的.
最后此篇关于解决DDD最大难题-如何划分领域的文章就讲到这里了,如果你想了解更多关于解决DDD最大难题-如何划分领域的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我想将 JavaScript 函数移动到 来自输入标签的标签,但它不起作用。 这个有效: 这不是: function FieldOnKeyUp() { this.value=this.
我遇到了这个问题:说给定两个权重1和3,您可以权衡1,2(乘以3-1),3,4(乘以3 + 1)(使用平衡的两面)。现在找到最小的砝码数量,以便可以测量1到1000。 答案是1,3,9,27 ...
这是代码 war 的套路,我似乎无法弄明白。我以前从未使用过 JavaScript。 我知道答案可能很简单,但即使经过许多小时的搜索,我似乎也无法弄清楚他们在寻找什么。我知道 greet 函数中的 n
在完成一项学校作业时,我有一个抽象类 Person、一个扩展 Person 的抽象类 Student 和一个扩展学生的普通类 CollegeStudent。 CollegeStudent 从文件中读取
下面的代码让我很头疼 var somearr = [1, 2, 3]; function operations() { for (var i
我在 3 个文件中有以下代码: Defines.h #ifndef Defines_h extern const unsigned int SIZE; #endif Defines.cpp #incl
我的任务是尝试创建一个从文本文档中删除个人信息的自动化系统。 电子邮件、电话号码相对容易删除。名字不是。这个问题很难,因为文档中有需要保留的名称(例如,引用资料、名人、人物等)。需要从内容中删除作者姓
我卡在这里了... #include #define DBG_LVL(lvl, stmt) \ do{ \ if(lvl>1) printf stmt; \ }while(0) #defi
我正在尝试使用动态编程解决类似桥梁和 torch 的问题。有关此问题的更多信息,请参见维基百科 (http://en.wikipedia.org/wiki/Bridge_and_torch_probl
我有数组 A[0...N]的 double和数组 B[0...N]的 int .每B[i]变化在 [0...P] .我只需要计算数组 C[0...P] : C[j] = SUM( A[i] : B[i
我目前在使用 jQuery 中的scrollTop() 函数时遇到困难。目前,平滑滚动功能正在滚动经过预期部分,然后在功能完成运行后弹回该部分。我在本文末尾添加了一个 jsFiddle,但这是我目前的
PHP代码 $t = strtotime( '2012-09-21T03:00:00+00:00 America/Chicago' ); $t2 = date('c',$t); echo $t2;
我知道使用 .运算符将函数链接在一起,如下所示: isLessThanZero x | x a -> a -> a 还可以看到: subtract :: Num a => a -> (a ->
PHP代码 $t = strtotime( '2012-09-21T03:00:00+00:00 America/Chicago' ); $t2 = date('c',$t); echo $t2;
我创建了两个 jar 文件 my.common.jar,其中包含辅助类和方法(主要是静态方法)。我还创建了一个 jar 文件 test.jar,其中包含一个 main 方法,该方法调用 my.comm
已解决:@Desolator 已让我的代码在下面的评论中完全正常工作 好的,所以我创建了 3 个类,它们都相互链接: 启动画面 > 项目分配 > CompareSignature 我想谈论的类是闪屏类
我正在尝试使用 firestore 的 .where() 功能来检测某个字符串是否在数据库的数组中。我曾尝试通过添加方括号和其他东西来表示数组的一部分来操纵函数的第一个参数,但无济于事。 //in t
我有一个 PHP 系统,允许用户以 1 - 5 的范围对照片进行投票,我想要做的是突出显示两个人给彼此相同的投票/分数的地方。我目前无法弄清楚我的 PHP 函数的 SQL。 数据库看起来像这样 id,
我在使用 SQLAlchemy 处理 Unicode 时遇到了一个奇怪的问题。简而言之,当我将 Python unicode 字符串插入 Unicode 列时我的 MySQL 数据库,我可以毫不费力地
我正在尝试使用 Selenium 自动执行 Google 翻译网络界面(但无需了解 Selenium 即可理解此问题,只需要知道它会找到元素并单击它们即可)。我一直在选择要翻译的语言。 我无法打开下拉
我是一名优秀的程序员,十分优秀!