一步步降低软件复杂性

前言

在进行软件开发时,我们常常会追求软件的高可维护性,高可维护性意味着当有新需求来时,系统易扩展;当出现bug时,开发人员易定位。而当我们说一个系统的可维护性太差时,往往指的是该系统太过复杂,导致给系统增加新功能时容易出现bug,而出现bug之后又难以定位。

那么,软件的复杂性又是如何定义的呢em>

John Ousterhout给出的定义如下:

Complexity is anything related to the structure of a software system that makes it hard to understand and modify the system.

可见,软件的复杂性是一个很泛的概念,任何使软件难以理解和难以修改的东西,都属于软件的复杂性。为此,John Ousterhout提出了一个公式来度量一个系统的复杂性:
C= ∑ p c p t p C = sum_{p}c_{p}t_{p}C=p?cp?tp?

式中, pp p表示系统中的模块, c p c_{p} cp?表示该模块的认知负担(Cognitive Load,即一个模块难以理解的程度), t p t_{p} tp?表示在日常开发中在该模块花费的开发时间。

从公式上看,一个软件的复杂性由它的各个模块的复杂性累加而成,而 ,也就是模块的复杂性即和模块本身有关,也跟在该模块上花费的开发时间有关。需要注意的是,如果一个模块非常难以理解,但是后续开发过程中几乎没有涉及到它,那么它的复杂性也是很低的。

导致软件复杂的原因

导致软件复杂的原因可以细分出很多种来,而概括起来莫过于两种:依赖(dependencies)隐晦(obscurity)。前者会让修改起来很费劲而且容易出现bug,比如当修改时,往往也涉及到、、 的改动;后者会让软件难以理解,定位一个bug,甚至是仅仅读懂一段代码都需要花费大量的时间。

软件的复杂性往往伴随着如下几种症状:

霰弹式修改(Change amplification)。当只需要修改一个功能,但又不得不对许多模块作出改动时,我们称之为霰弹式修改。这通常是因为模块之间耦合过重,相互依赖太多导致的。 比如,有一组Web页面,每个页面都是一个HTML文件,每个HTML都有一个属性。由于各个HTML的属性都是分开定义的,因此如果需要把背景颜色从橙色修改为蓝色时,就需要改动所有的HTML文件。

让模块更“深”一点!

一个模块由接口(interface)和实现(implementation)两部分组成,如果把一个模块比喻成一个矩形,那么接口就是矩形顶部的边,而实现就是矩形的面积(也可以把实现看成是模块提供的功能)。当一个模块提供的功能一定时,深模块(Deep module)的特点就是矩形顶部的边比较短,整体形状高瘦,也即接口比较简单;浅模块(Shallow module)的特点就是矩形顶部的边比较长,整体形状矮胖,也即接口比较复杂。

学会写代码注释!

注释是软件开发过程中的性价比极高的一种手法,它只需要花费20%的时间,即可获取80%的价值。它可以提高晦涩难懂的代码的可读性;可以起到隐藏代码复杂细节的作用,比如接口注释可以帮助开发者在没有阅读代码的情况下快速了解该接口的功能和用法;如果写的好,它还可以改善系统的设计

具体如何写好代码注释,参考《教你写好代码注释》一文。

总结

软件的复杂性是我们程序员在日常开发中所必须面对的东西,学会如何 “弄清楚什么是软件复杂性,找到导致软件复杂的原因,并利用各种手法去战胜软件的复杂性” 是一门必备的能力。有句话说得很好,“代码质量决定生活质量”,当你把软件的复杂性降低了,bug减少了,系统可维护性更高了,自然也就带来了更好的生活质量。

模块设计是降低软件复杂度最有效的手段,学会使用“战略编程”的方法,并坚持下去。我们常常提倡“一次把事情做对”,但这对于模块设计而言并不适用,几乎没有人可以第一次就把一个模块设计成完美的模样。二次设计是一个非常有效的手法,与其在系统腐化之后再花大量时间进行重构或重写,还不如在第一次完成模块设计后,再花点时间进行二次设计,多问问自己:是否有更简单的接口trong>是否有更通用的设计trong>是否有更简洁高效的实现p>

“罗马不是一天建成的“,降低软件的复杂性也一样,贵在坚持。

一步步降低软件复杂性

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2019年11月6日
下一篇 2019年11月6日

相关推荐