DEV Community

Cover image for SOLID Principles
Sebastián Barrera Herrera
Sebastián Barrera Herrera

Posted on

SOLID Principles

When starting in programming, there are steps that need to be taken, and one of them is the SOLID principles, guidelines that will help you improve code quality, regardless of your experience level. For those of us starting on this path, keeping these concepts in mind and applying them to our code can be overwhelming. Often, the initial explanations we receive don’t even mention clean code, which makes sense at the beginning; what’s important are the basics and not scaring beginners with much more complex concepts. The problem arises when, over time, the basics are solid but the code starts to become a scroll due to its length. Bad practices and limited knowledge become constants, and from there, bad practices become the norm.

To change this reality, a bit more effort is required. You’ve learned the basics and know how to kick the ball; now you need a coach who talks about strategy and teaches you how to work as a team. This is similar to scrolls; instead of being sacred, they become a headache and start hindering your learning. As mentioned earlier, you need guidance, a good coach to guide you and show you the path they’ve already traveled. In the age of online courses, having a mentor who becomes your pillar seems impossible, but even if it’s through a recording, there are many who are dedicated, and you can always find someone who genuinely cares and does it very well.

I’m speaking from my experience and what I’ve seen in this process; I’m still on this journey, my code is still a scroll, and it will take time to become solid. For someone else, it might be different, they might have a different opinion, or they might not have had to make these extra miles, but for those who identify with this, I will share and provide examples of the recommendations that will be the principles of change in my code.

S: Single Responsibility Principle

This first principle is about independence and responsibilities. It tells us that, regardless of how large or small our construction is, each part should have a single responsibility. Not overloading a class, function, or object with more weight than it can bear helps us avoid future problems.

class Student {
    constructor(public name: string, public age: number) {}
}

class School {
    constructor(public nameSchool: string, public type: string) {}
}

class Certificate {
    constructor(private student: Student, private school: School) {}

    generateCertificate(): string {
        return `Certificate for ${this.student.name}, age ${this.student.age}, from ${this.school.nameSchool} (${this.school.type})`;
    }
}
Enter fullscreen mode Exit fullscreen mode

O: Open/Closed Principle

This important principle tells us that every class should be open for extension but closed for modification. I can have a base class that serves as a reference in several places; this class, being efficient, can be extended, and thus the functioning of its child classes will improve. However, I should avoid modifying the main class so that the functioning of the child class is optimal. A tiger’s offspring looks like a tiger.

interface Car {
    inspect(): string;
}

class Mazda implements Car {
    constructor(public brand: string, public model: string) {}

    inspect(): string {
        return `Inspecting Mazda: ${this.brand} ${this.model}`;
    }
}

...More class
Enter fullscreen mode Exit fullscreen mode

L: Liskov Substitution Principle

This principle is named after its creator, Barbara Liskov. Personally, it has been the most challenging for me to understand, but I will make the effort to be as clear as possible so that you understand it. Each class that inherits from another can be used as its parent class without needing to know the differences between them and should act without causing unexpected errors.

class Animal {
    makeSound(): void {
        console.log("The animal makes a sound");
    }
}

class Dog extends Animal {
    makeSound(): void {
        console.log("The dog barks");
    }
}

class Fish extends Animal {
    makeSound(): void {
        console.log("The fish makes no sound");
    }
}

function makeItSound(animal: Animal) {
    animal.makeSound();
}

const dog = new Dog();
const fish = new Fish();

makeItSound(dog);  
makeItSound(fish);
Enter fullscreen mode Exit fullscreen mode

I: Interface Segregation Principle

One of the most important principles, this principle is key to bringing about change and reveals to us that it doesn’t matter to have many interfaces. If you have several clients with different arguments and behaviors, create interfaces that fit each one and do not force everyone to have a general interface with properties they will not use.

interface SportWithBall {
    ball: string;
}

interface SportWithPlayers {
    players: string[];
}

class Soccer implements SportWithBall, SportWithPlayers {
    players = ['Player1', 'Player2'];
    ball = 'Soccer ball';
}

class Swimming implements SportWithPlayers {
    players = ['Swimmer1', 'Swimmer2'];
}
Enter fullscreen mode Exit fullscreen mode

D: Dependency Inversion Principle

We come to the last principle, which clearly states: “High-level classes should not depend on low-level classes but on interfaces or abstractions that define what they need.”

interface NotificationService {
    send(message: string): void;
}

class EmailService implements NotificationService {
    send(message: string) {
        console.log("Sending email:", message);
    }
}

class SmsService implements NotificationService {
    send(message: string) {
        console.log("Sending SMS:", message);
    }
}

class Notification {
    private service: NotificationService;

    constructor(service: NotificationService) {
        this.service = service;
    }

    notify(message: string) {
        this.service.send(message);
    }
}


Enter fullscreen mode Exit fullscreen mode

These are the definitions I give; it might be better and more complete, but for now, on the path I’m traveling, it’s what I’ve understood. I hope these examples or the definitions of these principles can be useful to someone. I try to document my process and thus show the progress I’m making. Thank you very much for reading. Have a great day! 😀💪🎉

Top comments (0)