• 关于如何读懂别人的代码以及如何提高代码可读性的研究


    我现在正在做一个比较大的项目,于是我就在网上找到了一个目标比较接近的开源项目,大致测了下,大概有70%的功能是我所需要的,还有30%的功能和我要的不一样。所以我现在有2个选择:1. 自己全部重写。不过这个太费时,于是我选择 2. 修改这个项目,把自己想要的功能改出来。

    不过一个老问题又出现了:读懂这个项目比自己写更吃力。我想很多人都应该有这个感受,不然也不会有很多的轮子。所以,我干脆就仔细研究这个问题:为什么别人的代码总是那么难读。

    1. 什么叫读懂代码

    当然,读懂代码的语法是基本,但更重要的是读懂代码的意义。

    读代码的时候,我们更多思考这个问题:这行代码在做什么,为什么要这么做。然而实际上,我们仍然会碰到很多不明觉厉的代码。先看如下示例:

    int fn(int a, int b){
        int sum = 0;
        for(int i = a; i < b; i++){
             sum += fn(i - 1, i + 1);
        }
        return sum;
    }

    从语法上,代码是非常简单的几行。但是我们无法得出它的意义。因为:

    代码是在描述具体的执行步骤,而不是描述功能本身。

    这就是为什么大部分代码难读的主要原因。作者将它的意图描述成具体的步骤,而读者又需要根据步骤理解意图,这是一个多么吃力的过程。所以,如果想要提高代码可读性,你应该将你的意图写入代码中:即使用注释来描述代码的意图。当然,作者没有那么多时间留注释,所以,更多时候需要尝试自己尝试理解代码。2. 成员的嵌套

    先看如下代码:

    void fn(){
          int a = f1();
          int b = f2(a);
          int c = f3(b);
          int d = f4(a, b);
    }

    如果你想理解 fn(),那么就必须先理解 f1() f2() f3() f4() 。这就是残酷的现实。

    代码中总是互相引用和嵌套。

    所以,你需要在最后关头才能真正读懂它,并且不允许任何一部出现差错。然而实际上,读懂这样的代码是不可能的。

    比如下面的代码:

    void fn(){
       int value;
       if(this.header == null) {
           value = this.header;
       } else {
           value = this.main;
       }
    }

    这个代码让我抓狂:虽然我知道这个函数的目标是获取 header 的值,如果获取不到则使用 main 的值。但同时还有这些问题:

    header的值是什么?main的值是什么?什么时候可以获取到header的值,而什么时候又获取不到?

    如此读懂一行代码带来3个问题,在尝试解决这3个问题时又带来更多问题。这是导致代码最终很难读懂的重要原因。

    3. 代码的歧义

    有时候,一些语法现象也会造成理解代码的错误,如:

    function fn(){
    
    }
    
    function gn(){
      fn();
    
       // 这里是很长很长的代码。
    
      function fn(){
    
      }
    }

    是的,你需要读到最后才知道, fn(); 调用的是下面那个函数,而不是之前的。

    4. 运行时判断

    真的有很多代码,必须在运行时才能知道它的实际操作。虚函数和动态类型就是一个典型例子。

    这也是为什么弱类型的脚本语言的代码都普遍比较难理解的原因,有太多东西需要在运行时才知道。

    而读者只能一个个猜测它的意图。

    5. 代码的丢失

    对的,很多时候,特别是读别人的代码,你根本找不到一个效果和功能它的源码在什么地方。

    也许,代码隐藏在一个小角落,或者根本就不存在,或者是自动生成出来的。

    这是为什么C++项目难读的一个重要原因:因为有太多的自动生成的代码(通过#define) 。

    [待续]

  • 相关阅读:
    这是阿里技术专家对 SRE 和稳定性保障的理解
    阿里四年技术 TL 的得失总结:如何做好技术 Team Leader
    深度 | 阿里云蒋江伟:什么是真正的云原生?
    亲历者说 | 完整记录一年多考拉海购的云原生之路
    Seata RPC 模块的重构之路
    对容器镜像的思考和讨论
    20 行代码:Serverless 架构下用 Python 轻松搞定图像分类和预测
    怎么提升写代码的能力
    云原生 DevOps 的 5 步升级路径
    dubbo-go 白话文 | 从零搭建 dubbogo 和 dubbo 的简单用例
  • 原文地址:https://www.cnblogs.com/xuld/p/3365360.html
Copyright © 2020-2023  润新知