代码整洁之道读书记

3,167 阅读6分钟

有意义的命名

软件编程中命名随处可见, 如函数, 参数, 类名, 变量, 包名, 文件名等。一个好的命名能够望名知意, 方便后续的维护。

下面是一些基本的关于命名的规则:

  • 命名语意化: 有意义的命名能够替代注释

  • 避免误导性命名

    1. 命名外形上的相似
    如 数字0与字母O同时出现   变量xyzControllerForOrderOfSetting和xyzControllerForLoginSetting(需要花时间去区分)
    
    2. 语义废话,含混不清的命名
    如 同一个模块出现这样的方法或者命名(需要花时间去区分). getUserInfo/getUserData/getUser, userInfo/userData/user
    
    
  • 多使用能够读的出来的名称: 避免自造词, 多使用合乎规范的英文单词

  • 使用易搜索的名称

    1. 易搜索指的是在海量代码中快速定位到该命名
    2. 以单个字母命名的名称仅适用于短方法中的本地变量(如js中d(document),w(window))
    3. 命名的长短应该与作用域大小成对应关系
    
  • 类名

    类名与对象名应该是名词或者名词短语, 避免使用Processor, UserData等,类名不应该是动词
    
  • 方法名

    方法名应该是动词或者动词短语
    属性访问器,属性修改器,断言等应该加上get, set, is等前缀
    
  • 每个概念对应一个词, 并且一以贯之

    举例说明:
    比如你在一个类里面的同类型方法都是使用get作为前缀, 但是在另外一个类里面的方法又是使用fetch作为前缀。这就是没有保持一个概念一个词。
    
    另外就是保持你的代码风格统一性
    
  • 避免使用双关语

    避免同一个单词用于不同的目的,同一个术语用于不同的概念
    
  • 多使用大家达成统一认识的领域名称(术语)

    举例说明
    比如使用visitor(访问者)而不是accounrVistor
    Queue/jobQueue
    
  • 添加有意义的语境

    大多数时候我们是没法通过命名达到自我说明, 这个时候就需要添加适当的语境来方便我们理解。
    添加语境的方式就是给命名添加前缀。
    createXxxx / addXxx / deleteXxx / updateXxx
    
  • 避免添加无意义的语境

    当短名称足够描述清楚时候, 要优于长名称
    

    如何写好函数

  • 短小

    函数应该短小,不能太长, 20行封顶
    
  • 代码块和缩进

    if语句,else语句,while语句,switch/case中子句等, 其中的代码块应该只有一行,该行也应该是一个函数调用语句。
    例如:
    if (true) {
        // 函数调用
    } else {
        // 函数调用
    }
    
  • 一个函数应该只做一件事

    当你的函数不能再被拆开一个函数时候就标示做了一件事
    
  • 一个函数一个抽象层级(抽象逻辑块)

    代码应该保持一个自顶向下的阅读顺序。
    每一个函数后面尽可能紧跟下一个抽象层级的函数
    
  • switch语句

    switch/case语句有多个子句时候,可以把switch语句置于抽象工厂中,不对外暴露,然后工厂方法中针对不同的case语句创建不同的实体
    

  • 使用描述性的名称

  • 函数参数

    1. 函数参数个数: 理想情况函数参数个数依次为0,1,2,超过两个应该避免
    2. 当函数需要三个或者超过三个以上参数时候, 推荐把一些对象封装为类
    3. 当我们需要传入个数可变的参数时候, 可以使用参数列表
    
    
  • 动词与关键词结合

  • 对于一元函数时候, 我们可以使用动词与关键词结果方式来更好表述该函数的作用。
    举例:
    writeField(name): => 修改字段name
    
  • 无副作用

    虽然我们说函数只做一件事, 但是常常会隐式的做一些其他事情,导致异常的发生, 尤其像动态语言(Python,JavaScipt), 没有类型约束, 一不小心就修改了对象类型。
    
    避免使用输出参数, 如果参数必须要修改某种状态,索性就修改所属对象的状态
    
  • 分隔指令与询问

    函数要么做什么事情,要么回答什么事情,两者不可兼得。即
    函数要么修改某对象的状态, 要么返回该对象的有关信息
    
  • 使用异常替代返回错误码

    举例:
    一个函数deletePage(page)用错误码标示执行的结果: E_OK / E_ERROR
    如果你的代码中大量采用该风格的函数, 有时候会导致大量的if嵌套。
    
    if (deletePage(page) == E_OK) {
        if (deletePerson(person) == E_OK) {
            
        } else {
            
        }
    } else {
        
    }
    
    我们应该使用异常替代返回错误码的方式,这样错误处理代码就能把代码进行分离
    
    try (
    	// 主路径代码
    ) catch () {
        // 错误处理
    }
    
  • 抽离try/catch代码块

    函数应该只做一件事, 错误处理就是一件事 
    
  • DRY原则: 别重复自己

    消除重复 => 提取代码中能复用的模块, 复用的类, 复用的方法等
    

注释

与其给糟糕的代码添加注释不如重写

注释最大的隐患在于随着存在时间越久, 距离其所描述的代码越远, 所以对于程序员来说,应该时刻保持注释与代码的同步。

  • 注释不能美化糟糕的代码

    与其为糟糕的,难以理解的代码写注释不如花时间重写代码
    
  • 用代码来替代注释阐述内容

  • 好注释

    1. 提供信息的注释: 比如文件注释, 类注释, 函数注释等
    2. 阐述: 当我们无法通过参数或者返回值来描述代码内容时候需要通过注释来描述
    3. 警示类注释: 提醒后面维护者可能出现的结果
    4. TODO注释: 描述你未来要做的工作列表
    5. 编写公共的api注释文档
    
  • 坏注释

    1. 多余的注释: 无法提供比代码本身提供更多的信息, 或者说读注释并不比读代码效果好
    2. 误导性注释: 你的注释不够精确, 甚至本身就有错误
    3. 循规式注释(这个仁者见仁智者见智): 作者以java为例每个函数都要有javadoc是不可取的,pyhon其实也有文档字符串的约定
    4. 日志式注释: 记录代码变更或者代码log
  • 对于不再需要的注释直接删除而不是原地注释掉, 会对后续维护者产生误导