一个系统可以维持5年,10年,甚至20年以上,但是代码和设计模式的生命周期非常短,当对一个解决方案使用不同的方法进行迭代的时候,通常只能维持数月,数日,甚至几分钟的时间。
代码重要性区分
随着对代码是如何改变的研究,致力于代码修改艺术的人发现了一个代码库的规律曲线。每个系统都有很多从未改变的代码。但是也有小部分非常重要且有用的代码一次又一次的改变,经过了多次重构和重写。
当你对一个系统,问题域,或者架构方法越来越熟悉的时候,就更容易发现和预测哪些代码会经常修改,哪些代码不会被修改,即区分重要代码和非重要代码。
我们应该尝试追求完美代码?
众所周知,我们应该写干净整洁的代码,而干净整洁就应该是尽可能一致,易懂,简单。
有些人追求极致,强迫自己写的代码要漂亮且优雅,接近于他们所能达到的完美,疯狂的进行重构,并致力于每一个细节。
与写完代码不再变动相比,一直修改的代码会让完美的需求和具有前瞻性的设计变得有些多余和没必要。
你不能写出完美的软件,这样的结果会使你受伤了?没必要,把它当做人生格言,信奉并祝贺,因为完美的软件并不存在,在计算机历史中没一个人曾经写出过完美软件,当然,你也不可能成为第一个,只有接受这样一个事实,你才能不再在浪费时间,将精力放在可能实现的理想中。
Andrew Hunt, 实用程序员:从路人到大师
曾经写过的代码不需要优美优雅。它必须是正确的且容易理解的,因为在系统的生命周期中那些从不用修改的代码也会被多次访问。同样这些代码不需要又整洁又紧凑——只要整洁就足够了。在一定程度上, 复制粘贴 和其他快捷方法写出的代码是允许的。 即使这些代码周围的代码变了, 这些代码不需要反复修改,不需要重构(直到你需要修改它)。这样的代码是不值得花费额外的时间的。
那些经常修改的代码该如何处理呢?苦思冥想代码风格和提出最优雅的解决方案是浪费时间的,因为这些代码可能会在几天或几周之内再次修改,甚至重写。因为希望代码应该变得更好而 痴迷地重构 那些需要经常修改代码,或者重构那些基本不会修改的代码。代码一直可以变得更好,但这并不重要。
最重要的是:代码是否做到了它应该做的事?代码运行正确且可用又高效吗?能够 处理错误和错误数据 而不奔溃或者至少是 安全地出错 吗?容易调试吗?能简单又安全地修改代码吗?这些不是对于完美代码的主观想法,而是用来区分成功和失败的切实可行的措施。
实用的编码和重构
精益开发的核心思想是:不要浪费时间在那些不重要的事情上。这句话已告诉我们该怎样写代码,怎样重构代码,怎样评审代码,怎样测试代码。
为了把工作做好, 只重构你需要的 —— Martin Fowler 称为机会主义重构(理解、清理不切实际的东西)和预先重构。足够让修改变得更简单更安全即可,其他的不必考虑。如果你不修改那些代码,那么那些代码长什么样子是无所谓的事。
在代码评审中, 只关注那些重要的 。代码正确吗?有防范机制吗?安全吗?容易理解吗?能够安全地修改吗?
忘掉编码风格(除非编码风格达到可理解的程度)。让你的 IDE 处理格式化。不要过多争论:代码是否可以是“更多的OO”。只要它有意义,不管它是否适当地遵循这种或那种模式,这些都不重要。无论你喜欢还是不喜欢都没关系。无论你能否以更好的方式做到这一点并不重要——除非你在教一个对平台和语言都不熟悉的新手,而且你需要做一些代码评审作为指导的一部分。
写测试是有必要的。测试那些涵盖主路径和重要例外情况的测试。测试可以让你以最少的工作量获得最多的自信心。 大规模全范围测试或者小规模局部测试 ——在编写代码之前测试还是之后测试,都没关系,只要做了这个工作就行。
这不(仅)是关于代码
建筑学和工程学的隐喻从未在软件开发中生效。我们不是设计和建造桥梁或摩天大楼 —— 它们会在几年或几代内保持基本相同。我们正在建造一些更富有创造力和抽象性、更加短暂的东西。代码编写之后是用来修改的 —— 这就是为什么它被称为“软件”的原因。
“经过五年的使用和修改,成功的软件的源码通常与最初版本完全不一样,而五年之后的成功的建筑几乎没有什么变化。”
Kevin Tate, 可持续软件开发
我们需要将代码看作是我们工作的一个暂存:
…有时在面对更重要的事情时,我们被引导到盲目崇拜代码。我们经常会处于这样的幻象中:在移交产品时最有价值的东西是代码,实际上这可能是对问题域的理解、设计难题的进展甚至是客户反馈。
Dan Grover, 代码和创造性破坏
迭代开发教会了我们通过实验来验证我们工作的结果 —— 我们是否已解决了这个问题,如果没有,我们学到了什么,我们该如何改进?我们正在构建的软件永远不会完成。即使设计和代码是正确的,它们可能也只是在一段时间内是正确的,直到环境要求其再次改动或被替换为更好的东西。
我们需要编写好的代码:可理解、正确、安全和可靠的代码。我们需要重构和审查它,并写出好的有用的测试用例,直到其中的一些代码(也可能是全部(),可能会很快被抛弃,或者可能永远不会被再次看到,或根本不会使用了。我们需要认识到,我们的一些工作必然会被浪费掉,并要为此进行优化。做那些必须做的,不做无用功。不要浪费时间尝试编写完美的代码。