一个系统的迭代开发可能持续运行5年至10年甚至是20年。相比之下,某行代码甚至某个设计的生命周期则要短很多,只有几个月或者几天,甚至当你为了解决一个问题迭代测试不同方案时它们的生命周期只有几分钟。
一些代码的确比其他代码更重要
通过研究代码随时间发生的变化,Michael Feathers发现了代码生命线。通常,每个系统都有许多一次写成不再修改的代码。但是,有一小部分代码,包括最重要最有用的代码,却被经常被修改,重构或者重写数次。
随着对一个系统或者一类问题或者一个架构方案的深入了解,你应该能够更加轻易的知道或者预测到哪些代码会不停的变化哪些代码不会,换句话说,就是哪些代码比较重要哪些代码不重要。
是否应该努力去写完美代码?
大家都知道,我们应该写干净的代码,保持代码的一致性、易读性,并且尽可能地简单。
但是一些人走了极端,尽自己的最大努力,去写尽可能优雅的、接近完美的代码,痴迷于重构斟酌代码的每一个细节。
但是,如果这些代码不是一次写成不再修改,反而是一直不断的变化,那么,努力去写完美代码或者努力进行完美的设计岂不是浪费时间?
“你 不可能写出完美的代码。你难道为此倍受打击么?显然不该。应该将它作为一个生活中的公理,去拥抱它,庆祝它,因为完美的代码是不存在的。在计算机短暂的历 史中,没有任何人曾经写出过哪怕一段完美无缺的代码。显然,你也不太可能成为第一个写出完美代码的人。除非你接受这个事实,否则你会一直浪费时间和精力去 追逐一个不能实现的梦想!”——Andrew Hunt《程序员修炼之道:从初级到高级》
只写一次的代码首要不是美观和 优雅,而是正确运行,而且易读易懂,因为在系统的整个生命周期中,这些代码虽然不再修改,但是可能需要阅读很多次。不一定非要紧凑,干净即可。在这些代码 中,一定程度上的拷贝和粘贴等操作是可以接受的。这些代码不需要反复斟酌,除非你需要修改它,否则即使周围代码都在变,也不需要对这些代码重构。对于这些 代码,没必要花费过多额外的时间。
对于那些一直需要修改的代码呢?苦苦思索代码的风格和最优雅的方案是在浪费时间,因为,这些代码可能在随 后的几天或者几周就会被修改甚至重写。同样地,每次修改都痴迷于代码的重构,或者重构那些不需要修改的代码试图使其变得更好也是没有必要的。代码永远都可 以变得更好,但是这不应该是最重要的方面。
真正重要的是代码是否实现了想要的功能?代码是否正确运行?是否有用?是否高效?能否处理错误和损坏的数据而不会崩溃,至少也要安全的失效?调试是否方便?修改起来是否简单且安全?这些不是美观的组成部分,而是实际中衡量代码是否正确的标准。
务实地进行编码和重构
精益开发的核心思想是:不要把时间浪费到不重要的事情上。应该用这个原则指导我们如何编写代码,如何重构代码,如何进行代码审查以及如何进行代码测试。
为了完成工作,只进行必要的代码重构,Martin Fowler称之为机会主义重构(或理解为清理,童子军规则)和有预备的重构。这足以使代码修改起来更加简单和安全。如果你不是在修改代码,代码看起来是什么样子,真的无关紧要。
在代码审查中只关注真正重要的部分,这些代码是否正确?是否是防御性的代码?是否安全?你能否理解它的思路?修改起来是否安全?
不 要纠结于代码的风格(除非代码风格误导了你对代码的理解),把格式化代码的工作交给IDE。没有必要去争论这些代码能否“更加面向对象”。只要它有道理, 至于是使用这用模式还是别的模式,并不重要。同样,至于你是否喜欢,也不重要,尽管你可以用更好的方式完成它,除非你是在教对平台或者语言不熟悉的新手, 需要在代码审查中完成监督工作。
测试用例的编写很重要,需要覆盖到主要的执行路径和重要的异常情况。测试用例能够用最少的工作量给你尽可能多的信息和信心,具体是采用大而全的测试还是小而精的测试则无关紧要。至于是在写代码之前写测试用例还是在写代码之后写测试用例也不重要,只要测试用例有效即可。
不仅仅是关于代码
在软件领域里,建筑师和工程师的概念从来都不适用,我们不是设计建造屹立数年或者数百年大桥或者摩天大楼,我们构建的是更加具有可塑性的、更加抽象的,同时生命周期也更加短暂的东西。软件之所以称为“软件”,就是因为编写代码就是为了修改。
“经过五年的使用和修改,很多情况下,一个成功的软件源码和最初的样子已经面目全非了,但是一个成功的建筑经过五年,基本没有任何变化。”——《可持续软件开发》
我们应该将代码视为工作的一个临时假象:
有时在重要的事情面前,我们陷入了对代码的迷恋。我们经常遭受这样的误解,在产出的产品中代码是最有价值的东西,尽管它实际上是对一个问题的理解,或者是对设计的一种实现甚至是顾客的反馈。——Dan Grover《编码与创造性破坏》
迭代开发教会我们不断的尝试和检查尝试的结果——是否解决了问题,如果没有解决问题,如何去改进?我们正在构建的软件是永远做不完的。尽管设计和编码是正确的,那也可能只是一时正确,一旦需求发生变化,就会被更加适合的设计和编码替代。
我 们需要写好的代码:易懂,能够正确运行,有安全保障的代码。我们需要对它进行重构和代码审查,并且编写有效的测试用例。但是要记住,其中的一些代码或者全 部代码可能很快就被丢掉,或者再也不会被读到甚至从来就不会被用到。我们需要意识到,我们的一部分工作可能要被浪费掉并且对此进行优化。只做哪些需要被完 成的事情,不要浪费时间试图去编写完美代码。