The goal of every software developer is to be among the elite in his field, and this will only be done by hard work such as learning new technologies. Or reading some books and most importantly of all, how to write an integrated code with good performance that can be read, modified and tested, which makes you satisfied with the code that you wrote and happy with your achievement. In return, writing a random code will make its modification or test like hell, and since I love to see you Glad let’s chat about SOLID Software Design Principles.
Before we start, keep these things in mind:
- You must be familiar with the concepts of OOP in Java to understand the article.
- The codes are taken from various sources mentioned in the last paragraph.
- Four examples have to do with area computing in mathematics because they illustrate these concepts well.
- Finally, don’t take the aforementioned jokes seriously, however silly they are.
What is SOLID?
You may have heard of the book Clean code, or its writer uncle bob (Uncle Bob), if you haven’t heard of it then there is no problem, but it would be nice to look at this book that will lead you to write a code worth calling code instead of writing lines of scrap.Our friend or Uncle Bob collected 5 principles of software design and happened to take the first letter of each principle that gives us the name SOLID.
- Single responsibility principle.
- Open-closed principle
- Liskov substitution principle
- Interface segregation principle
- Dependency Inversion Principle
And if you are wondering about the benefit of it, it is writing good and clean code, and the goal of this article is to introduce you to the benefit of SOLID principles.
Easy to understand code
Not every programming code that the computer understands, the programmer in turn must understand it, but you yourself may not know its meaning and purpose until a month after writing it, you may need a spiritual medium to help you understand it , then you may want to write the code again in order to improve it or Developing it or just in order to make it more logical, and this certainly will be a little painful due to your lack of understanding of the previous code steps, and for this, these principles will facilitate your life.
Easy to modify code
Logically, the code that is easy to understand in most cases should be easy to modify also because, as we mentioned earlier, the code that you cannot understand you cannot modify it. You do not need to worry too much about making the code modifiable, all there is to it is to follow a set of rules, including SOLID DP, among the main goals of SOLID is to provide the ability to create a programmable code that can be modified at any time.
Code easy to test
The period will come later when you will have to test your code if it is running within its framework without affecting another code, whether in the development or modification stage, this is done through a set of Unit Tests that are applied to the code to find out the result, either it is a valid result And understandable, and either a bad result really confirms to you that the code that you wrote is junk that should not be touched or modified, which is the first rule in programming for beginners.
Principle No. 1: The principle of single responsibility
This principle from its simplicity seems complicated and I will explain to you why: This principle states that every part of the code should have one task to do, but we cannot just execute the command that easily, there are side spoilers that we have to consider: The Dilemma:For example, suppose you have a function called SaveAndPrint () where this function saves the invoice in the database and prints it to the customer, and it works well after trying it in a restaurant, but it is against the SRP principle, short for Single Responsibility Principle, meaning that the function performs two tasks At the same time, it is more correct to separate the Save and Print functions. Questioning: How do you know this one responsibility? I mean, think carefully, it is difficult to know if this code really does one responsibility, the answer is simply according to Uncle Bob is that the function or class has one reason to change, and if you insist on a more understanding of the subject, I recommend this video from Uncle Bob , and if not You have time to watch the video, the matter is simply that the class or function is in its stable state, then it must be moved (Triggered) for one reason only, by going back to the SaveAndPrint () function, we will find that this function moves for two reasons, the first is Save and the second is Print, either if we separate them Then, the Save () function will change its state only if you want to save, and the case is no different to the Print () function. – Example : To understand the matter better programmatically, let us assume that we have two clusters, each one representing a circle and a square geometric shape, the first carrying the radius of the circle and the second carrying the length of the square.
I will create another class called AreaCalculator and its task is to calculate and print the sum of the areas of an array of the aforementioned geometric shapes.
This is a multiplication of the SRP principle of wall width, this poor class performs two tasks and that makes it difficult to modify the code later, but what is bad is assuming, dear reader, that you want to add multiple outputs so that the user can extract the sum of spaces in several types of Json, HTML or PlainText.Instead of the previous solution, we can create another class named SumCalculatorOutputter that performs this task and it is possible to do several methods that differ according to each case.The result will be as follows:
In order not to complicate matters for you, just remember that any class or Function that you program must have one task or one state in which it is activated, in order to facilitate the process of adjusting it later if required and keeping the matter very simple.
Principle No. 2: Open / Close:
This is the English definition:Objects or entities should be open for extension, but closed for modification.The summary of this definition is that the objects must be extendable, but without the need to modify the class content. In other words, the class must be flexible and capable of adding any new content without the need to modify any other pre-existing content. In the previous code, we did not create the sum function, so let’s add it in the class:
This function calculates the sum of the area of the shapes inside the array. Since the method for calculating the area of a circle is different from the square, we need if / else. Where it checks the type of geometric shape if it is a square or a circle, then we cast a cast and calculate the values.But what if we wanted in the second version to add a new shape, which is a rectangle, of course, you will need to add another if / else in the AreaCalculator class. This contradicts the second principle of OCP.An alternative is to add an area () function to an interface so that Shape is responsible for calculating its area itself.
Then we will need to call the area function, regardless of the geometry:
Now, no matter what you add from the open for extension engineering shapes, the class will not need to modify the closed for modification.You notice that by using these principles, the command facilitates reading the code and makes it easy to modify at the same time, and of course it is flexible, as mentioned previously.
Principle Three: Liskov Substitution:
Or the Liskov substitution principle LSP. It is also called after a person called Leskov (who does not matter) and the principle states the following:Let q (x) be a property provable about objects of x of type T. Then q (y) should be provable for objects y of type S where S is a subtype of T.This principle is one of the most difficult principles to explain, as it is difficult to explain, but once you see many examples, you may understand it at the time, and for this I advise not to be satisfied with this article only, but to develop yourself more and research and delve into the whole SOLID principle. Let’s give a simpler definition of this principle:If S is a subordinate of T. The T-objects should be replaced by S-objects without something unwanted happening in the programSuppose your father is a football player, this means wherever we put him, he should be able to play the ball, and since you are a branch of it, you should be able to play the ball also, this of course from the point of view of the heir in programming. We can say that the same is true for this principle.Let us take an example of that, in mathematics, each square is a triangle and vice versa, so we will create a class Rectangle and inherit from it another class we call Square
Since the length must equal the width in the square, we will change both variables whether the length or the width are placed:
Therefore, the behavior of this class will be as follows:
As we can see, the square does not behave as a rectangle simply because the square will remain a square even if we do CastUp, so this should not be the solution, but rather it must inherit from the Shape class instead.
Then both Square and Rectangle inherit from this class, thus avoiding that the user of your code will not obtain undesirable behavior.
Fourth principle: Interface segregation
Well this is a nice and simple principle that states that you should never force an object to take a function it will never use: A client should never be forced to implement an interface that it doesn’t use or clients shouldn’t be forced to depend on methods they do not use.As usual, these definitions may always remain vague until we explore them and analyze them better through a few examples, and we will deal with geometric shapes again, it is the simplest trick now to understand the SOLID principle well:
Ok, geometric shapes, omal, why am I a geometric shapes worker, and I make geometric shapes that are Leah? And you are thinking, when you speak falsehood, will you fear me, or what? Chief Marshal if he was a programmer
Let us consider political jokes and suppose that we want to calculate the size and area for each geometric figure, and for this, dear programmer, you will suggest the following solution:
But the square is a two-dimensional shape whose size cannot be calculated, but its area can only be calculated, so I consider it a piece of scrap (but I am the one who suggested it ^ _ ^ Pass it, my friend, do not blame me). This is why Uncle Bob says that since the square will not need either today or tomorrow, the volume function, we will need to divide this interface.
The square will not have a volume function that will not be needed in any case. Have you begun to understand the usefulness of these principles? If you do not understand, here is a more simple explanation, in general, no class is obligated to anything that it will not use, there is no need to add functions (even if it is logical) to any class we know well that it only reserves a few lines of code, and we took the example of the box that We know that it is realistic in three-dimensional life that we can calculate its volume, but programmatically with a two-dimensional object, we do not need to calculate its volume and we do not need a function to do that because we will not use it from its basis, it is the Interface Segregation!
Fifth principle: Dependency Inversion principle
For me, this principle is my favorite and requires talking about it an article of its own, but there is no problem that we can explain in a simple way in this article, the principle states the following:the high level module must not depend on the low level module, but they should depend on abstractions.Well since the previous examples are based on geometric shapes, let’s change the rules a little bit in this example. The definition says that organisms should rely on abstraction rather than on one another. We will create a car class, and let’s say the car has an engine and wheels. You will suggest writing this code in order to create this class, and frankly, I cannot bear to see this code. Because the extent of the pain that it may cause you is tremendous, especially if your project is a project, I do not say huge but rather big.
According to this principle, it is best to do it better. As the Car class does not care about the type of engine, wheels, etc., simply what this class says:
Don’t teach me how to build the engine and wheels. Give me an engine and wheels of whatever type, and I will give you a ready car. – Car class
Because if you teach him how to simply create an engine and wheels, then every time he will create the same engine and the same wheels, and you will not be able to change that.
I tried very hard not to bring anything from Casey in order to avoid any errors or problems in understanding, and I tried to take an example from dedicated sites and only explain and explain it to you in this article. That is why I would be happy to discuss any error or suggestion with you in the comments.