是否必须检查前提条件?

时间:2010-05-28 11:19:00

标签: design-by-contract

这些天我习惯于检查每个函数的每个前提条件,因为我从大学那里的OS编程课程中习惯了这个习惯。

另一方面,在软件工程课程中,我们被教导只应检查一个共同的前提条件,例如,如果一个函数委托给另一个函数,第一个函数应该检查它们但是再次检查它们第二个是多余的。

我确实看到了冗余点,但我确实觉得总是检查它们更安全,而且你不必跟踪以前检查它们的位置。

这里的最佳做法是什么?

9 个答案:

答案 0 :(得分:11)

我没有看到关于如何检查前置条件的“硬性和快速”规则,但我通常将其视为方法文档。如果它是公开范围的,我断言满足前提条件。这背后的逻辑是,范围决定了你期望更广泛的消费和更少的影响。

就个人而言,将断言置于私有方法之外的努力是我为“关键任务”方法保留的,这些方法基本上是执行关键任务,受外部合规性要求约束或者不可恢复的方法。异常事件。这些主要是“判断力”。

节省的时间可以重新投入到彻底的单元和集成测试增强中,以尝试清除这些问题,并将工具放在适当的位置,以帮助强制执行输入断言的质量,因为它将由客户端使用,无论是否你控制中的课程与否。

答案 1 :(得分:5)

我认为这取决于团队的组织方式:检查来自团队外部的输入。

  • 检查最终用户的输入
  • 检查其他团队编写的软件组件的输入
  • 从您自己的组件/您自己的团队中收到的信任输入。

这样做的原因是支持和维护(即错误修复):当有错误报告时,您希望能够尽快知道哪个组件有问题,即哪个团队将错误分配给哪个组件

答案 2 :(得分:4)

  

如果某个功能委托给另一个人   功能,第一个功能应该   检查它们,但再次检查它们   第二个是多余的。

如果改变这些功能相互调用的方式怎么办?或者您在第二个函数中引入了新的验证要求,第一个函数委托给谁?我会说总是检查它们会更安全。

答案 3 :(得分:4)

我养成了区分检查断言前提条件的习惯,这取决于(正如人们在评论中指出的那样)来电是否来自外部(未经检查的异常,可能发生)或内部(断言,不应该发生)。

理想情况下,生产系统不会受到断言的惩罚,您甚至可以使用类似于Design By Contract(TM)的机制来静态释放断言。

答案 4 :(得分:3)

根据我的经验,这取决于你的封装。 如果内部函数是私有的,那么你可以非常肯定它的前置条件是否已设置。

猜猜这是关于得墨忒耳的法则,只与你的朋友交谈等等。

作为最佳做法的基础,如果通话是公开的,您应该检查您的输入。

答案 5 :(得分:2)

我认为最好的做法是只在有一天会失败的情况下进行这些检查。如果您执行以下操作将有所帮助。

<强>调试

当一个模块(具有单个维护者)中的多个私有函数交换数据时,检查它们是没有意义的。当然,也有例外,特别是如果您的语言没有静态类型系统,或者您的数据是“stringly typed”。

但是,如果您公开公共API,有一天会有人失败您的前提条件。维护呼叫模块的人(在组织结构和物理位置)越多,发生的可能性就越大。当它发生时,一个明确的前提条件失败声明,以及它发生的规范,可以节省数小时的调试。 The Law of Leaky Abstractions仍然是真的......

<强> QA

前提条件失败有助于QA调试其测试。如果模块的单元测试导致模块产生前置条件故障,则表示测试不正确,而不是代码。 (或者,您的前提条件检查不正确,但不太可能)。

如果其中一种执行QA的方法是静态分析,那么前提条件检查,如果它们有特定的表示法(例如,只有这些检查使用assert_precondition宏),也会救命。在静态分析中,区分错误的输入和源代码错误非常重要。

<强>文档

如果您没有太多时间来创建文档,您可以使代码辅助它附带的文本。清晰可见的前提条件检查与实施的其余部分分开,在某种程度上“记录”可能的输入。 (以这种方式记录代码的另一种方法是编写单元测试)。

答案 6 :(得分:2)

与所有事情一样,评估您的要求,为每种情况找到最佳解决方案。

当前置条件更容易检查(“指针不为空”)时,您可能经常这样做。难以检查的前提条件(“指向有效的以空字符结尾的字符串”)或者在时间,存储器或其他资源方面昂贵的前提条件可以以不同的方式处理。使用Pareto principle并收集低调的水果。

// C, C++:
void example(char const* s) {
  // precondition: s points to a valid null-terminated string
  assert(s); // tests that s is non-null, which is required for it to point to
  // a valid null-terminated string.  the real test is nearly impossible from
  // within this function
}

保证先决条件是来电者的责任。因此,几种语言提供了一个“断言”构造,可以选择跳过(例如,为C / C ++定义NDEBUG,Python的命令行开关),这样您就可以在不影响最终性能的情况下更广泛地测试特殊构建中的前提条件。然而,如何使用断言可能是一个激烈的争论 - 再次,找出你的要求并保持一致。

答案 7 :(得分:2)

这是一个有点老问题,但不是,每次都不必检查先决条件。这真的取决于。

例如,如果您对向量进行二元搜索,该怎么办?前提是排序的矢量。现在,如果每次检查向量是否已排序,则需要一个线性时间(对于每个向量),因此效率不高。客户必须了解前提条件并确保满足。

答案 8 :(得分:0)

最佳做法是始终检查它们。