图0:整洁代码的编码原则

什么是整洁代码

“整洁代码”是我在写代码中一直以来遵循的一条理论。事实上,对于我来说,与其说是一种理论,不如说是一种信仰。他是这么一种理念——你的代码必须够整洁且尽可能接近于完美。如果你所写出来的代码比你所需要的多,那么多出来的那部分代码不应该存在其中。任何的多余都是不可能容忍的,而且一直以来我甚至觉得一个空格都不允许多余。你要让你的代码不仅仅是解决了问题,而是尽可能的有效率、可读性好、易维护。同样,我经常花很多额外的时间去设计我的代码。

所有的一切开始于 2001 年,当时我正在读 Andy Hunt 和 Dave Thomas 写的《程序员修炼之道》。读到其中如“永远不要接受一个坏了的窗口”之类的观点时,让我产生了共鸣。

这设想起来十分简单。想象下,你有一间房子,然后因为没有设计图来修复它,墙面开始裂开,然后越来越严重,直到房顶坍塌。或者你有一辆购物手推车,你把它遗弃在街角,然后人们开始往里面扔垃圾。很快,整个推车都将塞满垃圾直到溢出来。在以上两种情况中,如果你不设定好清楚的界限和规则,长久之后你肯定会遇到问题。我以前入职过一家新公司,那里的团队写出很多脏代码,在那里工作一点都不开心。我意识到,当人们开始变得懒惰,对自己的代码毫无责任心时,问题就会累积。结果是,每一次有更新时,他们都要花不知道多少时间去进行一次次修改。没有人需要这样的代码。

我把自己称作是实用至上的完美主义者。这意味着,一方面,在特定情况下我解决问题时,使用的方法一般是合理并且恰当的,而不是依赖于模糊的想法和理论。另一方面,我希望我的代码能够在第一次就尽可能完美,不是我喜欢浪费时间,而是因为足够节约,我知道这将在之后给我省下更多时间。

如何完成“整洁代码”设计

那么,该怎样创造“整洁代码”呢?首先,你不能把你的项目当做一个代码项目;你要把它想象成一个设计和计划的过程。很多开发者经常一头猛扎进代码中一顿乱敲,因为他们受到他们领导们或者其他人的要求完成尽快任务的压力。相比之下,一个具有“整洁代码”编写习惯的开发者,会尽量确保自己在开始敲代码前已经理解了问题的重点所在。想象下你正在建一栋房子,而你却打算建一个薄弱的地基,如果你之后想要扩大你的房子,你将花费更多的时间和金钱去重筑地基。这就是为什么,对我来说,程序的第一步,就是和客户方了解清楚,他需要的结果具体是什么样的。

如果您遵循领域模型驱动设计,那么下一步让代码整洁的方法是:创建共用语言或“领域通用语言”。 代码的用词非常重要,因为您希望您的变量名称,类名称和包名称无论谁查看代码都能理解。 现在有些开发者会说:“拜托,我们只用了一些愚蠢的名字,稍后再改。”

虽然这看起来是最快的解决办法,但是团队,甚至是编写它的开发人员,可能会迷失在这些无意义的名字中。 代码中的每个抽象词语可能会给不同的团队成员带来不同的关于项目方向的概念, 如果我考虑编写一个梨,而你考虑编写一个苹果,我们最终会得到一个无用的苹果梨混合词。

如果每个人都参与进来,从客户到开发人员,在设计过程中进行良好的沟通,我们就开启了这门与项目一起发展的通用的“无处不在的语言”。目标是一个完整的、可理解的程序,由整个团队编写,但看起来好像是由一个人编写的。它应该由简单的元素组合在一起,来传达复杂的思想。我们应该避免模棱两可的术语而传达不了恰当的理解。以这种方式进行沟通将有助于我们预防问题,而不是以后再解决问题。现在,我们可以确认客户想要苹果还是雪梨,最终达成客户满意的结果。在刚开始时花些时间讨论,如果可以真正帮助选择项目的进行方向 ,就可以为以后节省许多时间。

估算上的赌博

整洁编码的难点之一是估算你的时间表。许多开发人员害怕对他们的经理诚实,这就是为什么我认为信任你的经理是很重要的。比方说你有一种直觉,认为一个项目需要十天,但是你害怕说“十天”,所以你会想:“嗯,如果我真地很努力,我加班,如果一切顺利的话,我应该能在八天内完成这项工作。” 我称之为估算上的赌博。于是,你就定下一个时间表,走到老板或客户跟前说: “我会在八天内搞定它。”你猜怎么着?许多经理会回你一句:“我给你四天时间!” 于是,一个你认为很可能要花十天时间的项目,如果没有缺陷(bug)的话,现在变得几乎没有时间了,现在你很忙,以至于你无法顾及你本应该做到的代码整洁。

通常,我把一切都考虑进去。如果我觉得一个项目需要十天,我通常会告诉我的客户十五天。那不是说我一开始先花五天四处闲逛。我尽我最大的努力按我直觉的时间完成那个项目,但经常发生的是,客户改变需求,或者可能我最初的设计不可行,所以我需要那额外的五天。

对于开发人员来说,这是一件困难的事情,尤其是当你的同事声称他或她能在一半时间内完成。当然,也许他们会得到这份工作,但是,当结果是一坨屎时,你就会得到下一份工作。在一个灵活的团队里,你的老板可能会让你有额外的时间,如果你不能按时完成,但那也是在赌博。客户很少会那么宽容。永远不要赌你要花多少时间。你必须相信你自己,相信你的知识。

对我来说,做一个软件工匠就是要有一种专注的态度,对你的代码、工作和时间负责。所以,从开始讨论到最终结果,你的一个焦点应该是保持你自己的高标准,尽可能为你的客户创造最好的产品。

系统设计

好了,所以现在我们有了我们的远景、共同语言和时间表,我们可以开始计划我们的代码了。我做这事的方法是在白板上画方框,表示我们的系统,以及我们系统的不同组件如何在一起工作。这样做的目的是可视化我们的系统将如何运行,并讨论使组件相互作用的最高效的方法。当你发现你的设计错综复杂,就要寻找方法来简化,因为错综复杂的区域是缺陷(bug)和代码崩溃的温床。

现在,你有了自己的设计,但是你的同事呢?他开发相同系统的想法可能与你的完全不同,而这正是我们需要更多讨论的地方。在小组工作时,我一向认为开发人员应该争辩和讨论他们的系统。这有助于提高系统的效率和效用。这也有助于保持统一的代码远景,并保持高昂的团队精神,因为每个人都在一起工作。

我喜欢拿这些方框图作为与客户进一步沟通的机会。他们通常不懂代码,但他们理解带有商业术语注解的方框图。你可以问他们:“这是你所想的吗?” 并让他们参与这个过程。这是许多开发人员未能利用的系统设计中最强大的方面之一,因为即使是不懂代码的人,仍然能够理解设计的总体概念。

当团队之中或团队与客户之间出现分歧时,不要过于担心。分歧是一个很好的征兆,意味着需要进一步的改进或调整,应该被看作是改善结果的机会,而不是威胁。这些征兆仅仅意味着你们在达成共识之前需要多说。一个轻量级的、基于团队的开放讨论是这里的关键方法。等级扁平的公司更容易促成这种讨论。总是要尽早让客户参与讨论。有时,意见不同的原因可能是客户不晓得他们的选择会导致性能不佳、维护困难或成本高昂。所以,问他们:“我们现在真的需要这个功能吗?如果需要,我们能简化它吗?”

从另一方面来看,开发者经常没有意识到,一些无法抗拒的商务因素往往会导致客户把任务变得更加地复杂。客户方面经常会提出一些不必要的需求,然后开发者们就尝试满足他们。但是我相信,开发者的工作不是这样的,不要为了迎合客户而盲目地接受用户的需求,当你觉得某些需求不切实际的时候,应当主动说出来。战胜分歧,需要双方对彼此抱有足够的尊重和信任。如果你能把自我放在一边并促进这个过程,结果将会是双赢。双方都必须不断问对方问题和挑战对方观点,直到达成共识。这样一来,才能最大可能地为客户创造出真正想要的产品。

除此之外,我经常听到开发者谈及的一件事是,“哦,让我们添加一些额外的功能,因为我们将来可能需要它。”永远不要这样做,这是无谓的时间浪费。更糟糕的是,它实际上是有害的。当你通过添加额外的功能来使代码复杂化时,你将使代码更难阅读、理解、维护和测试。这样做也容易在代码中引入错误。所以,这些不必要的额外功能真的是有害的!你不知道未来如何,所以你的假设有 90% 的可能是错误的。即使是对的,但要用到该功能可能是在两年之后的事情了,那时候,你可能已经找到了一个更好的方法。

如果你正在建房子,一旦建好了地基,你决定添加一个额外的房间,这将花费大量的时间和金钱。另一方面,软件是不同的。软件可以以较低的成本进行迭代更改。改变它是不容易的,但这肯定比在一个房子上添加房间更容易一些。软件架构的越好,就越容易,维护的成本就更便宜。作为程序员,简单的代码应该作为永远的追求。

开始写代码

终于,经过充分的设计之后,可以开始写代码了。你可以看到,在写代码之前,还是有很多事情需要做的,这就是“整洁代码”和“脏乱代码”的区别——设计在前。

很多人经常容易误解,我已经花了那么多时间来设计了,那么我的代码就将马上变得更好,只需要直截了当的写出来就可以了。其实并不是这样。你仍然需要在编程过程中保持足够的严谨和细心,并且尽可能的测试你的代码。即便你认为你的设计是完美无瑕的,也仍然要这么做。软件开发可不仅仅是做个快速设计然后写几行代码这么简单。

在一个理想状况下,你应当从测试开始。如果可能的话,我推荐使用测试驱动开发方法,TDD。从实现具体业务目标的集成测试或者验收测试开始,然后按照各个小的测试单元一项一项来。你应该在你写完测试要求后,然后再开始写代码,只要你有一个科学的测试过程,重写或者重构你的代码都将十分简便。

对于拥有非平坦型的组织结构的组织来说,这种“测试优先”的方法是非常具有挑战性的。为了能够如此工作,一个组织需要基于开放沟通和迭代的实验方法,而不是需要分层的、自上而下的管理风格。管理者需要完全信任他们的团队,并将责任交给他们。 然而,在大多数仍然有许多恐惧和封闭的公司中,这仍然有很长的路要走。这种方法与当今大多数组织仍然存在的层级管理文化形成鲜明的对照。

因此,我们需要以小步骤开始,同时企盼公司能够随着时间的推移而发展。 一个小的步骤是用“测试优先”方法来取代“测试最后”,最重要的是,在一天结束的时候最终的代码是实际测试的代码。测试将再次改进我们的要求,并允许我们专注于代码的功能 – 即其设计和结构,而不是其在技术上的运作方式。开发人员需要谨记,他/她主要是为企业编码,而不是为自己编写,所以措辞需要非常清晰。开发人员之间的任何误解都会导致错误。可以肯定的是,此类错误不会引起你的代码无法工作,但是当另一个开发人员试图以你计划以外的方式使用你的方法时,会导致进一步的错误。

我通常拿写代码和写书进行比较。没有作者会严格按照顺序去写,他们不会把前面的章节写完美了才开始下面的部分。一般的作者总是从一个轮廓开始,之后再来改进每一页,并不断修正直至完美。在编码上,经过一轮测试并得出“代码能工作”并不是好的代码标准。你必须改进你的代码直到它变得完美。如果代码能工作了,你不仅仅要测试,你还要一直保证代码尽可能明晰。

余下全文(1/3)

本文最初发表在oschina,文章内容属作者个人观点,不代表本站立场。

分享这篇文章:

请关注我们:

发表评论

电子邮件地址不会被公开。 必填项已用*标注