匿名nil

匿名nil是许多Swift代码库中都存在的一种微妙的代码味道。 它是什么? 为什么会出问题呢? 我们该如何解决呢?

最初在 mczarnik.com上 发布

让我们举一个简短, 虚构非常人为的示例。 假设您的代码库中有一个方法可以显示带有动画的视图。

很明显吧? 不,这不是显而易见的。 这甚至都不合逻辑。 这个例子非常人为 ,但我希望您能明白问题所在。

有什么问题?

无论您为获得此信息做出了什么选择,为什么都必须对自己问这个问题? 好的API可以自我说明,在给定某些输入的情况下解释其功能或性能将是其设计者的失败。 就像物理的东西一样-最好的设计不必解释,只要理解就可以。

这里的问题来自可选的过度使用。 可选的含义很严格。 它的意思是:

有一个值,它等于x或根本没有值

而已。 就是这样 。 在我们的例子中, nil的定义是“屏幕底部的默认动画”。 这个nil有一个意思,但是意思是不同的。 这就是我所说的匿名nil 是用作实际参数或变量/常量 nil ,其含义不仅仅是“根本没有价值”

有什么后果?

无论您在哪里使用nil作为具有特殊含义的值(而且它根本不是“毫无价值”),都会使您的API用户(包括未来的自我)感到悲伤:

  • 他们可能会浪费时间去弄清楚这是什么意思(有时答案可能隐藏得很深)。
  • 他们可能会遇到许多其他使用相似签名的方法,但是每次看到它们时,他们都需要问自己,来自其他方法的规则在相似的地方是否仍然成立?
  • 他们需要在头脑中保持有关API的易变的元知识
  • 他们甚至可能对系统的行为有错误的假设

您如何使它更好?

通常,我们无力进行适当的依赖注入,否则DI并不是解决此类问题的正确工具。 让我们尝试更多地了解问题,并提出可行的轻量级解决方案。

在我们的情况下,该方法有两种可能的结果:

  • 动画将从底部弹出
  • 特定的非零动画将被执行

难道不像是有两种情况的enum ? 确实是的。 如果我们在代码中使用这种枚举怎么办? 很简单:

现在,呼叫方不再有任何歧义:

实施方面呢? 为了能够在内部使用Animation对象,我们需要扩展我们的枚举以解开包装的值。

因此,我们可以在更深的地方写:

您可以轻松地将此解决方案改编为通用解决方案,也可以在unwrapped方法中使用参数。

这里的示例是人为的并且过于简化,但是我希望我强调了一个问题并使您对这个细微的问题敏感。