合同设计是否适合您?

时间:2008-08-25 17:26:47

标签: design-by-contract

您是否专业使用Design by Contract?这是您从项目一开始就要做的事情,还是可以改变方向并开始将其融入您的软件开发生命周期?您发现什么是设计方法的优缺点?

我在研究生课程中遇到Design by Contract方法。在学术环境中,它似乎是一种非常有用的技术。但我目前不专业地使用Design by Contract,而且我不知道任何其他开发人员正在使用它。听听SO群众的实际使用情况会很好。

10 个答案:

答案 0 :(得分:14)

我不能高度推荐它。如果你有一个采用内联文档合同规范的套件,那就特别好了:

// @returns null iff x = 0
public foo(int x) {
  ...
}

并将它们转换为生成的单元测试,如下所示:

public test_foo_returns_null_iff_x_equals_0() {
  assertNull foo(0);
}

这样,您实际上可以看到正在运行的测试,但它们是自动生成的。顺便说一句,生成的测试不应该被检查到源代码控制中。

答案 1 :(得分:7)

当您在必须相互交谈的应用程序之间建立接口时,您真的可以通过合同来欣赏设计。

没有合同,这种情况很快就会成为一场责怪网球的比赛。团队不断来回敲响指控,浪费了大量时间。

根据合同,责任很明确。

来电者是否满足前提条件?如果不是,客户团队需要修复它。

鉴于有效请求,接收方是否满足后期条件?如果不是,服务器团队需要修复它。

双方是否都遵守合同,但结果不理想?合同不足,问题需要升级。

为此,您不需要以断言的形式实施合同,您只需要确保所有各方都记录并同意这些合同。

答案 2 :(得分:3)

如果你研究STL,boost,MFC,ATL和许多开源项目,你会发现有太多的ASSERTION语句,这使得项目更安全。

设计按合同!它确实适用于真实产品。

答案 3 :(得分:3)

Frank Krueger写道:

  

Gaius:运行时会自动抛出Null Pointer异常,在函数序言中测试这些东西没有任何好处。

我对此有两个回应:

  1. Null就是一个例子。对于square(x),我想测试结果的平方根是(近似)参数的值。对于setter,我想测试实际更改的值。对于原子操作,我想检查所有组件操作是否成功或全部失败(实际上是一次成功测试和n次失败测试)。对于弱类型语言的工厂方法,我想检查是否返回了正确类型的对象。这个清单一直在继续。基本上,任何可以在一行代码中测试的东西都是序言合同中非常好的候选者。

  2. 我不同意你不应该测试东西,因为它们会产生运行时异常。如果有的话,你应该测试可能产生运行时异常的东西。我喜欢运行时异常,因为它们构成了系统fail fast,这有助于调试。但是示例中的null是某些可能输入的结果值。有一个论点是永远不会返回null,但如果你要去,你应该测试它。

答案 4 :(得分:2)

在SOA领域做任何事情时,不按合同设计是绝对愚蠢的,如果你正在从事任何类型的模块化工作,那么它总是有用的。片段可能会在以后被换掉,特别是如果涉及任何黑盒子。

答案 5 :(得分:1)

代替更具表现力的类型系统,我绝对会在军事级项目上使用合同设计。

对于弱类型语言或具有动态范围的语言(PHP,JavaScript),功能合同也非常方便。

对于其他一切,我会抛弃它依赖beta测试人员和单元测试。

Gaius:运行时会自动抛出空指针异常,在函数序言中测试这些东西没有任何好处。如果您对文档更感兴趣,那么我会使用可以与静态分析器等一起使用的注释(以确保代码不会破坏您的注释)。

更强大的类型系统加上契约式设计似乎是要走的路。请查看Spec#示例:

  

Spec#编程语言。规格#   是面向对象的扩展   语言C#。它扩展了类型   系统包括非null类型和   检查异常。它提供   方法以预先形式签订合同   和后置条件以及对象   不变式。

答案 6 :(得分:1)

单位测试和合同设计都是我经验中有价值的测试方法。

我尝试在系统自动测试框架中使用Design by Contract,我的经验是提供灵活性和单元测试不易获得的可能性。例如,它可以运行更长的序列并验证 每次执行某个操作时,响应时间都在限制范围内。

观察InfoQ上的演示文稿,似乎按合同设计是对组件集成阶段的传统单元测试的有价值的补充。 例如,可以先创建一个模拟界面,然后在之后使用该组件 - 或者当发布新版本的组件时。

我还没有找到一个工具包,涵盖了我通过合同测试设计的所有设计要求 在.Net / Microsoft平台上。

答案 7 :(得分:0)

我实际上并没有每天使用Design by Contract。我知道它已经被合并到D语言中,作为语言的一部分。

答案 8 :(得分:0)

是的,确实如此!实际上几年前,我为Argument Validation设计了一个小框架。我正在做一个SOA项目,其中不同的后端系统进行了所有类型的验证和检查。但是为了增加响应时间(在输入无效的情况下,以及减少加载那些后端系统),我们开始验证所提供服务的输入参数。不仅适用于Not Null,还适用于String模式。或者来自集合内的值。以及参数之间存在依赖关系的情况。

现在我意识到我们当时通过合同框架实现了一个小设计:)

以下是对小型Java Argument Validation框架感兴趣的人的链接。这是作为普通的Java解决方案实现的。

答案 9 :(得分:0)

我发现它告诉Go编程语言没有使合同设计成为可能的结构。恐慌/延迟/恢复并不完全是因为延迟和恢复逻辑可以忽略恐慌,IOW忽略破坏的合同。至少需要的是某种形式的不可恢复的恐慌,这是真的断言。或者,最好是通过契约构造(前后条件,实现和类不变量)直接支持设计语言。但是,由于掌舵Go船的语言纯粹主义者头脑清醒,我对这一切做了很少的改变。

可以通过在恐慌函数中检查最后一个延迟函数中的特殊断言错误并调用runtime.Breakpoint()来在恢复期间转储堆栈来实现类似断言的行为。断言 - 行为需要有条件。当然,当在执行断言之后添加新的延迟函数时,这种方法会分崩离析。这将在大型项目中恰好在错误的时间发生,导致错过错误。

我的观点是,断言在很多方面都很有用,不得不围着它跳舞可能会很头疼。