注意这几条,让代码少出bug或少被吐槽

254 阅读4分钟

目前关于代码质量或者代码规范的讨论和文章已经非常多了,这些讨论囊括了命名规范、代码格式、操作符的使用、质量评估和管理工具等等。本文则是作者在工作实践中总结的几条普适性地原则,不局限于语言或者框架,并且会持续更新。

不要写Magic Number

Magic Number在程序设计中有多种含义,这里指的是:

缺乏解释或命名的独特数值。常常在程序中出现多次,并且可以(从规范上而言也应当)被有名字的常量取代。

大家平时可能会遇到或写出如下代码:

switch(status) {
    case 1: {break;}
    case 2: {break;}
    case 3: {break;}
}

上述中的status就是一个Magick Number,如果不了解status取值对应的含义的话,这段代码理解起来可能就会有些障碍了。

对于这种情况,有如下建议:

  • 将这些Magic Number定义为Enum,JavaScript也可以通过对象定义 ,从而给这些数字赋予有表达意义的命名
  • 如果不采取第1条的方式,至少需要将取值的含义写在注释中,但是这种方式还是不被推荐的

条件语句的逻辑完整性

写代码时通常要写很多条件判断语句,很多人都会想,不就是if else么,没啥难的。但是根据作者的经历,相当多的业务bug都是因为if else没写好而导致,或者说就是逻辑完整性不够,更术语一点就是代码鲁棒性不足。比如下面这个h5视频播放的例子:

const video = document.getElementById('#video');
const playResult = video.play();
if (playResult instanceof Promise) {
    xxxx
}

这段代码就有一个明显的逻辑漏洞,完全没有考虑playResult不是Promise实例的情况(一些老版本的浏览器),结果就是这段代码在一些老版本的浏览器中就出bug了。

这里作者有两条建议:

  • 对于任何一个if条件,都需要思考一下是不是要处理对应的else逻辑
  • 对于多个条件组合的情况,尽量梳理一下流程图(即使是粗略地手工画一下),将所有的逻辑分支清晰地梳理出来后再进行编码

这里顺道提一句,其实刷算法题也是提升编码健壮性的一个非常好的手段,经常听到大家说刷题就是为了面试,其实不止。因为每一道算法题目的测试case都是非常全面的,除了可以学习和实践各种算法思想以外,做题目对于提升编码的健壮性同样是非常好的锻炼。

恰当的注释

关于注释的问题,团队中也有过一些讨论,甚至有同学提出完全不要写注释的观点(应该是来源于代码简洁之道)。不写代码注释这种做法的出发点是好的:代码应该是自解释的,并不需要额外的文字来解释代码的含义。但是在实际业务开发中,作者发现这种不写注释的做法是难以真正在团队中落地的,主要原因包括:

  • 在业务开发中难以避免地会使用一些hack的方法解决一些问题(比如前端设备兼容性问题),此时如果不写注释的话,不熟悉相关方式的同学必然难以理解代码的含义
  • 业务开发中,会有大量的业务逻辑代码,甚至会有一些反直觉的逻辑(产品同学秀操作。。。),一旦出现一些特殊的逻辑写法,如果不加以注释的话,其他同学必然是难以理解的

事实上,即使是非业务开发,大多数框架或者工具的代码中也都是会写注释的(比如Vue和React的源码),因此作者认为,恰当的注释是非常有必要的,但也并不意味着注释越多越好,在以下几种情况下建议是一定要写注释的:

  • 使用了一些hack的手段时
  • 编写特殊的业务逻辑时

url query中的url类型参数务必要进行encode

比如常见的登录页,一般情况下,登录成功后都会跳回到query中传入的某个url,比如这个url的query key为redirectUrl,那么当redicretUrl本身又带了查询参数时,登录页面解析query参数得到的redirectUrl就容易出现问题。

例如redirectUrl为:https://test.com/ucenter?query=queryValue&query2=query2Value

携带redirectUrl的登录页url为:https://test.com/login?redirectUrl=${redirectUrl}

如果不对redirectUrl进行encode,解析出来的redirectUrl中就会丢失query2参数,因为query2参数前也有一个&符号,会被认为是整体url中的参数之一。

正确的方式应该是:https://test.com/login?redirectUrl=${encodeURIComponent(redirectUrl)}