不要在 API 命名中使用 check

本文讨论的是 check 命名在业界的默认语义约定,而不是个人风格偏好。

在很多项目中,checkXxx 被滥用于 API、Service 甚至业务逻辑中,导致调用语义混乱。

check 的定位

check 是可以用的,但是它只能在一个非常窄的语义里使用。
在大多数项目里, checkXxx() 是一个前置条件检查,不满足时抛出异常且没有业务副作用。

  1. 返回类型 void不是 boolean
  2. 失败时抛出异常。
  3. 成功时什么都不发生。

例如:

1
2
3
private void checkStatus();
private void checkPermission();
private void checkConfig();

check 的滥用

对 check 的最严重最常见的滥用出现在命名 API 时。

命名 API 时,我们的目标是消除惊讶,而 check 在 API 语境下是语义不稳定的命名。 对外的 API 一旦叫 checkXxxx,使用者就会在多种猜测中不知所措:

  1. 成功时返回的是一个 boolean还是一个结果?
  2. 失败时是一个 false 异常 还是结果?
  3. 我调用这个 API 会不会修改一些状态?

举一个更具体的例子,当一个方法叫 checkOrder() 时:

如果想知道订单是否有效,我们会期待它叫 isValid()

如果想触发校验流程并拿到错误列表,我们会期待它叫 validateOrder()

如果想在订单无效时阻止程序运行,我们会期待它叫 ensureOrderValid()

check 就像一个黑色盲盒,不看实现永远不知道它会静默失败还是原地爆炸。 因此,它只适合作为类内部的辅助方法(Helper methods)。

正确命名 API 的方式是这样的:

1
2
3
validateXxx()    // 有结果
verifyXxx() // 鉴权 / 第三方
ensureXxx() // 业务保障(失败抛异常)

总结

团队中可以将 check 约定为仅用于内部前置校验的方法命名,对外 API 必须使用结果或行为导向的动词。

场景 用 check 吗
返回 boolean
返回 Result / Error
Controller / API
有业务副作用
失败直接抛异常
内部前置校验
private / protected
Domain 规则校验