• 代码整洁之道 读书笔记




    第1章 整洁代码
    1.1 要有代码
    1.2 糟糕的代码
         稍后等于永不
    1.3 混乱的代价
         假设前期不注意。后期的加入代码、改动效率都很低
    1.3.1 华丽新设计
    1.3.2 态度
    1.3.3 迷题
    1.3.4 整洁代码的艺术
    1.3.5 什么是整洁代码
    1.4 思想流派
    1.5 我们是作者
         读和写代码的时间可能是10:1。能够用编辑器的回放功能查看自己的编写记录
    1.6 童子军军规
    1.7 前传与原则




    第2章 有意义的命名
    2.1 介绍
    2.2 名副事实上
         变量名太任意,haha、list1、ok 这些都没啥意义
    2.3 避免误导
         包括List等keyword、字母o与数字0等
    2.4 做有意义的区分
         反面教材。变量名:a1、a2、a3
         避免冗余,不要出现Variable、表字段中避免出现table、字符串避免出现NameString - 直接Name就好
    2.5 使用读得出来的名称
         不要使用自己拼凑出来的单词,所谓的驼峰命名法,尽量使用完整的单词
    2.6 使用可搜索的名称
         一些常量,最好不直接使用数字,而指定一个变量名,这个变量名能够便于搜索到
    2.7 避免使用编码
         2.7.1 匈牙利语标记法
              避免像这样使用缩写
         2.7.2 成员前缀
              避免使用前缀,可是Android中一个比較好的喜欢用m表示私有等,个人感觉比較好
         2.7.3 接口和实现
              作者不喜欢把接口使用I来开头,实现也希望仅仅是在后面加入imp
    2.8 避免思维映射
         只使用简单的a、b、c等缩略一些单词
    2.9  类名
         类名与对象名应该是名词名词短语。不能使动词。
    2.10 方法名
         方法名应当是动词或者动词短语
         不使用构造器,而使用对应的public(构造器太经常使用了,为这些參数起名字也比較费脑筋,所以这个不太赞同)
    2.11 别扮可爱
         有的变量名叫haha、banana 
    2.12 每一个概念相应一个词
         项目中同一时候出现Control与Manager,为什么不统一使用当中一种?
    2.13 别用双关语
         有时可能使用add并不合适。比例insert、apped。add表示完整的新加入的含义。     
    2.14 使用解决方式领域名称
         看代码的都是程序猿,所以起名字的时候能够多考虑专业词汇。
    2.15 使用源自所涉问题领域的名称
    2.16 加入有意义的语境
         能够把相关的变量放到一个类中,使用这个类来表明语境。
    2.17 不要加入无用的语境
         名字中带有项目的缩写。这样全然没有必要
    2.18 最后的话
         取好名字最难的地方在于须要良好的描写叙述技巧和共同拥有文化背景。     



    第3章 函数
    3.1 短小
         不要写几百行的函数
    3.2 仅仅做一件事
         尽量保证每一个函数仅做一件事情
    3.3 每一个函数一个抽象层级
         自顶向下读代码:向下规则
    3.4 switch语句
         把switch放到工厂中,外面不须要考虑里面怎样详细实现。
    3.5 使用描写叙述性的名称
    3.6 函数參数
         參数的个数尽量小于3个,越少越好
         3.6.1 一元函数的普遍形式
         3.6.2 标识參数 - 假设须要向方法传入true或者false说明方法肯定要做两件事情
         3.6.3 二元函数
         3.6.4 三元函数
         3.6.5 參数对象 - 假设參数过多,能够直接把这些參数封装到一个对象中
         3.6.6 參数列表 - 即使是能够传入多个參数。可是超过3个还是要考虑下怎样精简
         3.6.7 动词与keyword
    3.7 无副作用
         方法可能须要某种场景下调用才干有理想的结果。比如有些仅能在初始化的时候被调用。能够通过命名checkPassowrdAndInitializeSession
         输出參数,函数的内容是在输入參数上修改。这种情况尽量避免或者使用appedFooter(StringBuffer report)这种命名
    3.8 分隔指令与询问
         假设方法里面设置一个变量的值,而且有返回值。能够命名为setAndCheckIfExists
    3.9 使用异常替代返回错误码     
         3.9.1 抽离Try/Catch代码块
              把try块中的内容抽取到一个方法中
         3.9.2 错误处理就是一件事
         3.9.3 Error.java依赖磁铁
    3.10 别反复自己
         避免项目中功能反复的代码,更切记直接把一个函数copy到几个地方使用
    3.11 结构化编程
         函数仅仅要短小,偶尔出现return、break、continue语句没有坏处
    3.12 怎样写出这种函数
    3.13 小结
    3.14 SetupTeardownIncluder程序
    3.15 文献




    第4章 凝视
    4.1 凝视不能美化糟糕的代码
         凝视除去编写的毫无疑义外,可能还会由于改动代码而忘记改动对应的凝视,导致代码上面的凝视事实上不是不是以下代码的意思。


    4.2 用代码来阐述
    4.3 好凝视
         4.3.1 法律信息 
         4.3.2 提供信息的凝视 - 在正則表達式上加入符合要求的样例。返回值的含义包括在函数名中。


         4.3.3 对意图的解释 - 有些地方编写的代码可能跟常识不符合,可是是由于某种特定环境下必须这样写,能够用凝视解释下。
         4.3.4 阐释
         4.3.5 警示 - 对代码改动的注意事项等。
         4.3.6 TODO凝视
         4.3.7 放大
         4.3.8 公共API中的Javadoc - 能够学习下javadoc
    4.4 坏凝视
         4.4.1 喃喃自语 - 有些凝视没解释清楚事情,好像是作者写给自己看的哑谜

         4.4.2 多余的凝视 - 函数的代码非常easy,非常容易理解。可是凝视却写的非常长
         4.4.3 误导性凝视 - 某种特别情况凝视中却没有描写叙述,可是使用函数却不是和凝视一样的效果。


         4.4.4 循规式凝视 - 每一个变量名、每一个函数都有凝视反倒成了愚蠢可笑。


         4.4.5 日志式凝视 - 加入谁改动了。可是如今SVN等代码管理工具能够查看了
         4.4.6 废话凝视
         4.4.7 可怕的废话
         4.4.8 能用函数或变量时就别用凝视
         4.4.9 位置标记 - 使用//// 把一些功能分开,书中不建议使用。可是我个人感觉这样能使代码清晰些。
         4.4.10 括号后面的凝视 - 多层嵌套。在括号的结尾加入上属于哪个控制keyword的结尾括号。这样的情况能够抽取到多个方法中
         4.4.11 归属与署名 - 不须要,由于有源码控制系统
         4.4.12 凝视掉的代码 - 临时不须要的代码能够直接删除,不是必需凝视掉。能够使用源码控制系统找到之前版本号
         4.4.13 HTML凝视
         4.4.14 非本地信息
         4.4.15 信息过多 - 主须要最核心信息,不是必需大段描写叙述
         4.4.16 不明显的联系
         4.4.17 函数头
         4.4.18 非公共代码中的Javadoc - public须要加入javadoc告诉使用者一些信息,可是private方法非常多时候不须要
         4.4.19 范例





    第5章 格式
    5.1 格式的目的
    5.2 垂直格式
         5.2.1 向报纸学习

              能够自顶向下阅读,最上面的是比較重要的。
         5.2.2 概念间垂直方向上的区隔
              代码通常都是从上向下、从左向右读。

              函数间一定要留有空白。这样可读性会好些
         5.2.3 垂直方向上的靠近
         5.2.4 垂直距离
              函数内变量声明 - 在靠近使用的地方
              全局变量 - 在类顶部
              相关函数 - 当前函数调用的函数应该垂直放到一起
              相关概念 - 比如函数名前缀都一样的,或者重载的函数都放到一起
         5.2.5 垂直顺序
              
    5.3 横向格式
              每一行代码放置多少个字符,假设须要横向滚动就让人难以接受,所以建议每行容纳120个字符左右。当然越短越好。
         5.3.1 水平方向上的区隔与靠近
              等号(=)两側加入空格、计算符号(* / ) 左右加入空格
         5.3.2 水平对齐
              非常多变量都变量名左側对齐。这样非常好看,可是处理成统一的格式须要时间。并且除了美观也没多大用途
         5.3.3 缩进
         5.3.4 空范围
              if函数的内容仅有一行就不加入括号,这样easy导致误读与改动上出现错误。
    5.4 团队规则
    5.5 鲍勃大叔的格式规则




    第6章 对象和数据结构
    6.1 数据抽象
         setter/getter加入这些方法的思考
    6.2 数据、对象的反对称性
    6.3 得墨忒耳律
         6.3.1 火车失事
         6.3.2 混杂
         6.3.3 隐藏结构
    6.4 数据传送对象
    6.5 小结
         对象暴露行为。隐藏数据。



    第7章 错误处理
    7.1 使用异常而非返回码
         不在方法中使用返回的方式。而是使用编程语言提供的异常机制来拦截
    7.2 先写Try-Catch-Finally语句
    7.3 使用不可控异常
    7.4 给出异常发生的环境说明
    7.5 依调用者须要定义异常类
    7.6 定义常规流程
    7.7 别返回null值
         返回空的字符串或者空的列表(Collections.emptyList())
    7.8 别传递null值
         避免传入null值而不是在函数内进行推断(还是在函数内做null推断吧,毕竟一起编写代码。难免别人会传入)
    7.9 小结
    7.10 文献




    第8章 边界
    8.1 使用第三方代码
    8.2 浏览和学习边界
    8.3 学习log4j
    8.4 学习性測试的优点不仅仅是免费
         在某个API的功能不全然了解的情况下,单独写一个demo測试下是否是自己理解的那样,很省成本并且准确。
    8.5 使用尚不存在的代码
         已经定义好接口。类似与写測试数据一样。


    8.6 整洁的边界
    8.7 文献




    第9章 单元測试
    9.1 TDD三定律

         1. 在编写不能通过的单元測试前。不能够编写生产代码;
         2. 仅仅有编写刚好无法通过的单元測试,不能编译也算不通过。
         3. 仅仅可编写刚好足以通过当前失败測试的生产代码。


    9.2 保持測试整洁

         測试代码和生产代码一样重要。它须要被思考、被设计和被照料。
    9.3 整洁的測试
         每一个測试都呈现构造-操作-校验(BUILD-OPERATE-CHECK)模式。
         9.3.1 面向特定领域的測试语言
         9.3.2 双重标准
    9.4 每一个測试一个断言
    9.5 F.I.R.S.T.
         高速(Fast):測试执行应该够快。
         独立(Independent):測试应相互独立。
         可反复(Repeatable):測试应当可在不论什么环境中反复通过。


         自足验证(Self-Validating):測试应该有布尔值输出。


         及时(Timely)測试应及时编写。
    9.6 小结





    第10章 类
    10.1 类的组织
    10.2 类应该短小
         10.2.1 单一权责原则

              书中建议:系统应该由非常多短小的类而不是少量巨大的类组成。每一个小类封装一个权责,仅仅有一个改动的原因,比与少数其它一起协同达成期望的系统行为。
         10.2.2 内聚
         10.2.3 保持内聚性就会得到很多短小的类
    10.3 为了改动而组织




    第11章 系统
    11.1 怎样建造一个城市
         讨论怎样在较高的抽象层级 - 系统层级上保持整洁。


    11.2 将系统的构造与使用分开
         11.2.1 分解main

              构造函数都放到入口的main中?
         11.2.2 工厂
              应用程序须要确定何时创建对象时能够使用工厂。
         11.2.3 依赖注入
              能够分析构造与使用。
    11.3 扩容
    11.4 Java代理
    11.5 纯Java AOP框架
    11.6 AspectJ的方面
    11.7 測试驱动系统架构
    11.8 优化决策
    11.9 明智使用加入了可论证价值的标准
    11.10 系统须要领域特定语言
    11.11 小结



    第12章 迭进
    12.1 通过迭进设计达到整洁目的
         Kent Beck关于“简单设计”的四条规则:
         1. 执行全部測试
         2. 不可反复
         3. 表达了程序猿的额意图
         4. 尽可能降低类和方法的数量
    12.2 简单设计规则1:执行全部測试
    12.3 简单设计规则2~4:重构
    12.4 不可反复
    12.5 表达力
    12.6 尽可能少的类和方法
    12.7 小结



    第13章 并发编程
    13.1 为什么要并发
    13.2 挑战
         并发的运行是无序的,须要确保线程安全。


    13.3 并发防御原则

         13.3.1 单一权责原则 
              方法/类/组件应当仅仅有一个改动的理由。建议:把并发与非并发的代码分离开。
         13.3.2 推论:限制数据作用域
              synchronized,谨记数据封装。严格限制对可能被共享的数据的訪问。
         13.3.3 推论:使用数据复本
              避免数据的共享。多线程返回的数据是单独的,运行完毕后在合并到主线程。


         13.3.4 推论:线程应尽可能地独立
    13.4 了解Java库

         限定资源 - 并发环境中有着固定尺寸或数量的资源。

    比如数据库连接盒固定尺寸读/写缓存等。

         相互排斥 - 每一时刻仅有一个线程能訪问共享数据或共享资源
         线程饥饿 - 一个或一组线程在非常长时间内或永久被禁止。比如:总是让运行的快的线程先运行。比如运行得快的线程没完没了。则运行时间长的线程就会“挨饿”
         死锁 - 两个或者多个线程互相等待运行结束。

    每个线程都拥有其它线程须要的资源,得不到其它线程拥有的资源。就无法终止。

         活锁 - 运行次序一致的线程,每一个都想要起步,但发现其它线程已经“在路上”。

    因为竞争的原因。线程会持续尝试起步,但在非常长的时间内都无法如愿,甚至永远无法启动。


    13.5 了解运行模型
         *** 13.5.1 生产者-消费者模型

              一个或多个生产则会线程创建某些工作,并置于缓存或队列中。一个或多个消费者线程从队列中获取并完毕这些工作。生产者消费者之间的队列是一种限定资源。


         *** 13.5.2 读者-作者模型
         *** 13.5.3 宴席哲学家
    13.6 警惕同步方法之间的依赖

         避免使用一个共享对象的多个方法。
    13.7 保持同步区域微小
    13.8 非常难编写正确的关闭代码
    13.9 測试线程代码
         13.9.1 将伪失败看作可能的线程问题
         13.9.2 先使非线程代码可工作
         13.9.3 编写可插拔的线程代码
         13.9.4 编写可调整的线程代码
         13.9.5 执行多于处理器数量的线程
         13.9.6 在不同平台上执行
         13.9.7 装置试错代码
         13.9.8 硬编码
         13.9.9 自己主动化
    13.10 小结
    13.11 文献



    第14章 逐步改进
    14.1 Args的实现
         我怎么做的? 要编写整洁代码,必须先写肮脏代码。然后再整理它。比如写作文,先写草稿。再写作文等。
    14.2 Args:草稿
         14.2.1 所以我暂停了
              再新增列需求须要修改代码的之后,才干发现有哪些代码须要修改。改进的方法就是找出这些修改的地方:
              1. 每一个參数类型都要有解析器范式元素、从而为该种类型选择HashMap的方法。

              2. 每种类型都须要再命令行字符串中解析,然后再转换为真是类型。

              3. 每种參数类型都须要一个getXXX方法。依照其真实类型向调用者返回參数值。


         14.2.2 渐进
    14.3 字符串參数
    14.4 小结

         改动前已经编写好Junit測试,这样能保证每次改动的时候都不会对系统功能造成影响。

         找出之后会爆炸式增长的地方。
         先加入一个变量等一步步的小范围改动,每次改动都须要通过Junit測试。



    第15章 JUnit内幕
    15.1 JUnit框架
    15.2 小结



    第16章 重构SerialDate
    16.1 首先,让它能工作
    16.2 让它做对
    16.3 小结
    16.4 文献


    第17章 味道与启示
    凝视 
    C1.不恰当的凝视 
    让不恰当的凝视保存到源码控制系统。 
    C2.废弃的凝视 
    过时、无关或不对的凝视就是废弃的凝视不应该保留必须立即删除。 
    C3.冗余的凝视 
    凝视应该谈及代码自身没提到的东西。否则就是冗余的。 
    C4.糟糕的凝视 
    值得编写的凝视必须正确写出最好的凝视,假设不是就不要写。

     
    C5.凝视掉的代码 
    凝视掉的代码必须删除。 
     环境 
    E1.须要多步才干实现的构建 
    构建系统应该是单步的小操作。 
    E2.须要多步才干实现的測试 
    仅仅须要单个指令就能够执行全部单元測试。 
     函数 
    F1.过多的參数 
    函数參数应该越少越好,坚决避免有3个參数 的函数。 
    F2.输出參数 
    输出參数违反直接,抵制输出參数。 
    F3.标识參数 
    布尔值參数令人迷惑,应该消灭掉。 
    F4.死函数 


           



    永不被调用函数应该删除掉。 
     
    一般性问题 
    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.封装边界条件 
    比如:+1或-1操作必须封装起来。

     
    G34.函数应该仅仅在一个抽象层级上 
    封装不在一个抽象层级上的代码,保持每一个函数仅仅在一个抽象层级上。

     
    G35.在较高层级放置可配置数据 
    把配置数据和常量放到基类里。 
    G36.避免传递浏览 
    “得墨忒耳律”,编写害羞代码。让直接协作者提供所需的服务。而不要逛遍整个系统。 
     JAVA 
    J1.通过使用通配符避免过长的导入清单 J2.不要继承常量 J3.常量VS.枚举 
    使用枚举enum取代常量。

     
     名称 
    N1.採用描写叙述性名称 
    名称相应可读性有90%的作用,必须认真命名。 
    N2.名称应与抽象层级相符 
    不要取沟通实现的名称:取反映类或函数抽象层级的名称。

     
    N3.尽可能使用标准命名法 N4.无歧义的名称 
    N5.为较大作用范围选用较长名称 N6.避免编码 
    不应该在名称中包括类型或范围的信息,比如:m_,f等前缀。 
    N7.名称应该说明副作用 
    名称应该说明类、变量或函数的全部信息,不应该隐藏副作用。 






     測试 T1.測试不足 
    保证足够的測试。 
    T2.使用覆盖率工具 
    覆盖率工具能够更好地找到測试不足的模块、类、函数。 
    T3.别略过小測试 
    T4.被忽略的測试就是对不确定事物的疑问 
    用@Ignore表达我们对需求的疑问。 
    T5.測试边界条件 
    边界判读错误非经常见。必须測试边界条件。 
    T6.全面測试相近的缺陷 
    缺陷趋向于扎堆,假设在函数中发现一个缺陷。那么就全面測试这个函数。 
    T7.測试失败的模式有启示性 
    你能够通过測试失败找到问题所在。 
    T8.測试覆盖率的模式有启示性 
    通过測试覆盖率检查,往往能够找到測试失败的线索。 
    T9.測试应该高速 
    慢測试会导致时间紧时会跳过,导致可能出现故障。


  • 相关阅读:
    storm源代码分析---Transactional spouts
    SQLServer 中存储过程
    实体添加映射
    SELECT INTO 和 INSERT INTO SELECT
    .NET System.Timers.Timer的原理和使用(开发定时执行程序)
    .net Framework 中的四种计时器
    AutoMapper 在你的项目里飞一会儿
    C#字符串、字节数组和内存流间的相互转换
    Entity Framework Code First使用者的福音 --- EF Power Tool使用记之二(问题探究)
    Entity Framework Code First使用者的福音 --- EF Power Tool使用记之一
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5076255.html
Copyright © 2020-2023  润新知