Does Design By Contract Work For You? [closed]

2019-02-02 04:33发布

Do you use Design by Contract professionally? Is it something you have to do from the beginning of a project, or can you change gears and start to incorporate it into your software development lifecycle? What have you found to be the pros/cons of the design approach?

I came across the Design by Contract approach in a grad school course. In the academic setting, it seemed to be a pretty useful technique. But I don't currently use Design by Contract professionally, and I don't know any other developers that are using it. It would be good to hear about its actual usage from the SO crowd.

10条回答
劫难
2楼-- · 2019-02-02 05:03

Frank Krueger writes:

Gaius: A Null Pointer exception gets thrown for you automatically by the runtime, there is no benefit to testing that stuff in the function prologue.

I have two responses to this:

  1. Null was just an example. For square(x), I'd want to test that the square root of the result is (approximately) the value of the parameter. For setters, I'd want to test that the value actually changed. For atomic operations, I'd want to check that all component operations succeeded or all failed (really one test for success and n tests for failure). For factory methods in weakly-typed languages, I want to check that the right kind of object is returned. The list goes on and on. Basically, anything that can be tested in one line of code is a very good candidate for a code contract in a prologue comment.

  2. I disagree that you shouldn't test things because they generate runtime exceptions. If anything, you should test things that might generate runtime exceptions. I like runtime exceptions because they make the system fail fast, which helps debugging. But the null in the example was a result value for some possible input. There's an argument to be made for never returning null, but if you're going to, you should test it.

查看更多
啃猪蹄的小仙女
3楼-- · 2019-02-02 05:05

I can't recommend it highly enough. It's particularly nice if you have a suite that takes inline documentation contract specifications, like so:

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

and turns them into generated unit tests, like so:

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

That way, you can actually see the tests you're running, but they're auto-generated. Generated tests shouldn't be checked into source control, by the way.

查看更多
太酷不给撩
4楼-- · 2019-02-02 05:07

You really get to appreciate design by contract when you have an interface between to applications that have to talk to each other.

Without contracts this situation quickly becomes a game of blame tennis. The teams keep knocking accusations back and forth and huge amounts of time get wasted.

With a contract, the blame is clear.

Did the caller satisfy the preconditions? If not the client team need to fix it.

Given a valid request, did the receiver satisfy the post conditions? If not the server team need to fix that.

Did both parties adhere to the contract, but the result is unsatisfactory? The contract is insufficient and the issue needs to be escalated.

For this you don't need to have the contracts implemented in the form of assertions, you just need to make sure they are documented and agreed on by all parties.

查看更多
啃猪蹄的小仙女
5楼-- · 2019-02-02 05:13

I don't actually use Design by Contract, on a daily basis. I do, however know that it has been incorporated into the D language, as part of the language.

查看更多
狗以群分
6楼-- · 2019-02-02 05:15

In lieu of more expressive type systems, I would absolutely use design by contract on military grade projects.

For weakly typed languages or languages with dynamic scope (PHP, JavaScript), functional contracts are also very handy.

For everything else, I would toss it aside an rely upon beta testers and unit tests.

Gaius: A Null Pointer exception gets thrown for you automatically by the runtime, there is no benefit to testing that stuff in the function prologue. If you are more interested in documentation, then I would use annotations that can be used with static analyzers and the like (to make sure the code isn't breaking your annotations for example).

A stronger type system coupled with Design by Contract seems to be the way to go. Take a look at Spec# for an example:

The Spec# programming language. Spec# is an extension of the object-oriented language C#. It extends the type system to include non-null types and checked exceptions. It provides method contracts in the form of pre- and postconditions as well as object invariants.

查看更多
Emotional °昔
7楼-- · 2019-02-02 05:18

I find it telling that Go programming language has no constructs that make design by contract possible. panic/defer/recover aren't exactly that as defer and recover logic make it possible to ignore panic, IOW to ignore broken contract. What's needed at very least is some form of unrecoverable panic, which is assert really. Or, at best, direct language support of design by contract constructs (pre and post-conditions, implementation and class invariants). But given strong-headedness of language purists at the helm of Go ship, I give little change of any of this done.

One can implement assert-like behaviour by checking for special assert error in last defer function in panicking function and calling runtime.Breakpoint() to dump stack during recovery. To be assert-like that behaviour needs to be conditional. Of course this approach fells apart when new defer function is added after the one doing assert. Which will happen in large project exactly at the wrong time, resulting in missed bugs.

My point is that is that assert is useful in so many ways that having to dance around it may be a headache.

查看更多
登录 后发表回答