本文书接上回《懂了这个道理,人月神话不再是神话!》,关注公众号(老肖想当外语大佬)获取信息:

  1. 最新文章更新;

  2. DDD框架源码(.NET、Java双平台);

  3. 加群畅聊,建模分析、技术交流;

  4. 视频和直播在B站。

关注公众号一定要星标,以及时获得最新推送。

背景

关于“复杂度”我在系列开篇《关于领域驱动设计,大家都理解错了》中就有所剖析,然而在与大家交流的过程中发现,很多对于软件设计决策的分析,最底层的观点冲突来自与对“复杂度”理解的冲突,大家的结论都是构建在它上面的,因此,在这里全面地展示我对于“复杂度”的理解,以期与大家能够在更深的层次上识别共识,明晰分歧。

软件成本与复杂度

我们在设计软件系统的过程中,有一个贯穿始终的约束条件,就是“软件成本”,时间成本、人力成本等等资源,都是有限的,衡量一支团队的效率,同样也可以用“软件成本”来作为计算依据,而软件成本,我认为最核心的因素就是软件的“复杂度”,如果“复杂度”是一个有刻度的尺子,那么我认为,复杂度越高,软件成本越高。而我的软件设计决策的所有依据,都构建在这个起点。如果我们期望降低软件成本,那么就意味着,我们需要降低软件的复杂度,那么理解复杂度就是我们的必经之路。

理解复杂度

要理解复杂度,我们不得不先回答一个问题:如何判断“复杂”和“简单”?我们先来看几个例子,下面两个系统,你觉得哪个更复杂?我想大部分人一定会选“系统2”,因为显然它的元素数量更多。

如果我们的系统元素之间存在一些关系,那么下面两个系统呢?是不是感觉“系统3”更复杂?

基于上面的例子,我们更极端地设想一下,假如你有一个系统A,有100个独立的模块,这些模块之间没有相互联系,另外一个系统B,有10个模块,这些模块之间相互会有影响。我们假设这里的一个个“模块”本身复杂度相同,那么你认为系统A和系统B哪个更复杂?对我而言,我会坚定地认为系统B更复杂。

基于上面的例子,我得出了两个判断:

  1. 系统复杂度与元素的数量元素的关系有关;

  2. 元素的关系对系统复杂度的影响远远大于元素的数量所产生的影响;

基于上述的观点,我们就可以根据元素数量元素关系这两个要素来衡量“复杂度”,也就是说我们可以有一个判断复杂度的标尺,这个标尺有两个重要参数:元素数量元素关系

我们知道,不可衡量则不可改进,而有了这个标尺,也意味着我们可以做衡量,可以对决策方案的优劣取舍做判断,这就是我们能够持续改进的起点。

尊重复杂度

经典的复杂度守恒定律表示,“复杂度不可被消除,只可被转移”,我深以为然,回到软件设计领域,我们的复杂度具体在哪里呢?我认为我们的软件系统复杂度的根源,来自于需求本身的复杂度,它决定了最终解决方案复杂度。

既然复杂度无法被消除,那我们是不是可以推导得出,解决方案的复杂度,最小等于需求的复杂度?那么我们在设计方案的过程中,要做的,就是尽可能避免引入额外的复杂度。这个过程,系统元素数量元素关系成为我们关注的要点,而且元素关系是其中的重中之重。

在我们分析需求,给出解决方案的过程中,复杂度由两方面组成,一个是业务逻辑本身的复杂度,一个是引入的技术复杂度,其中业务逻辑是来自需求,不能打折扣,因此这部分的复杂度是无法被消除的,这也就是为什么我所说的“尊重复杂度”,尊重业务固有复杂度,不要尝试消除它,我们能做的,仅仅是将它的复杂度尽可能封闭在一个个“收纳箱”里,这些收纳箱,就是我们常说的“领域”。

而对于“技术复杂度”,我们要做的就是避免过度设计,避免引入额外的复杂技术,避免牛刀杀鸡,尽可能采取与需求匹配的技术解决方案。

如果你了解“熵”的概念,也许会发现,我们在讨论复杂度逻辑,与“熵增定律”不谋而合,而软件系统的复杂度也是随着我们一步步迭代走向更加复杂和混乱的,我们能做的就是尽可能维持复杂度的增速尽可能地低,使得系统复杂度尽可能在我们所能掌控的范围内。

因此,尊重复杂度,也是对自然规律的尊重。

掌控复杂度

那么,在我们设计和实现软件系统的过程中,该怎么做呢?既然我们知道复杂度与元素数量和元素关系有关,而元素关系又是复杂度的核心来源,那么意味着我们设计的策略可以是:

  1. 尽可能避免引入元素关系;

  2. 实在不行,用元素数量来置换元素关系,也是划算的;

这些策略,体现在具体的软件系统建模中,具像化出来就是:

  1. 保持模型(聚合)之间的边界不被打破;

  2. 如果一个需求现有模型无法满足,就考虑创建一个新的模型,而不是把原有的多个模型耦合在一起;

要掌控关系,我们需要具体到代码层面,识别什么是关系,我认为有下面特征的代码都属于关系:

  1. 聚合类型之间的相互引用;

  2. 一个类型,同时对多个聚合类型产生操作或影响;

基于上述认知,我们就得出一些代码原则:

  1. 模型(聚合)之间不相互依赖;

  2. 如果现有模型(聚合)无法满足需求,就创建一个新的模型(聚合);

  3. 模型之间的相互影响,通过“事件”传递信息,从而实现数据最终一致;

关于具体的代码怎么写,我在《DDD建模后写代码的正确姿势(Java、dotnet双平台)》一文中有一些示例展示,也欢迎大家参与我们DDD实战项目d3shop,一起体验掌控复杂度的实践,具体参见《欢迎加入d3shop,一个DDD实战项目》。

后续

本篇是从一个平面的视角来解析复杂度,探讨的是元素之间的关系对复杂度的影响,而一个复杂的系统,并不是简单的一层,在不同的层次,进行展开,又可以看作是一个子系统,下篇我们将从纵深的视角来剖析复杂度与领域驱动设计思想的相互关联。

DDD之理解复杂度、尊重复杂度、掌控复杂度的更多相关文章

  1. 華氏溫度轉化為攝氏溫度的簡單JavaScript代碼

    今天,跟著W3School學到了"JavaScript函數",代碼都挺簡單的,在運算符調用函數的地方寫了一個小程序.原碼程序是這樣的: <!DOCTYPE html> ...

  2. 相似度度量:欧氏距离与余弦相似度(Similarity Measurement Euclidean Distance Cosine Similarity)

    在<机器学习---文本特征提取之词袋模型(Machine Learning Text Feature Extraction Bag of Words)>一文中,我们通过计算文本特征向量之间 ...

  3. 初学者浅谈我对领域驱动设计(DDD)的理解

    一.为什么要学习领域驱动设计 如果你已经设计出了优雅而万能的软件架构,如果你只是想做一名高效的编码程序员,如果你负责的软件并不复杂,那你确实不需要学习领域驱动设计. 如果用领域驱动设计带来的收获: 能 ...

  4. 面试官:谈一下你对DDD的理解?我:马什么梅?

    领域模型(domain model)是对领域内的概念类或现实世界中对象的可视化表示.领域模型也称为概念模型.领域对象模型和分析对象模型. ——<UML和模式应用> 我们在日常开发中,经常针 ...

  5. ABP 基于DDD的.NET开发框架 学习(四)时间控件采用datetimepicker注意事项

    $('#datetimepicker1').datetimepicker({ format: 'yyyy/mm/dd hh:ii:ss',//这是只能用小写的大写的与ABP中的字母识别起冲突 loca ...

  6. semantic versioning语义化版本号

    语义化版本号 是由github创始人 Tom Preston-Werner 发起的一个关于软件版本号的命名规范,关于这个规范详细的说明可以在 官网 查看,也可访问其 GitHub项目页面 ,官网文档: ...

  7. 语义化版本控制规范(SemVer)

    摘自: http://semver.org/lang/zh-CN/ 简介 在软件管理的领域里存在着被称作"依赖地狱"的死亡之谷,系统规模越大,加入的套件越多,你就越有可能在未来的某 ...

  8. 版本号严格遵守semver语义化标准

    地址:http://semver.org/lang/zh-CN/?spm=a219a.7629140.0.0.GUJMXE 语义化版本 2.0.0 摘要 版本格式:主版本号.次版本号.修订号,版本号递 ...

  9. RabbitMQ入门指南

    消息队列(Message Queue,以下简称MQ)常用于异步系统的数据传递.若不用MQ,我们只能[在应用层]使用轮询或接口回调等方式处理,这在效率或耦合度上是难以让人满意的.当然我们也可以在系统间保 ...

  10. 海量数据相似度计算之simhash短文本查找

    在前一篇文章 <海量数据相似度计算之simhash和海明距离> 介绍了simhash的原理,大家应该感觉到了算法的魅力.但是随着业务的增长 simhash的数据也会暴增,如果一天100w, ...

随机推荐

  1. springjdbc处理nvarchar

    当我们使用spring-jdbc来做持久化时(注意不是spring-data-jbc),有时候一些特殊字符存入数据库时会用到nvarchar.nvarchar2这种类型(比如存放化学式,如CO₂等), ...

  2. MJUCTF—WP

    1.猫娘 点开发现有两个文件, 一个加密压缩包, 一个word文档 点开word发现是兽音加密, 点开在线网站进行解密 # 得到一段文本, 先进行分割 小小年内则伏勤, 阵阵寒风刺骨寒. 是处寂寞无人 ...

  3. 【YashanDB知识库】使用select * 创建的物化视图无法进行查询重写

    问题现象 使用如下语句准备测试数据: alter system set query_rewrite_enabled=force scope=both; drop table test; create ...

  4. 物体检测序列之一:ap, map

    准确率(Precision),也叫正确预测率(positive predictive value),在模式识别.信息检索.机器学习等研究应用领域,准确率用来衡量模型预测的结果中相关或者正确的比例.而召 ...

  5. Redis 内存突增时,如何定量分析其内存使用情况

    背景 最近碰到一个 case,一个 Redis 实例的内存突增,used_memory最大时达到了 78.9G,而该实例的maxmemory配置却只有 16G,最终导致实例中的数据被大量驱逐. 以下是 ...

  6. TLB一致性维护

    TLB 是页表项的物理 cache,用于加速虚拟地址到物理地址的转换.CPU 在访问一个虚拟地址时,首先会在 TLB 中查找,如果找不到对应的表项,那么就称之为 TLB miss,此时就需要去内存里查 ...

  7. 开源项目更新|WPF/Uno Platform/WinUI 3三个版本的《英雄联盟客户端》

    ​ 哈喽大家好! 我们是中韩Microsoft MVP夫妇 Vicky&James^^很高兴能加入博客园和大家分享我们的技术! 自2008年以来,我们一直深耕于WPF技术,积累了丰富的经验.这 ...

  8. 66.有没有碰到过数组响应丢失(问的是ref和reactive的用法,什么情况下用)

    由于vue3使用proxy,对于对象和数组都不能直接整个赋值.  直接赋值丢失了响应性 只有push或者根据索引遍历赋值才可以保留reactive数组的响应性  : 可以使用 toRefs 解决这个问 ...

  9. npm install报错 Error: EACCES: permission denied

    报错内容 Unable to save binary /root/packageadmin/spring-boot-admin-2.1.6/spring-boot-admin-server-ui/no ...

  10. java工具篇-IDEA

    java的开发离不开好的开发工具,这就需要了解集成开发工具idea 背景黑白风格 设置方法File–>settings–>Appearance & Behavior–>App ...