8

我试图在关于数据验证的两种模式之间做出决定:

  1. 尝试遵循名义上的工作流程并捕获我的模型和服务引发的异常:违反唯一/外部约束、空字段、无效参数等...(!!我只捕获我知道我应该捕获的异常)

    • 优点:在我的控制器和服务中编写的代码很少:我只需要处理异常并将它们转录为用户可以理解的消息。代码非常简单易读

    • 缺点:我需要编写特定的异常,有时可能是很多不同的异常。我还需要捕获和解析数据库异常(违反约束等)的通用 PDO/Doctrine 异常,以将它们转换为有意义的异常(例如:)DuplicateEntryException。我也无法绕过一些验证:假设我的模型的一个对象被标记为锁定:尝试删除它会引发异常。但是我可能想强制删除它(例如,使用确认弹出窗口)。我将无法绕过这里的异常。

  2. 我使用代码和数据库查询明确地测试和预验证所有内容。例如,在将某些内容设置为我的模型中的属性之前,我将测试某些内容不是 null 并且是一个整数。或者我将进行数据库查询以检查我不会创建重复条目。

    • 优点:不需要编写特定的异常,因为我预先验证了所有内容,所以无论如何我不应该做很多尝试/捕捉。如果我愿意,我也可以绕过一些验证。

    • 缺点:需要在控制器、服务和模型中编写大量测试和验证。我将执行更多查询(验证部分)。数据库已经对外键、唯一约束、非空列进行了验证......我不应该忽略它并自己重新编码。这也会导致非常无聊的代码

我宁愿使用一种或另一种模式,而不是混合使用,以使事情尽可能简单。

第一个解决方案在我看来是最好的,但恐怕它可能是某种反模式?或者也许在其理论上的简单性背后隐藏着难以处理的情况?

4

1 回答 1

2

我建议数据验证应该发生在应用程序的外围。也就是说,应检查任何传入的数据以确保其符合您的期望。一旦允许进入应用程序,它就不再被验证,但它总是根据上下文(数据库、电子邮件等)进行转义。这使您可以将所有验证放在一起并避免验证工作的潜在重复(很容易实现)举个例子,数据可以被两个都使用它的模型验证两次。)Joe Armstrong 在他关于 Erlang 的书中推广了这种方法,他为电信站编写的软件可以运行多年而无需重新启动,所以它似乎运行良好: )

此外,模型预期并不总是与特定界面建立的预期完全一致(可能表单仅显示潜在选项的子集,或者界面可能有美国州的下拉列表,而模型存储了许多州的州)不同国家等)有时复杂的界面可以以增强用户体验的方式集成几个不同的模型对象。虽然对用户来说很好,但使用异常方法的这些模型的交互可能非常难以处理,因为某些输入可能是混合输入,这两个模型都无法单独验证。您始终希望首先确保验证符合 UI 的期望,而第二种方法允许您在最复杂的界面中执行此操作。

此外,异常处理在周期方面相对昂贵。验证问题可能非常频繁,我会尽量避免处理问题的昂贵操作,而不是可能非常频繁。

最后,一些验证对于模型来说并不是真正必要的,但它可以防止攻击。虽然您可以将其添加到模型中,但添加的功能会很快混淆模型代码。

因此,在这两种方法中,我建议使用第二种方法,因为:

  1. 你可以为你的应用设计一个清晰的边界。
  2. 所有的验证都在一个地方,并且可以共享。
  3. 如果两个或多个模型使用相同的输入,则不会重复验证。
  4. 这些模型可以专注于它们擅长的领域:将抽象实体的知识映射到应用程序状态。
  5. 即使是最复杂的 UI 也可以得到适当的验证。
  6. 抢占可能会更有效。
  7. 不属于任何模型的以安全为中心的验证任务可以干净地添加到应用程序中。
于 2012-10-26T18:53:14.920 回答