代码整洁之道 - 读书笔记
0 前言
永远没必要说这本书看的太晚了,只是能再早一点也许会更好。
这里只是一部分笔记和随笔。并非是划重点。原著才是根本。
1 整洁代码
- 记住一句话:让营地比你来时更干净
2 有意义的命名
起一个好名字,会给接下来的事情带来效率。
单字母和数字常量的问题:难以搜索。
但是,一个很长的常量同样不利于阅读。
书上的例子,MAX_CLASSES_PER_STUDENT,个人来说差不多快到极限了。
成员前缀殊无必要
m_lpszName纯属历史遗留。
之前写C#的时候,有时还喜欢用m_ 或者 g_ ,但并不是标准,也不指的提倡。
现代的IDE已经不需要这些额外信息了
前导字母I也是滥用
扫描二维码关注公众号,回复: 7225495 查看本文章- 好听点是干扰,难听点根本就是废话的程度。
- 用户需要知道是个接口吗?不需要
- C#中枪……
方法名应该是动词或动词短语
- postPayment, deletePage, save, 这些都是好名字
语境
要有意义,以及,包装为更大的概念更好
例如, addrName, addrZipCode还可以
但其实不如address.name, address.zipCode
不要添加额外的语境,比如给每个变量加上gsd前缀这种。
3 函数
函数应该做一件事。做好这件事。只做这件事。
应该少用switch函数,应以多态替换之。
函数参数:越少越好
- 最理想的是没有参数(0参数)
- 一个次之。
- 两个再次
- 三个以上就应当尽量避免。
函数应当没有副作用(亦即没有非名称中的作用)
举例而言
public void checkSession(session){ if(session.notValid()){ session.initialize(); } }
上面的函数含有了失败则初始化,这是名称所没有的副作用。
所有名称看不出的作用,都是有害的,是给将来挖的坑。
输出参数
输出参数是有害的。
尤其是在java里面。
在C#里面还算能容忍,因为有明确的out参数:
public int func(int a, out obj b);
在C++里面属于相当讨厌的东西:
public void func(obj* p);
如果不进入函数内部,不知道是不是会改。而在C++里面传递指针又超级普遍。
再说一遍,java中不应当使用输出参数
也许go那种多返回值才是最终答案。
依赖磁铁
例如一个错误枚举类就是依赖磁铁。其修改会导致大范围重新编译。应当尽量避免。
没人能按照这些规则来写函数
所以,正当的流程是:
1st=>operation: 实现 2nd=>operation: 重构 3rd=>operation: 再重构 1st->2nd->3rd
4 注释
真实只在代码里存在
用代码来阐述
if (empolyee.isEligibleForFullBenefits())
- 这个函数足够描述功能,无需再去写注释。
- 英文对于国内非英文母语者是个挑战(对我也是)
- 如果相信这个函数名,就无需再去看内部
若你想标记右括号,其实应该做的是缩短函数
}//while }//for(...)
- 如果一屏之内能看完,何必用这个来标记?
- 还有现代的IDE折叠功能
注释就是注释,不要带有html等格式化内容
5 格式
垂直距离
关系密切的概念应该互相靠近,也不应分布在不同的文件中。
水平对齐
可以考虑拿掉了。
虽然我自己有些时候还是习惯于这样做,特别是常量定义的时候。
6 对象和数据结构
得墨忒定律(The Law of Demeter)
模块不应了解他所操作对象的内部情形
亦即下面的代码:
final String s = ctxt.getOptions().getScratchDir();
调用ctxt的模块没有道理知道getOptions()函数返回的对象有什么操作。
7 错误处理
- 别返回null
- 别传入null
以上两条说起来容易,真正做起来难啊。
8 边界
9 单元测试
测试的FIRST规则
- Fast(快速)
- Independent(独立)
- Repeatable(可重复)
- Self-Validating(自足验证)
- Timely(及时)
10 类
11 系统
- “一开始就做对系统”纯属神话。反之,我们应当只去实现今天的用户故事,然后重构,明天在扩展系统,实现新的用户故事。
12 迭进
- 重复是拥有良好设计系统的大敌
13 并发编程
14 逐步改进
必须要吐槽一下,本章所说的Args适用的语法,居然没有给出。
依据对于代码的推测,我推算语法规则如下:- 命令 -参数 值 -参数2 值2...
- 值通过前缀(#, *)等来区别其格式
- 允许参数合并,如ls -lh这种
- 只有单字母参数
渐进
毁坏程序最好的办法就是以改进之名,大动其结构。有些程序将永远无法从这种所谓的“改进”之中恢复过来。
15 JUnit内幕
16 重构SerialDate
- Javadoc的HTML格式化工作让我畏惧。注释里面带有太多的语言。注释应当和最终输出没什么关系
- 纯文本注释输出可以保证格式的统一
17 味道与启发
前后一致
例如,如果某个函数用rsp来命名HttpServletResponse对象,那么其他的函数也应当这么做。
如果用的是response,那么大家也都用
重要的不是用什么而是一致
别用算子参数(selector参数)
例如这种函数:func(true,false,true) 完全是噩梦。
图书推荐:Implementation Patterns(实现模式)
封装条件
如果没有上下文,布尔逻辑就难以理解。
应该把解释了条件意图的函数抽离出来。
例如:
if(shouldBeDelete(timer))
要好于
if(timer.hasExpired() && timer.isRecurrent())
否定式难以理解。尽量用肯定式
亦即尽量少用 if(!xxx()) 这种
附录A 并发编程II
- 应当尽量选择基于服务端的锁定