在日常编程中,优雅的代码总是千篇一律,而“丑陋”的代码却是千奇百怪,接下来的几期,我们以 Java 代码为例,一起来看看“代码之丑”
一、命名
常见命名词汇
- data
- info
- flag
- process
- handle
- build
- maintain
- manage
- modify
上述词汇表达意义比较模糊。
不准确的命名
public void processChapter(long chapterId) {
Chapter chapter = this.repository.findByChapterId(chapterId);
if (chapter == null) {
throw new IllegalArgumentException("Unknown chapter [" + chapterId + "]");
}
chapter.setTranslationState(TranslationState.TRANSLATING);
this.repository.save(chapter);
}
以上代码是将翻译状态改为“翻译中”,即“开始翻译”,使用 processChapter 命名并不准确,改为任何状态都可以叫 处理状态,这个方法应该叫做 startTranslation。
所以进行命名时,我们应该明确方法或者变量的用途,然后进行命名,而不是根据他们的过程/内容甚至是结果进行命名。另外,使用大家(程序员)熟知的词语,例如
pageCount代表总页数,而用pageNum表示总页数就怪怪的,一般它表示当前页。
技术词汇命名
List<Book> bookList = service.getBooks();
bookList 是一个 业务+技术 的命名方法,但是如果技术改变,例如我需要一个不重复的列表,将 List 换成 Set,那我的变量名是不是也要变,不变是不是会引起歧义?所以,这个变量应该叫 books 更合理一些。
读你代码的都是程序员,变量的数据类型一看便知,不需要在名称上体现,更应该体现业务含义;当然如果有多个类型的变量表示类似的含义时,可以加上类型进行区分。
业务语言
public void approveChapter(long chapterId, long userId) {
...
}
上述代码是确认审核章节通过,chapterId 是审核章节的 ID,userId 是用户的 ID 吗?明显不是,它应该是审核人的 ID,所以不应该叫 userId 而是叫做 reviewerUserId(审核人 ID) 更为合理,这就是在业务视角进行命名。
在日常开发中,我们会遇到很多“同义不同音”的命名,例如我最近在读巡检类功能的代码,
inspection和patrol都能在代码里找到,其实成熟的业务开发组,可以在协同文档里维护一张“命名表”,常用的业务命名能够做到约定俗成即可。
避免中式英语
这个就不展开了,如果你的项目比较敏感,必须用中文简写命名字段、数据库属性等,那么请延续它,否则不要在程序中出现中文或拼音的命名。
二、代码重复
做真正的选择
if (user.isEditor()) {
service.editChapter(chapterId, title, content, true);
} else {
service.editChapter(chapterId, title, content, false);
}
上述代码的作用是通过 user.isEditor() 判断用户是不是编辑,是编辑就传 true,不是就传 false。
这并不需要选择来做这件事,就是传值问题,我们只需要把需要的值传过去就可以了。
所以我们应该用下面的写法,不进行判断,只进行传值。
所以如果
if和else里面的代码长得很像,多半是出现了这种假选择的情况。
boolean approved = user.isEditor();
service.editChapter(chapterId, title, content, approved);
又或者下面的代码
if (response.getCode() == 201) {
status = EpubStatus.CREATED;
} else {
status = EpubStatus.TO_CREATE;
}
一共就两个值的变化,else 写的很多余,完全可以改为
status = EpubStatus.TO_CREATE;
if (response.getCode() == 201) {
status = EpubStatus.CREATED;
}
下一期我们会继续聊聊如何避免不规范的编码(文件上传的内容先鸽几期),希望各位能在日常繁杂、无趣的业务开发中依然保持优雅的编码习惯,尽管这并不简单。
好看记得关注嗷~