业务validation逻辑代码气味

请考虑以下代码:

partial class OurBusinessObject { partial void OnOurPropertyChanged() { if(ValidateOurProperty(this.OurProperty) == false) { this.OurProperty = OurBusinessObject.Default.OurProperty; } } } 

也就是说,当OurProperty中的OurBusinessObject的值发生更改时,如果该值无效,请将其设置为默认值。 这种模式让我感觉像代码味道,但其他人(在我的雇主)不同意。 你的想法是什么?

编辑补充 :我被要求添加一个解释为什么这被认为是好的。 我们的想法是,业务对象可以validation自己的属性,并在validation失败的情况下设置干净的默认值,而不是让业务对象的生产者validation数据。 此外,有人认为,如果validation规则发生变化,业务对象生产者将不必更改其逻辑,因为业务对象将负责validation和清理数据。

这绝对太可怕了。 祝你好好调试生产中的问题。 它唯一可以导致的是覆盖错误,这些错误只会出现在其他地方,而在它们来自哪里并不明显。

我想我必须同意你的观点。 这肯定会导致逻辑意外返回到默认值的问题,这可能非常难以调试。

至少,应记录此行为,但这似乎更像是抛出exception的情况。

对我来说,这看起来像是症状,而不是实际问题。 真正发生的是, OurProperty的setter无法保留OnOurPropertyChanged事件中使用的原始值。 如果你这样做,突然变得更容易做出更好的选择。

就此而言,您真正想要的是OnOurPropertyChanging事件,该事件是实际发生分配之前从setter引发的。 这样,您可以首先允许或拒绝分配。 否则,您的对象无效的时间很短,这意味着该类型不是线程安全的,如果您认为并发性是一个问题,则不能指望一致性。

绝对是一个值得怀疑的做法。

如何将无效值分配给此属性? 这不是表示调用代码中某处有错误,在这种情况下你可能想立刻知道吗? 或者用户输入错误的内容,在这种情况下应立即通知他们

一般来说,“快速失败”使得追踪错误变得更加容易。 在幕后静默地分配默认值类似于“魔术”,并且只会导致混淆任何必须维护代码库的人。

对于“代码味道”一词的厌恶,你可能是对的 – 取决于它来自何处,默默地改变价值可能不是一件好事。 最好确保您的值有效,而不是仅恢复为默认值。

我强烈建议在设置属性之前重构它以进行validation。

你可以总是有一个更像是的方法:

 T GetValidValueForProperty(T suggestedValue, T currentValue); 

甚至:

 T GetValidValueForProperty(string propertyName, T suggestedValue, T currentValue); 

如果这样做,在设置属性之前,可以将其传递给业务逻辑进行validation,业务逻辑可以返回默认属性值(当前行为)或(在大多数情况下更合理),返回currentValue,所以设置没有效果。

这将更像是:

 T OurProperty
 {
    得到
     {
         return this.propertyBackingField;
     }
    组
     {
         this.propertyBackingField = this.GetValidValueForProperty(value,this.propertyBackingField);
     }
 }

它的作用并不重要,但在更改当前值之前进行validation非常重要。 如果在确定新值是否合适之前更改了值,那么从长远来看,您会遇到麻烦。

它可能会或可能不会“闻到”,但我更倾向于“是它闻起来”。

将OurProperty设置为默认值是否有合理的理由,或者在代码中这样做是否方便? 实际上,在实践中不太可能设想出这种预期行为的情况,但我猜测在大多数情况下你应该抛出exception并在某处干净地处理它。

将值设置为默认值会使您更接近或使您远离应用程序应如何工作的function规范描述吗?

完成后您是否正在validation更改? validation应在busyness属性更改之前完成。

回答您的任务:该代码段中显示的解决方案可能会在生产中产生大问题,您不知道是否由于输入无效而出现默认值,或者仅仅是因为其他内容将值设置为默认值

如果不了解背景或业务规则,很难说。 一般来说,您应该只在输入时进行validation,并且可能在持久性之前再次validation,但是您执行此操作的方式实际上不会允许您进行validation,因为您不允许属性包含无效值。

我认为如果要求使用无效值,validation逻辑应引发exception。 如果您的消费者想要使用默认值,它应该通过特殊的,记录的值或通过其他方法明确地要求它。

我认为唯一可以原谅的例外情况就是规范化案例,就像在电子邮件领域中检测重复一样。

此外,为什么世界上这部分? 除了生成的代码框架之外,使用部分类本身就是一个代码,因为你可能会使用它们来隐藏应该被拆分的复杂性!

我同意Grzenio并且会补充说,在域层(也称为业务对象)中处理validation错误的最佳方法是生成exception。 该exception可以一直传播到UI层,在那里可以处理它并与用户进行交互式纠正。 但是,根据所涉及的function和技术,这可能并不总是可行的,在这种情况下,您可能应该在UI层中进行validation(可能除了域层之外)。 它不太理想,但可能是你唯一可行的选择。 在任何情况下,将其设置为默认值都是一件可怕的事情,并且会导致几乎无法诊断的细微错误。 如果大规模完成,您将立即拥有一个不可维护的系统(特别是如果您没有为您提供unit testing)。

我对此提出的论点如下。 假设业务对象的用户/生产者意外地输入了无效值。 然后,此模式将掩盖该事实,并默认为清理数据。 但处理此问题的正确方法是抛出错误并让用户/生产者validation/清除其输入数据。

我会说,实现PropertyChanging并允许业务逻辑批准/拒绝一个值,然后为无效值抛出exception。

这样,您就没有无效值。 那,你永远不应该改变用户的信息。 如果用户将条目添加到数据库并跟踪其自己的记录,该怎么办? 您的代码会将值重新分配给默认值,他现在正在跟踪错误的信息。 最好尽快通知用户。