SOLID is an acronym for the first five object-oriented design (OOD) principles and is a series of guidelines that developers can use to build software in an easy way to maintain and extend. Understanding these concepts will make you a better developer and enable you to avoid code smells.

SOLID stands for:

  • S: Single-responsibility principle
  • O: Open-closed principle
  • L: Liskov substitution principle
  • I: Interface segregation principle
  • D: Dependency Inversion Principle

Let’s dive in deeper those principles!

Single-responsibility Principle

A class should have one and only one reason to change, meaning that a class should have only one job.

It means that if our class assumes more than one responsibility we will have a high coupling. The cause is that our code will be fragile at any changes.

Suppose we have a User class like the following:

In this case, the method store is out of the scope and this responsibility should belong to a class that manages the database. The solution here is to create two classes each with proper responsibilities.

Open-closed Principle

Objects or entities should be open for extension but closed for modification.

According to this principle, a software entity must be easily extensible with new features without having to modify its existing code in use.

Suppose we have to calculate the total area of some objects and to do that we need an AreaCalculator class that does only a sum of each shape area. The issue here is that each shape has a different method to calculate its own area.

If we add another shape like a Circle we have to change the AreaCalculator in order to calculate the new shape area and this is not sustainable. The solution here is to create a simple Shape interface that has the area method and will be implemented by all other shapes. In this way, we will use only one method to calculate the sum and if we need to add a new shape it will just implement the Shape interface.

Liskov Substitution Principle

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.

The principle says that objects must be replaceable by instances of their subtypes without altering the correct functioning of our system.

Imagine managing two types of coffee machine. According to the user plan, we will use a basic or a premium coffee machine, the only difference is that the premium machine makes a good vanilla coffee plus than the basic machine. The main program behavior must be the same for both machines.

Interface Segregation Principle

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.

This principle defines that a class should never implement an interface that does not go to use. In that case, means that in our implementations we will have methods that don’t need. The solution is to develop specific interfaces instead of general-purpose interfaces.

Imagine we invent the FutureCar that can both fly and drive…

The main issue, as you can see, is that the Car and Airplane have methods that don’t use. The solution is to split the VehicleInterface into two more specific interfaces that are used only when it’s necessary, like the following:

Dependency Inversion Principle

Entities must depend on abstractions not on concretions. It states that the high level module must not depend on the low level module, but they should depend on abstractions.

This principle means that a particular class should not depend directly on another class but on an abstraction of this class. This principle allows for decoupling and more code reusability.

Let’s get the first example of the UserDB class. This class could depend on a DB connection:

In this case, the UserDB class depends directly from the MySQL database. That means that if we would change the database engine in use we need to rewrite this class and violate the Open-Close Principle.

The solution is to develop an abstraction of database connection:

These principles represent the state of the art of the code quality and following them permit you to write software that will be easily extended, reusable and refactored.

I hope this article helps you to better understand what code quality is and maybe to improve your coding ability! Happy coding! 😄