可读的代码
---

过去，我有过在不同的场合吐槽别人的代码写得烂。而我写的仅仅是比别人好一点而已——而不是好很多。

然而这是一件很难的事，人们对于同一件事物未来的考虑都是不一样的。同样的代码在相同的情景下，不同的人会有不同的设计模式。同样的代码在不同的情景下，同样的人会有不同的设计模式。在这里，我们没有办法讨论设计模式，也不需要讨论。

我们所需要做的是，确保我们的代码易读、易测试，看上去这样就够了，然而这也是挺复杂的一件事:

 - 确保我们的变量名、函数名是易读的
 - 没有复杂的逻辑判断
 - 没有多层嵌套 (事不过三)
 - 减少复杂函数的出现（如,不超过三十行）
 - 然后，你要去测试它。这样你就知道需要什么，实际上要做到这些也不是一些难事。

只是首先，我们要知道我们要自己需要这些。对于没有太多编程经验的人，建议先从两个基本点做起：

 - 命名
 - 函数长度

首先要说的就是程序员认为最难的一个话题了——命名。

###命名

命名是一个特别长的，也是特别忧伤的故事。我想作为一个程序员的你，也相当恐惧这件事。一个好的函数名、变量名应该包含着这个函数的信息，如这个函数是干什么的，或者这个函数是怎么来的，这个变量名存储的是什么。

正因为取名字是一件很重要的事，所以它也是一件很难的事。一个好的函数名、变量名应该能正确地表达出它的涵义。如你可以猜到下面的代码中的i是什么意思吗？

```python
fruits = ['banana', 'apple',  'mango']
for i in fruits:        # Second Example
   print 'Current fruit :', i
```

那如果换成下面的代码会不会更容易阅读呢？


```python
fruits = ['banana', 'apple',  'mango']
for i in fruits:        # Second Example
   print 'Current fruit :', i
```

而命令还存在于对函数的命名上，如我们可能会用getNumber来表示去获取一个数值，但是要知道这样的命名并不是在所有的语言中都可以这样用。如在Java中存在getter和setter这种模式，如下的代码所示：

```
public String getNumber() {
  return number;
}
public void setNumber(String number) {
  this.number = number;
}
```

如果我们是去取某个东西的数值，那么我们应该使用retrieveNumber这样的更具代表性的名字。

在《编写可读代码的艺术》也提到了这几点：

1. 选择专业的词。最好是可以和业务相关的，它应该极具表现力。
2. 避免像tmp和retval这样泛泛的名字。不得不提到的一点是，tmp实在是一个有够烂的名字，将其变为timeTemp或者类似的会更直观。它只应该是名字中的一部分。
3. 用具体的名字代替抽象的名字。
4. 为名字赋予更多的信息。
5. 名字应该有多长。
6. 利用名字的格式来传递含义。

###函数长度

> 函数是指一段在一起的、可以做某一件事儿的程序。

这就意味着从定义上来说，这段函数应该只做一件事——但是什么才是真正的一件事呢？实际上还是TASKING，将一个复杂的过程一步步地分解成一个个的函数，每个函数只做他的名称对应的事。对于一个任务来说，他有一个稳定的过程，在这个过程中的每一步都可以变成一个函数。

因此，长的代码意味着一件事——这个函数可能违反了单一职责原则，即这个类做了太多的事。通常来说，一个类，只有一个引起它变化的原因。当一个类有多个职责的时候，这些代码就容易耦合到一起了。

对于函数长度的控制是为了有效控制分支深度。如果我们用一个函数来实现一个复杂的功能，那么不仅仅在我们下次阅读的时间会花费大量的时间。而且如果我们的代码没有测试话，那么这些代码就会变得越来越难以理解。而在我们写这些函数的时候就没有测试，那么这个函数就会变得越来越难以测试，它们就会变成遗留代码。

###其他

虽然只想介绍上面的简单的两点，但是顺便在这里也提一下重复代码~~。

####重复代码

在《重构》一书中首先提到的Code Smell就是重复代码（Duplicate Code）。重复代码看上去并不会影响我们的阅读体验，但是实际上会发生这样的事——重复的代码阅读体验越不好。

DRY(Don't Repeat Yourself)原则是特别值得玩味的。当我们不断地偏执的去减少重复代码的时候，会导致复杂度越来越高。在适当的时候，由于业务发生变更，我们还需要去拆解这些不重复的代码。


