Logo

dev-resources.site

for different kinds of informations.

SOLID Principles Explained in a Simple Way 🛠️✨ with Real-Life Examples

Published at
11/3/2024
Categories
solidprinciples
softwaredevelopment
code
development
Author
narmidm
Author
7 person written this
narmidm
open
SOLID Principles Explained in a Simple Way 🛠️✨ with Real-Life Examples

In software development, the SOLID principles are essential guidelines that help developers create code that is easy to maintain, extend, and understand. These principles were introduced by Robert C. Martin, also known as Uncle Bob, and they are widely adopted in modern software engineering.

Imagine you're building a house. You want it to be strong, easy to modify, and able to grow if needed. The SOLID principles are like rules for creating a "strong" house in programming.

Alright, let's make the SOLID principles even simpler by blending everyday examples with small, clear code snippets. This way, even if you're a beginner, you’ll get the core idea without any headaches.

S - Single Responsibility Principle (SRP)

Rule: Each class should only do one thing.

Real-World Example:

Think of a librarian in a library. Each librarian is assigned a specific task: one manages book loans, another manages book returns, and yet another handles cataloging. If the book return process changes, only the librarian responsible for book returns needs to adjust their workflow, not the entire staff.

Code Example:

Let’s say we have a Book class. If this class manages book information and saves the book to a file, it’s doing too much. Let’s split it.

Before SRP:

class Book:
def **init**(self, title, author):
self.title = title
self. Author = author

def save_to_file(self):
    with open(f"{self.title}.txt", "w") as file:
        file. Write(f"{self.title} by {self. Author}")
Enter fullscreen mode Exit fullscreen mode

After SRP:

class Book:
def **init**(self, title, author):
self.title = title
self.author = author

class BookSaver:
@staticmethod
def save_to_file(book):
with open(f"{book.title}.txt", "w") as file:
file.write(f"{book.title} by {book.author}")
Enter fullscreen mode Exit fullscreen mode

Now, Book just stores information about the book, and BookSaver handles saving it to a file. One class, one job!


O - Open/Closed Principle (OCP)

Rule: Your code should be open to adding new stuff but closed to changing old stuff.

Real-World Example:

Consider a TV remote battery. Your remote needs a battery but isn’t dependent on the battery brand. You can use any brand you want, and it will work. So, we can say that the TV remote is loosely coupled with the brand name.

Code Example:

Let’s say we have different shapes, and we want to calculate the area. Instead of adding conditions to handle each shape, we can extend the Shape class.

Before OCP (Bad Example):

def calculate_area(shape):
if shape["type"] == "rectangle":
return shape["width"] * shape["height"]
elif shape["type"] == "circle":
return 3.14 * shape["radius"] ** 2
Enter fullscreen mode Exit fullscreen mode

After OCP:

class Shape:
def area(self):
pass

class Rectangle(Shape):
def **init**(self, width, height):
self.width = width
self. Height = height
def area(self):
    return self.width * self.height

class Circle(Shape):
def **init**(self, radius):
self.radius = radius


def area(self):
    return 3.14 * self.radius ** 2

Enter fullscreen mode Exit fullscreen mode

Now, if we want to add a new shape, we just create a new class without changing the existing code.


L - Liskov Substitution Principle (LSP)

Rule: You should be able to use a child class wherever a parent class is used, without things breaking.

Real-World Example:

Imagine you rent a car. Whether it’s a sedan or an SUV, you should still be able to drive it the same way. You don’t need to learn a different way to drive each type.

Code Example:

If a subclass behaves differently in an unexpected way, it can break things. Here’s an example with a Bird class:

Before LSP (Problematic Example):

class Bird:
def fly(self):
print("Flying")

class Penguin(Bird):
def fly(self):
raise Exception("Penguins can’t fly!")
Enter fullscreen mode Exit fullscreen mode

After LSP:

class Bird:
def move(self):
pass

class FlyingBird(Bird):
def move(self):
print("Flying")

class Penguin(Bird):
def move(self):
print("Swimming")
Enter fullscreen mode Exit fullscreen mode

Now, Penguin doesn’t try to “fly” but uses move() like all Bird types, which avoids errors.


I - Interface Segregation Principle (ISP)

Rule: Don’t force a class to implement stuff it doesn’t use.

Real-World Example:

Think of a remote control. You don’t need TV buttons on a remote for an air conditioner. Each device should have only the controls it needs.

Code Example:

Suppose we have a Worker interface that requires all workers to both work and eat.

Before ISP:

class Worker:
def work(self):
pass

def eat(self):
    pass

class Robot(Worker):
def work(self):
print("Working")

def eat(self):
    raise NotImplementedError("Robots don't eat")

Enter fullscreen mode Exit fullscreen mode

After ISP:

class Workable:
def work(self):
pass

class Eatable:
def eat(self):
pass

class Human(Workable, Eatable):
def work(self):
print("Working")


def eat(self):
    print("Eating")



class Robot(Workable):
def work(self):
print("Working")
Enter fullscreen mode Exit fullscreen mode

Now Robot only implements the work method, without any eat method it doesn’t need.


D - Dependency Inversion Principle (DIP)

Rule: High-level modules shouldn’t depend on low-level modules. Instead, both should depend on abstractions.

Real-World Example:

Imagine your house's electrical system. The lights, fridge, and air conditioning all get power from one main connection, not directly from the power plant. This way, you can swap out appliances without redoing the entire house’s wiring.

Code Example:

Let’s say we have a Keyboard class that directly depends on a WindowsMachine class.

Before DIP (Tight Coupling):

class WindowsMachine:
def type(self):
print("Typing on Windows")

class Keyboard:
def **init**(self, machine):
self.machine = machine

def input(self):
    self.machine.type()

Enter fullscreen mode Exit fullscreen mode

After DIP:

class Machine:
def type(self):
pass

class WindowsMachine(Machine):
def type(self):
print("Typing on Windows")

class MacMachine(Machine):
def type(self):
print("Typing on Mac")

class Keyboard:
def **init**(self, machine: Machine):
self.machine = machine

def input(self):
    self.machine.type()

Enter fullscreen mode Exit fullscreen mode

Now, Keyboard relies on an abstract Machine class, not a specific type of machine. This way, it works with any machine that fits the interface.


Why SOLID is Useful in Real-World Development

In the software industry, code maintenance is a huge part of a developer’s job. Following SOLID principles helps in:

Reducing Bugs: When each part of the code has a single job, it’s easier to spot and fix issues.

Making Changes Easier: Since each class is focused on one task, you can modify or add features without messing up existing code.

Scaling: SOLID principles allow you to build systems that grow over time without falling apart.

While not every developer follows SOLID strictly, these principles are widely respected and used, especially in large projects where flexibility and maintainability are key.

By following SOLID, you make your code like a well-built, organized house—it’s sturdy, easy to upgrade, and keeps everything in its right place.

solidprinciples Article's
30 articles in total
Favicon
ISP - O Princípio da Segregação de Interface
Favicon
Disadvantages of the Single Responsibility Principle(SRP)
Favicon
Guia: O que Ă© SOLID
Favicon
Interface Segregation Principle (ISP)
Favicon
Dependency Inversion Principle (DIP)
Favicon
Liskov Substitution Principle (LSP)
Favicon
Create your own Logger using Open-closed principle
Favicon
SOLID: Dependency Inversion Principle (DIP) in C#
Favicon
SOLID: Principio de Abierto/Cerrado
Favicon
LSP - O Princípio da Substituição de Liskov
Favicon
SOLID: Principio de Responsabilidad Ăšnica
Favicon
SOLID Principles for React / React Native Development
Favicon
Single Responsibility Principle (SRP)
Favicon
Solid Prensipleri
Favicon
Mastering SOLID Principles in .NET Core: A Path to Clean and Scalable Code
Favicon
OCP - O PrincĂ­pio Aberto/Fechado
Favicon
SRP - O PrincĂ­pio da Responsabilidade Ăšnica
Favicon
SOLID Design Principles
Favicon
Rethinking interfaces in Flutter projects
Favicon
Understanding the SOLID Principles in PHP and How They Improve Code Quality
Favicon
SOLID: The Liskov Substitution Principle (LSP) in C#
Favicon
Is Clean Code really practical?
Favicon
Open/Closed Principle (OCP)
Favicon
Single Responsibility Principle (SRP)
Favicon
Solid Principle in Simple English
Favicon
Why Clean Architecture and SOLID Principles Should Be the Foundation of Your Next Project!
Favicon
Seja um desenvolvedor melhor com S.O.L.I.D.
Favicon
SOLID: Open-Closed Principle (OCP) in C#
Favicon
SOLID Principles Explained in a Simple Way 🛠️✨ with Real-Life Examples
Favicon
Object Oriented Design Balance With Understanding Anti-Single Responsibility Principle

Featured ones: