zoukankan      html  css  js  c++  java
  • 《代码整洁之道》

    第二章 有意义的命名

    2.2 名副其实:变量、函数或者类的名称要说明他们的目的。
    2.3 避免误导:避免使用关键字,避免使用0 o 1 l 等。
    2.4 做有意义的区分:要区分名称,就要以读者能鉴别不同之处的方式来区分。
    2.5 使用读得出来的名称:要使用恰当的英语词,而不是傻乎乎的自造词。
    2.6 使用可搜索的名称:避免使用单字母的名称,或者直接使用数字。
    2.7 避免使用编码:带编码的名称通常不便发音,容易打错,更容易让人混淆,而且给人增加了解码的负担。(比如:匈牙利命名法)
    2.8 避免思维映射:
    2.9 类名:类名应当是名词或者名词短语。类名不应当是动词。
    2.10 方法名:方法名应当是动词或者动词短语。
    2.11 别扮可爱:名称不能太耍宝。宁可明确,勿为好玩。
    2.12 每个概念对应一个词:给每个抽象概念选一个词,并且一以贯之。
    2.13 别用双关语:避免将同一单词用于不同母的。同一术语用于不同概念,基本上就是双关语。
    2.14 使用解决方案领域名称:只有程序员会读你的代码。
    2.15 使用源自所涉问题领域的名称:
    2.16 添加有意义的语境:需要用良好命名的类、函数或者名称空间来放置名称,给读者提供语境,如果没有这么做那就添加前缀说明吧。
    2.17 不要添加没用的语境:只要短名称足够清楚,就要比长名称好。别给名称添加不必要的语境。

    第三章 函数

    3.1 短小:函数的第一原则是要短小。第二条规则是还要更短小。(我认为短小是没错,但是要在干单一事情的前提下,把函数拆分,我觉得是不合理的)
    3.2 只做一件事:函数应该做一件事。做好这件事。只做这一件事。
    3.3 每个函数一个抽象层次:要确保函数只做一件事,函数中的语句都要在同一抽象层级上。
    3.4 switch语句:switch天生就是干N件事情。用多态实现switch我觉得使用看情况的,不能盲目的将switch转换为多态。
    3.5 使用描述性的名称:如果每个例程都让你感到深合己意,那就是整洁代码。
    3.6 函数参数:函数参数要尽量少,如果函数参数多余3个,则应该考虑创建一个新类了。参数起名要清晰的说明参数的意图。
    3.7 无副作用:副作用是一种谎言。函数承诺只做一件事,但还是会做其他被隐藏起来的事。
    3.8 分隔指令与询问:函数要么做什么,要么回答什么,但是二者不可兼得。函数应该修改某对象的状态,或者返回某对象的信息。两样都干常会导致混乱。
    3.9 使用异常替代返回错误码:使用异常代替错误码,错误处理本身就是一件事。错误码枚举类型会成为磁铁需要所有需要处理错误的文件包含它。
    3.10 别重复自己:重复是软件中一切邪恶的根源。
    3.11 结构化编程:每个函数中的买个代码块都应该有一个入口一个出口。

    第四章 注释 (别给糟糕的代码加注释---重新写吧)

    注释的恰当用法是弥补我们在用代码表达意图时的失败。
    4.1 注释不能美化糟糕的代码:与其花时间写注释解释你的代码,还不如花时间重新整理你的代码。
    4.2 用代码来阐述:尽量少写注释,用更形象的命名来取代注释。
    4.3 好注释:有些注释是必须的,也是有利的。

    (1). 法律信息:为程序提供法律注释。
    (2). 提供信息的注释:用注释提供基本信息。
    (3). 对意图的解释:提供现有代码后续的意图。
    (4). 阐释:把晦涩难明的事情阐述清楚。
    (5). 警示:用于警告其他程序员某种后果。
    (6). TODO注释:在代码中放置工作列表。注意:要定期检查 然后修护。
    (7). 放大:注释可以放大某种看来不合理之物的重要性。
    (8). 公共API的DOC:对公共API做的DOC。

    4.4 坏注释:坏注释是槽糕代码的支撑或借口,或是对错误决策的修正。

    (1). 喃喃自语:不要对程序加无用的注释,那样只会自说自话。甚至让人误解代码的真正意图。
    (2). 多余的注释:多余的注释使读程序的难度更大。
    (3). 误导性注释:误导的注释容易使使用你的代码的人陷于调试的困境中。
    (4). 循环性注释:简单的只阐述方法名,意图明确的参数或者作者等信息的注释,不需要总是放在每个函数前面。
    (5). 日志式注释:每修改一次就在文件开始处记录修改内容,修改日期等的日志方式。在有版本控制软件的今天这个已经是多余。
    (6). 废话注释:对于显然之事喋喋不休。
    (7). 可怕的废话:代码作者在复制代码时把注释也复制过来,但是结果代码修改了,而注释没有修改。
    (8). 能用函数或变量时就别用注释:
    (9). 位置标记:用来标记位置的特殊注释,一定要清理。
    (10). 括号后面的注释:放在长循环,或者长if比括号后,指示是那个语句的结束括号。如果你想在右括号后加注释,那你应该考虑下写个短小的函数。
    (11). 归属与署名:代码版本控制软件是这类注释的最佳归属。
    (12). 注释掉的代码:用版本控制软件做历史记录。把已经不需要的代码立即删掉。
    (13). HTML注释:还有这种注释吗,天啊。
    (14). 非本地信息:把注释加到离目标代码最近的地方。而不是加到远离目标代码的位置。否则目标代码被修改时,注释必然会被忘记修改。这是噩梦的开始。
    (15). 信息过多:别在注释中添加有趣的历史性话题或者无关的细节描述。
    (16). 不明显的联系:注释及其描述的代码之间的联系应该是显而易见。如果你不嫌弃麻烦要写注释,至少让读者能看着注释和代码,并且理解注释所谈何物。
    (17). 函数头:为短函数选个好命,显然要比函数前加注释要好。
    (18). 非公共代码的DOC:显然非公共代码API不需要DOC。

    第五章 格式

    5.1 格式的目的:为将来的修改减少阻力。
    5.2 垂直格式:短文件比长文件好理解。

    (1). 向报纸学习:名称简单一目了然;源文件顶部给出高层次概念和算法;细节应该从上到下逐次展开。
    (2). 概念间垂直方向上的区隔:每个函数、每个功能块之间用空行隔开。
    (3). 垂直方向上的靠近:紧密相关的代码应该互相靠近。
    (4). 垂直距离:变量声明应尽可能靠近使用位置。实体变量应该统一放在统一地方(C++统一放在类底部)。相关函数应该离得尽可能的靠近。概念相关的代码应该放在一起。
    (5). 垂直顺序:一般使用自上而下的顺序。函数调用尽量遵从。

    5.3 横向格式:每行字符个数应该遵从不需要拉动滚动条的原则。推荐120个字符。

    (1). 水平方向上的区隔与靠近:使用空格将不相关的东西分隔。使用空格把相关的东西紧密联系。(厄,好别扭的说法)
    (2). 水平对齐:不要刻意去水平对齐,这样只会让读者的注意力分散在不重要的东西上。
    (3). 缩进:层级之间一定要缩进固定宽度。
    (4). 空范围:尽量不要写只有一行的for 或者while,如果实在没有办法,那就把分号写到下一行,让读者重视这里。

    5.4 团队规则:如果团队有规则则要遵从团队规则。

    第六章 对象和数据结构

    6.1 数据抽象:取值函数和赋值函数并不是一个简简单单的函数那么简单,它代表了数据抽象以及数据封装的思想。实现和应用是隔离的。
    6.2 数据、对象的反对称性:对象把数据隐藏于抽象之后,暴露操作数据的函数;数据结构暴露其数据,没有提供有意义的函数。对象和数据结构之间的二分原理:过程式代码便于在不改动即有数据结构的前提下添加新函数。面向对象代码便于在不改动即有函数的前提下添加新类。也即:过程式代码难以添加新数据结构,因为必须修改所有函数。面向对象代码难以添加新函数,因为必须修改所有类。
    6.3 得墨忒耳律(The Law Of Demeter):模块不应了解他所操作对象的内部情形。也即方法不应调用由任何函数返回的对象的方法。

    (1). 火车失事:不要直接对函数返回的对象调用方法。声明一个对象将函数返回的对象赋值给它,然后再该对象的方法。
    (2). 混杂:不要把对象和数据结构混在在一起使用。这样你即得不到数据结构的好处也得不到对象的好处。
    (3). 隐藏结构:

    6.4 数据传送对象:只有公共变量没有函数的类叫做数据传送对象。用于传递参数等。

    第七章 错误处理

    7.1 使用异常而非返回码:返回错误码需要立刻检查错误码,但是程序员往往忘记检查,因此最好是使用异常。
    7.2 先写try catch finally语句:这样可以在程序中定义一个范围,而这个范围中的错误可以被系统捕获。即使你不做任何处理。
    7.3 我们不可控异常:
    7.4 给出异常发生的环境说明:在抛出异常的时候要提供详细的发送说明。
    7.5 依调用者需要定义异常类:
    7.6 定义常规流程:
    7.7 不要返回null值:在任何返回null值得地方都要进行判定,如果有一处没有判定那代码就将失控。
    7.8 不要传递null值:传递null值意味着每一处传递的地方都要进行判定,如果有遗忘的地方那代码同样会失控。

    第八章 边界

    8.1 使用第三方代码:第三方代码或多或少都会有些限制,要注意这些限制。有可能下一版本中就会有改变呢。
    8.2 浏览和学习边界:
    8.3 这一条款的电子书页缺失
    8.4 学习性测试的好处不只是免费:
    8.5 使用尚不存在的代码:
    8.6 整洁的边界

    第九章 单元测试

    9.1 TDD三定律:在编写不能通过的单元测试前,不可编写生产代码;只可编写刚好无法通过的单元测试,不能编译也算不能通过;只可编写刚好足以通过当前失败测试的生产代码。
    9.2 保持测试整洁:测试代码要和生产代码一样整洁。测试代码和生产代码一样的重要。
    9.3 整洁的测试:测试代码的要遵从的就是可读性。比生产代码更要可读。
    9.4 每个测试一个断言:每个测试函数只测试一个概念。
    9.5 F.I.R.S.T:快速(Fast) 测试应该够快、 独立(Independent) 测试之间应该相互独立、可重复(Repeatable) 测试应该可在任何环境重复通过、自足验证(Self-validating) 测试应该有布尔值输出 、及时(Timely) 测试应及时编写。

    第十章 类

    10.1 类的组织:次序先公用方法,保护方法,私有方法,共有数据,保护数据,私有数据。
    10.2 类应该短小:类中的共有方法不应该过多。

    (1). 单一职权原则:系统应该由许多短小的类而不是几个庞大的类组成。每个小类封装一个权责,每个小类只有一个修改的理由。
    (2). 内聚:内聚性高意味着类中的方法和变量互相依赖,互相组合成一个整体。
    (3). 保持内聚性就会得到许多短小的类:当类丧失内聚性的时候就拆分它。

    10.3 为了修改而组织:

    第十一章 系统

    11.1 如何建造一个城市:
    11.2 将系统的构造和使用分开:构造和使用不是一样的事情。

    (1). 分解main:将全部的构造过程放到main函数中。
    (2). 工厂:管理构造过程,把构造过程封装到这里。
    (3). 依赖注入:分离构造与使用的强大机制。

    11.3 扩容:
    11.4 Java代理:
    11.5 纯Java AOP框架:
    11.6 AspectJava的方面:
    11.7 测试驱动系统架构:将架构按需从简单演化到精细。没有必要先做大设计(Big Design Up Front),BDUF甚至是有害的,它阻碍改进,因为心理上抵制丢弃即成之事。也因为框架上的选择影响后续的设计思路。
    11.8 优化决策:提前决策是一种预备知识不足的决策。
    11.9 明智使用添加了可论证价值的标准:
    11.10 系统需要领域特定语言:使用领域特定语言可以提高效率。

    第十二章 迭进

    12.1 通过迭代设计达到整洁目的:运行所有测试;不可重复;表达了程序员的意图;尽可能减少类和方法的数量;遵循以上四条对良好设计有莫大帮助。
    12.2 简单设计规则1 运行所有测试:运行的测试越多,说明系统更健壮。
    12.3 简单设计规则2~4 重构:对有坏味道的代码及早进行重构,有利于以后的维护。也会让系统变的更明确。
    12.4 不可重复:重复是拥有良好设计系统的打敌。重复意味着额外的工作,额外的风险以及不必要的复杂度。
    12.5 表达力:代码应当清晰表达作者的意图。代码写的越清晰,维护人员花的时间就越少,从而减少缺陷,减少维护成本。其实维护人员最大可能就是自己,清晰代码,是对自己以后工作的减负。
    12.6 尽可能少的类和方法:在保持类和函数短小的情况下尽可能的减少类和函数的数量。

    第十三章 并发编程

    对象是过程的抽象,线程是调度的抽象。
    13.1 为什么要并发:最大限度的使用CPU资源,提高工作效率(自己的观点)。书中对并发的说法:并发会在性能和编写一些额外代码上增加一些开销;正确的并发是复杂的,即便对于很简单的问题也是如此;并发缺陷并非总能重现,所以常被看做偶发事件而忽略。并发常常需要对设计策略进行根本性修改。
    13.2 挑战:并发会引发一系列问题。死锁,竞争,饥饿。。。等等。
    13.3 并发防御原则:

    (1). 单一职权原则:分离并发相关代码以及一般代码。
    (2). 推论--限制数据作用域:谨记数据封装;严格限制对可能被共享的数据的访问。
    (3). 推论--使用数据副本:避免数据共享的好方法之一就是一开始就避免数据共享。
    (4). 推论--线程应尽可能的独立:尝试将数据分解到可被独立线程操作的独立子集。

    13.4 了解Java库:
    13.5 了解执行模型:根据并发应出的问题可以有如下模型

    (1). 生产者-消费者模型:一个或几个线程生产消息放入到共享队列中,然后一个或几个线程消费消息从共享队列。共享队列是一种限定资源。
    (2). 读者-作者模型:
    (3). 宴席哲学家:

    13.6 警惕同步方法之间的依赖:避免使用一个共享对象的多个方法。
    13.7 保持同步区域微小:尽可能的减小同步区域。
    13.8 很难编写正确的关闭代码:尽早考虑关闭问题,尽早另其工作正常。
    13.9 测试线程代码:编写有潜力暴露问题的测试,在不同的编程配置、系统配置和负载条件下频繁的运行。

    (1). 将伪失败看做可能的线程问题:不要将系统错误归咎于偶发事件。
    (2). 先使非线程代码可工作:不要同时追踪线程缺陷和非线程缺陷。确保代码在线程之外可工作。
    (3). 编写可插拔的线程代码:编写可插拔的线程代码,这样就可以在不同的配置环境下运行。
    (4). 编写可调整的线程代码:在编写过程中要随时可改动线程的数量以及自我调整。
    (5). 编写多于处理器数量的线程:系统在切换任务时发生一些事情,为了促使任务切换的发生,运行多处理器核心数量的线程。频繁的任务切换,可提高发现缺陷的几率。
    (6). 在不同平台上运行:尽早并经常地在所有目标平台上运行代码。
    (7). 装置试错代码:可以放置sleep、wait、yield、priority等操作,可以提高发现缺陷的几率。
    (8). 硬编码:找到合适的位置放置上面条款中的四个函数。
    (9). 自动化:使用异动策略搜出错误。

    第十四章 逐步改进

    14.1 Args的实现:要想写整洁的代码,必须先写脏代码,然后整理它。多数新手刚开始就只写能工作的代码,然后继续写下面的功能,而那些能工作的代码,仅仅保持在能工作而已。
    14.2 Args草稿:简单的系统通过多次的改动会变的庞大,杂乱。这时候你应该停下来,重构代码。
    14.3 字符串参数:

    第十五章 JUnit内幕

    第十六章 重构SerialDate

    第十七章 味道与启发

    代码的坏味道,与<<重构>>那本书中,有内容重叠。与前面的章节中的内容也有重叠。
    17.1 注释:

    C1:不恰当的注释。
    C2:废弃的注释。
    C3:冗余的注释。
    C4:槽糕的注释。
    C5:注释的代码。

    17.2 环境:

    E1:需要多步才能实现的构建。
    E2:需要多步才能做到的测试。

    17.3 函数:

    F1:过多的参数。
    F2:输出参数。
    F3:标识参数。
    F4:死函数。

    17.4 一般性问题:

    G1:一个源文件中存在多种语言。
    G2:明显的行为未被实现:最小惊异原则(函数或者类应该实现其他程序员有理由期待的行为)。
    G3:不正确的边界行为:不要依赖直觉。
    G4:忽视安全:切尔诺贝利核电站爆炸了,因为电厂经理一条又一条的忽略了安全机制。
    G5:重复。
    G6:在错误的抽象层级上的代码。
    G7:基类依赖于派生类。
    G8:信息过多。
    G9:死代码。
    G10:垂直分隔。
    G11:前后不一致。
    G12:混淆视听。
    G13:人为耦合:不要因为方便把代码随便放置在别的类。
    G14:特性依恋。
    G15:选择算子参数。
    G16:晦涩的意图。
    G17:位置错误的权责。
    G18:不恰当的静态方法。
    G19:使用解释性变量。
    G20:函数名称应该表达其行为。
    G21:理解算法。
    G22:把逻辑依赖改为物理依赖。
    G23:用多态替代if/else switch/case。
    G24:遵循标准约定。
    G25:用命名常量来代替魔术数。
    G26:准确:对于代码中的每一处都要做到准确。
    G27:结构基于约定。
    G28:封装条件。
    G29:避免否定性条件。
    G30:函数只该做一件事。
    G31:掩蔽时序耦合。
    G32:别随意:构建代码需要理由,而且理由应该与代码结构相契合。随意的代码别人想着改它,结构自始至终都一致的别人会去用它。
    G33:封装边界条件:边界条件的检查应该封装在一起,而不是散落在代码各处。
    G34:函数应该只在一个抽象层级上。
    G35:在较高层级放置可配置数据。
    G36:避免传递浏览:这条前面也有,这里的这个名字起的很含糊。其实很简单就是不要调用函数返回对象的函数。

    17.5 Java:

    17.6 名称:

    N1:采用描述性名称。
    N2:名称应与抽象层级相符。
    N3:尽可能使用标准命名法。
    N4:无歧义的名称。
    N5:为较大作用范围选用较长的名字。
    N6:避免编码。
    N7:名称应该说明副作用。

    17.7 测试:

    T1:测试不足。
    T2:使用覆盖率工具。
    T3:别略过小测试。
    T4:被忽略的测试就是对不确定事情的疑问。
    T5:测试边界条件。
    T6:全面测试相近缺陷。
    T7:测试失败的模式有启发性。
    T8:测试覆盖率的模式有启发性。
    T9:测试应该快速。

    完美之道,不在于无可增加,而在于无可减少。
  • 相关阅读:
    mac 终端常见指令
    git常见指令
    iOS8的autolayout和size class
    UIWindow详解
    操作系统Unix、Windows、Mac OS、Linux的故事
    iOS引用当前显示的UIAlertView
    Unexpected CFBundleExecutable Key
    《CODE》讲了什么?
    exit和return的区别
    php 登录注册api接口代码
  • 原文地址:https://www.cnblogs.com/Areas/p/2717056.html
Copyright © 2011-2022 走看看