简单设计

做者:袁英杰
原文地址:https://codingstyle.cn/topics/185ide

咱们一直在谈简单设计,但究竟什么是简单设计?更具体的说,对于同一个问题,设计决策A和B,究竟哪个更符合简单设计的要求?函数

对于这类问题,若是没有一个明确的标尺,那么"简单设计"就难免会成为一句没法评判的空洞口号,让程序设计者无从判断和遵照。测试

对此,Kent Beck给出了清晰的答案:ui

  1. 经过全部测试(Passes its tests)设计

  2. 尽量消除重复 (Minimizes duplication)code

  3. 尽量清晰表达 (Maximizes clarity)排序

  4. 更少代码元素 (Has fewer elements)接口

  5. 以上四个原则的重要程度依次下降。ip

这组定义被称作简单设计原则ci

初看上去,这组原则平淡无奇,彷佛是一组耳熟能详的原则的罗列。但只要细细品味,就会发现其精妙绝伦之处。

经过全部测试

直观的看,这句话貌似在讲测试:一个项目只有具有完善的自动化测试,才算在作简单设计。

但事实上并不是如此。这里提到的测试,真正的意思是客户验收。若是你的项目经过了客户的全部验收条件(Acceptance Criteria),那就说明大家已经完成与客户约定的所有需求。至于验收方式是靠人工仍是靠自动化测试则可有可无。

因此,这句话强调的是对外部需求——包括功能性需求和非功能性需求——正确的完成。

尽量消除重复

重复,意味着低内聚,高耦合。而消除重复的过程,也就意味着是让软件走向高内聚,低耦合,达到良好正交性的过程。识别和消除重复,对于加强软件应对变化能力的重要程度,怎么强调都不为过。关于这一点,我会另文说明,这里就再也不赘述。

不过,并非全部的重复均可以消除:好比,C++一个源文件里对外部公开的类,其每一个public方法原型,除了在源文件里定义时,须要声明一次,还须要在头文件里再次声明。这样的重复,是语言机制的要求,没法消除。

于是,这条原则被描述为最小化重复,而不是消除重复

尽量清晰表达

清晰性,指的是一个设计容易理解的程度。注意:这不只仅是对整洁代码(Clean Code)及声明式设计(Declarative Design)的强调。关于这一点,有着很是有趣的部分,咱们在随后的部分谈到。

更少代码元素

这一条是点睛之笔,正是由于它的存在,这组原则才被称作简单设计原则,从而区别于其它设计原则。

在这里,常量,变量,函数,类,包 …… 都属于代码元素。代码元素的数量,一般反映了设计的复杂度。于是,这句话强调的是:尽量下降复杂度,保持简单。

重要程度排序

这一句最容易让人忽视,却偏偏最为重要。若是第四条是点睛之笔,那么第五条就是将以前四条贯穿起来的那条龙。正是这一句,让你知道当以上四条发生冲突时,应该如何取舍。

咱们已经知道,第四条,是简单设计的精髓,可是,它在前四条原则却最不重要。

对于第一条,它强调:简单当然好,但你不能为了简单,而不去实现和客户约定好的需求。(固然,若是需求不合理,你应该在前期经过和客户协商拒绝,或修改。但那是关于需求管理这个话题有关的故事,感兴趣者能够去查阅相关文章和书籍)。

而对于第二条,好比,咱们如今有两个类:它们之间有一部分重复代码。为了消除掉这个重复,咱们将重复代码提取到一个新的类里。因而两个类变为三个类,增长了一个新的代码元素。这固然让设计变得更复杂了。但这种复杂度产生了更重要的价值(让软件更具有正交性,从而让软件更易于修改),因此,不能为了保持简单,而不去消除这个重复。

对于第三条也是如此,好比下面这句代码中有一个magic number:

a = 1000;

为了让这段代码更容易理解,咱们将代码修改成:

const int MAX_NUM_OF_CONNECTIONS = 1000;

a = MAX_NUM_OF_CONNECTIONS;

从而增长了一个新的代码元素。于是也稍微增长了设计的复杂度。但因为这个新的代码元素也产生了相对于简单更重要的价值,在简单和表达力之间,咱们应该选择后者。

反向价值

而简单设计的价值,也能够从相反的角度来看:若是新增的一条代码元素,不能产生上述三个价值,它就不该该存在。

对于第一条,你不该该去实现一个客户还不须要的需求,由于那会增长系统的复杂度。

对于第二条,你不该该为尚未出现的重复,或者为还没有出现的变化方向,去增长任何额外的复杂度。好比创建一个抽象接口,却只有一个对应的实现。

而第四条对于前两条的约束,就是咱们耳熟能祥的YAGNI(You Aren't Gonna Need It)。它强调,咱们要着眼当下,不去为本身猜测出的将来可能性去增长系统的复杂度。

总之,当你看到一个代码元素,没有产生以前三条中的任何一条价值,那么它就应该被删除掉。

而这正是简单设计可以简单的缘由。

需求最大

抛开第四条,单看前三条,它们以前的重要程度也是依次下降的。好比,你不该该由于怕产生很难消除、或干脆消除不掉的重复而放弃一个对客户有价值的需求。换句话说,哪怕一个需求会致使重复代码,你也要去实现它。

一样的,若是一个需求,会致使你的设计更加晦涩,你却不该该由于它损害了清晰性、可理解性而拒绝它。

对于这两点,绝大多数人都没有太多争议。(也有一派认为,不该该让需求破坏设计的优雅,当二者发生冲突时,选择优雅)。

最具争议话题的解决

咱们常常可以听到一种争议:一些人认为,放在一块儿的长篇累牍的大块流程代码,反而更容易理解。由于消除重复而致使的单一职责,会将一大段代码分布到不一样的类或者模块,为了理解它,就不得不在类或者模块间跳来跳去,反而不容理解了。

另一部分人并不认同这种见解。他们认为,因为模块或类的单一职责性,其每块逻辑都更加简单清晰,而后在另一个层面再去看它们之间的交互,就能够很快理解整个逻辑。 这比大坨的面条式代码更容易理解。而对于SLAP(Single Level of Abstraction Priciple)的遵照,会更进一步的增长可理解性。

因为可理解性属于更加我的、更加主观的事情,于是究竟哪一种方式更容易理解,可能永远也不会有统一的答案。

而简单设计原则经过第二条和第三条之间的排序,给出了清晰的决策依据:因为消除重复,把一大块代码分隔到了不一样的地方,即使团队认为这确实损害了可理解性,但因为重复所致使的恶果更加严重,于是优先选择消除重复。

另外,关于简单设计原则,社区内有多个版本,用词不一样,但意思大体相同。关键的差异是第二条和第三条的顺序:即消除重复提高表达力哪一个更重要。有一些人认为表达力比消除重复重要,于是把提高表达力放在第二条。但更多人认同的是本文以前的版本。

对于这一点,我我的的观点是,越是主观的东西,就越不具有可验证性或科学性,于是对于工程技术而言,重要程度就越低。

另外,回归到具体项目里,为了不争议,在不违背前两点原则的状况下,团队能够根据大多数人的审美和认知,决定怎样的设计才更具有可理解性。事实上,在重复已经被消除殆尽的状况下,对于可理解性问题,不管怎样选择,影响都是局部的。

于是,对于这个问题,团队以为舒服最重要。

结论

简单设计原则,经过对需求易修改性可理解性复杂度,这四个在设计决策中最关键的因素给出了排序,让简单设计再也不一个语义模糊的口号,而是对设计决策给出了清晰的guideline。

根据笔者经验,深刻理解、并在项目中反复品味和应用它,能够避免掉不少没必要要的争议,也会对设计质量产生很是显著的帮助。

相关文章
相关标签/搜索