Interface Oriented Design - Ken Pugh

Cover of Interface oriented design 

three laws that all implementations should obey, regardless of what services they offer.

1. An Interface’s Implementation Shall Do What Its Methods Says It Does
If the purpose and meaning of a method are not unambiguously obvious from the method’s name and its place within an interface, then those aspects should be clearly documented.3 The documentation may refer to interface tests, such as those described later in this chapter, to demonstrate method meaning in a practical, usage context.
2. An Interface Implementation Shall Do No Harm
3. If An Implementation Is Unable to Perform Its Responsibilities, It Shall Notify Its Caller
An implementation should always report problems that are encountered and that it cannot fix itself.

Michael Hunter suggests, “They should be documented regardless. Conversely, if
they need documentation, the name should be improved.”

To successfully use an interface, both the caller and implementer need to understand the contract—what the implementation agrees to do for the caller. You can start with informal documentation of that agreement. Then, if necessary, you can create a standard contract.
An interface implementation is not required to check the preconditions. You may assume that the user has met those preconditions. If the user has not, the implementation is free to fail. Any failures should be reported as in the Third Law of Interfaces.
An implementation with weaker preconditions can meet the contract for the interface. One that has stronger preconditions cannot.
An implementation with stronger postconditions meets the contract; one with weaker postconditions does not.
You also need to know the protocol to the interface—the set of allowable sequences of method calls.
As a general rule, no interface definition is complete until you have all the contractual tests successfully running for at least one implementation.
Design to an interface, not an implementation.
“Test to an interface, not an implementation”.
Writing tests for an interface can also help you work out difficulties in the interface.
If you find that your interface is hard to test, then it probably will be hard to use. If this happens, you can redesign your interface without even having coded an implementation.

Levels of contracts.19 The levels are:
• Basic type contracts as in typed programming languages
• Semantic contracts that include the preconditions and postconditions
• Performance contracts for real-time systems
• Quality of service contracts that are hard to quantify

Testing for quality of service contracts is usually more difficult than testing for performance contracts

An implementation of an interface should obey the three laws:
• Do what its methods say it does.
• Do no harm.
• Notify its caller with meaningful errors if unable to perform its responsibilities.
Establish a contract for each interface (either formally or informally):
• Indicate the preconditions and postconditions for each method.
• Specify the protocol—the sequence of allowable method calls.
• Optionally, spell out nonfunctional aspects such as performance or quality of implementation.
• Create tests to check that an implementation performs according to its contract and that it obeys the three laws.

Interfaces move data in one of two ways: push or pull. You ask a pullstyle interface—for example, a web browser—for data. Whenever you desire information, you type in a URL, and the information is returned. On the other hand, a push-style interface transfers data to you. An email subscription is a push-style interface.
PUSH STYLE
Advantage—can be simpler code, once paradigm is understood
PULL STYLE
Advantage—appears as a common control style (e.g., loop) in multiple languages

MANY METHODS
Advantage—implementer does not have to determine type of parameter
Disadvantage—implementer has to implement all the methods
SINGLE METHODS
Advantage—can be more resilient to change, because new methods do not have to be implemented
Disadvantage—must check parameter type to determine flow

STATELESS
Advantage—a small number of operators can service many requests. My mom would not be able to juggle more than a few requestors at a time.
STATEFUL
Advantage—there is less chatter to get the same amount of work done.

STATELESS
Advantage—order of the method calls does not matter
Disadvantage—parameter lists are longer
STATEFUL
Advantage—parameter lists shorter
Disadvantage—order of method calls important

If you don’t like way that an interface works, transform it into one you like.

One of the most difficult decisions in developing a program is determining what should be in an interface.
You often face another question: how many methods should you have in an interface? Many methods can make an interface more difficult to understand but can also make it more powerful.
Methods in an interface should be cohesive. They should provide services that revolve around a common concept.1 The problem is that the definition of commonness is relative.

SINGLE PRINTER INTERFACE
Advantage—can have single capability query method
Disadvantage—related capabilities may not be logically grouped together
MULTIPLE PRINTER INTERFACES
Advantage—printer need only implement interfaces it supplies
Disadvantage—lots of interfaces

Coupling measures how one module depends on the implementation of another module.

TIGHT COUPLING
Disadvantage—callers have to be changed if implementation changes
LOOSE COUPLING
Advantage—callers do not need to be changed if implementation changes

Interfaces
MINIMAL
Advantage—easier to implement and test with fewer methods
Disadvantage—user must code their particular functionality and may wind up with duplicate code for same functionality
COMPLETE
Advantage—user has all needed methods
Disadvantage—may be harder to understand an interface with numerous methods

SIMPLE
Advantage—easy for the user to perform common functions
Disadvantage—variations must be coded as new methods
COMPLEX
Advantage—users have flexibility to “do it their way”
Disadvantage—may be harder for users to understand

USING INTERFACES
Advantage—delay forming hierarchy until usage known
USING INHERITANCE
Advantage—less delegation of common operations

USING INTERFACES
Advantage—can cross hierarchies
USING INHERITANCE
Advantage—captures common attributes

USING INTERFACES
Advantage—can capture common set of usage
USING INHERITANCE
Advantage—captures set of common behavior

USING INTERFACES
Advantage—give more adaptability for roles that cross hierarchies
Disadvantage—may have duplicated code without helper classes to provide common functionality
USING INHERITANCE
Advantage—base classes can provide common implementations
Disadvantage—difficult to adapt to new situations.

When you have multiple implementations of an interface such as InputStream, you may duplicate logic in each implementation. If there are common implementation methods and you do not use a helper class, you may find yourself copying and pasting a lot. If you can create a well-defined hierarchy with many inheritable implementations, you are far better off using inheritance, rather than interfaces. But you may find that starting with interfaces and then refactoring to inheritance allows you to discover what is the best hierarchy.

INHERITANCE APPROACH
Advantage—easy to inherit an implementation
Disadvantage—may be difficult to adapt to changing roles
INTERFACE APPROACH
Advantages—can be clearer what methods must be implemented.
A class in another inheritance hierarchy can provide the services of an interface.
Disadvantage—may end up with lots of helper classes.

• Interfaces show commonality of behavior.
• Inheritance shows commonality of behavior along with commonality of implementation.
• Interfaces are more fluid than inheritance, but you need to use delegation to share common code.
• Inheritance couples the derived classes to the base class, but it allows them to easily share the common code of the base class.

PROCEDURAL STYLE interface
Advantage—remote and local interfaces can appear the same
Disadvantage—can require more communication (especially if fine-grained)
DOCUMENT STYLE interface
Advantage—can require less communication
Disadvantages—style is less familiar to programmers

SYNCHRONOUS
Advantage—practically immediate response
Disadvantage—cannot scale up as well
ASYNCHRONOUS
Advantage—can scale well, especially with document queues
Disadvantage—documents should be validated on client before transmitting

REMOTE STATELESS
Advantages—servers can be easily scaled. If you have multiple servers processing client requests, any server can handle any client.
The service has redundancy. Any server could go down and the client could continue with any other server.
Disadvantage—amount of state information passed between client and server can grow, especially for a full shopping cart. In most cases, this amount will be less than the size of the web pages for which the state information is transferred.
REMOTE STATEFUL
Advantage—less information to communicate between client and server
Disadvantage—if using central database where the state information is stored, the amount of simultaneous connections to that database could be a limiting factor to scalability

Stability is a needed trait for external interfaces.
Both procedural and document interfaces can be flexible.
You should follow a few guidelines in being flexible in interfaces. First, never alter the semantics of existing methods or data. Second, you can add methods or data; just don’t expect that users will add calls to the new methods or provide the new data.
But although adding functionality is easy, deleting methods or data is hard.
Whenever you have an remote interface that is available to the outside world, you need to worry about security.

No guaranteed way exists to determine what responsibilities should go with which interfaces; designing interfaces takes the same effort as designing classes. Bertrand Meyer says, “Finding classes is the central decision in building an object-oriented software system; as in any creative discipline, making such decisions right takes talent and experience, not to mention luck.” He goes on to say, “No book advice can replace your know-how and ingenuity.” The same can be said for finding the right set of cohesive interfaces.

In interface-oriented design, the emphasis is on designing a solution
with interfaces. When using IOD, here are some tips:
• Use IRI cards to assign responsibilities to interfaces.
• Keep service interface definitions in code separate from the code
for classes that implement it.
• Write tests first to determine the usability of an interface.
• Write tests against the contract for the interface.

Application confguration
USING CONFIGURATION
Advantage—hides implementation requirements
Disadvantage—services have dependency on a configuration interface
USING INVERSION OF CONTROL
Advantage—common feature (used in frameworks)
Disadvantage—can be harder to understand

You should review your interfaces before you implement them. Otherwise, you may implement methods that turn out to be useless.

Using interface-oriented design, just as with other techniques, does not guarantee that you’ll never have to restructure your interfaces or refactor your code. As you develop a system, you usually discover additional information that suggests a restructuring of the design.
</p>

 

Jun 26, 2012
comments powered by Disqus

Links

Cool

RSS