业务验证逻辑代码气味

时间:2009-03-11 17:18:49

标签: c# .net entity-framework business-logic

请考虑以下代码:

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

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

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

14 个答案:

答案 0 :(得分:17)

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

答案 1 :(得分:3)

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

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

答案 2 :(得分:3)

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

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

答案 3 :(得分:2)

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

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

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

答案 4 :(得分:1)

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

答案 5 :(得分:1)

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

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

T GetValidValueForProperty<T>(T suggestedValue, T currentValue);

甚至:

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

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

这将更像是:

T OurProperty
{
    get
    {
        return this.propertyBackingField;
    }
    set
    {
        this.propertyBackingField = this.GetValidValueForProperty(value, this.propertyBackingField);
    }
}

做什么并不重要,但在更改当前值之前进行验证非常重要。如果在确定新值是否合适之前更改了值,那么从长远来看就是问题。

答案 6 :(得分:0)

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

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

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

答案 7 :(得分:0)

您是在完成更改后验证的?验证应在busyness属性更改之前完成。

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

答案 8 :(得分:0)

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

答案 9 :(得分:0)

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

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

答案 10 :(得分:0)

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

答案 11 :(得分:0)

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

答案 12 :(得分:0)

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

答案 13 :(得分:0)

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

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