1. What?
正如Jack Reecves所发表的《源码就是设计》:源码就是最好软件设计文档,而其他非代码性的文档只是源码的辅助。本文并非为了讨论编程与软件设计的关系,只想借以说明源码的重要性。
简单讲,整洁代码行云流水如同阅读精美好文,代码能够尽可能的自解释;具体讲,整洁代码具备如下特性:
- 变量、函数、类、包、模块命名合理有意义
- 代码结构(格式)清晰
- 必要的合理的注释信息:代码能自解释只是理想,该注释的地方还是免不了
- 合理的异常处理机制
- 有效的日志信息
- 遵循面向对象设计原则
2. How?
我们写文章都是先构思再下笔,但一般不可能一气呵成。都是先出初稿再调整、使用精美词句慢慢打磨。写代码同写文章一样,也是一个不断调整修饰的过程(修改名称、分解函数、消除重复等操作不断重复)。只要你有一颗写出整洁代码的初心。
2.1. 有意义的命名
- 名副其实,必免误导:在给变量、函数等取个合适名字其实是很花时间的事,对于已有的变量等,如果想到更合适的名字则请记得马上换掉,必免误导其他开发人员。
- 遵守编码规范中的命名相关部分。
2.2. 清晰的代码结构
- 问题分解、模块职责划分
- 编码前需要有最基本的设计思路,不管是何种设计粒度(系统、模块、类),其核心骨架、流程都必须成竹于胸。
- 函数尽量精简,精简的函数不代表行数就一定是很少;只要保证一个函数只做一件事,这里的“一件事“比较抽象,不同人有不同的解读;我的区分原则为:有利于函数复用与阅读。
- 函数参数越少越好,这样能省很多测试用例;参数尽量只用于输入,通过返回值进行函数结果输出,参数尽量不同时承载输入与输出信息(多线程开发时除外)
- 函数要么做查询操作,要么做设置操作,不要同时都做。
2.3. 注释
2.3.1. 合理的注释
- 注释是为了弥补代码无力表达程序意图时的一个有效补充。
- 代码能自我表达固然是撸码的最高境界,但现实总是残酷的,当有段代码你发现需要写注释时,你需要先反省下是否代码写得太差以致于无法自解释。注释并不能美化糟糕的代码。
- 需要明白注释是有维护成本的,如果不及时更新就容易引起混乱
- 外部服务接口/API都需要提供必要的注释信息,有一定的维护成本,但一定不能省。
- 潜在的坑也需要注释以警告其他开发人员,最常见的是FIXME、为了解决出现线程不安全问题的代码逻辑(不写清楚无经验的同事可能会乱改而引入BUG,如SimpleDateFormat)
2.3.2. 不好的注释
- 个人觉得JavaBean的Getter/Setter方法是不需要注释的
- 对代码的修改不需要写一些日志式的注释、不写废话式注释
- 能用函数名或变量名自解释的,尽量不写注释
- 不需要在控制语句的花括号结尾加代表语句结束的注释,类似
} // while
- 也不需要写一大段的注释,如果出现这种情况,肯定是功能函数拆解不合理导致。
2.4. 格式
- 遵行编码规范中的格式部分
- 合理使用空行
- 联系紧密的代码尽量靠在一起
- 一个团队使用同一套格式规则
2.5. 对象与数据结构
- 认真对待抽象,不是简单的写个接口,加几个方法就算是抽象
- 对像隐藏数据,暴露操作;数据结构暴露数据,不提供操作函数
- DTO,DDD中的充血模型,类JavaBean的失血模型,个人项目中我更倾向于使用充血模型,所以书中所谓的混杂我是不太同意的。
2.6. 错误处理
- 面向对象设计中,严格实行快速抛异常原则,而不是返回错误代码,而不应该吃掉异常。
- 对于尽量不抛出Checked类型的异常这一说法,个人持保留态度
- 对于外部复杂的异常层次结构可做必要的封装以减少重复代码
- 尽量不使用null作为返回值、参数等,因为null可能引起歧义
2.7. 对第三方库的处理方式
- 建议对第三方接口进行包装,便于后续适配多个提供方
- 团队协作中,如果依赖的其他子系统的接口未定义,但我们已明确我方的需求,我们可以先定义接口并提供一个Mock类,这样可以保证我们的模块稳定性及可测试性
- 如果依赖的第三方接口在本系统中使用得比较多,也建议统一再包装一层以适应外部接口变化
- 包装的目的是屏蔽外部不确定性、增加鲁棒性
2.8. 类与系统的设计
- 遵循面向对象设计原则
转载请注明出处:cloudnoter.com