干净的架构 - 在哪里放置输入验证逻辑?

Duy*_*ham 5 coding-style business-logic clean-architecture

也许在应用程序中,我有一个功能允许用户使用带有一些验证逻辑的表单发送反馈:

  • 名称可以为空
  • 反馈信息应至少为 5 个字符

您会将这些验证逻辑放在何处,domain layer作为业务逻辑还是presentation layer作为 UI 逻辑?

这些逻辑适用于所有应用程序(android、iOS、web)。请注意,我们已经进行了服务器端验证。

Jem*_*rov 23

我认为许多开发人员在Presentation层中这样做,特别是在ViewModel/Presenter/Controller(不是in Activity/Fragment/View!) 中。我的方法是将该逻辑放在Domain层中。为什么?

  • 它是表示逻辑还是域逻辑?呈现逻辑是你决定“映射渲染模型”、“渲染模型格式”、“如何渲染”、“什么颜色、什么大小、哪个文本”、“它会在屏幕上停留多长时间”等......如果验证是表示逻辑,为什么后端代码具有相同的验证控制?从我的角度来看,验证是域逻辑
  • 为什么验证是域逻辑?谁决定用户名是否最多可以是 20 个字符?业务规则决定。谁决定购物篮中最大物品的数量?业务规则决定。用户名的长度由业务决定,该规则适用于项目的任何地方。CreateProfile/UpdateProfile/Register 等都具有相同的 max-20char-username 规则。该长度控制(验证)代码应驻留在域层中。
  • 如果验证代码在域层,流程是什么?用户单击视图中的按钮。ViewModel/Presenter 调用域层函数。领域层功能验证输入数据。如果输入参数无效,则返回ValidationException并说明。ValidationException将包含的名单无效的参数验证的类型,他们失败了(的minLength,最大长度,emailPatternMismatch等),预计什么(在最高等20个字符)。ViewModel/Presenter/Controller得到这个ValidationException,这里我们有演示逻辑。现在它决定渲染什么,如何渲染. 我们是呈现所有无效输入的错误还是仅呈现第一个无效输入的错误?应该显示什么文本/颜色(基于 ValidationException 中的数据)?我们是否将错误呈现为 popup/textView/tooltip?在做出所有演示决定并创建新模型之后,View就可以了!使用该模型进行渲染。
  • 还有一点是,在Domain层,验证码应该放在哪里?在用例函数或模型(为什么不)本身中?恕我直言,应该有具有通用验证逻辑的无状态通用接口/类。在那之后,每个 UseCase 类都可以实现 ValidationInterface 或将其作为 Class 对象注入。如果多个 UseCases 需要相同的验证,则验证控制逻辑将重复。如果我们将验证逻辑放在 Model 本身中会发生什么?模型将实现 ValidationInterface (它只有无状态的纯函数!)并具有fun validate():ValidationOutcome功能。我不认为将业务模型的验证逻辑放在自己身上是问题。所有用例只会调用model.validate()。Model 和 ValidationOutcome 之间存在依赖关系。

  • 富有洞察力。鲍勃叔叔在[其中一个线程](https://groups.google.com/d/msg/clean-code-discussion/latn4x6Zo7w/bFwtDI1XSA8J)中也说过类似的话。:) (2认同)
  • 从 Uncle Bob 的评论 @Sufian 中提到,在 Clean Arch 的背景下,每一层都可以/应该有自己的验证。因此,我认为将验证放在域层中可以对域进行验证,但不能对演示者或实体进行验证。例如,客户评论长度不应超过 100 个字符,但管理员最多可以回答 1000 个字符。与在干净的架构中一样,我们不应该通过更改外层来更改内层,似乎在这里我们需要在表示层中进行验证。 (2认同)

小智 5

我想@sufian 和这篇文章引用的鲍勃叔叔的这个例子在做出决定时很有用。

Naoto指出,正如 Clean Architecture 将职责按层拆分一样,每一层都有自己的验证逻辑

在每一层中,系统应该拒绝违反其层职责的输入。因此,验证的含义因上下文而异。

在应用层,作为验证,我们必须确保域对象可以接收输入。我们应该拒绝域对象无法接收的输入。

例如,当缺少某些必需参数时,应该拒绝它,因为域对象无法像该参数那样接收。