How to apply design principles in practice?
Ganesh Samarthyam, Tushar Sharma, Girish Suryanarayana
HOW TO APPLY DESIGN PRINCIPLES IN PRACTICE? WWW.DESIGNSMELLS.COM
How to apply design principles in practice?
"The critical design tool for software development is a mind well educated in design principles" -‐ Craig Larman
It is well known and widely accepted that applying design principles is essential to developing high-quality software. Booch’s object model mentions four fundamental principles viz. Abstraction, Encapsulation, Modularization, and Hierarchy for creating quality object oriented designs [2]. Table I lists these principles with their descriptions from our earlier work [1].
Conceptually, fundamental principles such as abstraction and modularization are quite generic, high-level, and seem easy to understand; however, our experience in creating designs for real-world projects shows that they are difficult to apply in practice for design problems we face on a day-to-day basis as designers! For example, consider abstraction – it is easy to say “simplify entities through reduction and generalization”; but it is difficult to understand and apply the specific techniques that are required to be followed to realize the conceptual understanding in practice?
HOW TO APPLY DESIGN PRINCIPLES IN PRACTICE? WWW.DESIGNSMELLS.COM
One solution we found is to use “enabling techniques” for applying each of these fundamental design principles. For instance, a few specific techniques that we can employ to apply modularization principle are to:
a) Localize related data and methods together in a class b) Break-down or decompose classes into manageable size (i.e., neither too small nor
too large) c) Create acyclic dependencies between classesd) Limit dependencies by reducing the number of incoming dependencies (i.e., fan-
in) and outgoing dependencies (i.e., fan out).
Figure I: Fundamental design principles and the enabling techniques
Figure I lists the enabling techniques we have created for Booch’s four fundamental design principles. favored since the product is always market-ready and refactoring can consistently improve the quality to sustain the product for a longer period.
Of course, it may be sometimes difficult to understand how to apply these “enabling techniques” themselves! For example, one of the enabling techniques for encapsulation is to “hide variations”. How do we “hide variations”? It is quite general and not really straight forward to understand. It requires deeper understanding and experience to notice specific actions to apply the enabling technique. Some of the guidelines that can be employed in the case of “hide variations” enabling technique are:
(a) separate algorithm from the clients that use it
HOW TO APPLY DESIGN PRINCIPLES IN PRACTICE? WWW.DESIGNSMELLS.COM
(b) separate abstraction from its implementation so that the two can vary independently
(c) separate policy from the implementation Let us consider the first guideline (separate algorithm from the clients that use it)
with the help of a detailed example to understand how encapsulation can be applied in practice by “hiding variations” enabling technique.
Separating algorithm from the clients that use it Consider the design of a cloud based application. In such applications, security is an
important consideration and often encryption is used for securing the information stored in the cloud. Assume a class named Encryption that uses DES (Data Encryption Standard) algorithm by default in its public Encrypt() method, as shown in Figure II.
Figure II: Initial design that requires support only for DES algorithm in Encryption class
Now, due to changes in requirements (for instance, introducing a more secure algorithm for encryption), the class needs to support another algorithm viz. AES (Advanced Encryption Standard). The Encrypt class now has two public methods named EncryptUsingDES() and EncryptUsingAES(). It may be the case that it is required to support yet another algorithm viz. TDES (Triple Data Encryption Standard) in some cases by the Encryption class. Figure III shows the resultant design with methods such as EncryptUsingDES(), EncryptUsingAES(), EncryptUsingTDES(), etc.
Is this a good design? Is it possible to improve (i.e., refactor) this design such that:• A specific algorithm (such as DES, AES, or TDES) can be “plugged” at runtime?
HOW TO APPLY DESIGN PRINCIPLES IN PRACTICE? WWW.DESIGNSMELLS.COM
• Reuse these algorithms in new contexts? • Easily add support for new algorithms in Encryption class?
Figure III: The Encryption class becomes “smelly”
There are many solutions for this problem, but here is a solution that isolates algorithms as a separate hierarchy (see Figure IV). With this solution, the Encryption class encapsulates the variation in the algorithm in the form of a hierarchy. The hierarchy rooted in EncryptionAlgorithm (which could be an interface or an abstract class) implements specific algorithms such as DESEncryptionAlgorithm, AESEncryptionAlgorithm etc as derived classes.
With this solution: • A specific DES, AES, TDES, or any other algorithm can be “plugged” at runtime.
How? From the constructor of the Encryption class or from a suitable method in Encryption class, the object “algo” can be made to point to the required derived object of EncryptionAlgorithm type. By employing runtime polymorphism, a new algorithm can be plugged at runtime.
• We can reuse these algorithms in different contexts. Since EncryptionAlgorithm hierarchy is a separate hierarchy which concerns providing specific encryption algorithms as a service to the clients of this hierarchy, it can be easily reused in other contexts within the same application or other applications.
HOW TO APPLY DESIGN PRINCIPLES IN PRACTICE? WWW.DESIGNSMELLS.COM
• We can easily add support for new algorithms in Encryption class. We can add new algorithm, such as support for TDES, as a new derived class of EncryptionAlgorithm type and the Encryption class (because it holds reference to a EncryptionAlgorithm object) can now use the new algorithm.
Figure IV: Separating encryption algorithms from its clients using Strategy pattern
Did you identify this solution structure? Yes, it is the “Strategy pattern” which “decouples an abstraction from its implementation so that the two can very independently” [3].
An important note: This example illustrates the application of design patterns for applying the principle of encapsulation. However, applying principles might not result in a design that employs patterns.
Coming back to our discussion on applying the principle of encapsulation, this example illustrates how the enabling technique of “hide variations” can be applied in practice.
In addition, this example is also an illustration of Open Closed Principle (OCP) [4]: “Software entities should be open for extension, but closed for modification”. What does it mean? It means that an entity such as a class, component, or a module must support extending the behavior without need to modify the source code within that entity. Consider Figure III: Adding support for new encryption algorithms requires changing the entity (i.e., it is NOT open for extension) and hence violates OCP. In contrast, consider the design in Figure IV: Adding support for new encryption algorithms does not require changing the entity (i.e., it is open for extension) and hence follows OCP.
HOW TO APPLY DESIGN PRINCIPLES IN PRACTICE? WWW.DESIGNSMELLS.COM
To summarize: Since high-level principles such as abstraction, encapsulation, modularization and hierarchy are quite generic, it is usually difficult to understand how to apply them in practice. To solve this problem, we can break-down the fundamental principles to more granular “enabling techniques” [1]. Enabling techniques not only help us to understand the fundamental principles to a greater depth but also ease the task of applying the principle in real-world situations.
References: [1] “Refactoring for Software Design Smells: Managing Technical Debt”, Girish
Suryanarayana, Ganesh Samarthyam, Tushar Sharma, ISBN - 978-0128013977, Morgan Kaufmann/Elsevier, 2014. URL: http://amzn.com/0128013974
[2] “Object-Oriented Analysis and Design with Applications”, Grady Booch, Robert Maksimchuk, Michael Engle, Bobbi Young, Jim Conallen, and Kelli Houston, Third Edition, Addison-Wesley Professional, 2007.
[3] “Design Patterns: Elements of Reusable Object-Oriented Software”, Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, Addison-Wesley, 1995.
[4] “Object-Oriented Software Construction”, Bertrand Meyer, Prentice Hall, 1988.
About the Authors: Ganesh Samarthyam ([email protected]) is an Independent Consultant and Corporate Trainer based in Bangalore.
Tushar Sharma ([email protected]) is a Technical Expert at Research and Technology Centre, Siemens Technologies and Services Pvt. Ltd., Bangalore.
Girish Suryanarayana ([email protected]) is a Senior Research Scientist at Research and Technology Centre, Siemens Technologies and Services Pvt. Ltd., Bangalore.
HOW TO APPLY DESIGN PRINCIPLES IN PRACTICE? WWW.DESIGNSMELLS.COM