|
3 | 3 | 1. 我们就像一群代码猴子,上蹿下跳,自以为领略了编程的真谛。可惜,当我们抓着几个酸桃子,得意洋洋坐到树枝上,却对自己造成的混乱熟视无睹。那堆“可以运行”的乱麻程序,就在我们的眼皮底下慢慢腐坏。
|
4 | 4 |
|
5 | 5 | ## 第一章 整洁代码
|
6 |
| -1. 勒布朗法则:稍后等于永不(Later equals never.) |
| 6 | +1. 勒布朗法则:稍后等于永不(Later equals never)。 |
7 | 7 | 1. 制造混乱无助于赶上期限。混乱只会立刻拖慢你,叫你错过期限。赶上期限的唯一方法——做的快的唯一方法——就是始终尽可能保持代码整洁。
|
8 | 8 | 1. Javadoc 中的 `@author` 字段告诉我们自己是什么人。我们是作者,作者都有读者。实际上,作者有责任与读者做良好沟通。下次你写代码的时候,记得自己是作者,要为评判你工作的读者写代码。
|
9 | 9 |
|
10 |
| -## 第二章 有意义的命名 |
11 | 10 | ## 第三章 函数
|
12 | 11 | 1. 函数的第一规则是要短小。第二条规则是还要更短小...经过漫长的试错,经验告诉我,函数就该小。
|
13 | 12 | 1. 函数应该做一件事。做好这件事。只做这一件事。判断函数是否不止做了一件事,有一个方法,就是看是否能再拆出一个函数,该函数不仅只是单纯地重新诠释其实现。
|
14 | 13 | 1. 要确保函数只做一件事,函数中的语句都要在同一抽象层级上。函数中混杂不同的抽象层级,往往让人迷惑。读者可能无法判断某个表达式是基础概念还是细节。更恶劣的是,就像破损的窗户,一旦细节与基础概念混杂,更多的细节就会在函数中纠结起来。
|
15 |
| -1. 写出短小的 switch 语句往往很难。写出只做一件事的 switch 语句也很难。我们总不发避开 switch 语句,不过还是能够确保 switch 都埋藏在较低的抽象层级,而且永远不重复。 |
| 14 | +1. 写出短小的 `switch` 语句往往很难。写出只做一件事的 `switch` 语句也很难。我们总不发避开 `switch` 语句,不过还是能够确保 `switch` 都埋藏在较低的抽象层级,而且永远不重复。 |
16 | 15 | 1. 最理想的参数数量是零,其次是一,再次是二...从测试的角度看,参数甚至更叫人为难。想想看,要编写能确保参数的各种组合运行正常的测试用例,是多么困难的事。如果没有参数,就是小菜一碟。
|
17 | 16 | 1. 函数承诺只做一件事,但还是会做其它被藏起来的事。有时,它会对自己类中的变量做出未能预期的改动,导致古怪的时序性耦合及顺序依赖。
|
18 | 17 |
|
@@ -52,7 +51,7 @@ public class UserValidator {
|
52 | 51 | 1. 若某个函数调用了另外一个,就应该把它们放在一起,而且调用者应该尽可能放在被调用者上面。
|
53 | 52 |
|
54 | 53 | ## 第六章 对象和数据结构
|
55 |
| -1. 最为精炼的数据结构,是一个只有公共变量、没有函数的类。这种数据结构有时被称为数据传送对象,或 DTO(Data Transfer Objects)。DTO 是非常有用的结构,尤其是在于数据库通信、或解析套接字传输的消息之类的场景中。 |
| 54 | +1. 最为精炼的数据结构,是一个只有公共变量、没有函数的类。这种数据结构有时被称为数据传送对象,或 `DTO`(Data Transfer Objects)。DTO 是非常有用的结构,尤其是在于数据库通信、或解析套接字传输的消息之类的场景中。 |
56 | 55 |
|
57 | 56 | ## 第七章 使用异常而非返回码
|
58 | 57 | 1. 在很久以前,许多语言都不支持异常。这些语言处理和汇报错误的手段都有限。你要么设置一个错误标识,要么返回给调用者检查的错误码。这类手段的问题在于,它们搞乱了调用者代码。调用者必须在调用之后即可检查错误。不幸的是,这个步骤很容易被遗忘。最好是抛出一个异常,这样其逻辑不会被错误处理搞乱。
|
@@ -109,4 +108,42 @@ public class UserValidator {
|
109 | 108 | - **互斥**:每一时刻仅有一个线程能访问共享数据或共享资源。
|
110 | 109 | - **线程饥饿**:一个或一组线程在很长时间内或永久被禁止。例如,总是让执行得快的线程先运行,加入执行得快得线程没完没了,则执行时间长的线程就会“饥饿”。
|
111 | 110 | - **死锁**:两个或多个线程互相等待执行结束。每个线程都拥有其它线程需要的资源,得不到其它线程拥有的资源,就无法终止。
|
112 |
| - - **活锁**:执行次序一致的线程,每个都想要起步,但发现其它线程已经“在路上”。由于竞步的原因,线程会持续尝试起步,但在很长时间内却无法如愿,甚至永远无法启动。 |
| 111 | + - **活锁**:执行次序一致的线程,每个都想要起步,但发现其它线程已经“在路上”。由于竞步的原因,线程会持续尝试起步,但在很长时间内却无法如愿,甚至永远无法启动。 |
| 112 | + |
| 113 | +## 第十四章 逐步改进 |
| 114 | +1. 代码能工作还不够,能工作的代码经常会严重崩溃。满足于仅仅让代码工作的程序员不够专业。他们会害怕没时间改进代码的结构和设计,我不敢苟同。没什么比糟糕的代码给开发项目带来更深远和长期的损害了。 |
| 115 | +1. 进度可以重订,需求可以重新定义,团队动态可以修正。糟糕的代码只会一直腐败发酵,无情地拖着团队的后腿。 |
| 116 | +1. 保持代码持续整洁和简单,永不让腐坏有机会开始。 |
| 117 | + |
| 118 | +## 第十五章 JUnit 框架 |
| 119 | +1. 成员变量的前缀可以删除。在现今的运行环境中,这类范围性编码纯属多余。 |
| 120 | +1. 条件判断应当封装起来,从而更清晰地表达代码的意图。可以拆解处一个方法,解释这个条件判断。 |
| 121 | +```java |
| 122 | +public String compact(String message) { |
| 123 | + if (expected == null || actual == null || areStringsEqual()) { |
| 124 | + return Assert.format(message, expected, actual); |
| 125 | + } |
| 126 | +} |
| 127 | + |
| 128 | +// 拆解后... |
| 129 | +public String compact(String message) { |
| 130 | + if (shouldNotCompact()) { |
| 131 | + return Assert.format(message, expected, actual); |
| 132 | + } |
| 133 | +} |
| 134 | + |
| 135 | +private boolean shouldNotCompact() { |
| 136 | + return expected == null || actual == null || areStringsEqual(); |
| 137 | +} |
| 138 | +``` |
| 139 | + |
| 140 | +## 第十七章 味道与启发 |
| 141 | +1. 让注释传达本该更好地在源代码控制系统、问题追踪系统或任何其它记录系统中保存的信息,是不恰当的。 |
| 142 | +1. 除函数签名之外什么也没说的 Javadoc,也是多余的。 |
| 143 | +1. 看到注释掉的代码,就删除它!别担心,源代码控制系统还会记得它。 |
| 144 | +1. 每次看到重复代码,都代表遗漏了抽象。将重复代码叠放进类似的抽象,增加了你的设计语言的词汇量。其它程序员可以用到你创建的抽象设施。编码变得越来越快,错误越来越少,因为你提升了抽象层级。 |
| 145 | +1. 死代码就是不执行的代码,可以在检查不会发生的条件的 if 语句中找到,可以在从不抛出异常的 try/catch 块中找到,可以在从不调用的小工具方法中找到,也可以在不会发生 switch/case 条件中找到。如果你找到死代码,就体面地埋葬它,将它从系统中删除掉。 |
| 146 | +1. 特性依恋是 Martin Fowler 提出的代码味道之一。类的方法只应对其所属类中的变量和函数感兴趣,不该垂青其它类中的变量和函数。我们要消除特性依恋。 |
| 147 | +1. 用多态替代 if/else 或 switch/case。对于给定的选择类型,不应有多于一个 switch 语句。在那个 switch 语句中的多个 case,必须创建多态对象,取代系统中其它类似 switch 语句。 |
| 148 | +1. 用命名常量替代魔术数。 |
| 149 | +1. 现在 enum 已经加入 java 语言了,放心用吧!别再用那个 `public static final int` 老花招。那样做 int 的意义就丧失了,而用 enum 则不然,因为它们隶属于有名称的枚举。 |
0 commit comments