美文网首页
个人精进系列-好的代码-命名/注释

个人精进系列-好的代码-命名/注释

作者: JayWu的架构笔记 | 来源:发表于2020-05-09 13:07 被阅读0次

    为什么需要好的代码?

    大部分时间用于阅读和理解代码

    • 词不达意的命名将影响思考和注意力
    • 好代码会明确告诉你它在做什么

    借鉴学习

    • 当我们看到写得很漂亮的代码时,会很受启发
    • 鼓励你把自己的代码写得更好

    防止破窗

    破窗效应

    • 环境中的不良现象如果被放任存在,就会诱使人们仿效,甚至变本加厉。

    • 一幢有少许破窗的建筑,如果破窗不被修理好,可能将会有破坏者破坏更多的窗户。
      最终,他们甚至会闯入建筑内,如果发现无人居住,也许就在那里定居或者纵火。

    • 一面墙,如果出现一些涂鸦而没有被清洗掉,那么很快,墙上就布满了乱七八糟、不堪入目的东西

    • 一条人行道有些许纸屑,不久后就会有更多垃圾,最终人们会视若理所当然地将垃圾顺手丢弃在地上。

    • 这个现象,就是犯罪心理学中的“破窗效应”。

    如何防止

    • 任何不良现象会无线扩散,不要做“打破第一扇窗”的人
    • 整洁的代码需要每个人的精心呵护,需要整个团队都具备一些工匠精神
    • 编码前,多想想别人是否觉得你的代码容易理解
    • Code Review机制,及时发现和修复“破窗”

    什么才是好的标准?

    代码约少越好?

    • 单行代码:

      findId(x) >= 0 ? y * (1 + y) : y / (1 - z);
      
    • 等价代码:

      if (findId(x) >= 0) {
        y * (1 + y);
      } else {
        y / (1 - z);
      }
      

    好的标准

    别人理解代码所需的时间最小化

    命名

    命名很难

    • 表达性好的名字需要深思熟虑
    • 抽象和思考过程(人是懒惰的)
    • 找不到合适名字,说明对问题理解不够透彻

    保持一致性

    每个概念一个词

    • 贯穿其中
    • 常用方法名称约定
      • 新增create
      • 添加add
      • 删除remove
      • 修改update
      • 查询(单个结果)get
      • 查询(多个结果)list
      • 分页查询page
      • 统计count

    使用对仗词

    • 保持对称
    • 常用组合
      • add/remove
      • increment/decrement
      • open/close
      • begin/end
      • insert/delete
      • show/hide
      • create/destroy
      • lock/unlock
      • source/target
      • first/last
      • min/max
      • start/stop
      • get/set
      • next/previous
      • up/down
      • old/new

    后置限定词

    • 表示计算结果的变量,限定词置后
    • 突出主要含义
      • revenueTotal(总收入)
      • expenseTotal(总支出)
      • revenueAverage(平均收入)
      • expenseAverage(平均支出)

    统一业务语言

    • 减少各方沟通成本

    统一技术语言

    • 如ddd术语

    为名字附带更多信息

    public String start(long delay)
    

    调整

    若变量是一个度量(如时间、长度),带上它的单位。

    public String start(long delaySecs)
    

    用具体代替抽象

    例1

    // 检查服务是否可以监听某个指定的TCP端口
    public void canStart(int port)
    // 完成后触发
    public void trigger()
    

    调整

    要具体,不能空泛

    public void canListenOnPort(int port)
    
    public void triggerAfterCompletion()
    

    例2

    processingData
    

    调整

    validateUserCredentials
    

    例3

    popRecord()
    

    调整

    要体现做什么,而不是怎么做

    getLatestEmployee()
    

    显化隐藏的计算过程

    Matcher matcher = headerPattern.matcher(line);
    if(matcher.find()){
        headers.put(matcher.group(1), matcher.group(2));
    }
    

    调整

    命名有含义中间变量,显化隐藏的计算过程

    Matcher matcher = headerPattern.matcher(line);
    if(matcher.find()){
        String userId = matcher.group(1);
        String userName = matcher.group(2);
        headers.put(userId, userName);
    }
    

    名字应该有多长?

    采用非常具体的描述性的名字?

    public String newNavigationControllerWrappingViewControl()
    

    只用单个单词或者单一字母的名字?

    public String s2d()
    

    名字应该恰如其分

    在小的作用域可以使用短的名字
    if (debug) {
        Map<String,Integer> m = new HashMap();
        lookUpNamesNumbers(m);
        System.out.println(m);
    }
    
    为作用域大的名字采用更长的名字
    Map<String,Integer> userNameAgeMap = new HashMap();
    // more code
    public void someMethod() {
        lookUpNamesNumbers(userNameAgeMap);
    }
    
    缩略词
    doc => document
    str => string
    
    丢掉没用的词
    convertToInt() => toInt()
    

    不会误解的名字

    例1

    假设有一个函数用于剪切段落的内容:

    public String clip(String text, int length)
    

    猜想

    • 从尾部删除length的长度?
    • 截掉最大程度为length的一段?

    调整

    public String truncate(String text, int maxLength)
    

    例2

    public static final int CART_TOO_BIG_LIMIT = 10;
    

    CART_TOO_BIG_LIMIT的边界?

    使用代码

        if(shoppingCart.size() >= CART_TOO_BIG_LIMIT){
          System.out.println("Too many items in cart.")
        }
    

    购物车逻辑为最多不能超过10件商品

    调整

        public static final int MAX_ITEMS_IN_CART = 10
    

    给布尔值命名

    boolean readPassword = true;
    

    猜想

    • 我们需要读取密码?
    • 已经读取了密码?

    调整

    boolean needPassword = true;
    
    boolean userIsAuthenticated = true;
    

    更多

    加上像is、has、can或者should,把布尔值变得更加明确

    与使用者的期望想匹配

    public double getMean() { 
        // Iterate through all samples
        // and return total / samplesSize
    }
    
    • 期望中的get应该是“轻量级访问器”,可以随意调用。
    • 假如存在大量的数据,随意调用将付出很大的代价。

    调整

    public double computeMean()
    

    注释

    什么不需要注释?

    不要为那些从代码本身就能快速推断的事实注释

    // Find the Node in the given subtree,
    // with the given name, using the given depth.
    Node findNodeInSubtree(Node subtree, String name, int depth);
    
    • 不要复述功能

    • 对于这种注释,要么删除,要么改进

      // Find a Node with the given 'name' or return NULL.
      // If depth <= 0, only 'subtree' is inspected.
      // If depth == N, only 'subtree' and N levels below are inspected.
      Node findNodeInSubtree(Node subtree, String name, int depth);
      

    不要给不好的名称加注释

    // Releases the handle for this key. 
    // This doesn't modify the actual registry.
    void deleteRegistry(String key);
    

    调整

    void releaseRegistryHandle(String key);
    

    好代码 > 坏代码 + 好注释

    代码即文档

    加入评论

    例1

    // 出乎意料的是,对于这些数据用二叉树比用哈希表快40%

    // 哈希运算的代价比左/右比较大得多

    例2

    // 作为整体可能会丢掉几个词,这没有问题,要100%调整太难了

    例3

    注释也可以用来解释为什么代码写得不那么整洁:

    // 这个类正在变得越来越乱

    // 也许我们应该建立一个ResourceNode子类来帮助整理

    为代码中的瑕疵写注释

    // TODO 采用更快的算法

    • 随时把代码将来应该如何改动的思想用注释记录下来 {:&.moveIn}。

    • 这种注释给读者带来对代码质量和当前状态的宝贵见解,甚至可能会给他们指出如何改进代码的方向。

    给常量加注释

    public final static int NUM_THREADS = 8;
    

    这一行看上去可能不需要注释,但很可能选用这个值的程序员需要知道得比这个要多。

    调整

    ```java
    // as long as it's >= 2 * num_processors, that's good enough.
    public final static int NUM_THREADS = 8;
    ```
    

    站在读者的角度

    意料之中的提问

    • 当别人阅读你的代码时,有些部分更可能让他们有这样子的想法:

      什么?

      为什么会这样?

    • 你的工作就是要给这部分加上注释。

    公布可能的陷阱

    • 当作为一个函数或者类写注释时,可以问自己这样的问题:

      这段代码有什么出人意料的地方?

      会不会被误用?

    • 未雨绸缪,预料到人们使用你的代码时可能会遇到的问题。

    “全局观”注释

    对于团队的新成员来讲,最难的事情之一就是理解“全局观”。

    // 这段代码把我们的业务逻辑与数据库粘在一起。任何应用层代码都不应该直接使用它。

    // 这个类看上去很复杂,但它实际上只是个奇妙的缓存。它对系统中的其他部分一无所知。

    这正是那种应该包含在高级别注释中的信息。

    克服“作者心理障碍”

    当你对写注释犹豫不决时,

    最好的办法就是直接把你心里所想写下来,

    虽然这种注释可能是不成熟的:

    // 哦,天啊,如果一旦这个东西在列表中有重复的话会变得很难处理的。

    调整

    • 不管你心里想什么,先把它写下来
    • 读一下这段注释,看看有没有什么地方可以改进
    • 不断改进

    // 小心:字段代码不会处理列表中的重复数据(因为这很难做到)

    相关文章

      网友评论

          本文标题:个人精进系列-好的代码-命名/注释

          本文链接:https://www.haomeiwen.com/subject/jbzhnhtx.html