曾经以为只要能够满足需求的代码就是好的代码,直到真正从事项目的开发。反复修改,总也找不到技巧。究竟什么是好的代码呢?如何才是简洁高效的表达,如何才能一次approve?我有问题,你知道答案吗?
这是Clean Code的阅读笔记,简单介绍clean code法则。
一句话总结什么是好的代码:
- 消除重复代码
- 提高代码的表达力
- 提早构建简单的抽象
如何确保有意义的命名
- 命名需要有含义:
假设我们有这样一段代码:
#include <iostream>
#include <list>
#include <string>
int main() {
std::list<std::string> myList = {"A", "B", "C", "D", "E", "F"};
if (myList.size() >= 4) {
auto it = myList.begin();
std::advance(it, 3); // 从第一个元素开始,向前移动 3 步 -> 第四个元素
std::cout << "第四个元素是: " << *it << std::endl;
} else {
std::cout << "list 中元素不足 4 个" << std::endl;
}
return 0;
}
看起来是不是思路很清晰,从list中获取第四个参数。
但是如果放在项目中,我并不清楚myList是什么。
如果是一个扫雷游戏,那么可以选择gameBoard来命名,这样依据具体的项目来表达,会更加易读。
- 避免误导
accountList 看起来是符合规则的,但是List在JAVA中是特殊的含义,可以考虑使用accountGroup,看起来更为明确。
像hp,aix等Unix的专有名称也不适用于直接拿来命名。
maxReplicationCheckerTestRunCount, maxReplicationCheckerRunCount,这些看起来几乎一样的名称,使得代码的可读性变得很差。
真正可怕的还是用小写字母 l 和大写字母 O 作为变量名,实在是难以区分。
- 做有意义的区分:
a1, a2, … aN, ProductInfo and ProductData, 这样的区分就像a,an和the一样,毫无意义。想要区分名称,就要以读者能鉴别出的不同之处来区分。 - 使用读得出来的名称
比如genymdhms,看起来不知道是何含义,改成generationTimestamp,一眼就能了解其含义。 - 使用可以搜索的名称
单字母名称和数字常量有个问题,就是很难在一大篇文字中找出来。 - 避免使用编码
Java 程序员不需要类型编码,也不必用 m_前缀来标明成员变量。
有时也会出现采用编码的特殊情形。比如,你在做一个创建形状用的抽象工厂(Abstract Factory)。该工厂是个接口,要用具体类来实现。你怎么来命名工厂和具体类呢?IShapeFactory 和 ShapeFactory 吗?不想让用户知道我给他们的是接口,就想让他们知道那是个 ShapeFactory。如果接口和实现必须选一个来编码的话,我宁肯选择实现。ShapeFactoryImp,甚至是丑陋的 CShapeFactory,都比对接口名称编码来得好。
- 避免思维映射
传统上惯用单字母名称做循环计数器。 - 类名
类名和对象名应该是名词或名词短语,如 Customer、WikiPage、Account 和 AddressParser。避免使用 Manager、Processor、Data 或 Info 这样的类名。类名不应当是动词。 - 方法名
方法名应当是动词或动词短语,如 postPayment、deletePage 或 save。属性访问器、修改器和断言应该根据其值命名,并依 Javabean 标准[10]加上 get、set 和 is 前缀。
重载构造器时,使用描述了参数的静态工厂方法名。
例如:
Complex fulcrumPoint = Complex.FromRealNumber(23.0);
好于
Complex fulcrumPoint = new Complex(23.0);
可以考虑将相应的构造器设置为 private,强制使用这种命名手段。
-
每个概念对应一个词
给每个抽象概念选一个词,并且一以贯之。例如,使用 fetch、 retrieve 和 get 来给在多个类中的同种方法命名。 -
别用双关语
避免将同一单词用于不同目的。同一术语用于不同概念,基本上就是双关语了。
比如,在多个类中都有 add 方法,该方法通过增加或连接两个现存值来获得新值。假设要写个新类,该类中有一个方法,把单个参数放到群集(collection)中。该把这个方法叫做 add 吗?这样做貌似和其他 add 方法保持了一致,但实际上语义却不同,应该用 insert 或 append 之类词来命名才对。把该方法命名为 add,就是双关语了。 -
使用解决方案领域的名称
尽管用那些计算机科学(Computer Science,CS)术语、算法名、模式名、数学术语吧,例如JobQueue. -
使用源自所涉问题领域的名称
如果不能用程序员熟悉的术语来给手头的工作命名,就采用从所涉问题领域而来的名称吧。 -
添加有意义的语境
很少有名称是能自我说明的——多数都不能。反之,你需要用有良好命名的类、函数或名称空间来放置名称,给读者提供语境。如果没这么做,给名称添加前缀就是最后一招了。
设想你有名为 firstName、lastName、street、houseNumber、city、state 和 zipcode 的变量。当它们搁一块儿的时候,很明确是构成了一个地址。不过,假使只是在某个方法中看见孤零零一个 state 变量呢?你会理所当然推断那是某个地址的一部分吗?可以添加前缀 addrFirstName、addrLastName、addrState 等,以此提供语境。至少,读者会明白这些变量是某个更大结构的一部分。当然,更好的方案是创建名为 Address 的类。这样,即便是编译器也会知道这些变量隶属某个更大的概念了。
-
不要添加没用的语境
只要短名称足够清楚,就要比长名称好。别给名称添加不必要的语境。Address 是个好类名。如果需要与 MAC 地址、端口地址和 Web 地址相区别,我会考虑使用 PostalAddress、MAC 和 URI。这样的名称更为精确,而精确正是命名的要点。 -
总结
取好名字最难的地方在于需要良好的描述技巧和共有文化背景。与其说这是一种技术、商业或管理问题,还不如说是一种教学问题。其结果是,这个领域内的许多人都没能学会做得很好。
9604

被折叠的 条评论
为什么被折叠?



