前言
通常我们学习都是从一门语言开始,但是一旦脱离对应的语言及平台,我们所学的知识可能没有任何用武之地。
而 clean code
是一个通用的技术,除了需要极少量的语言特性。而且这种越底层越通用的技术学会了,能够极大的提升内功,日常迭代过程中的增强我们代码的可维护性,可以帮助我们可以毫不费力的就可以写出质量非常高的代码。
而我们日常做 code review
时,这个也会是一个很大的指导原则。
怎么做?
- 命名有意义(参数、方法名、常/变量名),不要直接使用数字,使用常量代替。
- 尽量短 (类、函数名、函数体、参数)
- dry (意图、结构、代码)
- 保持一致性
命名
- 精准命名
- 不能过于宽泛
- 应该描述意图,而非细节
- 不要用技术术语命名
- 用业务语言写代码,建议团队的语汇库
- 常量、变量、类、字面量命名应该使用名词, 函数命名应该使用动词
// 精准命名
processChapter(id) => changeChapterToTranslating(id) => startTranslation(id)
yyyymmdd => currentDate
yyyymmddhhmmss => currentTime
86400000 => MILLISECONDS_PER_DAY
cityZipCodeRegex[1], cityZipCodeRegex[2] => [_, city, zipCode] = address.match(cityZipCodeRegex) || []
// 不要用技术术语命名
bookList / bookArray / bookSet => books
函数
- 不能有意图重复,只要意图不重复哪怕一模一样也是可以接受的
- 参数小于等于2个,不能使用 boolean 参数。如果超过3个参数,考虑封装成类。
- 函数行数小于20行
- 有返回值的函数不能有副作用,没有返回值的函数可以要有副作用,且副作用应该成对出现
- 保证函数内部的所有事情都处在同一个抽象层级
- only try block, expect error is one thing
- 保证可测试性
verifyUsername() / verifyPassword()
createElement('div', {...props})
参数
- remove flag argument
- 动静分离,如果一个参数他们的字段变化频率并不一致时,考虑拆分他们到不同的对象中
- 聚沙成塔:如果参数很多时,应该封装成对象。如果些对象还具有某些行为,封装成类
createFile(isTemp) => createFile() + createTempFile()
类
- 职责单一、尽量小(字段少、参数少)
- 字段分组 - 和参数的动静分离对应
控制语句
- 卫语句: 提前
return
- 判断条件重复时可以状态模式/策略模式(可以使用表单法来构造) - 开闭原则的体现
if (xxx) {
} else {
}
=>
if (xxx) return xxx
return xxx
function getPrice(type) {
switch(type) {
case .type1: return price * 0.8
case .type2: return price * 0.7
case .type3: return price * 0.6
}
}
function getEpubPrice() {
switch(type) {
case .type1: return price * 0.85
case .type2: return price * 0.75
case .type3: return price * 0.65
}
}
=>
interface Type {
getPrice()
getEpubPrice()
}
class Type1 implements Type {
getPrice()
getEpubPrice()
}
class Type2 implements Type {
getPrice()
getEpubPrice()
}
class Type3 implements Type {
getPrice()
getEpubPrice()
}
switch(type) {
case .type1: return new Type1()
case .type2: return new Type2()
case .type3: return new Type3()
}
// 或者使用表单法
{type1: new Type1(), type2: new Type2(), type3: new Type3()}[type]
function getPrice() {
return type.getPrice()
}
function getEpubPrice() {
return type.getEpubPrice()
}
封装
- 避免火车残骸代码(迪米特法则/最少知道原则的体现)
- 基本类型偏执(这个可以使用
ts
解决) - 一次性完成变量的初始化
- 增加防腐层,主要在于判断是不是有可能被替换。
比如我完成一些功能后将其发送到钉钉,但是这个完全可能被替换,那么这个时候,我们是不能在业务直接调用,而应该增加防腐层。(依赖倒置原则的体现 - 高层不应该依赖低层,二者都应该依赖抽象。抽象不依赖于细节,细节应该依赖于抽象。)
a.b.c.d => a.bb
number => type Money = number
let value = ''
if (xxx) value = xxx
else value = xxx
=>
getValue() {
if (xxx) return xxx
return xxx
}
class Test {
feishuService
sendBook() {
try {} catch(error) {
feishuService.send(error)
}
}
}
=>
interface FailureService {
send(error)
}
class FeishuService implements FailureService {}
class Test {
failureService: FailureService
sendBook() {
try {} catch(error) {
failureService.send(error)
}
}
}
引用
- clean-code-javascript
- 极客时间《代码之丑》