“软件领域永恒的主题是如何做正确的事和如何正确的做事”
——《实例化需求》Gojko Adzic
01
—
大咖的编码进化史
“初学编程的时候,我埋头就写程序,浑浑噩噩地进行开发。然而很快我便发现,事先做好设计可以让我节省返工的高昂成本。于是我很快加强这种“预先设计”风格。”
——《重构》 Martin Fowler
这是一段老马关于“编码进化”的自我描述,大多数程序员们也是循着这样的一条轨迹成长起来的,开始的时候总是想写点什么,抓耳挠腮却不得,到后来慢慢学会了用纸笔把想法画下来启发思考,再到引用高级工具规划架构。在这个进化的过程中,设计的引入(无论是脑海中的还是成稿的)就如同催化剂,一点一滴地加强着程序员对于问题领域的认识以及软件世界观的构建。
老马的亲身经历还讲述了另一个事实,即设计不是一天造就而需要长期实践摸索,中间会有一个相当长的时间跨度,而程序员们也会在演进中逐步学习到诸如流程图、UML等辅助设计工具,最后建立起一个有边界、可操作的软件蓝图。
当我们拿到软件蓝图是否就可以期待一个优雅的软件产品顺利诞生呢?很不幸,现实的答案非常无情地回答我们——不尽然!为何会这样,大咖不是已经在描述中讲道通过设计摆脱了浑浑噩噩的编码了吗?
别着急,老马的话还没讲完,接着往下看。
“许多人都把设计看做软件开发的关键环节,而把编程看做只是机械式的低级劳动。他们认为设计就像画工程图而编码就像施工。但是你要知道,软件和技巧有着很大的差异:软件的可塑性更强,而且完全是思想产品。”
——《重构》Martin Fowler
从蓝图到实现,中间还横亘着一个大脑,由它来完成翻译工作,鉴于大脑背景参数(对问题领域的认知程度以及对软件世界观的完善程度)的不一致,因而可以预期每个大脑翻译的成品不尽相同。现实中也是这样,随手拣起手边的代码就能发现同样的设计,有的实现精巧、干净利落而有些则充斥着大量冗长、晦涩与复杂。那些冗长的代码实现又是如何蹦出来的呢?
02
—
情怀、教育、技术与压力
独行侠
程序员这个行当其实和武侠小说中行走江湖的侠客却有几分相似,毕竟都是凭着“手艺”吃饭,还多少有些不羁,有时总想着在独步码林,更是期望独孤求败,所以一些天生侠骨的程序员行走江湖秉承“一寸长一寸强”的不二真谛。代码便是他们手中的长剑,正所谓“长刀在手,天下我有”,在他们看来无法使用“长剑”的侠客终究只是未出师的学徒,而“仗剑天涯、快意恩仇”方才为人生大境界,快哉!壮哉!
学霸
对于一个刚起步编程的人,无论是阅读或编写一段稍长代码都充满了挑战,而短小的代码容易让初学者对编程有个大体印象,也容易让初学者模仿,更容易让人起步,所以几乎所有编程例子都是从只有若干行的hello world开始。
随着学习时间的增加,一些人希望摆脱初学者的卑微称号,于是他们开始向着更长更具挑战的代码前进。忽地一夜之间,长长的代码成了区分菜鸡与老鸟的分界线,谁的代码越长、嵌套的分支、循环越多,水平就越高。老师们也在这个时候推波助澜,让我们向着长代码策马奔腾,毕竟这有助于锻炼代码整体结构和逻辑理解能力。
技术习惯
“早期的编程语言中,子程序调用需要额外开销,这使得人们不太乐意使用小函数”
——《重构》 Martin Fowler
技术上的考量有时候会让一些人使用冗长代码,原因是由于担心函数切换过程中产生的开销,特别是在那些对资源使用存在较大限制的场景中。不过这种考虑却和现实中大家对待长篇幅事物的态度相悖,试想一下当你置身与一个冗长篇幅的事件中,例如会议、报告、说明书,你很快就反应出各种不适应,包括但不限于:注意力不集中、困倦、抵触甚至拒绝。显然,从大家对事物的接受度上看,短篇幅更加受欢迎。
如此小心翼翼地控制子程序的使用,实际上是为了假想的机器性能而牺牲了人的创造性,你不得不把花在的创造性上的能量投放到阅读理解程序的上下文转换,还有一部分要用来抑制由于长篇幅对自身机体造成的不良反应。
压力
实际中外部压力,比如时间,更是长代码出现的重要诱因。时间恐怕可以称得上是软件开发者最大的敌人了,它的约束迫使开发者会采用照搬修改现有实现或者平铺直叙的方式来进行对抗。无论多么好的设计,只要时间压力足够大,就一定会有足够糟糕的实现。堆砌补丁是开发人员在面临巨大交付压力时通常会选择的方法,在这加一个条件判断,在那加一个循环,日积月累造就了“危楼高百尺”的长代码。
03
—
破局
“从公元1500年开始的这种技术和政治上的差异,是现代世界不平等的直接原因。使用钢铁武器的帝国能够征服或消灭使用石制和木制武器的部落。”
——《枪炮、病菌与钢铁:人类社会的命运》
类比人类的进化,程序员也大致存在4个进化阶段。
原始人,即刚入门的初学者,一个方法或函数会囊括所有流程,一条main路通罗马,开发者通常在这个阶段停留的时间很短;
摩登原始人,会把流程拆分到几个函数中,但每个函数其实只是main的微缩,多数人会在此停留很长时间,这个阶段会给人一种错觉,那就是“你已经足够好,只有高手才能驾驭长代码”;
近代人,函数按照功能分解,表意清晰,适当采用设计模式,这个阶段是大部分人通过工作经验积累,特别是工作环境下的编码规范最终达到的,函数布局已经趋向合理,但仍会有长代码偶尔发生;
现代人,在近代人的基础上,增加了重构,并能敏锐地嗅探出代码的各种坏味道,这个阶段依靠开发者的自身修炼,通过读书、思考和实践,逐渐地找到消除长代码的合理方法
当进入近代人(大多数的我们所处的位置),之前的各种各样、奇形怪状的代码开始被标准化、一致性代码所替代:
大部分开发者会采用相似的编程手段、风格,对代码的理解、协作趋于一致
大部分开发者都会受到相似的外部压力,对于外部压力的外应也会趋于一致,甚至带有继承性和传递性
大部分开发者都会犯相似的问题,并且会被大部分人接受为传统或风格
在这种环境下设计到实现的变形会产生发酵,由于得到了多数人的认同,长代码会逐渐成为多数人允许的灰色地带,直到拥有更先进思想和技术的“现代人”来“消灭”它。
因此进化始终都是事物唯一的出路,对生物如是,对技术亦如是,既然我们中的大多数人已经适应了从原始人到近代人的转变,那为何不再做点努力,让自己蜕变成现代人呢?
领取专属 10元无门槛券
私享最新 技术干货