8

How To Use The SOLID Principles In Your Code

 2 years ago
source link: https://www.cleanthecode.com/2021/07/06/how-to-use-the-solid-principles-in-your-code/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Writing solid code, requires SOLID principles. We all had to learn to program at some point. And let’s be honest. We were STUPID. And so was our code. Thank god, we have SOLID.

Solid Principles

So, how do you write SOLID code? That’s actually easy. You just have to follow these five rules:

Don’t worry! These principles are a lot easier than they look!

Single Responsibility Principle

In his book, Robert C. Martin describes this principle as follows:

“A class should have only one reason to change”

Martin, Robert C. (2003). Agile Software Development, Principles, Patterns, and Practices

Let’s look at two examples together.

What NOT to do

We have a class named User that allows the user to do the following things:

  • Register an account
  • Log in
  • Receive a notification when he logs in for the first time

Now, this class has multiple responsibilities. If the registration process changes, the User class will change. This will also happen if the login process or the notification process changes. That means that this class is overloaded. It has too many responsibilities.

The easiest way to fix this, is to move the responsibilities to their own classes, so the User class is only responsible for combining the classes. If the process then changes, you have one clear, distinct class to change.

What to do

Imagine a class that is supposed to show a notification to a first-time user, FirstUseNotification. This would consist of three functions:

  • Check if the notification has already been shown
  • Show the notification
  • Mark the notification as shown

Does this class have multiple reasons to change?

This class has one, clear functionality, namely showing a notification to a first-time user. That means the class has one reason to change. Namely, if that goal changes. So, this class does not violate the Single Responsibility Principle. Of course, there are multiple things that could change: the way you mark notifications as read could change, or the way you display the notification. However, since the purpose of the class is a clear and elementary one, that is okay.

Open-closed Principle

The open-closed principle was actually not first coined by Robert C. Martin, but by Bertrand Meyer:

“Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”

Meyer, Bertrand (1988). Object-Oriented Software Construction

This principle is actually very straight-forward. You should write your code so that you will be able to add new functionalities without changing the original code. This helps to prevent a situation where you have to change the classes that depend on your changed class.

The implementation of this principle is a lot harder, however. Meyer suggested to use inheritance to achieve this principle. However, this results in tight coupling, as we will discuss in the Interface Segregation Principle and the Dependency Inversion Principle.

Therefore, Martin came up with a better approach: use polymorphism. Instead of using regular inheritance, this approach makes use of abstract base classes. This way, inheritance specifications can be reused, whiles the implementation does not have to be.

The interface can be written once and then closed for changes. New functionalities then have to implement that interface and extend on it.

Liskov Substitution Principle

This principle was first introduced by a woman, Barbara Liskov. She was eventually rewarded a Turing Award for her contributions to the design of programming languages and software methodology.

In her paper, she defined the principle as follows:

Subtype Requirement: Let Φ(x) be a property provable about objects x of type T. Then Φ(y) should be true for objects y of type S where S is a subtype of T.

Liskov, Barbara; Wing, Jeannette (1994-11-01). “A behavioral notion of subtyping”. ACM Transactions on Programming Languages and Systems

Yeah. What she said. As you might have guessed, Liskov is a mathematician.

Let’s look at this principle as a programmer.

Imagine we have a Square. This could be derived from a Rectangle, which sounds logical, since a square is a specialized form of a rectangle. This is where the Liskov Substitution Principle comes in.

Everywhere you expect a Rectangle in your code, Square should also be possible. Now imagine your Rectangle has the method SetWidth and SetHeight. That means that Square also needs these methods. Sadly, this would not make any sense. This means that the Liskov Substitution Principle is violated here.

Interface Segregation Principle

As all other principles, the interface segregation principle is a lot easier than it sounds. This one was actually written down by Robert C. Martin himself, while working at Xerox.

“Clients should not be forced to depend upon interfaces that they do not use.”

Martin, Robert C. (2003). Agile Software Development, Principles, Patterns, and Practices

As with the Single Responsibility Principle, the goal is to reduce side effects and the amount of required changes.

Of course, no one writes code like this on purpose. However, this happens fairly easily.

Remember the Square from the previous principle? Now imagine that we decided to go through with our plan: we derive Square from Rectangle. Now we force Square to implement setWidth and setHeight, which probably do nothing. If they would, we would probably break things because the width and height would not be the size that was expected.

Luckily for us, this means that we no longer violate the Liskov Substitution Principle, since we now allow Square to be used everywhere we use Rectangle. However, this introduces a new problem: we now violate the Interface Segregation Principle. We force a derivative class to implement a functionality it prefers not to use.

Dependency Inversion Principle

The last principle is a simple one: high-level modules should be reusable, and they should not be affected by changes in the low-level modules.

A. High-level modules should not depend on low-level modules. Both should depend on abstractions (e.g., interfaces).

B. Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions.

Martin, Robert C. (2003). Agile Software Development, Principles, Patterns, and Practices

This is possible by implementing an abstraction that decouples high- and low-level modules.

The name of the principle applies that the direction of the dependency changes: this is not true. It only splits the dependency by introducing an abstraction between the two. In the end, you end up with two dependencies:

  • A high-level module, depending on the abstraction
  • A low-level module, depending on the same abstraction

This might sound hard, but actually happens automatically if you apply the Open-closed Principle and the Liskov Substitution Principle correctly.

Wrap up!

And that’s it! You’ve now seen the five basic principles that are the foundation for SOLID:

With these five principles, you should be able to make your code rock!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK