《代码整洁之道》学习笔记

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