Clean Code Tips #1 -- if...else...到底如何写才易懂?

Clean Code Tips #1 -- if...else...到底如何写才易懂?

程序员真正拥有一段代码的时间是从打出第一个字符到合并进master分支之前,在这之后这段代码就是遗留代码(legacy code),它将会被其他人维护,理解和吐槽。这也是clean code所存在的价值,它让我们的每一行遗留代码都变得易于维护和理解。我并不打算把clean code tips写成《clean code》的读书笔记,我认为知识只有付诸于实践之后才能成为自己的,所以,clean code tips是用来记录我工作中经常会碰到的一些代码异味和我是如何重构他们的。

if...else...语句应该是每个程序员每天都会涉及的代码,但是,恰恰是这种高频率的代码却经常会出现非常难以理解和维护的情况,比如下面这种

if (null != fish 
        && (fish.getExpiredTime() >= System.currentTime() 
            || !fish.isCooked() 
            || !fish.isPrepared())) {
    ... code block ...
}
复制代码

为了不必要的麻烦,我用了一个类似的关于fish的代码来描述。

假如这段代码是你留下来的,那么,对于正在阅读这段代码的同事,其效果就如同他(她)正打算走进一家餐馆吃饭,却突然发现门口立了这么一个牌子。

你的同事会怎么想? ... ... ...

也许作为这个牌子的作者,你会觉得自己的逻辑好清晰。但是,相信我,除了你自己,每一个看到这段代码的人的表情都会和上面的差不多。

也许你会问,那应该如何重构?其实很简单,就如同很多餐厅会直接挂出“正在营业”或是“暂停营业”的牌子一样,你只需通过把这段逻辑放到一个方法中来直接告诉读者你到底要判断什么即可。而方法的命名最好以is或者has开头。

private boolean isFishReadyToEat(Fish fish) {
    return null != fish 
                && (fish.getExpiredTime() >= System.currentTime() 
                || !fish.isCooked() 
                || !fish.isPrepared())
}
复制代码
if (isFishReadyToEat(fish)) {
    ... code block ...
}
复制代码

这样,当有人再读到这段代码的时候,就可以很容易的理解你的逻辑,而不需要像一个编译器一样去处理你的每一个and和or的逻辑关系。

你也许会问,是不是如果只有一个判断条件就不用这种方式了呢?这是一个非常错误的想法,代码的可维护性需要日积月累的完善,而不是因为到了不可维护,所以,才考虑维护。

所以,哪怕是一个条件,也最好做到用一个方法来封装起来。比如,上面的代码还可以更进一步的优化

private boolean isFishReadyToEat(Fish fish) {
    return null != fish 
                && (isFishExpired(fish) 
                || !fish.isCooked() 
                || !fish.isPrepared())
}

private boolean isFishExpired(Fish fish) {
    return fish.getExpiredTime() >= System.currentTime();
}
复制代码

可以看到,我把检查fish是不是过期放到了另一个方法中不管对于isFishReadyToEat的可读性来说,还是从之后的可复用性上来讲,这都是一个好的开始。比如,当其他的代码需要查看fish是不是过期的时候,就只需要复用isFishExpired即可。

最后,希望这篇文章对你有一点点的启发,也希望在代码的世界中我们也能做到“不因善小而不为”。

本文所涉及到的Clean code相关概念

Do one thing

Don't repeat yourself (DRY)

Descriptive coding

分类:
代码人生
标签: