【猫布克】代码整洁之道

代码整洁之道

0.前言

是github上的一篇资源,根据RObert C.Martin 代码整洁之道总结了适用于js的软件工程原则 Clean code js 的翻译。

这是根据代码整洁之道的代码优化建议,但也仅仅只是一份建议。你需要之道的是,软件工程已经发展50多年,至今仍在不断发展,这些原则也可能会过时。

最后你需要知道的是,这些东西不会让你立刻变成一个优秀的工程师,长期奉行他们也并不意味着你能够高枕无忧不再犯错。

1.变量

使用有意义,可读性好的变量名。

使用es6的const来定义常量,对功能类似的变量名采用统一的命名风格。

1.1.使用易于检索名称

我们需要阅读的代码远比自己写的要多,使代码拥有良好的可读性且易于检索非常重要。阅读变量名晦涩难懂的代码对读者来说是一种相当糟糕的体验。 让你的变量名易于检索。

反例:

// 525600 是什么?
for (var i = 0; i < 525600; i++) {
runCronJob();
}

正例:

// Declare them as capitalized var globals.
var MINUTES_IN_A_YEAR = 525600;
for (var i = 0; i < MINUTES_IN_A_YEAR; i++) {
runCronJob();
}

1.2.不要重复描述

反例:

var Car = {
carMake: 'Honda',
carModel: 'Accord',
carColor: 'Blue'
};
function paintCar(car) {
car.carColor = 'Red';
}

正例:

var Car = {
make: 'Honda',
model: 'Accord',
color: 'Blue'
};
function paintCar(car) {
car.color = 'Red';
}

1.3.避免无意义的条件判断

反例:

function createMicrobrewery(name) {
var breweryName;
if (name) {
breweryName = name;
} else {
breweryName = 'Hipster Brew Co.';
}
}

正例:

function createMicrobrewery(name) {
var breweryName = name || 'Hipster Brew Co.'
}

2.函数

2.1 函数参数

限制函数参数数量很有必要,这么做使得在测试函数时更加轻松。过多的参数将导致难以采用有效的测试用例对函数的各个参数进行测试。

应该避免3个以上参数的函数。通常情况下,参数超过2个意味着函数功能过于复杂。大多数情况下你可以将参数封装为一个对象。

2.2 函数功能单一性

这是软件功能种最重要的原则之一。

功能不单一的函数将导致难以重构,测试和理解。功能单一的函数易于重构,并使代码更加干净。

2.3 函数名应该表面其功能

2.4 函数应该只做一层抽象

当函数的需要的抽象多于一层时通常意味着函数功能过于复杂,需要将其进行分解以提高其可重用性和可测试性。

(感觉和函数功能单一性好像)

2.5 移除重复的代码

永远永远永远不要再任何循环下有重复代码!

这意味着逻辑变换时需要修改的地方不止一处。js弱类型的特点使函数拥有更强的普适性,好好利用这点。

2.5 采用默认参数精简代码

反例:

function writeForumComment(subject, body) {
subject = subject || 'No Subject';
body = body || 'No text';
}

正例:

function writeForumComment(subject = 'No subject', body = 'No text') {
...
}

2.6 使用Object.assign设置默认对象

没搞懂

2.7 不要使用标记(flag)作为函数参数

这通常意味着函数的功能的单一性已经被破坏。此时应考虑对函数进行再次划分。

没搞懂?

2.7 避免副作用

当函数产生了除了“接受一个值返回一个结果”之外时,称该函数产生了副作用。比如写文件,修改全局变量或将你的钱全转给了一个陌生人。

某些情况下确实需要副作用行为,比如创建文件,应该将副作用抽离,比如函数只负责输入值,而变量值修改的操作交给赋值符=

2.8 不要写全局函数

2.9 封装判断条件

2.10 避免否定情况的判断

3.对象和数据结构

3.1 使用getters和setters

js没有接口或类型,因此实现这一模式是很困难的,因为我们没有类似public和private的关键词。然而,使用getters和setters获取对象的数据远比直接使用点操作符更具有又是。

  1. 当需要对象的属性执行额外操作时。
  2. 执行set时可以增加规则对要变量合法性进行判断。
  3. 封装了内部逻辑。
  4. 在存取时可以方便的增加日志和错误处理。
  5. 继承该类可以重载默认行为。
  6. 从服务器获取数据时可以进行懒加载。

反例:

class BankAccount {
constructor() {
this.balance = 1000;
}
}
let bankAccount = new BankAccount();
// Buy shoes...
bankAccount.balance = bankAccount.balance - 100;

正例:

class BankAccount {
constructor() {
this.balance = 1000;
}
// It doesn't have to be prefixed with get or set to be a getter/setter
withdraw(amount) {
if (verifyAmountCanBeDeducted(amount)) {
this.balance -= amount;
}
}
}
let bankAccount = new BankAccount();
// Buy shoes...
bankAccount.withdraw(100);

3.2 让对象拥有私有变量

可以通过闭包完成

4.类

只简述一些原则,在开发过程中是否要类,自行决定

4.1 单一职责原则(SRP)

将多个功能塞进一个类的想法很诱人,但这将导致你的类无法达到概念上的内聚,并经常不得不进行修改。

最小化对一个类需要修改的次数是非常有必要的,若一个类具有太多太杂的功能,当你对其中一小部分进行修改的时候,很难想象对依赖这个类的其他模块会带来怎么样的影响。

4.2 开闭原创(OCP)

实体类,模块,函数灯应该易于扩展,难于修改。

也就是说我们想要开发新功能,应该注入新的代码而不是在原有基础上修改?

4.3 利斯柯夫替代原则(LSP)

子类对象应该能替换其超类对象被使用

也就是说,若有一个父类和一个子类,当采用子类替换父类时不应该残生错误的结果。

4.4 接口隔离原则(ISP)

在js中,当一个类需要许多参数设置才能生成一个对象时,需要考虑减少参数设置来源。

4.5 依赖反转原则(DIP)

  • 高层模块不应该依赖于底层模块,他们都应该依赖于抽象接口。
  • 抽象接口应该脱离具体实现,具体实现应该依赖于抽象接口。

5.并发

6.杂项

  • 调用函数的函数和被掉函数应该放在较近的位置
  • 只对逻辑复杂的地方进行注释
  • 避免位置标记
  • 优先使用组合模式而非继承

7.测试