代码的职能
个人认为,同时具备以下3个职能的代码才是好的代码。
- 正确执行,没有bug。
- 简单易懂,方便他人理解。
- 设计巧妙,功能易于扩展,需求容易变更。
绝大多数的代码并不能满足以上3点要求,由于任务工期的紧张,很多代码仅仅能够满足第一点要求。不,有时候连第一点要求也无法满足。因为只能证明当前的代码有bug,而不能保证代码永远没有bug。尤其是在代码没有满足第二点职能的时候。
短期内,第1种职能的重要性最高。但从长期的收益考虑,第2种职能最重要,代码的易读性往往影响着另外两个职能的实现。
代码的本质
在没有注释的情况下,为什么一个程序员能读懂另一个程序员的代码?
因为代码的本质是语言,是程序员之间交流的工具。代码语义的清晰正确保证了代码的可持续性。对于一段代码,所有程序员花在它身上的阅读时间远大于书写时间。编写一段代码是一个人的事情,而阅读一段代码是整个团队的事情,如果一个团队成员写出的代码难以理解,那么会导致以下问题:
- 单次阅读理解时间增长。
- 如果理解错误,写出bug,修复bug,再重写代码,增加额外开销。
- 含糊不清的代码容易增殖含糊不清的代码,蔓延到相关逻辑。
检查变量名/函数名 语义是否清晰最好的方法,就是看一段代码能否流畅地读出来。
火箭式代码
工作中遇到的代码
if(Random.CrossThreshold())
{
foreach(var pickItem in array)
{
if(pickItem.CannGet)
{
if(player.level > pickItem.levelNeed)
//do
else
continue;
if(...)
else
{
if(pickItem.Level < prevItem.Level)
{
}
else if(...)
{
if(...)
{
}
}
}
}
}
}
火箭式代码的一个特点就是关键字if的数量远大于else的数量。N多个if相互嵌套而又没有else与之对应,于是形成了if层层嵌套的代码,俗称火箭式代码。
这样的代码结构是不利于程序员阅读的,因为程序员在阅读这些代码的时候,需要在脑内维持一个栈的结构,极其消耗脑力,因此将if嵌套式(火箭式)的代码修改为if并列式的代码有利于帮助理清思路,减少bug的出现率。
厉害的程序员不是脑力有多厉害,而是选择了容易维护的实现方案。
消除火箭式代码的核心方法是找到最外层没有else对应的if语句,将逻辑置反,直接return/continue/break即可。
几个案例和修改方案
案例1——变量名语义不清晰
if(checkActivity) //如果检查活动, 检查活动什么??活动是否开启,关闭?是否参与人数超过10000?
{
//todo
}
修改方案
if(activityIsOpen) //如果活动开启,
{
//todo
}
案例2——代码过于分散
i=0; //表达的意思是遍历数组元素并操作
while(i<array.Count) //但遍历数组这个操作需要由 3行代码一同表示,不仅啰嗦,而且代码分散在各处,容易出bug
{
Do(array[i]);
i++;
}
修改方案
foreach(var pickItem in array)
{
Do(pickItem);
}
案例3——火箭式代码
if(win)
{
if(tmpSoldier >0)
{
//do something
if(costSoldier > tmpSoldier)
{
if(taticId == 1)
…
else if(taticId == 2)
…
}
}
}
修改方案
if(tmpSoldier > costSoldier)
{
//
Return;
}
if(soldier>costSoldier && gold > costGold)
{
//
return;
}
//fight fail logic
总结
代码编写的过程中,语义表达可能存在的问题有
- 语义表达错误
- 语义表达不清
- 语义表达多余【存在无用代码】
确定语义的方法有
- 约定代码规范
- 注释确定语义
- 使用更特殊的语法确定语义
- idom(习语)确定语义
语义的表达实际上就是在告诉阅读代码的人,我这部分的代码是做什么的,并且降低阅读者误解的概率。经常通过将语法上的行为(赋值语句,for语句)抽象为逻辑上的行为(函数)来降低阅读者需要的脑力。
附录
结构化的语言内在的哲学理念 由迪杰斯特拉取缔goto,通过函数实现分治,将语法的行为抽象为逻辑行为说起。
远古的代码往往充斥着goto关键字,因此代码往往难以复用。迪杰斯特拉对比了数理证明和代码之间的关系,函数名对应数学定理,而函数实现对于定理证明。将语法的行为抽象为逻辑行为的过程之一就是将一部分代码以函数的形式抽象出来,调用函数等价于使用数学定理,而函数的实现等价于数学定理的证明。