What are the SOLID principles?

What are the SOLID principles?

Learn the SOLID principles of programming in simple steps

Developed by renowned software programmer Robert C Martin, SOLID is an acronym for 5 industry-standard object-orientated design principles.

Why use SOLID Principles in your design?

Using these principles leads to more maintainable, extensible code, that can be refactored more easily and facilitates Agile software development. Using SOLID principles the programmer can avoid "Code Smells" that may not have been picked up.

So what does the SOLID acronym stand for:

  • S - Single Responsibility Principle

  • O - Open-closed Principle

  • L - Liskov Substitution Principle

  • I - Interface Segregation Principle

  • D - Dependency Inversion Principle

In today's article, we will go through these principles and discuss them in more detail. Hopefully, together we can better our understanding of the SOLID principles and how to use them to make us better developers.

SOLID Principles key aspects

Single-Responsibility Principle (SRP)

The Single-Responsibility principle states that each class should only have one job. Practically, this means a class should only have one reason to change.

Each class should only contain properties and methods related to that class. For example, if you have a class named DataAccess then the items in that class should only be about DataAccess. In other words, your DataAccess class should only contain items related to data access and not logging or reading files for example.

Names of classes should also be simple and clear so that it is easy to understand at a glance what the class is used for.

Open Closed Principle

The open-closed principle suggests that entities such as classes, modules, and functions should only be open for extension, not modification.

What does that mean?

In simple terms, it means that you should be able to add more functionality to code, without changing existing code. This means changing code in one of your classes would not require a change in dependent classes.

You could do this with inheritance, however, there is a risk here that you might introduce tight coupling in your code if the child classes rely on the implementation details from the parent class.

Instead, polymorphism could be used. This uses interfaces instead of parent classes, removing the details of the implementation that a parent class would provide. For more detail on the difference between inheritance and polymorphism read our article on object-orientated programming.

This means that classes and interfaces are loosely coupled. The implementation of interfaces is independent and doesn't rely on each other.

When creating your interfaces you would only include critical parts of your class. This allows the interface to be flexible and extensible.

Liskov Substitution Principle

The Liskov Substitution Principle is the third of the SOLID principles. It states that objects of parent classes are replaceable by objects of subclasses without breaking the application. This means that subclasses must behave the same way a parent class would.

For example, if you override a method in a subclass, this needs to accept the same parameter values a parent class would. You can be less restrictive in your parameter specifications, e.g. use a long instead of an int, ensuring the parent class and the subclass work.

You cannot, however, be more restrictive in subclass parameters as that would mean the parameters might not work on the parent class.

The issue with this is that there is no way the compiler will be able to enforce a specific behaviour of your code. A compiler would only check if the structure is correct. Your checks and tests will need to be put in place.

Interface Segregation Principle

Robert C. Martin defined the Interface Segregation Principle as follows:

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

Robert C. Martin

The goal is to reduce or eliminate the number of changes needed in your code.

Similar to the Single Responsibility Principle mentioned earlier, this principle suggests that you should not add any methods to existing interfaces if it does not match the responsibility of the interface. Doing this results in a "bloated interface", where the interface has several responsibilities.

If you add methods to interfaces that aren't needed by all the classes that implement those interfaces then you have to write extra code to override those methods. It would be better if a new interface was created.

Dependency Inversion Principle

The Dependency Inversion Principle suggests that High-level modules should not depend on low-level modules. Using abstractions helps us as developers to implement this principle.

If you've already implemented other parts of the SOLID principle, you may have already implemented the Dependency Inversion Principle. Namely, the Open/Closed Principle and the Liskov Substitution Principle.

By implementing these two principles your classes should already be using interfaces for abstraction between high-level and low-level classes. They are also open for extension but closed for modification. The only final thing to do is potentially use dependency injection to avoid compile-time dependency.

Doing this should enable you to modify high-level and low-level classes without affecting others.

Conclusion on the SOLID principles

The SOLID design principles help you as a developer to write code that is robust, maintainable and easily extensible. By following these principles your application will be much more maintainable. What are your thoughts on using the SOLID principles?

Did you find this article valuable?

Support Simplifying Code by becoming a sponsor. Any amount is appreciated!