代码整洁之道
零、基础认知
首先,代码设计是一门艺术,作为一门艺术,书中描述的是一个主流潮流,我们更多的是学习其中的思想。大多数的工程师都是希望自己能够写出清晰、漂亮的代码,做出更加明确的系统构成、架构风格。
一、别人眼中的我
尝试从第三人视角看待自己的代码
我的变量命名、注释以及项目组织结构都会对第三人的阅读产生影响,我已经完成的代码是否已经有了让别人能够轻松看懂的能力。
可能很多时候我会更多的通过“说”这个行为来描述一件事情,因为可以不断的补充。
能不能一眼能看出含义的命名?
在我想表达一个灯是开还是关的时候。诸如此类问题从字段可延伸至方法,类,包,系统,每一层都需要一个一个明确的命名
// 灯的开关状态
boolean open;
// 而不是
boolean lightStatus;
能不能一眼看出我写的代码要做什么?
需要提到一个设计原则:单一职责原则,很常见的一个设计原则,但是我认为这个原则适用于几乎生活中所有的场景。
我的方法、类、包、组件、系统没一层都应该有单一职责的影子。其“单一职责”的概念会随着抽象层级的升高而不断变化。
从文件系统举例:
boolean uploadFileToAliyun() 这个方法的职责就是上传文件到阿里云。
class UploanFileService 这个类的职责就是文件上传服务,可能上传到阿里云/七牛云/腾讯云等等。
project: file-system 这个项目的职责就是文件系统,包含文件的上传/下载/预览等行为,作为一个基础功能单元为业务系统服务。
随着系统抽象层次的升高,其实“单一职责”一直在延伸。
别人看我的代码眼睛累吗?
遥想当时学python的时候,开始学习没有接触pycharm等优秀工具,严格的换行,空格数量经常看的头晕眼花(不过yml格式我倒是系挺喜欢的)。
很多的开源项目,在提交贡献指南中会明确提出需要统一代码格式,为得就是保护每一个使用者的眼睛。
代码可读性放到现代是一个性价比极高的操作,在写完代码后,现代IDE工具可以直接进行格式化。
尝试从服务调用方视角看待自己提供的服务
这个服务如何调用?
我的输入、输出结构明确不?你要是给我返回一个Map 我直接两眼一黑。
在功能设计上数据流 输入-> 处理 -> 输出,其中【输入】【输出】一定需要具体的结构对象。无需多言。
这个服务一定会按要求返回吗?
我的服务的Call/Retrun是如何设计的,会不会直接抛异常,甚至直接服务500,怎么进行约定呢?
最小意外原则(Principle Of Least Surprise,PLS)
举个🌰:
在mybatis设计中,如何获取一个实体,查询不到为null,如果获取一组实体,查询不到则为empty。
null和空存在着天大的区别,其实都是对“有没有”的阐述。
在获取指定实体的时候,我们更希望拿到具体的对象,而在范围查询汇总中,我们更多的是对结果集进行操作,如果结果集为null,则需要耗费大量的心神去处理NPE。
其实Apache、Guava、Java、C# 等等著名工具类设计都存在此类方案。
二、我的关注点
更加清晰的层次设计
1.系统如何分层
Spring中我们按照范式大概约定了 Dao、Service、Controller,在某些应用中是否可以进行简化或者延伸。合理的分层可以使得系统架构更加简单易懂。
3.每一层的职责的划分
诸如Dao数据操作、Service功能服务、Controller接口控制
更加明确的类设计
1.单一职责
方法、类等应当简短,功能简单,职责单一
2.高扇入低扇出
扇入:被引用,被引用越多,说明类的复用越好
扇出:引用,引入的越多,说明类的职责越复杂
高内聚低耦合
功能内聚 > 偶然内聚
非直接耦合 > 内容耦合
三、自我审视、反省
好的代码是重构出来的
在做设计之前,我认为需要先考虑是否花费大量的心神、精力来做设计。是否可以先简单实现,后期迭代中进行设计演化。
代码检查code review的重要性
代码检查是一个很好的学习的机会,对整个系统的文化传承以及风格具有很多的帮助。如何正确的看待代码检查。
整体->局部 == 抽象->细节
面向抽象开发,如何理性的看待抽象。
实用大于一切
技术服务于功能,而非功能服务于技术,在设计中应保持理性,不要多度设计。