如何写出自我解释性很强的代码

好的代码是不需要注释的,因为它本身就能够自我说明,加上注释反而显得比较多余。不好的代码只看代码本身没法明白代码所表达的东西,必须借助注释才可以。虽然说注释应该作为一种规范,但我们还是应该尽量去提升代码的易读性自我解释性

说一下我对自我解释性很强的代码的理解和实践吧,不一定完全正确,仅供参考。

计算机中有个“ 元数据”的概念,即描述数据的数据,比如描述进程的pcb,描述文件的fcb,描述http请求体的头字段等,说起来注释也是一种元数据。

个人觉得在程序中, 变量名就是一个元数据,他描述了他所存储的变量的内容,我们要求变量名要见名知意,这样阅读代码的时候就能清晰的理出哪段逻辑处理的是什么数据,其实这个和注释的功能类似。自我解释性很强的代码就依赖于此。同理,函数名、类名、文件名、模块名、甚至项目名都有类似的作用,我们封装函数、类,拆分文件、模块、划分项目等,除了是为了逻辑复用,也有描述逻辑本身的作用。自我解释性很强的代码正是基于此。

1. 复杂逻辑的中间结果需要用变量存储

有一些逻辑需要从输入经历一系列的处理步骤才能得到最终的数据,这个过程会有很多的中间结果,有时候逻辑特别复杂,而一些中间结果比较有意义,这时候把这些中间结果用见名知意的变量所存储,会使得代码更加易读。举个栗子:

一段描述“如果明天下雨,我就不去动物园了”的逻辑的代码

     if (空气湿度大于 xxx  && 风力大于xxx && 温度低于 xxx) {
        不去动物园();
    }
     去动物园();

其中“ 空气湿度大于 xxx && 风力大于xxx && 温度低于 xxx ”描述的逻辑就是 下雨,但看逻辑却并不能一眼看出来,这时候最常见的优化思路当然就是注释:

     if (空气湿度大于 xxx  && 风力大于xxx && 温度低于 xxx) { // 如果明天下雨
        不去动物园();
    }
     去动物园();

这样是可以提升代码的易读性和可维护性,但可能会有如果这段逻辑变更,那么注释也要同步更新等一系列的问题,最好的优化方式就是提升代码本身的自我解释性,比如这里简单的加一个变量或者封装一个函数或工具类。

     let 明天下雨 = 空气湿度大于 xxx  && 风力大于xxx && 温度低于 xxx;
     if (明天下雨) { 
        不去动物园();
     }
     去动物园();

or

    function 明天是否下雨() {
        return 空气湿度大于 xxx  && 风力大于xxx && 温度低于 xxx;
    }      
    if (明天是否下雨()  === true) { 
        不去动物园();
    }
    去动物园();

以上两种方式都是自我解释性很强的,当然别的封装形式也可以。封装和拆分, 复用是一个目的,同时见名知意的名字也能起到元数据的作用,提高代码的简洁和易读性。

2. 步骤清晰的逻辑应当在代码中清晰的表现出来

有一些逻辑步骤很清晰,这时候就应该在代码中明确的表现出这种清晰来,比如:

把大象装冰箱一共分几步:

一种写法:

    把冰箱门打开xx();
    把冰箱门打开yy();
    把冰箱门打开zz();
    把大象装进去xx();
    把大象装进去yy();
    把大象装进去zz();
    把冰箱门关上xx();
    把冰箱门关上yy();
    把冰箱门关上zz();

这样是很常见的写法,也能实现功能,但是代码的可维护性却可能很低,我遇到的很多一个函数好几百行代码的,一个文件几千行代码的都是这种问题。

这种逻辑清晰的,这样封装一下会更好:

   function 把冰箱门打开(){
         把冰箱门打开xx();
         把冰箱门打开yy();
         把冰箱门打开zz();
   }
   function 把大象装进去() {
        把大象装进去xx();
        把大象装进去yy();
        把大象装进去zz();
  }
   function 把冰箱门关上() {
        把冰箱门关上xx();
        把冰箱门关上yy();
        把冰箱门关上zz();   
 }
   把冰箱门打开();
   把大象装进去();
   把冰箱门关上();

虽然总体代码量是增加的,但是逻辑的清晰度却提升了一个档次。当然这里的函数换成类、模块等都可以。

3.用到的一些设计模式要加上对应的名称

代码在拆分的过程中,我们可能会用到一些设计模式,这时候如果在名字上不体现出来,那么可能看很久才能看懂。但是只要在命名类、函数、变量的时候加以区分,那么可以让阅读代码的人很快get到代码整体的组织方式,比如Factory、Facade、Proxy、Decorator、Command等。

其实很多框架的源码在书写过程中也是这样做的,比如Struts2的RequestFacade、Mybatis的SqlSessionFactory等。这样读者在读到响应的类名的时候就能够理解这个类的功能。

同样,除了设计模式,我觉得各个目录下的代码也应该加上对应的前缀或后缀,比如XxxUtils、BaseXxx、CommonXxx等。

总结

以上,虽然只列了3点,但是主要的思想已经表达清楚了,就是合理的运用一些变量名、函数名、类名、模块名等,通过见名知意的名字来描述代码本身。

你可能感兴趣的:(如何写出自我解释性很强的代码)