扁平化箭形代码
作为《嵌套条件的重构》 的姊妹篇,补充说明箭形代码的缺点,并以函数分解的方式扁平化箭形代码。
经常看到这种代码:
1 | if (rowCount > rowIdx) { |
太多的条件嵌套使代码变成一个箭头的样子:
1 | if |
当你在1280x1024 分辨率下阅读代码时会超出右边边界。这就是箭头反模式。
我重构的首要任务之一是把这样的箭形代码 “扁平化”。那些锋利的尖钩很危险!箭形代码有着很高的圈复杂度 -- 衡量贯穿代码有多少不同路径:
研究表明程序的质量与它的圈复杂度(WIKI, 百度百科)有关。低圈复杂度的程序更简单易懂,修改时的风险也更低。模块的圈复杂度与它的可测试性也是高度相关的。
在适当的地方,我通过以下方式扁平化箭形代码:
- 替换条件为
guard clauses
,这个代码..
1 | if (SomeNecessaryCondition) { |
.. 改成 guard clause
会更好:
1 | if (!SomeNecessaryCondition) { |
- 用函数来分解条件块。在上例中,我们把 do..while 循环里的条件分解。
1 | do { |
- 将否定检查转为肯定检查。主要规则是把肯定比较置前,让否定比较自然落到 else 中。我认为这样可读性肯定更好,更重要的是,避免 “我永远不会不做” 句式。
1 | if (Array.isArray(attributes[attrVal.attributeClassId])) { |
- 总是尽快从函数返回。一旦工作完成,马上退出。这个并非永远合适的 -- 你可能需要清理资源。但无论如何,你必须放弃只应在底部有一个出口的错误想法。
目的是让代码在垂直方向滚动多些...而不是在水平方向上。