选自《架构整洁之道》
一直以来,设计(Design)与架构(Architecture)这两个概念让大多数人十分迷惑——什么是设计?什么是架构?二者究竟有什么区别?
本书的一个重要目标就是要清晰、明确地对二者进行定义。首先我要明确地说,二者没有任何区别。一丁点区别都没有!
“架构”这个词往往使用于“高层级”的讨论中。这类讨论一般都把“底层”的实现细节排除在外。而“设计”一词,往往用来指代具体的系统底层组织结构和实现的细节。但是,从一个真正的系统架构师的日常工作来看,这样的区分是根本不成立的。
以给我设计新房子的建筑设计师要做的事情为例。新房子当然是存在着既定架构的,但这个架构具体包含哪些内容呢?首先,它应该包括房屋的形状、外观设计、垂直高度、房间的布局,等等。但是,如果查看建筑设计师使用的图纸,会发现其中也充斥着大量的设计细节。譬如,我们可以看到每个插座、开关以及每个电灯具体的安装位置,同时也可以看到某个开关与所控制的电灯的具体连接信息;我们也能看到壁炉的具体安装位置,热水器的大小和位置信息,甚至是污水泵的位置;同时也可以看到关于墙体、屋顶和地基都有非常详细的建造说明。
总的来说,架构图里实际上包含了所有的底层设计细节,这些细节信息共同支撑了顶层的架构设计,底层设计信息和顶层架构设计共同组成了整个房屋的架构文档。
软件设计也是如此。底层设计细节和高层架构信息是不可分割的。它们组合在一起,共同定义了整个软件系统,缺一不可。所谓的底层和高层本身就是一系列决策组成的连续体,并没有清晰的分界线。
所有这些决策的终极目标是什么呢?一个好的软件设计的终极目标是什么呢?
就像我之前描述过的:
软件架构的终极目标是,用最小的人力成本来满足构建和维护该系统的需求。
一个软件架构的优劣,可以用它满足用户需求所需要的成本来衡量。如果该成本很低,并且在系统的整个生命周期内一直都能维持这样的低成本,那么这个系统的设计就是优良的。如果该系统的每次发布都会提升下一次变更的成本,那么这个设计就是不好的。就这么简单。
下面来看一个真实案例,该案例中的数据均来源于一个要求匿名的真实公司。
首先,我们来看一下工程师团队规模的增长。你肯定认为这个增长趋势是特别可喜的,像图1.1中的这种增长线条一定是公司业务取得巨大成功的直观体现。
现在再让我们来看一下整个公司同期的生产效率(productivity),这里用简单的代码行数作为指标(参见图1.2)。
这明显是有问题的。伴随着产品的每次发布,公司的工程师团队在持续不断地扩展壮大,但是仅从代码行数的增长来看,该产品却正在逐渐陷入困境。
显然,图中展示的趋势是不可持续的。不管公司现在的利润率有多高,图中线条表明,按这个趋势下去,公司的利润会被一点点榨干,整个公司会因此陷入困境,甚至直接关门倒闭。
究竟是什么因素造成了生产力的大幅变化呢?为什么第8代产品的构建成本要比第1代产品高40倍?
我们在这里看到的是一个典型的乱麻系统。这种系统一般都是没有经过设计,匆匆忙忙被构建起来的。然后为了加快发布的速度,拼命地往团队里加入新人,同时加上决策层对代码质量提升和设计结构优化存在着持续的、长久的忽视,这种状态能持续下去就怪了。
图1.4展示了系统开发者的切身体会。他们一开始的效率都接近100%,然而伴随着每次产品的发布,他们的生产力直线下降。到了产品的第4版本时,很明显大家的生产力已经不可避免地趋近为零了。
对系统的开发者来说,这会带来很大的挫败感,因为团队中并没有人偷懒,每个人还都是和之前一样在拼命工作。
然而,不管他们投入了多少个人时间,救了多少次火,加了多少次班,他们的产出始终上不去。**工程师的大部分时间都消耗在对现有系统的修修补补上,而不是真正完成实际的新功能。**这些工程师真正的任务是:拆了东墙补西墙,周而往复,偶尔有精力能顺便实现一点小功能。
如果你觉得开发者们这样就已经够苦了,那么就再想想公司高管们的感受吧!
请看图1.5,该部门月工资同期图。
如你所见,产品的第1版是在月总工资10万美元左右的时候上线的。第2版又花掉了几十万美元。当发布第8版的时候,部门月工资已经达到了2千万美元,而且还在持续上升。
也许我们可以指望该公司的营收增长远远超出成本增长,这样公司就还能维持正常运转。但是这么惊人的曲线还是值得我们深入挖掘其中存在的巨大问题的。
现在,只要将图1.5的月工资曲线和图1.2的每次发布代码行数曲线对比一下,任何一个理性的CEO都会一眼看出其中的问题:最开始的十几万美元工资给公司带来了很多新功能、新收益,而最后的2千万美元几乎全打了水漂。应立刻采取行动解决这个问题,刻不容缓。
但是具体采取什么样的行动才能解决问题呢?究竟问题出在哪里?是什么造成了工程师生产力的直线下降?高管们除了跺脚、发飙,还能做什么呢?
大约2600年前,《伊索寓言》里写到了龟兔赛跑的故事。这个故事的主题思想可以归纳为以下几种:
1.慢但是稳,是成功的秘诀。
2.该比赛并不是拼谁开始跑得快,也不是拼谁更有力气的。
3.心态越急,反而跑得越慢。
这个故事本身揭露的是过度自信的愚蠢行为。兔子由于对自己速度的过度自信,没有把乌龟当回事,结果乌龟爬过终点线取得胜利的时候,它还在睡觉。
这和现代软件研发工作有点类似,现在的软件研发工程师都有点过于自信。哦,当然,他们确实不会偷懒,一点也不。但是他们真正偷懒的地方在于——持续低估那些好的、良好设计的、整洁的代码的重要性。
这些工程师们普遍用一句话来欺骗自己:“我们可以未来再重构代码,产品上线最重要!”但是结果大家都知道,产品上线以后重构工作就再没人提起了。市场的压力永远也不会消退,作为首先上市的产品,后面有无数的竞争对手追赶,必须要比他们跑得更快才能保持领先。
所以,重构的时机永远不会再有了。工程师们忙于完成新功能,新功能做不完,哪有时间重构老的代码?循环往复,系统成了一团乱麻,生产效率持续直线下降,直至为零。
结果就像龟兔赛跑中过于自信的兔子一样,软件研发工程师们对自己保持高产出的能力过于自信了。但是乱成一团的系统代码可没有休息时间,也不会放松。如果不严加提防,在几个月之内,整个研发团队就会陷入困境。
工程师们经常相信的另外一个错误观点是:“在工程中容忍糟糕的代码存在可以在短期内加快该工程上线的速度,未来这些代码会造成一些额外的工作量,但是并没有什么大不了。”相信这些鬼话的工程师对自己清理乱麻代码的能力过于自信了。但是更重要的是,他们还忽视了一个自然规律:无论是从短期还是长期来看,胡乱编写代码的工作速度其实比循规蹈矩更慢。
图1.6展示的是Jason Gorman进行的一次为期6天的实验。在该实验中,Jaosn每天都编写一段代码,功能是将一个整数转化为相应罗马数字的字符串。当事先定义好的一个测试集完全通过时,即认为当天工作完成。每天实验的时长不超过30分钟。第一天、第三天和第五天,Jason在编写代码的过程中采用了业界知名的优质代码方法论:测试驱动开发(TDD),而其他三天他则直接从头开始编写代码。
首先,我们要关注的是图1.6中那些柱状图。很显然,日子越往后,完成工作所需的时间就越少。同时,我们也可以看到当人们采用了TDD方法编程后,一般就会比未采用TDD方法编程少用10%的时间,并且采用TDD方法编程时最差的一天也比未采用TDD方法编程时最好的一天用时要短。
对于这个结果,有些人可能会觉得挺意外的。但是对常年关注软件开发本质的人来说,它其实揭示了软件开发的一个核心特点:
要想跑得快,先要跑得稳。
综上所述,管理层扭转局面的唯一选择就是扭转开发者的观念,让他们从过度自信的兔子模式转变回来,为自己构建的乱麻系统负起责任来。
当然,某些软件研发工程师可能会认为挽救一个系统的唯一办法是抛弃现有系统,设计一个全新的系统来替代。但是这里仍然没有逃离过度自信。试问:如果是工程师的过度自信导致了目前的一团乱麻,那么,我们有什么理由认为让他们从头开始,结果就会更好呢?
过度自信只会使得重构设计陷入和原项目一样的困局中。
不管怎么看,研发团队最好的选择是清晰地认识并避开工程师们过度自信的特点,开始认真地对待自己的代码架构,对其质量负责。
要想提高自己软件架构的质量,就需要先知道什么是优秀的软件架构。而为了在系统构建过程中采用好的设计和架构以便减少构建成本,提高生产力,又需要先了解系统架构的各种属性与成本和生产力的关系。
这就是这本书的主题。本书为读者描述了什么是优秀的、整洁的软件架构与设计,读者可以参考这些设计来构建一个长期稳定的、持久优秀的系统。