人最大的痛苦,便是无法跨越知道和做到的距离 ——罗翔

该篇不写那些费脑的硬常识点了,聊点认知方面,些许轻松点的话题: 代码整齐之道。

对本职工作认真负责,是一种基本素养,对于一线正在撸代码的程序员,写好代码是一种本分,所以给我个人给本篇再加一个副标题—— 程序员工作素养。

引子

编程文明拥有悠久的历史,这个话题也被前辈们广泛讨论过,自己也在不同场合中和朋友、搭档零零碎碎的聊过一些,还在某乎上答复过几个问题,之所以再正式的聊这个话题,是由于在近期我司产品研发部总监做了一次共享,叫做代码整齐之道,听完仍是有所牵动。

声明:该篇不是照本宣科,是《代码整齐之道》+ 总监的技术共享 + 自身工作经历结合。

代码整洁之道

  • 在座有多少人读过此书?我认为这本书应该是所有程序员都需求去读的。
  • 有谁曾为自己写了一段好的代码沾沾自喜?
  • 又有谁在过了许久看自己之前写的代码有过感触:写的依旧不错/糟糕透顶?

这是来自共享开篇的一些提问,不知是否牵动了各位读者,咱们也能够在心中答复一下,沉思过后信任各位读者会有些话要说,对于现已手撸千万行的你,也一定有自己的一套“代码整齐之道”,咱们不妨一同走过下文,在这过程中比照一下你心中的“道”。

本文目的:重温一些代码整齐之道,希望能够给日常撸事务的你带来一些动力/兴致/小幸福。

为什么要写整齐的代码

说这个问题,咱们反向的想一下,面临不整齐的代码会怎么样(“屎山”),是不是有很多话想说,我来起个头,说一下自己曾吐槽过的(代码就不上图了):

  • 这么杂乱的逻辑,变量/函数姓名给个缩写,你让咱们猜它是谁/干啥呢?
  • js 里一个函数有 7、8 个参数,又没类型,光看调用来回切换要花十几分钟,闹呢?
  • 一个函数放好几百行代码,让我来回切换,你是怕我得颈椎病啊?
  • 在一些底层核算呈现莫名的数值,不明不白的就加上或减去一个数字,咱也不知道它表达的啥?
  • if 判断的条件,直接写核算表达式或函数,能有个 4、5 行,每次看这段代码都要花很长时刻,还总是出 bug,这不当妥的“雷区”?
  • 这注释分明写的是 a 逻辑,成果下面代码写的是 b 逻辑,坑啊…
  • 如出一辙的代码,复制 n 遍,写这段代码的脑子有坑吧。
  • 一个函数分明写的是 getXXX,成果里边改原始数据?出 bug 找半响,nm。
  • ……

所以,写出整齐的代码便是防止少呈现以上呈现的状况,能够总结为以下几条:

  • 更具可读性
  • 更节约时刻、更高效
  • 更易保护
  • 更具扩展性
  • 更易重用
  • 更简单测试

命名

命名是程序界一级难题

起一个好的姓名,至关重要,但并不简单,我常常为了起一个好的姓名抓耳挠腮的,有时分跟协作的人会 battle 半响,咱们需求建立一个认知: 在久远来看,花费大量时刻来挑选一个好姓名是值得的,由于它所带来的价值或节约的时刻远远超过了起名所花费的时刻

起姓名也分几个等级:

  1. 最基本的也是见名知意
  2. 好一点的能够更恰当的体现事务
  3. 再高档一点的能够覆盖领域的概念

有爱好咱们能够看下,《架构师修炼之道》提出对的 7 个阶段,以及怎么提炼一个好的姓名,下图是之前截的片段

代码整洁之道

假如要写全关于怎么命名我怕是再写上 1000 字也不一定够,所以下面只写一些比较简单做到的,也是最基本的底线:

  1. 姓名尽或许具体些(不要怕长),少用缩写 ,除非是咱们一致的(JDBC、XML)
    // bad
    const act = 1; // 不清楚是 active 仍是 action
    function recursion() {}; // 只知道递归,可是不知道为什么要递归
    // good
    const action = 10;
    function getAllChildrenByNodes() {}
  1. 尽或许起一些简单的单词,最好能读出来,能写出来,简单记住的常规单词 ,幻想一下,搭档之间讨论读不出来这个单词的尴尬场景,记得之前做的一个商城项目,搭档在规划表的时分用了一个单词 integration ,这个单词的本意是数学中的积分,而事务中实际上表达用户积分。这里有一份软件开发常用词汇表: 这里
  2. 变量用名词或形容词 + 名词,函数名用动词 + 名词或动词 + 形容词 + 名词,类名用名词
    function calculateTotalPrice(){} // 核算总价
    function validateUserPermission(){} // 验证用户权限
    const customerName = "zhangsan"; // 客户姓名
    const recentOrders = [] // 最近的订单
    class PermissionBuilder() {} // 权限结构器
  1. 布尔值或函数用 is 或 has 开头,能优先用必定,不要用否定,更不要用两层否定表示必定 ,这很不高效
    // bad
    isNotVisible = true;
    // good
    isVisible = false;
    // bad
    isNotInvisible = true; // 不是不行见的,表示可见的
    // good
    isVisible = true;

函数

  1. 函数尽或许的短小 ,有爱好看一些知名函数编程的库: Lodash 。
  2. 参数尽或许的少 ,最佳状态是没有参数,其次是 1 个、2 个、3 个,理论上最好不要超过 3 个,不过具体仍是要根据实际场景,有些状况下也难以防止。
  3. 遵从单一原则,一个函数只做一件事 。一个判断的小技巧:尝试幻想对一个函数做单元测试,每能够测的一点就能够罗列一个函数。
  4. 参数最好不用布尔值,在参数多的状况最好运用对象替代 ,由于每次调用时都需求看一下原函数的参数是什么,顺序也要对照好,扩展也不方便,会越来越长。示例:
    function getUsersByIds(ids: string[], isDeleted?: boolean, isArchived?: boolean){}
    getUsersByIds([], true, true);
    // good
    function getUsersByIds(ids, options: {isDeleted?: boolean, isArchived?: boolean}) {}
    getUsersByIds([], { isDeleted: true, isArchived: true})
  1. 函数尽或许不要依靠上下文 ,这点能够按照纯函数原则。
  2. 函数名、签名和函数逻辑和回来值有必要保持一致, 挂羊头卖狗肉的行为非常可气,误导比读不明白代码更可怕,比方:
    // 这个函数本意只是验证用户名是否合法,成果内部却包括修正用户信息的逻辑
    function verfiyUserName(user) {
      const regexp = /^[a-zA-Z0-9_-]{3,16}$/;
      if(regexp.test(user.name)) {
    	user.name = 'legal_' + user.name;
        return true;
      } else {
      	return false;
      }
    }
    const user = {id: 1, name: 'zhangsan' };
    const result = verfiyUserName();
  1. 函数不要发生副作用,尽或许不要改动原数据或上下文数据,运用不行变数据(Immutable Data) ,js 中也有一些让人诟病的原生函数,比方 sort、reverse、splice 等能够 filter 、map 或解构替代
    const users = [
      {id: 2, name: '张三'},
      {id: 1, name: '李四'},
      {id: 3, name: '王五'}
    ];
    // 从用户列表中删去姓名是王五的元素
    const newUsers = users.filter(x=> x.name !=='王五');
    // 按照 id 排序
    const newUsers = [...users].sort((a, b) => a.id - b.id);
  1. 提取重复的逻辑:咱们应该时刻警醒,不要重复自己,当遇到两块一样的代码时,就要反思是不是能够提取出来。

注释

注释是弥补咱们在用代码表达意图的失败体现 ——《代码整齐之道》

代码是具有体现力,所以书中以及我个人也是激烈不主张不加注释的,便是说能用代码表达就不要用,用注释表述不如起一个更恰当的姓名,更好的函数签名。

由于很大程度上,咱们添加了注释就要保护这段注释,又由于注释是不参与真正运行的,所以在后续的需求变化以及重构很简单呈现注释没有及时更新,注释所描绘的状况和实际运行的代码是不相匹配的,等其他人再看到这段代码时就会被误导,这种状况下过错的注释比没有注释更可恶。

再考虑一下,你平常是怎么运用注释的,又为什么注释?

有意义的注释

  • 法律信息或许可证相关信息

代码整洁之道

  • 对外的接口,如 Public API、RPC Interface 等,通过注释能够让调用者快速了解怎么运用,回来成果完整的描绘

代码整洁之道

  • API Doc 用来生成文档的注释,并且经常要通过 URL 快速定位 API

代码整洁之道

  • 描绘杂乱的程序或事务

代码整洁之道

代码整洁之道

  • TODO:定义待办,应该做,可是由于某些原因目前还没做的, 需求留意的是,定期回忆这些 TODO,补充并删去

代码整洁之道

  • 抛弃的办法注释

代码整洁之道

  • 警示

代码整洁之道

  • 特殊阐明的注释 ,由于某些事务优先级高,经常出 Bug 的代码,改动需求做出解释

代码整洁之道

无意义的注释

  • 现已不在运用的代码,你或许觉得有或许还需求运用,所以暂时先注释,对于这种注释咱们大胆的删掉,别慌,版别控制东西会保存修正记载

代码整洁之道

  • 变量或函数名、签名现已表明清楚意图的代码,就不要额外再用注释

代码整洁之道

代码整洁之道

用代码的体现力替代注释

  • 运用新变量 ,由于变量名自身就有阐明的意义

代码整洁之道

  • 起一个好姓名 ,与其花心思写注释,不如把这个时刻和精力用来起一个好点的命名,如以下代码,第一个直接从姓名上很简洁的阐明该函数是核算平均值的,而第二段代码描绘不清楚,需求用两条注释来阐明先累加再求平均值,显然第一个更好

代码整洁之道

结语

正文内容就暂时告一段落,最后送给咱们三句话

  1. 觉得写的不错,能够点点赞
  2. 假如有共鸣,或者有需求补充的,能够到谈论区留言沟通
  3. 赶快把项目中的“屎山”,做个小优化吧

PS:关于怎么写出整齐的代码涉及方面实在太多了,这一篇就先到这里,假如反响好的话,后续或许会继续更。