SOLID is one of the most important concepts in the world of Object Oriented Programming.
The importance of SOLID comes from the fact that it is practically impossible to write a “clean” code if you don’t know what distinguishes a “clean” code from a “dirty” one. Understanding of these five principles allows developers to analyze the code using standard models and terminology, and qualitatively assess code’s “cleanness”.
This post opens a series of posts about SOLID principles of Object Oriented Design.
One of the main goals of this series of posts is to show a real-life examples that demonstrate the importance of SOLID principles. In order to achieve this goal, we will be reviewing a real production code from Android Open Source Project (AOSP). Specifically, we are going to look at design and implementation of
Context class and its sub-classes.
Even though the examples come from Android world, this series of posts assumes no prior experience in Android development.
In late 90s, Robert “Uncle Bob” Martin formulated The First Five Principles of Object Oriented Design. The principles themselves had already been known, but Uncle Bob was the first one to state that these five are the most fundamental to class level design. [There are also fundamental principles for package level design, but they are not as famous as SOLID]
According to Wikipedia, it was Michael Feathers (the author of “Working Effectively with Legacy Code”) who “acronymized” these principles to SOLID.
There is no rigorous prove that SOLID principles work, but the accumulated experience shows that bad designs can be shown to violate part (or all) of these principles. Refactoring of such designs in accordance with SOLID principles leads to better designs. Even though “bad” and “better” have no metrics associated with them and are subjective judgements of experienced developers, such a strong correlation between subjective feeling of a “better design” and adherence to SOLID principles is indicative.
At this point, it is important to note that Uncle Bob himself clarified that SOLID are principles, not laws:
The SOLID principles are not rules. They are not laws. They are not perfect truths. They are statements on the order of “An apple a day keeps the doctor away.” This is a good principle, it is good advice, but it’s not a pure truth, nor is it a rule.
The principles are mental cubby-holes. They give a name to a concept so that you can talk and reason about that concept. They provide a place to hang the feelings we have about good and bad code. They attempt to categorize those feelings into concrete advice. In that sense, the principles are a kind of anodyne. Given some code or design that you feel bad about, you may be able to find a principle that explains that bad feeling and advises you about how to feel better.
These principles are heuristics. They are common-sense solutions to common problems. They are common-sense disciplines that can help you stay out of trouble. But like any heuristic, they are empirical in nature. They have been observed to work in many cases; but there is no proof that they always work, nor any proof that they should always be followed.Robert C. Martin
When first learned about SOLID, I myself treated these principles as laws and perfect truths. This misconception led me to write code that is too complicated and over-engineered for the tasks at hand. Therefore, it is also important to understand, that religiously following these principles will not automatically make your code clean.
SOLID principles are:
- Single Responsibility Principle (SRP)
- Open Closed Principle (OCP)
- Liskov Substitution Principle (LSP)
- Interface Segregation Principle (ISP)
- Dependency Inversion Principle (DIP)
Initially, I wanted to describe all SOLID principles in a single article. However, such an article would be way too long and difficult to read (even by the standards of this blog). Therefore, each principle will be given the honor it deserves by being described in a separate post. You can navigate to these posts by clicking on the links above.
Since SOLID is a general concept, I’m assuming that some readers won’t know much about Android development. Therefore, this section provides basic description of
Context. Android developers may skip this section.
Context class is the most fundamental concept in Android development. The class itself is abstract, but its sub-classes are corner stones of any Android application. The most important sub-classes of
Application class represents a single application. Android framework instantiates one
Application object for each launched application. This object will be “live” as long as the application is not terminated. Therefore, in the scope of a single application,
Application object can be treated as “singleton”.
Activity class represents a screen. In order to build Android application that has user interface,
Activity class should be extended with application specific logic that makes the screen usable. Android framework instantiates application’s sub-classes of
Activity when user navigates between screens.
Service class represents “background” task. It is used when application needs to perform tasks even when its user interface is not shown anymore (e.g. playing music even after the user “exited” the application). In order to define a background task,
Service class should be extended with task specific logic. Android framework instantiates application’s sub-classes of
Service when the task needs to be started.
Seasoned Android developers will notice that the above description is simplified. Indeed, there is much more that can be said about any of
Service. However, the intent here was not to teach Android development, but provide all readers with information that will allow them to understand the examples in the rest of this series of posts. The level of details in the above description is sufficient for that purpose.
This post introduced SOLID principles, provided short historical background and “cleared the ground” for the upcoming posts in the series that will discuss each of SOLID principles individually.