软件的复杂度分析——领域驱动设计总结系列

软件的复杂度分析——领域驱动设计总结系列

​ 选择领域驱动设计,就是要与软件系统的复杂作一番殊死拼搏,降低软件的复杂度。Eric Evans 的经典著作《Domain-Driven Design - Tackling Complexity in the Heart of Software》(领域驱动设计:软件核心复杂性应对之道)的副标题就是软件核心复杂性应对之道,甚至Eric Evans 认为“领域驱动设计只有应用在大型项目中才能产生最大的收益”。

一、什么是复杂?

​ 复杂并没有一个标准的定义,《复杂》一书的作者架构专访时曾经给过一个定义:

由大量相互作用的部分组成的系统,与整个系统比起来,这些组成部分相对简单,没有中央控制,组成部分之间也没有全局性的通讯,并且组成部分的相互作用导致了复杂行为。

​ 对于软件系统来说,组成部分就是设计单元, 不同的粒度可以是函数,对象,模块,组件和服务。这些单元相对简单,但彼此之间的互相作用就导致了软件系统的复杂行为。

​ 《管理3.0:培养和提升敏捷领导力》 作者Jurgen Appelo对复杂系统理论做出了这样的阐释:

将Complicated与Complex分别放在理解力与预测能力两个迥然不同的维度。Complicated与Simple(简单)相对,意指非常难以理解,而Complex则介于Ordered(有序的)与Chaotic(混沌的)之间,认为在某种程度上可以预测,但会有很多出乎意料的事情发生。如下图所示:

系统的规模和结构会干扰我们对系统的理解,需求的变化无法预测。理解软件复杂度的成因,就应该结合理解力预测能力这两个因素来思考。

理解力

影响理解力的第一要素——规模

软件的需求决定了系统的规模,当需求呈线性增长趋势时,为实现功能,软件规模也会以近似的速度增长。同时 需求不可能做到完全独立, 互相影响互相依赖关系的出现,导致修改功能时牵一发而动全身,形成一种辐射效应的拥堵。

  • 函数存在副作用,调用时可能对函数的结果作了隐含的假设;
  • 类的职责繁多,不敢轻易修改,因为不知这种变化会影响到哪些模块;
  • 热点代码被频繁变更,职责被包裹了一层又一层,没有清晰的边界;
  • 在系统某个角落,隐藏着伺机而动的 bug,当诱发条件具备时,则会让整条调用链瘫痪;
  • 不同的业务场景包含了不同的例外场景,每种例外场景的处理方式都各不相同;
  • 同步处理与异步处理代码纠缠在一起,不可预知程序执行的顺序

“奶牛规则”:奶牛逐渐衰老,最终无奶可挤;然而与此同时,饲养成本却在上升。

决定系统复杂度的关键因——结构

迷宫,相似而回旋繁复的结构使得本来封闭狭小的空间被魔法般地扩展为一个无限的空间,如果没有找到正确的路径,则陷入其中无休无止,永远无法退出。规模小但复杂的软件,就如同一座迷宫。

结构之所以变得复杂,在多数情况下还是因为系统的质量属性决定的。满足高性能、高并发的需求,就需要考虑在系统中引入缓存、并行处理、CDN、异步消息以及支持分区的可伸缩结构

纵观软件设计的历史,不是分久必合、合久必分,而是不断拆分、继续拆分、持续拆分的微型化过程。

不论设计是否优雅,都可能因一些设计权衡而导致系统结构变得复杂,唯一的区别在于,优雅的设计时主动地控制结构的复杂,而拙劣的设计带来的复杂是偶发的,是会随着系统规模增大而导致的一种无序设计

分解的软件元素不可能单兵作战,怎么协同、怎么通信,就成为了系统分解后面临的主要问题。

微服务“分而治之”的核心思想从系统规模着手,将一个大系统拆分为一个个细粒度的服务来应对系统的复杂度。但即使不考虑拆分的合理性,我们也可以看到,它虽然控制了规模带来的复杂度,但却加强了结构的复杂性。复杂并没有消失,而是

《架构之美》 第二章 “混乱的大都市” 列出了无序设计的警告信号:

  • 代码没有显而易见的进入系统中的路径;
  • 不存在一致性、不存在风格、也没有统一的概念能够将不同的部分组织在一起;
  • 系统中的控制流让人觉得不舒服,无法预测;
  • 系统中有太多的“坏味道”,整个代码库散发着腐烂的气味儿,是在大热天里散发着刺激气体的一个垃圾堆;
  • 数据很少放在使用它的地方,经常引入额外的巴罗克式缓存层,目的是试图让数据停留在更方便的地方。

出自《架构之美》第二章

巴罗克式缓存层:

​ 巴罗克一词的原意是“扭曲的珍珠”,古典主义者用它来称呼这种被认为是离经叛道的建筑风格。

​ 巴罗克式缓存层所要表达的是软件设计中,引入了不符合常规思维方式的或者怪异且让人难以理解的缓存层

看一个无序设计的软件系统,好像隔着半透明的玻璃观察事物,系统中的软件元素模糊不清,技术债充斥其中。细节上,代码污浊,违背高内聚,低耦合原则,代码错位或重复;架构层面,边界不清,通信依赖纠缠,同一问题域解决方案花样百出。

预测能力

当我们掌握了事物发展的客观规律时,我们就具有了一定的对未来的预测能力。

变化之殇——不可预测的未来

由于不可预测带来的复杂度,令人惶恐不安,我们不知道何时会发生变化,变化走向哪里。

设计系统时,如果拒绝对变化做出理智预测,设计将变得僵化,变化发生时,修改的成本会很大;但如果过于看中变化产生的影响,渴望涵盖一切变化的可能,一旦预期的变化不曾发生,我们为变化付出的成本将无法补偿,这就是过度设计

变化之难,在于平衡~

本文如与张逸《领域驱动设计实践》专栏内容有所雷同,纯属我抄他的!

参考资料:https://www.cnblogs.com/wayfarer/p/2017-ddd-submit-china.html

https://gitbook.cn/gitchat/column/5cdab7fb34b6ed1398fd8de7?utm_source=zyhd001