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

  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. macOS 查看网络接口信息

    networksetup -listallhardwareports 执行结果: Hardware Port: Ethernet Adapter (en4) Device: en4 Ethernet ...

  2. maven 网关应用:[NACOS ConnectException httpPost] currentServerAddr: http://localhost:8848,

    网关应用运行忽然报错:[NACOS ConnectException httpPost] currentServerAddr: http://localhost:8848, 虽然调整了代码逻辑,但是n ...

  3. 合合信息通过ISO/IEC国际标准双认证,为全球用户提供高合规标准AI服务

    互联网.AI等技术的全球普及为人们提供便捷服务的同时,也带来了信息安全领域的诸多挑战.保护用户隐私及数据安全,是科技企业规范.健康发展的重心.近期,上海合合信息科技股份有限公司(简称"合合信 ...

  4. CSS & JS Effect – Show More

    效果 show more 是很常被使用的效果, 因为空间总是不够的丫. 比起 scroll, show more 的体验通常会好一些, 尤其在手机, 它有更好的引导. 实现思路   1. 卡片需要一个 ...

  5. 全网最适合入门的面向对象编程教程:49 Python函数方法与接口-函数与方法的区别和lamda匿名函数

    全网最适合入门的面向对象编程教程:49 Python 函数方法与接口-函数与方法的区别和 lamda 匿名函数 摘要: 在 Python 中,函数和方法都是代码的基本单元,用于封装和执行特定的任务:它 ...

  6. Windows系统无法打开‘’网络发现‘’功能

    Windows10无法开启网络发现 解决办法: 1. services.msc 2. 开启 SSDP Discovery ,设置 启动类型为 自动 ,服务状态为 启动 Windows7 无法开启网络发 ...

  7. C4996 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS.

    错误原因 VS平台认为scanf函数不安全,要求换成scanf_s函数 解决方案 方案一:将scanf换成scanf_s[不建议] 将scanf换成scanf_s 但是,scanf_s函数只能在vs上 ...

  8. Thinkphp原生验证码的使用

    Thinkphp原生验证码的使用 一. 获取验证码 public function verifyCode(){ $captcha = new \think\captcha\Captcha(); $ca ...

  9. 2021年11月数据库排行解读:openGauss跃居第三,人大金仓晋身前十

    2021年11月墨天轮国产数据库流行度排行榜出炉,本月前三的数据库产品分别是:TiDB.达梦.openGauss,openGauss 数据库是首次跻身前三强. TiDB 自2020年以来,持续稳居榜首 ...

  10. HRM平台的登录页的背景图片- scss

    .login-container {   // 设置背景图片   background-image: url("~@/assets/common/login.jpg");   ba ...