0%

代码整洁之道

第2章 有意义的名称

2.2 名副其实

  • 变量 函数或类的名称都应该已经回复了所有的大问题。它应该告诉你,它为什么会存在,它做什么事,应该怎么用。如果名称需要注释来补充,那就不算是名副其实。

2.3 避免误导

程序员必须避免留下掩藏代码本意的错误线索。

  • 1.避免使用与本意相悖的的词: 别用accountArray来指称一组账号,除非它真的是Array类型。
  • 2.提防使用差别较小的名称。
  • 3.别用人眼误导性名称:小写i和大写O和常量“1”与“0”很相似。

2.4 做有意义的区分

  • 废话是另一种没意义的区分。如果有一个Product类。如果还有一个ProductInfo或ProductDate类,那它们的名称虽然不同,意思却无区别

2.5 使用读得出来的名称

2.6 使用可搜索的名称

  • 单字母名称和数字常量有个问题,就是很难在大篇文字中找出来。单字母的名称仅用于短方法中的本地变量,名称长短应与其作用域大小相对应。

2.9 类名

  • 类名和对象名应该是具体的名称或名词短语,如Customer,WikiPage,Account,AddressParser。避免使用不具体的Manager,Processor,Data,Info这样的类名。类名不应该是动词。

2.10 方法名

  • 方法名应当是动词或者动词短语,如postPayment,deletePage,或save

2.12 保持命名风格统一

  • fetch,retrieve,get意思上相当相近,如在同一个项目中只使用一个则阅读起来相当明了。

2.16 添加有意义的语境

  • 通常添加前缀为读者提供语境,会让读者明白这些变量是某一个更大结构的一部分。

2.17 不要添加没用的语境

  • 如果短名称足够清楚,就要比长名称好。别给名称添加不必要的语境。

第3章 函数

3.1 短小

  • 函数第一规则就是要短小,每行都不应该有150个字符那么长。函数也不应该有100行那么长,20行封顶最佳。

3.2 只做一件事

  • 1.如果函数只是做了该函数名下同一抽象层的步骤,则函数还是做了一件事
  • 2.要判断函数是否不止做了一件事,还有一个方法,就是看是否能再拆出一个函数,该函数不仅是单纯的重新诠释其实现。

3.3 每个函数一个抽象层级

  • 我们想让代码拥有自顶向下的阅读顺序。我们想要每个函数后面都跟着位于下一抽象层级的函数,这个样子我们查看函数列表时,就能依循抽象层级向下阅读了。

3.4 switch语句

  • 我们无法避开switch语句,不过还是能确保每个switch都埋在较低的抽象层级,而且永远不重复

3.5 使用描述性的名称

  • 别害怕长名称。长而具有描述性的名称,要比短而费解的名称好。

3.6 函数参数

  • 1.对于输入参数最理想的参数数量是零,其次是一,再次是二,应当尽力避免三
  • 2.不要通过参数输出(也是就通常的对象改变影响外部对象),我们惯于通过参数输入函数,通过返回值从函数中输出。我们不太期望信息通过参数输出。
  • 3.标示参数丑陋不堪。向函数传入布尔值简直就是骇人听闻的做法,着意味着大声宣布本函数不止做一件事。

3.7 无副作用

  • 有副作用的函数,都是具有破坏性的,会导致古怪的时序耦合及顺序

3.8 分割指令与询问

  • 函数要么做什么事,要么回答什么事,但二者不可兼得。函数应该修改某个对象的状态,或者返回该对象的有关信息。

3.9 使用异常代替返回错误码

  • 将指令式函数错误代码返回一反面违反了分割指令与询问,另一方面有可能导致更深层的嵌套解构。使用try/catch将错误处理代码从主路径中分离出。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    if(delatePage(page)  == E_OK) {
    if(registry.deleteReference(page.name) == E_OK) {
    if(configKeys.deleteKey(page.name.makeKey()) == E_OK ){
    console.log("page deleted");
    } else {
    console.log("configKey not deleted");
    }
    } else {
    console.log("deletReference from regitry failed");
    }
    } else {
    console.log("delete failed");
    return E_ERROR;
    }
1
2
3
4
5
6
7
try{
deletePage(page);
registry.deleteReerence(page.name);
configKegs.deleteKey(page.name.makeKey());
} catch(e){
console.log(e.message);
}

3.9.1 抽离try/catch代码块

  • 将try/catch代码块从主体中抽离出来,形成单独的函数。代码更整洁

3.10 别重复自己

  • 重复可能是软件中一切的邪恶根源

3.12 如何写出这样的函数

  • 写代码和写文章一样都是需要打磨的,一开始的混乱需要一点点的改变

第五章 格式

5.2 垂直格式

  • 单个文件代码行数在500行以下平均在100左右是一个很好的建议。

5.2.2 概念间垂直方向上的区隔

  • 几乎说有代码都是从上往下读,从左往右读。每行展示一个表达式或一个子句,每组代码行展示一条完整的思路。这些思路用空白行区隔开来。

5.2.3 垂直方向上的靠近

  • 如果说空白行隔离概念。靠近的代码行则暗示它们之间紧密关系。所以,紧密相关的代码应该相互靠近。

5.2.4 垂直距离

关系密切的概念应该相互靠近。

  • 如变量声明应尽可能靠近其使用位置
  • 相关函数:若某个函数调用了另一个,就应该把它们放在一起,而且调用者应该尽可能放在被调用者上面.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    let request = null;
    let crawler = null;

    function makeResponse(context, request){
    let pageName = getPageName(request, "FrontPage");
    loadPage(pageName, context);
    if(page == null){
    return notFoundResponse(context, request);
    }else{
    return makePageResponse(context);
    }

    function getPageName(){}
    function loadPage(){}
    function notFoundResponse(){}
    function makePageResponse(){}
    }
  • 概念相关:概念相关的代码应该放在一起。相关性越强,彼此之间的距离就该越短,相关性赖在如函数间调用,或者使用某个变量,也可能来自执行相似操作的一组函数。

5.2.5垂直顺序

  • 一般而言,我们想自上向下展示函数调用顺序。也就是说,被调用的函数应该放在执行调用的额函数下面。 我们希望最重要的概念先出来,指望以包括最少细节的方式表述它们,我们希望底层细节最后出来,而不是一开始就沉迷于细节。

5.3.1 水平方向上的间隔与靠近

  • 我们使用空格字符将彼此紧密的连接到一起,也用空格字符将相关性较弱的事物隔开。

第6章 对象和数据结构

  • 类并不是间断的取赋值,更多是抽象接口,以便用户无需了解数据的实际就能操作数据本体
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    function Point(){
    let x;
    let y;

    function getX(){
    return x;
    }
    function getY(){
    return Y;
    }
    function getArea(){
    return x*y*2;
    }

    return {
    x:getX,
    y:getY,
    area:getArea
    };
    }