知名作家Jules Verne道出了一句真理:极简适用于所有事物。
当今世界,极简被广泛应用于各种事物,代码也不例外。然而令人沮丧的事实是:当前的代码过于冗长。更准确地说,不必要的代码太多,已经到了妨碍有效代码的地步。
也就是说,不必要的代码本质就是有害的:它会腐烂,需要定期维护,需要找出漏洞。新特征意味着要更新旧代码。代码越多,存在漏洞的地方就越多。校验或编译所需的时间越长,新员工理解编译系统所需的时间也越长。
除此之外,代码是由工程师编写的。要写的代码越多,需要的工程师就越多,进而沟通成本也越高,并进一步促进代码维护和开发成本的不断提高。
解决上述所有问题的一个方法就是减少代码量。
减少代码量有很多好处:
- 开发的代码越少=开发成本越低
- 开发的代码越少=维护成本越低
- 开发的代码越少=代码漏洞越少
- 开发的代码越少=有效检测越多
最最重要的一点是:代码量越少,人们阅读代码的概率越高。
以下介绍一些减少代码量的方法。
你不需要它
你不需要它(You Aren’t Gonna Need It,通常缩写为YAGNI)是一个极限编程原则,指:
“等你真正要用的时候再编码,永远不要因为你猜测以后将会用到而编码。”
即使你百分百确定之后将会用到某一个特征,也不要现在就编写代码。
实行YAGNI原则主要基于两个原因:
- 第一,避免写不必要的代码可以节省时间。
- 第二,猜测或多或少会出错,而因猜测提前写下的代码则会一直在,并损害代码的整体表现。避免写不必要的代码可以使最终完成的代码性能更好。
YAGNI原则对所有项目管理都是合理有效的。好的代码设计考虑周到,特征平衡。不好的代码设计则塞满了各种糟糕设计,变得运转不灵,成为“维护的噩梦”。
这带给我们的经验法则就是,专注于明确需要的事物,不要被可能需要的事物分心。
不要写防弹代码
防弹代码指在任何输入或意外条件下都能起效的完美代码。
这是一种非常吸引人的想法,特别是对于那些不能容忍代码在某些场景下失效的高级开发人员。即便如此,编写或尝试编写防弹代码不仅不切实际,而且不必要,因为世界上的所有事物,包括软件,都有其局限性。
要试着编写一个完美的模块,就要编写额外的条件,而这将会使代码变得非常复杂,毁掉编写代码的初衷。到时候,模块会变得更庞大、成本更高,并可能更难维护。
这也解释了为什么编写更少代码的经验法则是编写能够起效的最简单的代码。
极限编程阐明了两个写简单代码的黄金原则:
- 第一,以你认为能够起效的最简单的方法。不要搭建太多使人眼花缭乱的超级结构,不要搞花里胡哨的噱头,只要有效就好。对新特征的代码进行单元检测(所有特征都需要这一步)。
- 第二,也是极其重要的一点,重构系统,使其在保留现有所有特征的情况下,尽可能使用最简单的代码。遵循“有且仅有一次”原则和其他代码质量原则,使得系统尽可能地简单明了。
时刻记住,我们需要的不是最快捷的方法,而是最简单的结果。因此,首先将现有方法分解为多个部分,保留现有测试用例继续运行。其次,简单地修改其中一小部分方法,用于处理下一个测试用例。如此循环。
记住,简约是极致的优雅。优秀编程的本质在于控制和消除复杂性。
永远不要让代码变得更糟糕
这可以说是开发人员的“希波克拉底誓言”。开发人员常常被建议不要图省事走捷径,否则将会导致代码质量下降,变得更糟糕。
和医疗程序一样,软件工程程序具有入侵性和破坏性,其使用的工具和技术也可能是全新的、未经检测的(或随意检测的)。然而不同的是,软件工程的实践和采用的工具没有得到类似医疗资格理事会或食品药品管理局(FGA)这样的组织的规范。因此,软件工程开发者有时会在尚未完全了解风险的情况下对“病人”——即软件——进行不必要的风险性操作。
在解决问题的过程中,我们所做的有时会得不偿失。Steve McConnell在其软件工程经典著作《代码大全(Code Complete)》中提到,如果不解决问题的根源,而仅仅局限于问题的表面,往往是弊大于利的,开发者会自我欺骗,让自己相信这个问题已经解决了。
然而有时候这是很难的。遗留代码增强了恰到好处地增加功能而又不损害代码的难度。实际上,把“永远不要让代码变得更糟糕”改成“故意降低代码质量”更加符合事实。
是的。如果你不知道如何在保持代码质量不变的情况下更改代码,那么就在更改之前告知团队其他成员。重点在于,你是故意降低代码质量的。
当然,这并不能够防范不好的代码,但是可以给你一些时间来思考。经验告诉我们,人们在无法想到好的解决办法时,会停止思考,转而做脑海中想到的第一件事。需要注意的是,我们并不是在要求获得准许或得到一个更好的结果。
“故意降低代码质量”的另一个优点在于它可以防范在错误的时间发生令人不悦的意外,并且使团队成员意识到可能出现的问题。这样,团队就可以很好地合作,处理这些问题。
避免不必要的并发性
并发性是一把双刃剑,应该只在必要的时候使用。
如果源代码是按顺序执行的,那么代码更容易被理解和调试。但如果使用了并发性,代码执行可能会出现并行或不规律。这种执行上的差异使得代码调试变得非常困难。更不用说,它会以多种方式导致程序设计和执行复杂化。由于实行不当的并发性可能导致的问题有:
- 竞争条件(race conditions):出现预料之外的操作。
- 死锁(deadlocks):表格被锁定,需要等待同步操作推进。
- 资源匮乏(resource starvation):操作被永久拒绝访问需要的资源。
世界上最臭名昭著的一个软件灾难就是由并发行使用不当造成的。Therac-25放射治疗仪的一个编程问题导致了4个人的死亡。
即便如此,现代编程语言和架构还是提供了多种并发性工具。但是最终决定权还是在开发者手上。开发人员决定了如何、何时、何处使用并发性来达到最好的结果。
最后,不要囤积代码
强迫性囤积,或者说囤积障碍,特指一种过度获取、无法或不愿丢弃大量物品,最终导致占用大量生活区域并带来灾难或损害的行为模式。
如果开发者有囤积障碍,他们会牢牢抓住有漏洞甚至是已经废弃的代码不放。这样的开发者永远不会删除任何代码,也拒绝调动代码。而当你去质问他们时,他们会给出“我们总有一天可能会用到这个代码”或“我需要这个代码来执行活动X”,诸如此类的回答。
你是代码囤积者吗?你是否以没有时间为借口而拒绝清理一团糟的代码?如果你的回答是肯定的,那么你就是一个代码囤积者,你的工作就是一团乱麻。
囤积是一种非理性行为。如果你不确定代码的存在是否合理,可以对它进行恰当地标记,以便让你注意到它,并再稍后重新审视它。最后,定期清理无效的、不需要的代码。
一个好的编程人员每天都在使自己的代码变得更好,精益求精。他们的代码质量会随着时间的增长而提高。优秀的编程人员总是留下比旧代码更加简洁的遗留代码,而不是一团乱麻。他们的名誉被嵌在代码中永久保留。
就像Robert Martin说过:真相只存在于代码之中。
【责任编辑:赵宁宁 TEL:(010)68476606】