Slashdot Mirror


Why Is "Design by Contract" Not More Popular?

Coryoth writes "Design by Contract, writing pre- and post-conditions on functions, seemed like straightforward common sense to me. Such conditions, in the form of executable code, not only provide more exacting API documentation, but also provide a test harness. Having easy to write unit tests, that are automatically integrated into the inheritance hierarchy in OO languages, 'just made sense'. However, despite being available (to varying degrees of completeness) for many languages other than Eiffel, including Java, C++, Perl, Python, Ruby, Ada, and even Haskell and Ocaml, the concept has never gained significant traction, particularly in comparison to unit testing frameworks (which DbC complements nicely), and hype like 'Extreme Programming'. So why did Design by Contract fail to take off?"

32 of 178 comments (clear)

  1. Comment removed by account_deleted · · Score: 4, Insightful

    Comment removed based on user account deletion

  2. Contracts by VGPowerlord · · Score: 2, Funny

    Darl put it best: "Contracts are what you use against parties you have relationships with."

    I don't have relationships with random other programmers (even if they are female and cute).

    --
    GLaDOS for President 2016! "Well here we are again. It's always such a pleasure." -- GLaDOS, 2011
  3. Who cares? by jrockway · · Score: 2, Insightful

    Who cares if it's popular? If it solves your problem, use it.

    --
    My other car is first.
    1. Re:Who cares? by heinousjay · · Score: 2, Insightful

      You win the topic. Everything else is masturbation.

      --
      Slashdot - where whining about luck is the new way to make the world you want.
    2. Re:Who cares? by Just+Some+Guy · · Score: 4, Insightful

      Who cares if it's popular? If it solves your problem, use it.

      Two reasons: first, the more people use it, the wider it will be supported. It's nice to be involved with something on the upswing that more people are interested in than bored with. Second, it's nice to know why something's unpopular. Maybe it's hard to use, but you're a genius and will be able to put it to work. Or, maybe, everyone else realized that it's awful and moved on to something less heinous.

      --
      Dewey, what part of this looks like authorities should be involved?
  4. no bang for your buck by majiCk · · Score: 3, Insightful

    Design by contract seems like a lot of extra work and runtime cost for something that might once in a while catch a bug in already-deployed code. Lighter weight methods like static typing catch (certain kinds of) errors before the code is even compiled; unit testing is usually done before code is deployed, and with the express aim of exposing incorrect behavior in corner cases.

    Just what niche is design-by-contract supposed to fill? It's heavyweight, costly at runtime, undirected, and likely to catch bugs only after deployment -- too-little-too-late. Maybe it's unpopular because it's a poor tradeoff.

    1. Re:no bang for your buck by barrkel · · Score: 4, Insightful

      In a phrase, the niche is professional coders, rather than hack-a-day cowboys.

      Assertions, whether invariants, preconditions or postconditions, can be viewed as extensions to the type system [1]. Since they are expressions of a boolean type and don't modify state (at least, no sane ones would mutate state), they're very easily analysed.

      Combine that with a runtime like .NET or the JVM. Compilers and analysers can use such contracts to perform extra typechecking of e.g. arguments to methods, where the methods have preconditions. "Runtime cost" doesn't exist if the runtime has support, especially where verification also exists. Consider the old conundrum: do you check your parameters, or do you expect your caller to check the arguments before they're passed? What if the parameters being wrong leads to a subtle error that manifests later rather than a dramatic failure? With properly stated contracts, these checks can be inserted at the lowest level and automatically propagated higher statically by the compiler or dynamically by the runtime as necessary.

      The niche that DbC is supposed to fill is formalising what is already recognised good practice - stating your assumptions while writing your code. If you have much experience as a programmer, you'll know that it's useful to use assert, ASSERT, or some other feature of your environment at choice places where you make certain assumptions that you think can't be broken. And if you've read The Pragmatic Programmer, you'll know why you'll want to leave those assertions in the final release.

      Most popular languages, such as C#, Java, C++ etc., capture very little programmer intent in their type systems. There's a lot more potential there - preconditions and postconditions can e.g. state that a variable will be in a certain range dependent on the values of other variables, and then automatically detect range mismatches with e.g. loop invariants. Basically, assertions are really useful extensions to the type system.

      [1] For example, consider that a 'requires x != null' constraint and a notional non-nullable reference type from C# or Java, analogous to 'MyType!' in C-w (C Omega):
      http://blogs.msdn.com/cyrusn/archive/2004/06/03/14 7778.aspx

    2. Re:no bang for your buck by Coryoth · · Score: 3, Insightful

      Design by contract seems like a lot of extra work and runtime cost for something that might once in a while catch a bug in already-deployed code. Lighter weight methods like static typing catch (certain kinds of) errors before the code is even compiled; unit testing is usually done before code is deployed, and with the express aim of exposing incorrect behavior in corner cases. DbC doesn't incur any runtime cost if you choose not to bother - any good contract system allows you to turn off contract checking for production code. That is, DbC provides a test harness during testing but needn't do any checking of finished code after testing is complete. Moreover good contract systems like JML and Spec# are smart enough to allow static checking which allow you to catch a whole host of errors before compilation that static types just aren't going to be able to catch. And I have to admit that I am unsure how DbC is "a lot of work" given that you should be writing unit tests anyway, and if you have constraints or invariants then you ought to be checking those with unit tests - writing the constraint as a contract is less work than writing the equivalent unit test. Finally DbC enables testing that for which unit tests of corner cases simply can't compare - by using the contracts as a test oracle you can do automated randomised testing of several integrated units. That is to say, you can automatically generate data to search the input space delimited by preconditions, and use postconditions, invariants, and preconditions of any called code, to test that several units all work together correctly and potentially catch weird interelated corner cases that you hadn't anticipated. Honestly, check out AutoTest or Quickcheck sometime, they are suprisingly powerful and have found bugs in established production code that had already undergone extensive standard testing.
    3. Re:no bang for your buck by Tablizer · · Score: 2, Interesting

      In a phrase, the niche is professional coders, rather than hack-a-day cowboys.

      I think you are being naive. In the real world they often want as many features as possible with the smallest staff possible. This means that things like formal testing are glossed over. It is an art-form to deliver tons of features on the cheap. Of course, it depends on the nature of the business. If it is the Space Shuttle or medical equipment, then you better spend the extra money or you will get sued up the wazoo. An intranet app will also have a different Q.A. profile than packaged software, since the ratio of users per line-of-code is different. The US's comparative advantage is being nimble, not formal, such that the beurocracy for Q.A. is often bypassed to keep up. If the idea becomes a commodity idea such that requirements and thus testing it is easy and stable, development gets shipped overseas.

    4. Re:no bang for your buck by epine · · Score: 2, Insightful

      In a phrase, the niche is professional coders, rather than hack-a-day cowboys.

      Unfortunately, hack-a-day cowboys gained control of both the house, the senate, and the clone army, so hack-a-day coding practices are now the accepted norm, and people look at you funny when you pinch your brow in abject frustration.

      The problem with DbC is that the benefits are best understood by an examination of the system as a whole, rather than the culturally ascendant analysis that permits the cable companies and telcos to put forward the view, in all seriousness, that the demise of net neutrality increases their incentive to invest in their network infrastructure, whereas game theory shows that it has precisely the opposite effect. Most people--in any professional context--are heavily invested not in full systems analysis, but careerist analysis whose principle arguments reference the power hierarchy rather than the behaviour of the system in which the power hierarchy is embedded. The careerist analysis that DbC is relatively worthless is accurate enough in its own scope: after all, the cowboys now rule the world.

      I incorporated DbC principles into a large and complex C application (at that time still MSDOS based) shortly after the Meyer book was published in 1988. I never believed that DbC can only be practiced in a language that directly supports it (I regard that as outright language bigotry propoganda). DbC is an intellectual practice. What you can't achieve in a language that doesn't support DbC is the imposition of DbC on participants who don't otherwise choose to participate voluntarily. However, managing to impose DbC on a participant who wouldn't do so voluntarily is at best a hollow victory: compliance over enthusiasm rarely produces the best results.

      We imposed DbC by a different tactic. Anyone caught tracing through code in the symbolic debugger was subject to anyone walking past making police siren noises. "How am I supposed to concentrate on debugging this code if everyone is making stupid sound effects?" Answer: "If you have to concentrate that hard to understand your code, you aren't doing it right." Time spent in a debugger produces no asset to the code base, yet it requires the greatest level of concentration. How could that be right?

      After we instituted DbC principles, we didn't get many bug reports. Over a three year period, about half of all our bug reports pertained to *one* module written before DbC was instituted. No one wanted to rewrite that module because it involved an external file format which needed to remain compatible, but the exact requirements of the file format were hard to reverse engineer from the conceptually-damaged code base.

      The other critical aspect of that situation is that I vetoed many design choices where DbC would have been less beneficial. Some design approaches don't mesh well with DbC. You can still go through the motions, but the conditions you can actually express never catch what you really want to catch at the moment it most needs to be caught. For DbC to work well, you need to choose designs where consistency is a local property of your data structures rather than a global property that can only be enforced by some kind of global fsck. If you have sideways paths into a recursive data structure, you have no hope of checking invariants on the nested context you didn't descend through.

      When we did have a bug report, it never took us long to find the code responsible. Most of the plausible theories were eliminated immediately because we shipped with the vast majority of DbC assertions enabled. "This bug would result if function foo returned NULL, but wait, there is a live assertion right here that proves this never happens." Then when we did find the right chunk of code, we rarely felt we needed to test the change for a week or more before shipping out the patch to the affected customer: there was so many assertions in so many directions, it was hard to construct a theory

  5. Extreme Programming by andy314159pi · · Score: 4, Funny

    I employ what is known as "Extreme Programming." It mostly involves alot of screaming at the monitor and yelling at my coworkers. I get fired alot but I never have a hard time getting a new job with my Extreme Programming skills that I write all over my resume.

  6. Design by Contract by VGPowerlord · · Score: 2, Informative

    Design by Contract adds more complexity to code, particularly if you're dealing with a language that doesn't natively support it.

    Of course, you don't actually need special constructs to check values on input then tossing an exception/returning an error when the data is not in the expected range. In fact, you should go back to remedial programming classes if you're not already doing this.

    The last thing you should do is try to figure out what the caller really meant if the value is out of range. Assuming a default works in some cases (which, btw, wouldn't work with Design by Contract as I understand it), but most of the time it's just better to fail and make the programmer fix their mistake.

    --
    GLaDOS for President 2016! "Well here we are again. It's always such a pleasure." -- GLaDOS, 2011
  7. It needs serious language support by Animats · · Score: 5, Informative

    If you're serious about design by contract, you need to use a language that supports it. Eiffel does, of course, and so does "Spec#", Microsoft's verifiable variant of C#, but other than that, "support" is a collection of half-baked add-ons that don't provide any strong assurances.

    If you're going to take object invariants seriously, you have to take object invariance seriously. Objects can't be allowed to change other than when control is inside them, and when control is inside the object, no public method of the object can be called. This means you have to be able to catch cases where object A calls object B which then calls a public method of A. The invariant of A isn't established at that point, and so, calls into A are illegal. This strict notion of inside/outside is fundamental to class invariants, but many so-called "design by contract" approaches gloss over it. You need a way to explicitly say "control is now leaving this object temporarily" when calling out of an object, and the object's invariant must be true at that exit.

    Threading and locking have to be handled in the language. The language needs to know which locks protect what data, or invariants aren't meaningful.

    Then there's the problem of how to express an invariant, entry, or exit condition. Are quantifiers provided, or what? How do you talk about concepts like "forward and back pointers of the tree must be consistent"? There's known formalism for that sort of thing, but it's not something you can express cleanly in, say, C or C++.

    Without smarts in the compiler, run time checking tends to be too expensive. The compiler needs to know that member function F can't change member variables X and Y, and therefore, invariants concerning X and Y don't have to be rechecked. Without optimizations like that, you end up rechecking everything on every call to every access function.

    I'd like to see more design by contract, and I'd like to see it work well enough that when something breaks, you know which side of the interface to blame. I used to do proof of correctness work, and it's quite possible to do this. But you can't do it in C or C++; the languages are too loose. It's been done well for Modula and Java, and a DEC R&D group had a very nice system going just before Compaq canned DEC's Palo Alto research labs. The rise of C killed off verification work; the decline of C may bring it back.

    1. Re:It needs serious language support by Coryoth · · Score: 2, Informative

      By whom? I'd like to look into it for my Java projects. DEC R&D made ESC/Java (Extended Static Checking for Java) that used a theorem prover and specification annotations to verify contracts. Development stopped, but it is now open source as ESC/Java2 which uses JML as annotation markup. I actually listed this as the Java DbC implementation in the article description.
  8. Re:Management by ShieldW0lf · · Score: 3, Insightful

    A good business analyst will answer the question "What is it that we (the client) need." They help make sure that the excellent code you write, when it's doing as you were hired to write it to do, solves problems instead of making them.

    A good architect will help establish clear separation of authority, giving team members more autonomy to go do what they're good at without having other peoples fingers in their pies or needing to leave their area of scope.

    There are a lot of people with pieces of paper from a school that are terrible at these things, and they muddle along leaving wreckage behind them. But that doesn't dismiss the value of having someone competent in those roles when you can find them.

    --
    -1 Uncomfortable Truth
  9. Too many layers by Geoffreyerffoeg · · Score: 3, Insightful

    You know the aphorism about how any CS problem can be solved by another layer of indirection -- except the problem of too many layers of indirection. That's what design-by-contract is. Instead of having the intrinsic type-safety checks and the social trust that the code author has run unit tests if necessary and makes the code do something reasonable, design-by-contract formalizes all this and makes you specify conditions on the code manually. That's quite a bit of effort for relatively little advantage. The popular design-by-informal-agreement works almost as well and doesn't have the extra, unneeded layer of indirection.

  10. If you can contract it it's coded already by IICV · · Score: 2, Insightful
    Or, in other words, it's because we're lazy.

    I feel that the reason why design by contract (DBC from now on) isn't popular is because the entire point of the paradigm is that it doubles or triples your code length without adding any actual information; first, you tell the computer what should be true so you can do what you're going to do, then you tell it what to do, then you tell it what you should have done. That's a lot of typing just to make sure the computer fucks up in exactly the way you told it to.

    Admittedly, I haven't programmed much in any language that has built in support for DBC, but from exercises in classes (I'm a CS major) I've found that generally it's sort of a waste of time at worst and a duplication of effort at best.

    Regardless, the theory remains: if you can write pre- and postconditions for a function, you already know what the function is supposed to be doing so you might as well have spent your time writing the function and doing something else.

    For instance, consider some list class's addElement function, with some (sorta) DBC assertions:

    (And I apologize for no indenting, but the tabs got stripped out in preview so I'm assuming they're not there when I post)

    class List<E>{
    ...
    void addElement(E whatever)
    {
    assert(!full() && canExpand());
    int oldSize = size();
    if(full())
    {
    expand();
    }
    myArray[last+1] = whatever;
    assert(size() == (oldSize+1));
    assert(getElement(currentIndex+1) == E);
    }
    };

    Of course, this is an overly simple example and I'm probably not even doing it right; however, hopefully it's close enough that you can see what I mean. All of the assertions are semantically redundant; they don't add any meaning to the code. In fact, I don't think it's possible for that to be true in DBC; if an assertion somehow adds information to the code, it's not an assertion any more.

    1. Re:If you can contract it it's coded already by Coryoth · · Score: 2, Insightful

      Regardless, the theory remains: if you can write pre- and postconditions for a function, you already know what the function is supposed to be doing so you might as well have spent your time writing the function and doing something else. Do you document your code at all? Do you test your code at all? That's all DbC is doing, it is just doing both at once for any tests that can be written as constraints. And remember DbC is as much about other people knowing what a function does as about you knowing - it provides clear conditions for anyone calling your code as to what they must provide, and what they can expect of any returned results, information that, for any decent DbC system, is automatically included in API documentation. You, the original coder, might know what the function does, but it would be useful if someone else who wants to use your code could get that information (or, at the least, soem useful constraints of the function) without having to dig through the source code to try and find out. If you're coding a project entirely by yourself for CS class then you won't see the advantages of DbC. If you're part of a large coding team, where you only ever understand a small part of the entire codebase, and are relying on other peoples code (which you don't have time to read) doing what you expect, then DbC starts to make more and more sense.

      The other point is maintenance. You know what the function is supposed to do now, and you'll probably still remember tomorrow. A year from now, or later, however, that might not be so obvious. The code isn't going to help because the code only tells you what it does, not what it was intended to do, so how can you tell whether it is functioning as intended, or not? You could, of course, write comments that help explain this, but then writing a contract that states intention is hardly any more work than a comment, and provides testing and potentially extra static checks into the bargain. DbC only does work that you should be doing anyway (again, if it's a small project you're coding entirely yourself that you don't expect to maintain, then okay, DbC doesn't make sense) in terms of documenting an testing your code, so it shouldn't be any extra work.
  11. Already mostly done by Todd+Knarr · · Score: 3, Informative

    As has been noted, most programmers already do design-by-contract, they just don't call it that. They call it argument checking. The first thing most routines do is validate their arguments, and return an error if any of them are invalid. The last thing done is to check the results and return an error if the results aren't valid. The calling code then checks for error codes or invalid results (eg. a search function returning a null pointer indicating the item wasn't found).

    In the real world I often skip this overhead when the conditions are enforced elsewhere. For example, a data structure needed by an internal function may not have to be checked for existence since if it hadn't been created my initialization function would've detected this and signaled an error and the program would've exited. In cases like that, I either omit the check or wrap it in an ifdef so it's only done during development and ignored by the compiler during the release build.

    Don't make the mistake of confusing the name of a concept with the concept itself. You'll find quite often that that nifty shiny-new concept someone's presenting as their own has actually been around for 30-40 years and they've just added some chrome, filed off the serial numbers and changed the name to keep you from noticing this.

  12. been doing that for years already by imbaczek · · Score: 5, Insightful

    assert(condition) is your friend. It's not called a contract, it's not design (but a very good practice!) and it does the job well.

  13. Programmers don't find it easy by smcleish · · Score: 2, Informative

    I do some teaching on an Open University course here in the UK which uses the concept, and my experience is that many students, including experienced programmers, find it difficult to do. Common errors include:

    - confusing the signature of the function (in terms of the types of permitted input) with the pre-condition. It may be true for some implementations of pre-conditions that you need to include information of the form "input is a string" but it isn't for the way we do it in the course.
    - ignoring input cases (e.g. giving a post-condition which only makes sense when the input is a non-empty string, but using a "true" pre-condition); students know theoretically that every possible permitted input needs to have an appropriate output in the post-condition but can't put this into practice
    - difficulty in creating conditions which are precise; this is both in the early part of the course, which uses English language conditions, and later on when algebraic conditions are introduced
    - designing tests which use inputs which fail the pre-condition (which is partly because the testing tool used in the course doesn't check the validity of the pre-condition, so invalid inputs can produce sensible looking outputs)
    - confusion between pre- and post- condition rules: they often want to restrict the input by changing the post condition

    It seems to be the case that it is at a particular level of abstraction vs practicality that many find difficult to cope with.

    --
    You can rent this space for $5 a week.
  14. Re:I'd like to use DbC, but... by Coryoth · · Score: 4, Informative

    I don't want my software to fail in the field (at my day job, we write stock trading software - reliability is key because lack of availability can quickly become very expensive). If I could define a number of pre- and post-conditions for each function and have the compiler check these for me, I'd be happy. And indeed, this can be done, and is available for a number of DbC systems. Check out JML which has ESC/Java2 to provide static contract checking for Java, Spec# (C# with contracts) which uses the Spec# verifier for static checking of contracts, and Eiffel with ESpec-Verify for static checking of Eiffel contracts.

    If the conditions are only going to be checked at runtime, then I'm going to have to write unit tests anyway - otherwise, the failure's going to be beautifully detected and localised and so forth, but crucially, it's going to be one of my customers that detects it. If I'm writing unit tests anyway, why bother with DbC? The difference between DbC and unit tests (and really, you should be doing both) is that if a test can be expressed as a constraint then it is useful to simply express that as a contract, while if the test is a specific input to output matching test then it is going to be useful as a separate unit test. When you run your unit tests the contract constraints will automatically get checked. More importantly they will help isolate exactly where the error occured when testing integrated systems. Furthermore, by putting constraints as contracts you have improved your API documentation (any decent DbC system includes automated inclusion of contract information in API documentation) which helps other people use your code correctly, and makes maintenance easier.

    Finally contracts allow automated testing. That's where you automatically generate data to pass to the code and let the contracts act as a test oracle to catch and locate problems. With something like AutoTest for Eiffel the data generation can be purely random (constrained by preconditions of course), or designed to sample the input according to best coverage via genertic algorithms, etc. The result is that you find corner cases that you might not have anticipated with your unit tests - and you would be surprised how often that happens, AutoTest found a number of subtle bugs in Eiffel's base libraries which had been production code for years.

    When there's a DbC language or add-on that checks the contracts at compile time, I'll be interested. Then you really need to check out JML and ESC/Java2, and Spec#, because you would be interested.
  15. DbC and Unit Tests cover similar ground by FrnkMit · · Score: 2, Insightful

    Apart from "it's too hard", I think Unit Testing has overtaken DbC as an approach.

    - You can write unit tests in any language, with or without a framework. (I saw a "mini-framework" for C that consisted of three macros and a coding convention.)

    - In a test, you can specify assertions before and after each method call. It's a little more tedious to represent classic DbC assertions, but the Abstract Test pattern among others allows you to collect common code.

    - You can strip out assertions in production code simply by leaving test code out of the product.

    - Unit tests also run scenarios automatically, without an extra "test driver".

    The one thing Unit Testing *can't* do is check production code as it's running. On the one hand, that's great at catching conditions you never thought of. On the other hand, customers tend to get annoyed if their app shuts down. I'm sure there's some work on partial in the Eiffel world, but so far I haven't seen any.

    See also http://onestepback.org/index.cgi/Tech/Programming/ DbcAndTesting.html and particularly the postscript.

  16. Re:Management by Anonymous+Brave+Guy · · Score: 4, Interesting

    People have a tendency to confuse bluster and arrogance with ability and experience.

    They do, yet in my experience, these things are inversely correlated. This applies to all guidance/oversight roles, including business analysts, software architects, consultants, and indeed managers themselves. As I've commented here before, you can always identify a good leader by three characteristics:

    • They can set a clear direction and convey this to others.
    • They organise adequate resources and set realistic expectations.
    • Having done the above, they get out of the way as much as possible.

    The third one is usually the easiest way to identify morons. If you come across a leader in software development who places more value on reports and metrics so they can track things than they do on supporting the developers and test teams working for them, then you know you're dealing with an incompetent.

    And yes, that does mean many leaders in software development organisations today are incompetent. That's why the genuinely good people are worth so much.

    --
    If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
  17. Side Effects by somepunk · · Score: 2, Insightful

    A lot of functions in real world programs just don't fit this model. Especially in GUIs. Or functions that manipulate internal data structures. Only the most trivial programs (or contrived exercizes of academics) strictly fit the functional, no-side-effects model for all functions. And if you can't apply this method to your entire program, you are going to find a more flexible way to verify behavior.

    --
    Those people who think they know everything are a great annoyance to those of us who do. (Isaac Asimov)
  18. But what kind of language? by Anonymous+Brave+Guy · · Score: 2, Insightful

    I'd agree with much of your post, but I think there's an unwritten assumption about programming style in what you wrote: you seem to be restricting your scope to imperative languages with mutable state (talking about locks and threading, for example).

    If you're working in a language that doesn't permit generally mutable state, it's much easier to use concepts of design by contract, essentially because all you have to do is check that when you've finished constructing a new value, it is valid for whatever type it has. Of course, such languages have disadvantages as well.

    I suspect that a great deal of work in programming languages over the next few years is going to focus on how to identify and localise side-effects more explicitly. Pure functional languages that don't allow mutable state at all seem to be quite inefficient, and have fundamental problems for high performance applications that have yet to be resolved. Things like the monads widely used in Haskell today provide some powerful features like mutability but built on a much sounder base than many of today's imperative languages, but at the cost of horrendous syntactic overheads, which kinda spoils one of the big advantages of adopting a functional language: conciseness.

    However, multi-core and multi-processor machines are fast becoming mainstream, and loose imperative programming languages have failed to provide satisfactory tools to take advantage of these architectures. I expect this to drive a general move towards more declarative rogramming styles in the industry. Meanwhile the academics, who have seen it all before, will be working on more powerful models of scoping and side effects, well beyond the glorified block scope/lambda calculus stuff that most of today's mainstream programming languages are effectively built on. Once we start getting programming languages with more powerful ways to signify when it is acceptable for what sorts of side effects (including changes in state) to occur, we'll have the sort of foundation needed for your ideas about being inside/outside an object, and compilers will have the sort of framework needed to optimise DbC checks so they're only applied when they're really needed and don't carry unfortunate performance penalties.

    --
    If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
  19. Or, better yet... by Chemisor · · Score: 4, Informative

    > assert(condition) is your friend.

    And assert(condition && "Explanation of why it's bad and what to do to fix it") is even better. Don't make me read your code and figure out why the hell you put some obscure assert(n != 455) in there.

  20. Re:Design by contract is 25+ years old by Waffle+Iron · · Score: 3, Funny

    We call it include files and C coders have been doing it for ages. You noobs and your silly OO languages.

    I especially like contractual gems such as:

    char *gets(char *s);

  21. Very simple by jilles · · Score: 2, Insightful

    Design by contract, like most formal method approaches, doesn't scale to interesting levels. If you are working on a 200KLOC project on a tight schedule, the last thing you can afford yourself is increasing time spent per line of code by equipping classes, loops and methods with pre & post conditions. And you would need to do this on a substantial scale to make a significant impact on overall quality. I'm sure most projects could boost quality significantly if you double their budgets but then doing so is unacceptable in most real life situations. Good enough involves balancing a lot of factors and quality is just one of them.

    It's great if you can specify that a piece of code is a 100% correct implementation of a given specification but in real life the requirements are sketchy at best & keep changing during development. So, you are likely to end up with the wrong system if you don't adjust your interpretation of them to reality during development. Besides, pre and post conditions need maintenance too if you are doing maintenance on your code, so effectively they increase the cost of what is the single most expensive development activity already: maintenance.

    Besides there are other, much more useful tools for improving code quality: unit testing, integration testing, static code checkers, compile time type checking, inspections & reviews are all part of the toolkit of an experienced software engineer and largely remove the need for more formal approaches. Additionally clustering and redundant setups are a far cheaper way of guaranteeing uptime than proving the system to be correct. Risk management is better than trying to avoid risk at all cost.

    And finally, the value of 100% correctness is overrated. Most commercial software functions acceptably despite the approximately 10 bugs per kloc. In theory disaster could strike any second, in practice it is a rare event that it does and the consequences are quite manageable usually. Of course things do go spectacularly wrong sometimes and usually people then find out a lot was wrong with the overall development process aside from not applying design by contract. So even then, the added value of design by contract is very questionable. You can't compensate for general incompetence with a couple of pre and post conditions.

    --

    Jilles
  22. Re:I'd like to use DbC, but... by Tablizer · · Score: 2, Insightful

    if a test can be expressed as a constraint then it is useful to simply express that as a contract,

    Us table-heads who like to shift the processing burden to the database instead of application languages would point out that this resembles database constraints and triggers.

  23. Re:You need to have a contract first by khchung · · Score: 2, Insightful

    Why do you need a complete set of user requirements? If you don't know what the function should do right now, how can you possibly write it?

    How interesting for you to put these 2 questions together! Didn't your 2nd question just answered your first question (at least in theory)?

    Now in practice, we obvious will be start developing before we got a complete set of requirements, which bring us to...

    You might as well complain that you can't do automated unit testing, because the tests may have to change during development, or that you can't write code because that code might have to change during development.

    The big difference between code + unit tests vs contracts (at least from my understanding and experience), is that code and tests are "constructive" in nature, while contracts are mainly "prohibitive" in nature. By "constructive", I mean code and tests tell you something the program will do, vs "prohibitive" which means what the program will not do.

    A piece code to parse a string "1234" into an integer 1234 and with test to call it using "1234" and asserting the result == 1234, now that tells you what the code does. The test does not tell you what other things the code might also do, such as it maybe the code can also handle -ve numbers ("-1234"), or formatted numbers ("1,234"), or even decimals "1,234.56" (if the return type is general enough to support it, such as returning type Number in Java).

    When you put in assert() into the code, however, it tells what the code does not do. assert(result is integer) tells us the parse does not handle decimals, assert(string contains only numbers) tells us the code does not handles formatted strings, etc.

    Comparing the two, code and tests are "constructive" as they give more features to your program, while contracts are "prohibitive" as they restrict what you program can do. More contracts you add, more things you prohibit your code from doing.

    When the requirements change ("we have to handle dollar signs in front too, but no more decimals"), the now unused decimal feature and its tests can be ignored, but any contract ("string only contains [0123456789.,-]") that blocks the new requirement has to be removed. Guess which one, tests or contracts, make more problem for the team as the development progress and requirements change?
    --
    Oliver.
  24. Re: Absolutely not "Already mostly done" by Todd+Knarr · · Score: 2, Insightful

    Unfortunately Mr. Meyer runs up against the halting problem. If the definition of a function, or the contract, says that a parameter must never be the NULL pointer, there are two choices: the code must check whether that pointer is NULL, or it must be proven that that pointer can never possibly be NULL. The second is, with the current state of the art, impossible no matter what language constructs are around to help. That means the check has to be done, the only question is whether it's done by the caller or the called function. And the first rule I learned is to eliminate redundancy, which means that given a choice of doing a check in one place or doing it in a large number of places you do it in the one place.

    Design by contract is many things, a large number of them good, but it is not a replacement for error-checking.