Complexity

什么是软件设计的复杂度

软件技术发展的使命之一就是控制复杂度(Complexity)。从高级语言的产生,到结构化编程,再到面向对象编程、组件化编程等等。关于复杂度的定义并不一致,想要详细了解的可以读读[The Many Faces of Complexity in Software Design].

英文中Complex和Complicated有着微妙的不同。但总结起来,软件复杂度偏负面意义,包括两个要点:

- 难以理解 (难以维护和扩展。)

- 无法预测行为 (会降低客户的信心。)

复杂度是随着软件规模不断扩大而必然产生的。它本身又是一个相对的概念,同一个系统对于设计者、开发者,以及维护者而言,复杂度是不同的。不同时期,一个程序员所能掌握的复杂度也是不同的,这也是一个程序员不断提升的目标。

既然业界已经对抗复杂度几十年了,我们就来整理一下。

以分解降低复杂度

以分解的方式进行的设计,主要特点是:

- 分离职责(Seperation of Concerns,参考单一职责原则)

- 关注接口(定义交互)

这是最常使用的技术了。将一个大问题,不断的拆解为各个小问题进行分析研究,然后再组合到一起。在西方称为Divide and Conquer Principle (分而治之原则)。

在结构化编程的时代,提倡模块化(Modularization)。最早提出软件复杂度的工程师提出了基于组件的软件(Component Based Software)。不知道是不是从乐高积木上得到的启发,将系统中拆分为不同的组件,各自实现,然后再组装在一起。

在架构设计中,无论是C/S风格,分层,还是N-Tier,SOA,和前面组件式一样,都是在进行分解,它们都更加强调组合交互。设计上,分分职责,定义好接口,然后就可以各自开发了。然后将交互限定于接口层,就可以很好的控制整个系统的复杂度了。

比如应用层使用一个语音库(Speech Library,一个以库的形式的模块化应用), 根本不用关心其内部实现,只要了解如何使用它的API就可以了。

减少低赖降低复杂度

改进依赖关系的要点:

- 无环形依赖

- 稳定依赖原则(SDP)

分解可以降低系统层级的复杂度,但还有一种复杂度无法解决,即依赖的问题。这在敏捷软件开发:原则、模式与实践中关于依赖性的讨论很详细。当参与者增加时,交互就会随之变得复杂。而当前的软件规模,系统中的各类SDK的API, Framework的API, 各种第三方库越来越多,模块间的依赖就会越来越复杂。

显然系统中的模块或者组件太多了,需要进一步整理。但真正的问题在于出现了双向和环形的依赖。比如上图中负责计算的Computing模块也依赖到了UI模块,或许是因为UI层持有一个计算所需的关键参数。如果UI层变更,就可能会影响到Computing,出现无法预测的行为,给客户以不稳定的印象。

所以模块间的依赖关系必须简化,绝对不能出现环形的依赖。以Chromium为例,它对各个模块的依赖就有严格的定义,并且有DEPS在编译期保证程序员不会犯错。下图是Chromium Component依赖关系的定义,其中Component内部目录的依赖关系也有定义:

当底层模块需要依赖上层模块的实现时,就要通过依赖倒置(DIP)来处理。简单而言就是由底层模块定义一个接口,要求上层模块实现并注入到底层模块。

使用抽象降低复杂度

人的学习过程最有效的一种方式就是归类,其中运用的就是抽象思维。面对变幻无常的天气,人类通过对云的形状进行抽象,就可以预测天气变化。这里有一个抽象建模的过程。

抽象并不是面向对象语言专属,其实它和语言无关,本质上是一个思考的方式。它和分离的最大区别在于,抽象强调将细节隐藏,只关注核心的本质。而后者则重视于细节问题的分解和组合。

以求固定两点的最快捷路线为例。从分离的角度来,可以分解为以下问题:

  1. 步行需要多少时间?
  2. 乘公共交通多少时间?
  3. 乘的士多少时间?
  4. 组合以上答案,再评估哪一个最快捷的方式。

而从抽象的角度来看,解决的思路会是这样的:

遍历所有可能的交通工具,取耗时最小的:

1. 步行

2. 乘公共交通

3. 乘的士

先给出一个抽象的解决思路,至于细节,则是进一步的实现。抽象最大的威力在于它比实现要稳定,也最能用于固化核心设计。在开发过程中,常常围绕着各种细节讨论,似乎抽象过于虚。但是如果没有以抽象来建立系统的设计全景,有些讨论将变得效率低下。

敏捷软件开发:原则、模式与实践中,Martin大叔简单的用抽象类在总类个数中的占比作为抽象性的度量,再结合稳定性的度量,用来评估设计。详情可以参考组件设计原则之概念篇(三)

小结

软件设计是一个平衡的过程,软件的复杂度决定着系统的可维护性、可扩展性和灵活性。我们再来回顾一下前人定义出软件设计的三原则:模块化、抽象和信息隐藏。McCabe也曾有论文专门讨论将圈复杂度应用度量设计的复杂度,不过已经历史久远。现在来看以依赖关系来评估设计的复杂度会更为有效。有兴趣可以了解一下CppDepend。另外Google的工程师则基于LLVM IR也实现了一个工具用于依赖关系分析(Generateing Precise Dependencies for Large Software)。

转载请注明出处: http://blog.csdn.net/horkychen

时间: 2024-10-08 04:22:47

Complexity的相关文章

Examples of complexity pattern

O(1):constant - the operation doesn't depend on the size of its input, e.g. adding a node to the tail of a linked list where we always maintain a pointer to the tail node.int i=0;i++;++i;i+=6; O(n):linear - the run time complexity is proportionate to

cyclomatic complexity

tag: complexity, sourcemonitor, cyclomatic, refactor, 所谓圈复杂度是一种代码复杂度的衡量标准,中文名称叫做圈复杂度.在软件测试的概念里,圈复杂度“用来衡量一个模块判定结构的复杂程度,数量上表现为独立现行路径条数,即合理的预防错误所需测试的最少路径条数,圈复杂度大说明程序代码可能质量低且难于测试和维护,根据经验,程序的可能错误和高的圈复杂度有着很大关系”.它的计算方法很简单,计算公式为:V(G)=e-n+2.其中,e表示控制流图中边的数量,n表

普林斯顿大学算法课 Algorithm Part I Week 3 排序算法复杂度 Sorting Complexity

计算复杂度(Computational complexity):用于研究解决特定问题X的算法效率的框架 计算模型(Model of computation):可允许的操作(Allowable operations) 成本模型(Cost model):操作数(Operation counts) 上界(Upper bound):最多的成本 下界(Lower bound):最少的成本 最优算法(Optimal algorithm):最有可能性的成本的算法(Algorithm with best pos

How to Change Password Complexity Requirements in Windows XP

Original Link: http://www.ehow.com/how_4812793_password-complexity-requirements-windows-xp.html#ixzz32PEZAbOn When you create a new account in Windows XP, you choose a username and a password, which must be a certain length. If you want to get rid of

Such complex, very wow – A guide to Algorithmic Complexity

Such complex, very wow – A guide to Algorithmic Complexity Prerequisites: Exponentiation Basic algebra Functions and asymptotes Prior knowledge of Insertion Sort and other basic sorts of sorts This post is roughly divided into three parts, so feel fr

Runtime Complexity of .NET Generic Collection

Runtime Complexity of .NET Generic Collection I had to implement some data structures for my computational geometry class. Deciding whether to implement the data structures myself or using the build-in classes turned out to be a hard decision, as the

UVA - 586 Instant Complexity

Description  Instant Complexity  Analyzing the run-time complexity of algorithms is an important tool for designing efficient programs that solve a problem. An algorithm that runs in linear time is usually much faster than analgorithm that takes quad

The Brain vs Deep Learning Part I: Computational Complexity — Or Why the Singularity Is Nowhere Near

The Brain vs Deep Learning Part I: Computational Complexity — Or Why the Singularity Is Nowhere Near July 27, 2015July 27, 2015 Tim Dettmers Deep Learning, NeuroscienceDeep Learning, dendritic spikes, high performance computing, neuroscience, singula

空间复杂度是什么?What does ‘Space Complexity’ mean? ------geeksforgeeks 翻译

这一章比较短! 空间复杂度(space complexity)和辅助空间(auxiliary space)经常混用,下面是正确的辅助空间和空间复杂度的定义 辅助空间:算法需要用到的额外或者暂时的存储空间. 空间复杂度:是指算法所需要的所有存储空间,这是跟输入数据的大小决定的.空间复杂度包括辅助空间和保存输入的存储空间. 如果我们想比较几个标准的排序算法所需要的空间,那么用辅助空间来分析会比空间复杂度好.归并排序用了O(n)的辅助空间.而插入排序和堆排序用的O(1)的辅助空间.但是他们这些算法的空