整洁代码:是时候整理烂代码了

7,589 阅读7分钟

前言

如果你想成为更优秀的程序员,如果你不满足于目前的代码质量,如果你不想你的代码成为屎山的一部分,那请你看完本文,并在往后的开发中反复练习。

整洁的代码,是每个程序员所追求的。当你看到一份文件有上千甚至上万行代码,里面充满了abcdef的变量和函数,是不是只能一遍又一遍的fxxk。如果你不希望自己的代码被他人吐槽,那本文将和你一起分析为什么会产出垃圾代码什么是整洁代码,并告诉你如何去编写整洁代码。当然,最重要的还在于你,因为整洁代码要求你抱着谨慎的心态去反复练习

编写整洁代码的程序员就像是艺术家,他能用一系列变换把一块白板变作由优雅代码构成的系统。《代码整洁之道》

为什么会产出垃圾代码

一般我们 review 代码的时候,遇到垃圾代码究其原因,通常有以下这些情况:

  • 在尚未明确需求前,就开始开发:

    程序员对改需求的厌烦情绪无需多言,而如果在对需求有充分的理解之前,就盲目地开始开发,得到的产品很可能不是用户需要的,最终的结果无非是改代码。随着改动次数的增加,可以想象的是,可维护性和可读性将很快成为一个难题。

  • 以代码跑起来为最终目标:

    这是很多程序员的误区,会想当然的认为的代码已经成功满足了当下的需求,并且看起来一切完好。除非又接到新的需求,要不然就再也不会投放任何精力在这块代码上了。但是需要记住的是,祖传的屎山也总是能跑的,当我们去维护的时候作何感想呢?

  • 随意的心态:

    很多时候,我们会抱着「领导给了我这个需求,那我 C/V 一下吧」的心态去编写代码,虽然我们心知肚明这段代码可以复用,但我们随意的心态让我们一次一次机械的 C/V。直到有一天,需求发生了变动,再去找到分散在各个文件的代码,然后一处一处进行修改,如果改漏了一个,就喜提一个 BUG。

整洁代码的定义

在《代码整洁之道》一书中,几位大师给出了这样几条结论:

  • 优雅、高效:

    优雅高效的代码读起来应该是让人愉悦的,读这种代码就像见到设计精美的艺术品,能让人会心一笑。

  • 简单、直接:

    整洁的代码应该是简单直接的,能让人一目了然代码传递的信息,不需要猜测代码的意图。

  • 整洁的代码应可由作者之外的开发者阅读和增补:

    当我们回顾我们曾经写下的代码,有没有遇到过已经无法看懂代码的含义和背后的逻辑的情况。整洁的代码应该具有良好的可读性,并且当新增、改变需求时,能通过新增代码来完成需求,而不是只能靠修改原有的代码来堆砌代码。

  • 整洁的代码总是看起来像是某位特别在意它的人写的:

    何为在意代码,就是当别人 review 我们的代码时,因为几乎没有更好的方案,就算想改进也无从下手,所以只能发出赞叹。也只有抱着在意代码的心态,才能让代码更优秀,让人赞叹。

我们可以看到,整洁代码最突出的就是可读性可维护性。如果说写出让机器能跑起来的代码是一个程序员必备的条件,那么写出可读性高,甚至让人赏心悦目的代码就是一名优秀程序员该奋力追求的目标。有了可读性才能让代码易于维护,整洁代码能帮助开发者使用较小的成本完成需求的变更。

如何整洁代码

逐步改进

要写好代码,类似于写作,都是循序渐进的过程。写文章需要先有草稿,再经历一次次的修改润色才能写出一篇让自己和读者满意的文章。代码亦是如此,我们无法随意写出整洁的代码,那我们就需要不断思考存在的不足并做出改进。可怕的不是肮脏的代码,而是错误的心态。没有人可以随意写出整洁的代码,重要的需是从最小的细节开始,逐步做出改进。

我想再强调一下逐步的重要性,因为如果一次性调整过大,很可能会导致代码出现不可预期的问题,而回过头来排查又显的困难重重,最后只能放弃。所以调整的幅度要小,哪怕是一个变量名称的修改,一个方法参数的调整,都需要保持警惕。

童子军军规

童子军军规引用自美国童子军一条简单的规则:营地应该比来时更干净。借用到代码中就是要求我们需要让代码比我们对其进行改动之前更整洁。这并不一定要花多少功夫,也许只是改好一个变量名,调整一下函数参数,解决一些重复代码。总之,当我们离开一段代码的时候,它应该更接近整洁代码。

测试代码

有了测试,就不用担心对代码的修改!没有测试,每次修改都有可能带来缺陷,那么对于改动总会忧心忡忡,生怕遇到不可预知的问题。如果问测试代码最重要的一点是什么?那必须是可读性,测试代码需要明确、简洁,并且有足够的表达力。

整洁的测试应遵循的5条规则:

  • 快速:测试应该足够快。才能频繁的进行运行测试。
  • 独立:测试应该互相独立。某个测试不应为下一个测试设定条件。
  • 可重复:测试应当可在任何环境中重复通过。
  • 自足验证:测试应该有布尔值输出。
  • 及时:测试应及时编写。

整洁代码常用方案

用有意义且常用的单词命名变量:

// bad
const yyyymmdstr = moment().format('YYYY/MM/DD');
// good
const currentDate = moment().format('YYYY/MM/DD');

命名每个常量:

// bad
setTimeout(blastOff, 86400000);
// good
const MILLISECOND_IN_A_DAY = 86400000;
setTimeout(blastOff, MILLISECOND_IN_A_DAY);

参数不超过两个:

// bad
function createMenu(title, body, buttonText, cancellable) {
  // ...
}
// good
function createMenu({ title, body, buttonText, cancellable }) {
  // ...
}
createMenu({
  title: 'Foo',
  body: 'Bar',
  buttonText: 'Baz',
  cancellable: true
});

只做一件事:

// bad
function emailClients(clients) {
  clients.forEach((client) => {
    const clientRecord = database.lookup(client);
    if (clientRecord.isActive()) {
      email(client);
    }
  });
}
// good
function emailActiveClients(clients) {
  clients
    .filter(isActiveClient)
    .forEach(email);
}
function isActiveClient(client) {
  const clientRecord = database.lookup(client);    
  return clientRecord.isActive();
}

封装条件语句:

// bad
if (fsm.state === 'fetching' && isEmpty(listNode)) {
  // ...
}
// good
function shouldShowSpinner(fsm, listNode) {
  return fsm.state === 'fetching' && isEmpty(listNode);
}

if (shouldShowSpinner(fsmInstance, listNodeInstance)) {
  // ...
}

上面只列举了一部分整洁代码常用技巧,你也可以参考文章底部链接获取更多技巧。

工具

如果你想要检测代码的整洁度,可以尝试以下几个工具:

  1. SonarQube:SonarQube empowers all developers to write cleaner and safer code.
  2. DeepScan:Make Your JavaScript Better;
  3. codacy:Automate code reviews on your commits and pull requests;

总结

本文向你介绍了:

  1. 为什么产生垃圾代码;
  2. 什么是整洁代码;
  3. 怎么去整洁代码;
  4. 整洁代码的常用技巧;

感谢你阅读本文,希望能给你一点点启发。不过,文章只能告诉你理论基础,要编写整洁代码,更重要的在于往后开发中的实践。最后我想引用汉代刘向《说苑·政理》中说的:

耳闻之不如目见之;目见之不如足践之;足践之不如手辨之。——汉代刘向《说苑·政理》

推荐阅读

《代码整洁之道》

《重构:改善既有代码的设计》

JavaScript 代码简洁之道

7 个顶级静态代码分析工具