S.O.L.I.D – The Principles of Object Oriented Design




Abstract

In this post, and in the following 6 posts (described later on), I'd like to write a bit about The Principles of Object Oriented Design, also known as SOLID.

This is one of my favorite topics in software engineering as I'm a great believer in well-designed applications, and understand the importance of investing a proper amount of time in the design phase prior to implementing the solution.

As a young software engineer, I blindly followed the historical determination that prior to every implementation we need to perform relevant research and to create a proper design.

I followed this directive diligently, with the aim of optimizing & enhancing the development process; however, I didn't fully understand the true meaning of this action.

Almost 10 years ago, in my quest to learn software designs, I encountered a very important article by Robert Cecil Martin (a.k.a Uncle Bob) - The Principles of Object Oriented Design which revealed the beauty & science of software design.

I was definitely enriched by this article which, of course, contributed to my development skills, and I'm very proud to say I'm practicing ever since.

Every couple of years I read some of the material I gathered over the years just to remind myself how to correctly write robust & clean solutions.

In this article, I'd like to describe these design principles and provide examples that illustrate the importance of the SOLID principles to software application.

We’ll emphasize how, by maintaining the SOLID principles in our code, we’ll create better robust solutions, easier code maintenance, faster bug fixing, the overall impact on the application performance, and especially while adding new features to existing design, as the application evolves with new requirements.




Content

            1.     Introduction
-        Benefits of good design

            2.     Software Design Smells
1.     Rigidity
2.     Fragility
3.     Immobility
4.     Viscosity
5.     Needless Complexity
6.     Needless Repetition
7.     Opacity

            3.     S.O.L.I.D
1.     The Single Responsibility Principle
2.     The Open-Close Principle
3.     The Liskov Substitution Principle
4.     The Interface Segregation Principle
5.     The Dependency Inversion Principle

            4.     Summary




Introduction


Benefits of good design

There are many advantages of a design that conforms to the SOLID principles, which effects on the Maintainability, Testability and Scalability of our product.


A good design in our code-base provides:

-        Implementation: A shorter time while implementing new features – since we could extend existing features and not modify good working old code.

-        Debugging: The debugging process is much easier and cleaner – we don’t need to read many lines of code just to understand what a particular method performs.

-        Bugs: Reduce the number of bugs – since we are focusing on the new feature and not trying to understand old complex legacy code.

-        Regression issues: Prevent regression issues – especially these magical bugs that appear only on production. (exceptions no one tested nor predicted)


Developing applications while maintaining the SOILD principles would provide all of the above and more.
The S.O.L.I.D design principles are well-used when they are applied together and across the entire codebase.

In addition, using the SOILD principles also helps to prevent Software Design Smells.




Software Design Smells

Software Design Smells are symptoms of bad design and violation of software patterns and object-oriented design principles that our codebase would experience, if we’ll not take measures to prevent them.


There are 7 well known 'Design Smells' that could have negative effects on our solution codebase, in short:

           1.      Rigidity - The software is difficult to changes. (every change impact depended modules)
           2.      Fragility - The software breaks in many places when a single change is made.
           3.      Immobility - Components can't be reused.
           4.      Viscosity
1.      Software Viscosity - Preserving the existing complicated design, or Hacking it.
2.      Environment Viscosity - The development environment is very slow and inefficient.
           5.      Needless Complexity - Over Engineering & Over Design.
           6.      Needless Repetition - Duplicate code that could be avoided by abstraction.
           7.      Opacity - Writing modules that are not clear and hard to understand.

For additional detailed description, please review the Software Design Smells article I posted.




S.O.L.I.D

For this topic, I’ve written a series of 7 articles describing the SOLID principles and the software design smells, their negative impact on our codebase, and how to prevent them.

Intro:
          2.      Software Design Smells

S.O.L.I.D
          3.      The Single Responsibility Principle (SRP)
          4.      The Open-Close Principle (OCP)
          5.      The Liskov Substitution Principle (LSP)
          6.      The Interface Segregation Principle (ISP)
          7.      The Dependency Inversion Principle (DIP)




The Single Responsibility Principle
The single responsibility principle states that:
A class should have only one responsibility and only one reason to change.
This means that when we are writing a class its members and behavior should represent only one responsibility, otherwise, we could experience undesired coupling between the class different responsibilities.
As young developers…




The Open-Close Principle
The open-closed principle states that:
Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.
This statement looks as a contradiction, meaning how could any software entity be open for extension and, at the same time, be closed for modification.
How could we extend our code without modifying it?
Well, the answer is by using abstraction…!




The Liskov Substitution Principle
The Liskov substitution principle states that:
Subtypes must be substitutable for their base types.
This means that base types could be replaced by their corresponding derived types without manipulating or breaking the code.
Simply put, we could use the base type in our code to invoke all its corresponding derived types.
Seemingly, this determination seems very implicit and simple to accomplish…




The Interface Segregation Principle
The interface segregation principle states that:
Clients should not be forced to depend on methods they do not use.
When we are designing interfaces that other classes could implement, sometimes with the aim to adhere to generic behavior, we add needles methods, properties etc., that are not needed by all clients of that interface.
In other words, the natural tendency is…




The Dependency Inversion Principle
The dependency inversion principle states that:
High-level modules should not depend on low-level modules. Both should depend on abstractions.
Abstractions should not depend upon details. Details should depend upon
abstractions.
When we design software applications, most often we use a ‘Layering Techniques’, in which…






Summary

Whenever I was discussing code design with my friends and colleagues, describing the importance of extensible code, one of my close friends used to joke and ask me: "If a lion was to enter our room, what would the code do?"

I immediately used to tell him that in order to maintain a robust solution and to support scalability & maintainability, we should also consider such an extreme case.

However, the truth of the matter is that we should also consider such potential low risks in a common-sense manner, and not support "every lion" that enters our room.

This notion is actually a 'Key Design Principle' which states that a good architectural behavior would be to minimize upfront design (a.k.a YAGNI - You ain’t gonna need it), meaning we should only design what is necessary and avoid over-design, especially when the requirements are not fully crystallized.

So to sum up, I'll state that I truly believe in well-designed applications and we should practice the SOLID principles all together while integrating with other design concepts (such as: DRY, LoD, Rule of Three, CQRS, Composite Reuse Principle etc.) and obviously the GoF Design Patterns, but we should always consider common-sense and not forget to:

Design & Develop Clean Robust Solutions…, Maintain Deadlines…, Strive for Zero Bugs…, and (most importantly) Enjoy the Process…! 





The End

Hope you enjoyed!
Appreciate your comments…

Yonatan Fedaeli

No comments: