Compartilhar via


API Design Myth: Interface as Contract

I often hear people saying that interfaces specify contracts. I believe this is a dangerous myth. Interfaces, by themselves, do not specify much beyond the syntax required to use an object. The interface-as-contract myth causes people to do the wrong thing when trying to separate contracts from implementation, which is a good engineering practice. Interfaces separate syntax from implementation, which is not that useful, and the myth provides a false sense of doing the right engineering.

Contract is semantics -- and these can actually be expressed with what many unjustifiably consider unwanted implementation. For example, the contract of IList<T> says that when an item is added to the collection, the Count property is incremented by one. Such simple contract can be expressed and what’s more important locked for all subtypes, using something like the following abstract class.

public abstract class CollectionContract<T> : IList<T> {
public void Add(T item){
AddCore(item);
this.count++;
}
public int Count {
get { return this.count; }
}
protected abstract void AddCore(T item);

private int count;

    ...
}

Comments

  • Anonymous
    October 25, 2004
    I always thought the real problem was the change in the meaning of the word "interface": it used to mean contract. Then after interfaces were added to languages, such as the C# concept of interface, the word became tied to a specific type of interface. It was no longer generic.

    I still use the word "interface" to mean "contract" in conversation sometimes, but it cause a lot of confusion. People assume I mean a C#-type interface. So I must specify contract.... :(

  • Anonymous
    October 25, 2004
    As soon as you went into the example my brain told me I was about to encounter postcondition syntax...but I didn't. Are you guys even remotely considering adding some pre/post-condition support and invariants much like what Eiffel offers? Only then, I think, we would really be talking about contracts.

  • Anonymous
    October 28, 2004
    The comment has been removed

  • Anonymous
    January 12, 2005
    The comment has been removed

  • Anonymous
    June 05, 2007
    I agree that the interface by itself is not enough to specify a contract. I like to write unit tests against my interface in order to specify its dynamic behavior. Then, a build against an implementation will both compile the class against the interface checking its structure, as well as run the tests thus verifying its behavior. I've written about this here: http://udidahan.weblogs.us/2006/05/06/behavior-specification-the-next-generation-of-unit-testing/ Since you'll want client code to depend only the interface, not on some abstract base class for reasons of extensibility, this approach documents for that client code what assumptions in can make. So, I'd have to say that interfaces are a necessary part of the solution, but not sufficient by themselves.

  • Anonymous
    June 06, 2007
    Udi, having a set of reference tests for abstractions is a great idea. But I don't see why interface gives you more/better extensibility than an abstract class, besides cases where you need "multiple inheritance."

  • Anonymous
    June 11, 2008
    kcwalina, another very  good part of interface is we can use it to ensure proper/effective naming in our code. if we can identify similarities (properties/functions/events) between related or unrelated classes then we can prepare a interface with those functions/properties and make it a practise to implement appropriate interface when those properties and functions are used. this will make sure we are not using different names for similar funtions/ properties eg. i may have 3 classes Circle/RoofTop/Carpet its usefull to implement IhaveArea interface and then implement the GetArea() function of the Interface. This will make sure even if differnet people are working on the project they all have identical names for similar work.

  • Anonymous
    September 16, 2010
    While I would agree that contract is semantics, contracts usually specify terms and conditions on an agreement, and not the methods by which those terms and conditions are satisfied. Your example above does much more than introduce “unwanted implementation”- it grossly violates the tenet principle conventionally called (oddly enough) “separation of implementation and interface”. In computer science and software engineering, the terms and conditions on a contract are typically referred to as pre- and post-conditions. While abstract classes could be used to validate that these conditions are satisfied through the use of the template-method pattern, this approach can introduce unacceptable run-time overhead even when limited to debug builds.  Most importantly the design decision to use abstract classes has an enormous consequence on design in languages that don't allow for multiple inheritance such as C#. As Udi Dahan pointed out above, unit testing is the most appropriate place to validate that contracts are being honored. Your example above does much more than merely express the requirement that “when an item is added to the collection, the Count property is incremented by one”. It forces that :  1) The count be an explicitly maintained integer field.  2) The count be maintained in a field which is a private member of CollectionContract. Your bold assumptions as to how CollectionContract will be used has made it rigid and inflexible. Interfaces are much more than merely syntax. At the end of the day, the machine doesn't care what label you assign a method. That label is intended for a human being.  A method to add an object to a collection is typically called “Add” because that is what it does, thus communicating semantics. If the contract needs further specification, comments are a powerful tool which are well supported by and integrated into most modern development environments. Despite the age of this article, I felt compelled to reply, as this sort of thinking merely reinforces the naïve decisions commonly made by novices. I find that poor design decisions motivated by misguided principles proliferate many frameworks and libraries. Such misinformation serves only to frustrate developers and limit the availability of quality software.

  • Anonymous
    April 27, 2011
    Interfaces approach contracts as implementations reduce statefulness.  Thus, a stateless implementation's contract would be perfectly described by an interface, otherwise you have to do the precondition/postcondition stuff.