What are SOLID principles in programming?
SOLID principles are the set of software design principles used by software engineers in object-oriented software development to follow, scale and maintain a proper structure to the codes & programming. SOLID is a popular set of SOLID is an acronym that stands for five key design principles: single responsibility principle, open-closed principle, Liskov substitution principle, interface segregation principle, and dependency inversion principle.
The SOLID principles were developed by Robert C. Martin in a 2000 essay, “Design Principles and Design Patterns,” although the acronym was introduced later by Michael Feathers. As successful software changes, it becomes increasingly complex. Software becomes rigid, fragile, immobile, and viscous without good design principles. The SOLID principles were developed to combat these problematic design patterns.
What is the importance of SOLID principles?
These five principles help us understand the need for certain design patterns and software architecture in general. SOLID principles aim at reducing the dependencies of software engineers. As if they know and understand the basic architecture & design principles, it'll be easier for them to change or edit codes and alter a few changes if required.
Additionally, SOLID principles enable engineers to make designs easier to understand, maintain, and extend. Ultimately, using these design principles makes it easier for software engineers to avoid issues and to build adaptive, effective, and agile software.
What is Object-oriented programming (OOP)?
Object-oriented programming (OOP) is a modeling system and one of the classifications of programming languages built on the concept of "objects" which can contain data and code. Where "data" denotes fields, attributes, or properties and "code" is referred to as the methods or procedures.
Object-oriented programming is about modeling a system as a collection of objects, which each represent some particular aspect of the system. Objects contain both functions (or methods) and data. An object provides a public interface to other code that wants to use it, but it maintains its private internal state: which means that other parts of the system don't have to care about what is going on inside the object. Object-oriented programming is faster and easier to execute and provides a clear structure for the programs.
The SOLID Principles
S — Single Responsibility
O — Open-Closed
L — Liskov Substitution
I — Interface Segregation
D — Dependency Inversion
It states that a class should do one thing and therefore it should have only a single reason to change. If a Class has many responsibilities, it increases the possibility of bugs, because making changes to one of its responsibilities, could affect the other ones without you knowing. One potential change around database logic, logging logic, or attribute can affect the objects of a specific class.
This means that if a class is a data container, like an Animal class or an Employee class, and it has some fields regarding that entity, it should change only when we change the data model. Generally, many teams work on the same project and edit the same class for different reasons, which could lead to incompatible modules and glitches. Hence, this principle focuses on assigning or adding single functions to class & objects.
The Open-Closed Principle suggests that classes should be open for extension and closed to modification. Sometimes, we need to add certain functions to the existing class to perform additional tasks. So according to the Open-Closed Principle, We should add new functionality without touching the existing code for the class. This is because whenever we modify the existing code, we risk creating potential bugs. So we should avoid touching the tested and reliable (mostly) production code if possible. In simple words, this principle aims to extend a Class’s behavior without changing the existing behavior of that Class.
The Liskov Substitution Principle works on the Inheritance mechanism, where a subclass inherits the features (fields and methods) of the parent class. As it's very important in Object-Oriented Programming to allow the reusability factor from the functionality perspective. The Liskov Substitution Principle states that subclasses should be substitutable for their base classes. Suppose class Bob is a subclass of class Alex, then we should be able to pass a function or an object of class Alex to class Bob to give the same outputs if needed. The important thing to take from dynamic languages is that if your program “promises” to do something, you need to keep to your promise and not surprise your clients.
Segregation means keeping things separated, and the Interface Segregation Principle is about separating the interfaces. The principle emphasizes having one general-purpose interface rather than many client-specific interfaces. Clients should not be forced to depend on methods that they do not use. Because, when a Class is required to perform actions that are not useful, it is wasteful and may produce unexpected bugs if the Class cannot perform those actions. It is advisable for software engineers to start by building a new interface and then let the class implement multiple interfaces as needed rather than using an existing interface and adding new methods.
Let's understand these terms before getting ahead with the Dependency Inversion Principle:
High-level Module(or Class): Class that executes an action with a tool.
Low-level Module (or Class): The tool that is needed to execute the action.
Abstraction: Represents an interface that connects the two Classes.
Details: How the tool works.
The Dependency Inversion principle states that our classes should depend upon interfaces or abstract classes instead of concrete classes and functions. This means that developers should depend on abstractions, not on concretions. It also instructs that high-level module should not depend upon low-level modules. And, abstractions should not depend on details, but Details should depend upon abstractions.