SOLID Principles with Ruby
In this article we will learn about the SOLID principles and how to use them in Ruby 💎.
SOLID Principles are concepts in object-oriented design that are relevant to software development. Single Responsibility Principle, Open-Closed Principle, Liskov Substitution Principle, Interface Segregation Principle, and Dependency Inversion Principle are all acronyms for SOLID.
Single responsibility principle (SRP)
A class should have one, and only one reason to change — Robert C. Martin
Every class should have a single task to complete. To be more specific, there should only be one reason to switch classes. Here’s an example of a Ruby class that violates the principle of single responsibility (SRP):
However, this code violates the single responsibility principle; in order to avoid breaking things, we must separate these logics into separate classes:
This method aids in the decoupling of responsibilities and ensures predictable change. We can change the print functionality without changing the paint function if we only need to change the print functionality. It also aids in the prediction of any changes in functionality.
Open-closed principle
the most important principle of object-oriented design — Robert C. Martin
Software entities (e.g., classes, modules, functions) should be open for an extension, but closed for modification.
It instructs you to write your code in such a way that you can add new functionality without changing the existing code. As shown in the preceding example, we have print functionality, but it is very generic; what if we want to print an A4 sheet of paper?
We can change the same class and method, but this is a bad pattern because it violates the open/closed principle. We risk making unintended changes by modifying the class. When something is changed or added, it may cause unknown problems in the existing code.
We can extend the functionality to add functionality while avoiding changing the entity. So, let us make a class for each of these. We can extend the functionality to add functionality while avoiding changing the entity. So, for each of these, let us create a separate class:
Liskov substitution principle (LSP)
The Liskov Substitution Principle (LSP) applies to inheritance hierarchies such that derived classes must be completely substitutable for their base classes.
To comprehend this principle, we must first comprehend the problem. We designed the software to be extensible in accordance with the open/closed principle. We developed a subclass printer
that performs a specific function. The class being called is unknown to the caller. These classes must behave identically so that the caller cannot tell the difference. By behavior, we mean that the class's methods should be consistent. These classes' methods should have the following characteristics:
- Take the same number of arguments and data types.
- The same data type should be returned.
- share the same surname
Assume we have a Comic painter and a Landscape painter, and we want to demonstrate the paint functionality:
First of all, let’s define our Base class.
Now that we have our base class, let’s create the comic and the landscape painters:
The paint method must be present in any subclass that inherits the base class. If it is not present, an error will be generated indicating that the method must be implemented. We can ensure that the subclass is consistent this way. The caller can always be certain that the paint
method is present.
This principle helps substitute any subclass easily without breaking things and without the need to make a lot of changes.
Interface segregation principle (ISP)
Clients should not be forced to depend upon interfaces that they don’t use. — Robert C. Martin
The Interface Segregation Principle (ISP) clients should not be forced to rely on interface members they do not use In other words, don’t force any client to implement an interface that isn’t relevant to them; ISP is only applicable to static languages, and Ruby is a dynamic language with no concept of interfaces. Interfaces define the rules for class abstraction (Contracts).
Although Ruby does not have interfaces, we can use the class and subclass concepts to create something similar.
The subclass LandscapePainter
was inherited from the general class Artist
in the example used for the Liskov substitution principle. However, Artist
is a very generic class that may contain additional methods. If we need another functionality, such as Sketch
, it must be a subclass of Painter
. The Sketch
does not have to have a paint
method, but it will be dependent on it. So, rather than a generic class, we can create a specific class for this:
Dependency inversion principle (DIP)
The Dependency Inversion Principle (DIP) states that we should depend on abstractions (interfaces and abstract classes) instead of concrete implementations (classes). The abstractions should not depend on details; instead, the details should depend on abstractions.
Any class with a single responsibility requires items from other classes in order to function. To paint the next monolisa, we need to get the information from the database and paint to a file. We are attempting to have only one job for each class using the single responsibility principle. However, reading from the database and writing to a file must be done within the same class.
It is critical to eliminate these dependencies and decouple the primary business logic. This allows the code to be more fluid during changes, and changes become more predictable. The dependency must be inverted, and the module’s caller must have control over the dependency.
Let’s look at an example to see what I mean:
By doing so, we decoupled the classes and removed any hardcoded values.
Summary
SOLID design helps to decouple code and make modification easier. Building programs that are decoupled, reusable, and change-responsive is crucial. All five SOLID principles should coexist since they compliment one another. A well-designed codebase is adaptable, simple to modify, and pleasurable to work with. Any new developer may get right in and grasp the code.
I hope you found the article interesting ❤️!