【外评】谷歌测试:复杂难读的布尔表达式

这是我们 “代码健康 “系列的另一篇文章。本文章的一个版本最初作为 “谷歌厕所测试 “插曲出现在全球的谷歌厕所中。您可以下载便于打印的版本,在您的办公室展示。

作者:孙一鸣(Yiming Sun)

您可能在代码库中遇到过一些复杂难读的布尔表达式,希望它们更容易理解。例如,我们想判断比萨饼是否美味:

// Decide whether this pizza is fantastic.

if ((!pepperoniService.empty() || sausages.size() > 0)

    && (useOnionFlag.get() || hasMushroom(ENOKI, PORTOBELLO)) && hasCheese()) {

  ...

}

改进的第一步是将条件提取为一个名称明确的变量:

boolean isPizzaFantastic = 

    (!pepperoniService.empty() || sausages.size() > 0)

    && (useOnionFlag.get() || hasMushroom(ENOKI, PORTOBELLO)) && hasCheese();

if (isPizzaFantastic) {

  ... 

}

然而,布尔表达式仍然过于复杂。根据给定的输入集计算 isPizzaFantastic 的值可能会令人困惑。您可能需要拿起笔和纸,或在本地启动服务器并设置断点。

取而代之的是,尝试将细节归类为提供有意义抽象的中间布尔值。下面的每个布尔值都代表一个定义明确的质量,你不再需要在表达式中混合使用 && 和 || 。在不改变业务逻辑的情况下,您可以更轻松地查看布尔值之间的关系:

boolean hasGoodMeat = !pepperoniService.empty() || sausages.size() > 0;

boolean hasGoodVeggies = useOnionFlag.get() || hasMushroom(ENOKI, PORTOBELLO);

boolean isPizzaFantastic = hasGoodMeat && hasGoodVeggies && hasCheese();

另一种方法是将逻辑隐藏在单独的方法中。这也提供了使用guard clauses 提前返回的可能性,进一步减少了跟踪中间状态的需要:

boolean isPizzaFantastic() {

  if (!hasCheese()) {

    return false;

  }

  if (pepperoniService.empty() && sausages.size() == 0) {

    return false;

  }

  return useOnionFlag.get() || hasMushroom(ENOKI, PORTOBELLO);
}

本文文字及图片出自 isBooleanTooLongAndComplex

你也许感兴趣的:

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注