---
title: "S.O.L.I.D Principles"
description: "If you've ever written OO code, you've probably heard of this paradigm."
canonical_url: "https://otabek.io/blogs/solid-principles"
md_url: "https://otabek.io/blogs/solid-principles.md"
language: "en"
last_updated: "2024-03-12"
tags: ["Object Oriented Programming"]
---

# S.O.L.I.D Principles

If you've ever written Object-Oriented (OO) code, you've probably heard of S.O.L.I.D principles. You may not have fully grasped the concepts, but let's dive into them today (I'll discuss their shortcomings in the next episode).

### Single Responsibility

> Each class should have only one responsibility!

Let's say you created a class named `Open`. It doesn't really matter what it opens; if you ask it to open a **DB connection**, it will do so. If you ask it to open a file in 'w' mode, it will do that too. There's no real difference. But this is not a good solution because the more responsibilities a class has, the higher the chance it will contain bugs. Instead, it is recommended to create separate classes like `OpenDBConnection`, `OpenFile`, and `OpenFolder`.

### Open/Closed Principle

> Classes should be open for extension but closed for modification.

Take the `OpenFolder` class as an example. You could add functionality to it for opening files, but without changing or removing any existing functionality. For example, you can create a separate method like `open_file(filename: str, mode: str)` and use the `OpenFile` class for simplicity. This way, you're not adding extra logic but instead using single-purpose classes as mentioned earlier.

### Liskov Substitution Principle

> If class B is a subclass of class A, then an object of class B should be able to replace an object of class A without affecting the functionality.

Don’t rush to judge. To simplify, this means the child class should be able to do everything the parent class can do. For instance, if the son asks, "Hey, Dad, I can't make the coffee, can you make it for me?" the father shouldn’t respond with "Drink some water, I can't make coffee." The son should still be able to make the coffee. This is what we mean by the child class being able to perform the same tasks as the parent class. I think there’s no need for an overly complicated example, this should suffice. :)

### Interface Segregation Principle

> Clients should not be forced to depend on methods they do not use.

For example, the `OpenFile` class doesn’t need to connect to a database. Forcing it to do so would be unnecessary and counterproductive. Each class should only handle the tasks relevant to its specific responsibility. To make it clearer, even static methods should follow this principle and not become a hassle. 😉

### Dependency Inversion Principle

> High-level modules or classes should not depend on low-level modules or classes. Instead, both should depend on abstractions.

- **High-level class**: the performer of the task.
- **Low-level class**: the tool performing the task.
- **Abstraction**: the connector between the two.

For example, consider a TV remote. The remote should not depend on the TV's internal mechanisms. If the TV's internal mechanism breaks, you wouldn't call a technician for the remote; you’d call for the TV. Instead, the remote should be an abstraction that can be fixed separately. If the remote’s battery is dead, you wouldn’t open the TV to fix it—you’d replace the remote battery. If the remote breaks, you don’t need to fix the TV, you just fix the remote. In this case, abstraction serves as the connection between the two.

---

The above concepts have been briefly explained to make them easy to understand. The goal was to provide a general idea of these principles. In future posts, we will dive deeper into each one, discussing their pros and cons in detail.

---

```quiz
{
  "quiz": {
    "id": "solid-principles-quiz",
    "title": "SOLID Principles Quiz",
    "description": "Test your understanding of SOLID principles",
    "questions": [
      {
        "id": "q1",
        "type": "single-choice",
        "question": "What does the 'S' in SOLID stand for?",
        "options": [
          { "id": "a", "text": "Single Responsibility Principle", "description": "" },
          { "id": "b", "text": "Simple Responsibility Principle", "description": "It's Single, not Simple - each class should have only one responsibility." },
          { "id": "c", "text": "Shared Responsibility Principle", "description": "It's Single - the opposite of shared! Each class handles one thing." },
          { "id": "d", "text": "Secure Responsibility Principle", "description": "Security is important, but the S stands for Single Responsibility." }
        ]
      },
      {
        "id": "q2",
        "type": "single-choice",
        "question": "According to the Open/Closed Principle, classes should be:",
        "options": [
          { "id": "a", "text": "Open for modification, closed for extension", "description": "It's the opposite! You extend functionality without modifying existing code." },
          { "id": "b", "text": "Open for extension, closed for modification", "description": "" },
          { "id": "c", "text": "Open and closed at the same time", "description": "It means open FOR extension but closed FOR modification - not both states at once." },
          { "id": "d", "text": "Neither open nor closed", "description": "The principle specifically states classes should be open for extension, closed for modification." }
        ]
      },
      {
        "id": "q3",
        "type": "drag-drop",
        "question": "Match the SOLID principles in order (S-O-L-I-D):",
        "items": [
          { "id": "s", "content": "Single Responsibility" },
          { "id": "o", "content": "Open/Closed" },
          { "id": "l", "content": "Liskov Substitution" },
          { "id": "i", "content": "Interface Segregation" },
          { "id": "d", "content": "Dependency Inversion" }
        ]
      },
      {
        "id": "q4",
        "type": "single-choice",
        "question": "In the Liskov Substitution Principle, what should a child class be able to do?",
        "options": [
          { "id": "a", "text": "Override all parent methods", "description": "It's not about overriding - it's about being able to substitute for the parent." },
          { "id": "b", "text": "Do everything the parent class can do", "description": "" },
          { "id": "c", "text": "Have more methods than the parent", "description": "Having more methods is fine, but the key is it must fulfill the parent's contract." },
          { "id": "d", "text": "Be smaller than the parent class", "description": "Size doesn't matter - what matters is it can replace the parent without breaking functionality." }
        ]
      },
      {
        "id": "q5",
        "type": "single-choice",
        "question": "What does the Interface Segregation Principle prevent?",
        "options": [
          { "id": "a", "text": "Classes having too many methods", "description": "It's about interfaces, not class method count directly." },
          { "id": "b", "text": "Clients depending on methods they don't use", "description": "" },
          { "id": "c", "text": "Using multiple interfaces", "description": "Actually, it encourages smaller, more specific interfaces." },
          { "id": "d", "text": "Inheritance between classes", "description": "It's about interface design, not inheritance." }
        ]
      },
      {
        "id": "q6",
        "type": "single-choice",
        "question": "In the Dependency Inversion Principle, what should high-level modules depend on?",
        "options": [
          { "id": "a", "text": "Low-level modules directly", "description": "This is exactly what DIP says to avoid!" },
          { "id": "b", "text": "Abstractions", "description": "" },
          { "id": "c", "text": "Concrete implementations", "description": "Both high and low level modules should depend on abstractions, not implementations." },
          { "id": "d", "text": "Nothing at all", "description": "Modules need to depend on something - DIP says it should be abstractions." }
        ]
      }
    ]
  },
  "answers": {
    "q1": { "correctOptionIds": ["a"] },
    "q2": { "correctOptionIds": ["b"] },
    "q3": { "correctOrder": ["s", "o", "l", "i", "d"] },
    "q4": { "correctOptionIds": ["b"] },
    "q5": { "correctOptionIds": ["b"] },
    "q6": { "correctOptionIds": ["b"] }
  }
}
```


## Sitemap

See the full [Markdown sitemap](/sitemap.md) for all pages.
