CSC/ECE 517 Fall 2009/wiki3 8 agummad
Interface Segregation Principle vs. Principle of Small Interfaces
Introduction
Software changes. To enable software to chage gracefulllyspend a lot of time in designing. Use of oo best practices. We present two specific design rules that deal in different levels abstractions in the design phase. We present an explanation of both and provide a comparision of both strategies and their application.
Background
OO programming and design patterns
The object oriented paradigm of programming and their associated design patterns have long been studied heavily by a computer programmer. Ever since object oriented programming replaced the functional type programming style of the early 70s, it has been used extensively to develop commonly used software. However, as the scope and the size of these projects grew, researchers studied ways to maintain the quality of the software written. They introduced patterns of programming within OO in part to address some very common problems occurring while programming and maintaining a large project. This study of object oriented design programming patterns and related principles is a vast field, and its understanding is considered vital for developers.
Modularity
A modular system is one that is made of autonomous elements which are connected and inter-operate in a simple yet coherent structure. However to formally define modularity, one needs to look at the concept from different view points. We may define modularity along the following concepts, as defined in [1].
- Decompose-ability: A software development method is Decomposable if it helps in the task of decomposing functionality into a small number of less complex subproblems. These smaller units of functionality are then connected by a simple structure, allowing them to be independent from each other in that each of them is extensible without affecting the others.
- Composability:A software development method is Modular composable if it allows the production of software elements which may then be freely used as building blocks for newer systems. Each of these elements may be combined with each other to produce new systems,quite often in an environment very different from the ones in which they were initially developed.
- Understandability: A software development method should produce software, which is non trivial enough in that a human can understand the functionality and working of each module without having to learn about others or, at worst, by having to examine only a few of the others.
- Continuity: A software development method satisfies Modular Continuity if, in the software architectures that it yields, a small change in a problem specification will trigger a change of just one module, or a small number of modules.
- Protection: A method satisfies Modular Protection if it yields architectures in which the effect of an abnormal condition occurring at run time in a module will remain confined to that module, or at worst will only propagate to a few neighboring modules.
Rules for Modularity
From the preceding criteria, five rules follow which we must observe to ensure modularity in a given system. These rules were collectively postulated by Bertrand Meyer:
- Rule of Direct Mapping: The modular structure devised in the process of building a software system should remain compatible with any modular structure devised in the process of modeling the problem domain.
- Rule of Few Interfaces: Every module should communicate with as few others as possible. The effect of a change or of an error may propagate to a large number of modules as a result of too many relations between modules of an implementation. It
- Rule of Small interfaces (weak coupling) : If two modules communicate, they should exchange as little information as possible. This rule relates to the size of inter-module connections rather than to their number. This rule corresponds directly with our topic and will be dealt in more depth.
- Rule of Explicit Interfaces: When modules interact, we expect them to do so "loudly" or "in public", in full view of all the other modules of the system.
- Rule of Information Hiding: The designer of every module must select a subset of the module’s properties as the official information about the module, to be made available to authors of client modules.
SOLID Design Principles
The SOLID principles of Object Oriented Design are five basic class design principles. These were first stated by Bob Martin and are outlined extensively on his websites. Collectively, they provide a set of guidelines that help design better objdect oriented systems. The SOLID principles are most concerned with dependency management, or the ability to keep code loosely coupled and flexible. The 5 principles are given below :
- SRP - The Single Responsibility Principle< - A class should have one, and only one, reason to change. The SRP says a class should focus on doing one thing. This doesn't mean it should only have one method, but instead all the methods should relate to a single purpose. For example, an Invoice class might have the responsibility of calculating various amounts based on it's data. In that case it probably shouldn't know about how to retrieve this data from a database, or how to format an invoice for print or display.
- OCP - The Open Closed Principle - You should be able to extend a classes behavior, without modifying it. Change a class' behaviour using inheritance and composition. Bob Martin's initial paper on the OCP linked from The Principles of OOD attributes the idea to Bertrand Meyer, who wrote that classes should be "open for extension, but closed for modification"[2]. The idea is that we can use OO techniques like inheritance and composition to change (or extend) the behavior of a class, without modifying the class itself.
- LSP - The Liskov Substitution Principle - Derived classes must be substitutable for their base classes.
- ISP - The Interface Segregation Principle - Make fine grained interfaces that are client specific.
- DIP - The Dependency Inversion Principle - Depend on abstractions, not on concretions.
The Interface Segregation Principle
Statement
The Interface Segregation Principle (ISP) is a SOLID Principle that states the following:
"Make fine grained interfaces that are client specific."
Motivation
This principle deals with the disadvantages of polluted interfaces -"fat" interfaces and unnecessary recompilation.
Explanation
In simpler terms, consider a client that depends upon a class that contains interfaces that our client does not use, but that other clients of that class do use. The problems that exist are as follows:
- The class now has to provide a null or a valid implementation for all those extra interfaces that our client does not use. Any change to any part in this hierarchy needs a complete recompilation.
- Our client now will be affected by the changes that those other clients force upon the class.
We would like to avoid such couplings where possible, and so we want to separate the interfaces where possible.
Example of a Violation
Consider a secirity system with Door objects that can be locked and unlocked.
class Door { public: virtual void Lock() = 0; virtual void Unlock() = 0; virtual bool IsDoorOpen() = 0; };
We make this an abstract class and each type of door that we wish to create use this class and provides its own implementation of Door.Consider a TimedDoor, which sounds an alarm when a when a door is left open for too long. For this, it communicates with a Timer object.
class Timer { public: void Regsiter(int timeout, TimerClient* client); }; class TimerClient { public: virtual void TimeOut() = 0; };
Thus, when a TimedDoor object wishes to be informed about a timeout, it calls the Register function of the Timer. We force Door, and therefore TimedDoor, to inherit from TimerClient. This ensures that TimerClient can register itself with the Timer and receive the TimeOut message.
The problem with this implementation is that Door class now depends on TimerClient. For Door types that dont need timing, we still need to provide nil implementations for Timeout method. Also all these derivatives need a #include for TimerClient, even though, they don't use it. Thus, our TimedDoor has forced a change in all the tyes of Doors that we have.
Resolution
Possible ways to ensure that ISP is enforced is to use the Adapter Pattern. this makes sure that the interfaces of the class can be broken up into groups of member functions. Each group serves a different set of clients. Thus some clients use one group of member functions, and other clients use the other groups. The other solution is to use Multiple Inheritance.
The problem is resolved using the ADAPTER pattern as follows: We create an adapter object that derives from TimerClient and delegates to the TimedDoor. That is, when the TimedDoor wants to register a timeout request with the Timer, it creates a DoorTimerAdapter and registers it with the Timer. When the Timer sends the TimeOut message to the DoorTimerAdapter, the DoorTimerAdapter delegates the message back to the TimedDoor. Thus DoorTimerAdapter TimedDoor does not have to have the exact same interface as TimerClient. The DoorTimerAdapter can translate the TimerClient interface into the TimedDoor interface.
Object Form of Adapter Pattern class TimedDoor : public Door { public: virtual void DoorTimeOut(int timeOutId); }; class DoorTimerAdapter : public TimerClient { public: DoorTimerAdapter(TimedDoor& theDoor) : itsTimedDoor(theDoor) {} virtual void TimeOut(int timeOutId) {itsTimedDoor.DoorTimeOut(timeOutId);} private: TimedDoor& itsTimedDoor; };
PSI
Statement
This rule states that
If two modules communicate, they should exchange as little information as possible
Motivation
The Small Interfaces or “Weak Coupling” rule relates to the size of intermodule connections rather than to their number or their size. One would want to reduce the size of the intermodule connections to the very minimum, thus enabling tem to communidcate effectively exchanging the very leasy amount of information.
Explanation
The rule for smaller interfaces is desirable in most engineering fields. For example, in the field of electrical sciences, one would paraphrase to say that the communication channels between any two modules. This requirement follows from the criteria of continuity and protection (see discussion of modular systems). Once the modules are tightly coupled with each other, they are harlder to change and harder to protect. This is because by having larger fields of communication, every module might increase the risk of misusing the common data. Therefore in tightly coupled systems, the problems of propagation of changes and propagation of errors are really nasty.
Example of a Violation
An example of violation is an established Fortran practice of using COMMON.
A common block in Fortran shows up the following directive form:
COMMON /common_name/ variable1... variablen Example: >> COMMON block1 A[75], B[25] >> COMMON block1 C[50], D[50]
This indicates that the variables listed are accessible not just to the enclosing module but also to any other module which includes a COMMON directive with the same common_name. It is not infrequent to see Fortran systems whose every module includes an identical gigantic COMMON directive, listing all significant variables and arrays so that every module may directly use every piece of data. This runs the risk of data misuse as discussed above. Developers using nested structures also face similar problems.
Resolution
Developers using languages with nested structures can suffer from similar troubles.
With block structure as introduced by Algol and retained in a more restricted form by Pascal, it is possible to include blocks, delimited by begin ¼ end pairs, within other blocks. In addition every block may introduce its own variables, which are only meaningful within the syntactic scope of the block. For example:
local-- Beginning of block B1 x, y: INTEGER do Instructions of B1 local -- Beginning of block B2 z: BOOLEAN do Instructions of B2 end --- of block B2 local -- Beginning of block B3 y, z: INTEGER do Instructions of B3 end -- of block B3 Instructions of B1 (continued) end -- of block B1
Variable x is accessible throughout the block, whereas the two variables called z (one BOOLEAN, the other INTEGER) have scopes limited to B2 and B3 respectively. Like x, variable y is declared at the level of B1, but its scope does not include B3, where another variable of the same name (and also of type INTEGER) locally takes precedence over the outermost y. Block structure. However introduces may still violate the Small Interfaces rule. The architecture of object-oriented software will involve three levels: a system is a set of clusters; a cluster is a set of classes; a class is a set of features (attributes and routines). Clusters, an organizational tool rather than a linguistic construct, can be nested to allow a project leader to structure a large system in as many levels as necessary; but classes as well as features have a flat structure, since nesting at either of those levels would cause unnecessary complication.
Comparision summary
The following table summarises the contrasts and similarities between the two principles.
Criteria | Interface Seggregation Principle | Principle of Small Interfaces |
---|---|---|
Statement | Make fine grained interfaces that are client specific. | If two modules communicate, they should exchange as little information as
possible. |
History | Postulated by Bob martin in early 2000s, as part of SOLID framework, to aid in designing better structured Object Oriented Systems. | These were postulated by Bertrand Meyer, together with the rules for ideal modules. |
Scope | This is a class-design principle, largely dealing with the size of the interfaces - eliminating fat interfaces as part of better design. Thus this rule serves to promote coherence and cohesion of the classes invloved | This priciple largely deals with the size of communication channel between modules, minimizing the data that is transferred between the different modules invloved. Thus this promote loose coupling between the modules of a system |
How to Fix Violations | By using the Adapter Design Principle, basically breaking down interfaces along the lines of responsibilities and apply the SRP principle. | Use of block strucuture instead of global variables largely reduces stress on unintended data manipulations between differnent modules. |
Benefits of Use | Better structured code that lends itself more freely to the benefits of using Object Oriented Programming. With the disappearance of fat clients and the use of the Apdapter pattern, code is more flexible to extensibility. | Conforming to this rule along with others listed in the section above results in the architecting truly modular code, exhibiting the different features of true modularity as defined by Meyer |
Conclusion
The principle of small interfaces and principle of interface separation subtly differ from each other in that one deals with the size of the interface and the other deals with the size of the communication channels between the interfaces. Therefore these are used in different abstraction levels. One would benefit by using the SOLID principles to design better structured OO software. Using the rules of modularity one would develop software that lends itself to better architect-ed software solutions.
Appendix
- Adapter pattern: is a Design Pattern that translates an interface for a class into a compatible interface. It's main goal is decoupling of classes so as to make clients less dependent upon interfaces they do not use, which causes them to conform to the Interface Segregation Pattern.
- Object Oriented Design Patterns are design patterns used in languages such as Java and C++ to better exploit the advantages of object Oriented Design and associated principles and solve common problems associated with the same
- Object Oriented Software Construction, Second Edition, Bertrand Mayer
- http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod
- http://www.davesquared.net/2009/01/introduction-to-solid-principles-of-oo.html
- http://www.oodesign.com/design-principles.html
- http://wikipedia.org