Necessary and Sufficient

A good interface contains only the methods that it needs. The interface has enough methods to accomplish its task: the set methods is sufficient. In addition, the interface does not have any methods that it doesn't need: the set of methods is necessary. If you find that an interface has unnecessary methods, you should remove them. And if you find that it is insufficient, you must add to it.

A good contract is also both necessary and sufficient. A contract is more than the set of methods (the interface) that a type supports. It is also the constraints: preconditions, postconditions, and invariants. If it has unnecessary constraints, then there are otherwise valid situations that violate the contract. If it has insufficient constraints, then the contract allows some invalid situations.

A good unit test suite is also both necessary and sufficient. If it has unnecessary tests, then it is harder to maintain than it could be. If it has insufficient tests, then it won't detect all defects.

The balance of necessity and sufficiency is found all throughout mathematics. Software, being a form of applied mathematics, inherits this trait. Something that achieves this balance is beautiful to behold.

Two examples of this balance in literature can be found in my recommended book links. Euclid's Elements is the foundation for modern mathematics. He provides a small number of axioms, and from those he derives a large number of theorems. The axioms are necessary and sufficient to describe all of geometry. Bertrand Meyer's Object-Oriented Software Construction contains example after example of necessity and sufficiency in software contracts. Pay close attention to his Stack type.

Examples of software that do not achieve this balance are abundant. Many parts of the JDK have "convenience methods", which by definition are unnecessary. The SOAP specification is an insufficient contract, which leads to many interoperability problems.

Achieving this balance takes time. Only with experience can we hope to get there. It's something I strive for every day.

3 Responses to “Necessary and Sufficient”

  1. Tam Hanna Says:

    Hi,
    but I dare to pose one question:

    Whats bad about centralizing convinience functions? In the Palm OS world, every product contains a function called getObjectPtr(in fact, its almost considered a part of the API).

    If Palm had included that call into its OS, apps would be smaller and code would be simpler to reuse...

    Best regards
    Tam Hanna

  2. Michael L Perry Says:

    I haven't coded to the Plam OS, but it sounds like getObjectPtr is a necessary function that has no alternative. And it certainly sounds like the OS would have been better had it included that basic functionality itself.

    The type of convenience method that I'm talking about is one that has an alternative. The method simply saves the programmer a little typing. For example, the constructor for java.io.FileReader is overloaded to accept either a java.io.File object or a string. Either form specifies the file name. The File object itself has a constructor that takes a string. So the following lines of code are equivalent:

    FileReader reader = new FileReader("input.txt");

    FileReader reader = new FileReader( new File( "input.txt" ) );

    The cost of this convenience is a bloated API, which implies a larger footprint, more to learn, and confusion. How do I really know that these two forms are identical? Could they have some subtle difference?

    It also makes the maintenance path more obscure. If I started off using the more convenient form, and now want to load the input file from a subdirectory, the path isn't obvious. But if I started with the longer form, I could just add a parameter to get this:

    FileReader reader = new FileReader( new File( "sub", "input.txt" ) );

    or better yet:
    FileReader reader = new FileReader( new File( new File("sub"), "input.txt" ) );

    The convenience hides degrees of freedom that may be important to later modifications. Therefore, I assert that there should be one way to express any given idea, and that the API should contain only those methods necessary and sufficient for that expression.

    Thanks for the question.

  3. Adventures in Software » Blog Archive » Definitive Behavior Says:

    [...] If there are two ways of expressing the same idea, then the object’s interface is bloated (see Necessary and Sufficient). The constructor should only set a value only if it can be set in no other way. It’s parameters should be those things that do not change over the course of an object’s lifetime. [...]

Leave a Reply

You must be logged in to post a comment.