• 代码质量第 3 层 可读的代码


    点击一键订阅《云荐大咖》专栏,获取官方推荐精品内容,学技术不迷路!

    可读的代码能极大的提高开发效率。在开发的过程中,有很大一部分时间是在阅读代码。可读的代码,容易理解,也容易改。反之,不可读性的代码,读起来心情很差,改起来也容易出错。

    下面是一段不可读读的代码:

    const user = ...
    const foo = (cb) => ...
    const bar = (list, cb) => ...
    const other = (list1, list2) => ...
    
    if(user ? user.isAdmin : ((user.permission && user.permission.view) ? user.permission.view === true :  false)) {
      foo((res) => {
        if(res && res.ok && res.list && res.list.length > 0) {
          bar(res.list, (res2) => {
            if(res2 && res2.ok && res2.list && res2.list.length > 0) {
              other(res.list, res2.list)
            }
          })
        }
      })
    }
    

      

    以上代码有这些问题:

    • 函数的命名和功能不符。
    • if 条件太复杂,而且嵌套深。
    • 回调函数嵌套深。

    将上面的代码改成可读的代码:

    const user = ...
    const fetchChannel = () => ...
    const fetchArticle = (list) => ...
    const render = (channelList, articleList) => ...
    
    const hasViewPermission = user.isAdmin || user.permission?.view
    if(!hasViewPermission) {
      return
    }
    
    const { ok, list: channelList} = await fetchChannel()
    if (!(ok && channelList?.length > 0)) {
      return
    }
    
    const { ok: fetchArticleOk, articleList } = await fetchArticle(channelList)
    
    if (!(fetchArticleOk && articleList.length > 0)) {
      return
    }
    render(channelList, articleList)
    

      

    总结来说,可读的代码主要有如下的特点:

    • 一致的代码风格。
    • 合理的命名。
    • 必要的注释。
    • 没有大文件。
    • 没有嵌套很深的代码

    如何写出可读代码?

    写出可读代码,要满足上面提到的特点。

    一、一致的代码风格

    一致的代码风格指:空格,缩进,命名风格(驼峰,中划线等)等在整个项目里是一致的。一致的代码风格,看起来很整齐,也能减少理解成本。在项目中,用怎样的代码风格不重要。重要的是,风格要一致。

    前端业界比较有名的代码风格有:Airbnb JavaScript Style GuideJavaScript Standard Style。不想折腾的,可以使用 JavaScript Standard Style。JavaScript Standard Style 的特点:

    • 无须配置。 史上最便捷的统一代码风格的方式,轻松拥有。
    • 自动代码格式化。 只需运行 standard --fix 从此和脏乱差的代码说再见。
    • 提前发现风格及程序问题。 减少代码审查过程中反反复复的修改过程,节约时间。

    确定了代码风格后,可以用检查工具 ESLint 来保证代码风格的统一。每次代码提交前,做检查,可以用工具:husky。对于大项目,检查整个项目太慢。用 lint-staged 只检查本次改动的文件。

    二、合理的命名

    There are only two hard things in Computer Science: cache invalidation and naming things. 计算机科学中只有两件事很难:缓存失效和命名。 -- Phil Karlton

    好的命名是“看其名而知其意”。具体来说,好的命名有如下特点。

    直白的,有意义的

    好的命名是易于理解的,也就是直白的,有意义的。比如:fetchUserInfo

    推荐:故宫命名法

    提取目标对象的关键特征来命名。

    推荐命名工具: CODELF。它帮你搜索 Github、GitLab 等网站中,你想查找的内容的不同命名。

    注意,命名中的单词不要拼错。推荐单词拼写检查工具:Code Spell Checker

    遵循行业惯例

    好的命名也应该遵循行业的习惯惯例。如:业界惯例 id 作为唯一标识命名,不要用 identifier。i、j、k 用来做循环计数变量命名。

    符合代码风格

    好的命名应该符合当前项目的代码风格。如:驼峰风格等。

    不好的命名有如下特点:

    无意义的名字

    无意义的名字,如:foo, bar, var1, fun1。

    太过抽象的名字

    太过抽象的名字,如:data,res,temp,tools。

    会有歧义的简称

    会有歧义的简称,如:mod。你可能无法确认到底是 mode 或 module。

    不必要的上下文信息

    // bad
    function async getUserName (userId) {
      const userName = await fetchUser(userId)
      return userName
    }
    
    // good
    function async getUserName (id) {
      const name = await fetchUser(id)
      return name
    }

    太长的名字

    太长的名字,不容易理解。如:fetchGraintYoungestBoyName。优化方式:将不重要内容省略掉。如改成:fetchBoyName。

    三、必要的注释

    注释是是对代码的解释和说明。好的代码是自我解释的。对于不复杂的代码,不需要注释。如果写的注释,只是解释了代码做了什么,不仅浪费读者的时间,还会误导读者(注释和代码功能不一致时)。

    需要写注释的场景:

    • 当代码本身无法清晰地阐述作者的意图。
    • 逻辑比较复杂。

    四、没有大文件

    大文件指:代码行数很多(超过1千行)的文件。大文件,意味代码做了很多事,很难跟踪到底发生了什么。

    可以用 ESLine 中 max-lines 规则来找出大文件。

    优化方案:按功能,将大文件拆分成若干小文件。

     

    五、没有嵌套很深的代码

    嵌套很深的代码,可读性很差,让人产生“敬畏感”。比如:

    fetchData1(data1 =>
      fetchData2(data2 =>
        fetchData3(data3 =>
          fetchData4(data4 =>
            fetchData5(data5 =>
              fetchData6(data6 =>
                fetchData7(data7 =>
                  done(data1, data2, data3, dat4, data5, data6, data7)
                )
              )
            )
          )
        )
      )
    )

    下面是几种常见的嵌套很深的场景。

    1.回调地狱

    用回调函数的方式来处理多个串行的异步操作,会造成嵌套很深的情况。俗称“回调地狱”。如:

    fetchData1(data1 =>
      fetchData2(data2 =>
        fetchData3(data3 =>
          done(data1, data2, data3)
        )
      )
    )

    2.if 嵌套很深

    在条件语句中,如果判断条件很多,会出现嵌套很深或判断条件很长的情况。比如,判断一个值是否是: 1 到 100 之间,能被 3 和 5 整除的偶数。这么写:

    const isEvenNum = num => Number.isInteger(num) && num % 2 === 0
    const isBetween = num => num > 1 && num < 100
    const isDivisible = num => num % 3 === 0 && num % 5 ===  0
    
    if (isEvenNum(num)) { // 是偶数
      if(isBetween(num)) { // 1 到 100 之间
        if(isDivisible(num)) { // 能被 3 和 5 整除
            return true
        }
        return false
      }
      return false
    }
    return false

    三元表达式也会出现嵌套很深的情况:

    a > 0 ? (b < 5 > ? (c ? d : e) : (f ? g : h)) : (i ? j : k)

    3.函数调用嵌套

    执行多个函数调用,每个函数输出是下个函数的输入,会造成很深的嵌套。如:

    // 模拟炒蛋的过程:买蛋 -> 打蛋 -> 炒蛋 -> 上桌。
    toTable( // 第四步: 上桌
      fry( // 第三步: 炒蛋
        handle( // 第二步: 打蛋
          buy(20) // 第一步: 买蛋
        )
      )
    )

    4.React 高阶组件嵌套

    在 React 写的应用中,会出现一个组件被很多个高阶组件(HOC)包裹,造成嵌套很深的情况。如:

    class Comp extends React.Component {...}
    
    Wrapper5(
      Wrapper4(
        Wrapper3(
          Wrapper2(
            Wrapper1(Comp)
          )
        )
      )
    )

    5.React Context 嵌套

    在 React 写的应用中,可以用 Context 来管理子组件间的数据共享。如果共享数据很多,而且类型不同,容易造成顶部组件 Context 嵌套很深。如:

    <PageContext.Provider
      value={...}
    >
      <User.Provider
        value={...}
      >
        <Project.Provider
          value={...}
        >
          <ChildComp />
        </Project.Provider>
      </User.Provider>
    </PageContext.Provider>

    优化方案见: 这里

    总结

    符合本文提到的可读代码特点的代码,可读性都不会差。当然,还有很多能提升代码的可读性的技巧。比如:

    • 限制函数的参数数量。
    • 限制函数的圈复杂度。
    • 禁用 with 语句。

    要了解更多提升代码可读性的技巧,推荐撸一遍 ESLint 的规则

    代码质量的下一层次就是:可复用的代码。我会在下一篇文章中介绍。

    金伟强往期精彩文章推荐:

    代码质量第 4 层 - 健壮的代码

    代码质量第 5 层 - 只是实现了功能

    聊聊代码质量 - 《学得会,抄得走的提升前端代码质量方法》前言

    《云荐大咖》是腾讯云加社区精品内容专栏。云荐官特邀行业佼者,聚焦于前沿技术的落地及理论实践之上,持续为您解读云时代热点技术、探索行业发展新机。点击一键订阅,我们将为你定期推送精品内容。

     
    海量技术实践经验,尽在云加社区! https://cloud.tencent.com/developer
  • 相关阅读:
    better-scroll 外层可以用positon:fixed 内层只能用position:absolute,不能用positon:fixed
    react中let一些数据是在render里,不是在retrun里
    onClick和ontouchmove一个是pc端一个是移动端,但是还是不知道有什么具体差别
    react中reder->return里: 1.有引号输入内容为'123' 2.没有引号输入内容为<p>123</p>
    if( 1<a<5 )这种写法是错误的,计算机不认识。正确写法是( a>1 && a<5),要不然会有运算法呢
    e.target
    transform: translateY(-50%) 实现元素垂直居中效果
    Uncaught TypeError: Cannot read property 'trim' of undefined
    push()方法返回的是数组新的长度
    transparent是透明的意思,实际上background默认的颜色就是透明的属性
  • 原文地址:https://www.cnblogs.com/qcloud1001/p/15797193.html
Copyright © 2020-2023  润新知