# SOLID

is a set of five design principles introduced by Robert C. Martin (Uncle Bob) to make software designs more maintainable, scalable, and robust. It stands for:

1. **S**ingle Responsibility Principle (SRP)
2. **O**pen/Closed Principle (OCP)
3. **L**iskov Substitution Principle (LSP)
4. **I**nterface Segregation Principle (ISP)
5. **D**ependency Inversion Principle (DIP)

## Single Responsibility Principle (SRP)

**Definition**: A class (or struct) should have one and only one reason to change.

Before applying SRP:

```go
type Report struct{}

func (r Report) GenerateReport() {
    fmt.Println("Generating report...")
}

func (r Report) SaveToFile(filename string) {
    fmt.Println("Saving report to file:", filename)
}
```

After applying SRP:

```go
type ReportGenerator struct{}

func (r ReportGenerator) GenerateReport() {
    fmt.Println("Generating report...")
}

type FileSaver struct{}

func (f FileSaver) SaveToFile(filename string) {
    fmt.Println("Saving to file:", filename)
}
```

**Explanation**: Each struct has a single responsibility now: one generates the report, and another saves it.

## Open/Closed Principle (OCP)

**Definition**: Software entities should be open for extension but closed for modification.

Before OCP:

```go
type AreaCalculator struct{}

func (a AreaCalculator) CalculateArea(shape string, dimensions ...float64) float64 {
    if shape == "circle" {
        return 3.14 * dimensions[0] * dimensions[0]
    } else if shape == "rectangle" {
        return dimensions[0] * dimensions[1]
    }
    return 0
}
```

After OCP (Extensible with interfaces):

```go
type Shape interface {
    Area() float64
}

type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return 3.14 * c.Radius * c.Radius
}

type Rectangle struct {
    Length, Width float64
}

func (r Rectangle) Area() float64 {
    return r.Length * r.Width
}

type AreaCalculator struct{}

func (a AreaCalculator) CalculateArea(s Shape) float64 {
    return s.Area()
}
```

**Explanation**: New shapes can be added by implementing the `Shape` interface without modifying `AreaCalculator`.

## Liskov Substitution Principle (LSP)

**Definition**: Subtypes must be substitutable for their base types without altering the correctness of the program.

Before LSP:

```go
type Bird struct{}

func (b Bird) Fly() {
    fmt.Println("Flying")
}

type Penguin struct {
    Bird
}

func (p Penguin) Fly() {
    panic("Penguins cannot fly!")
}
```

After LSP:

```go
type Bird interface {
    Move()
}

type Sparrow struct{}

func (s Sparrow) Move() {
    fmt.Println("Flying")
}

type Penguin struct{}

func (p Penguin) Move() {
    fmt.Println("Swimming")
}

func main() {
    var bird Bird
    bird = Sparrow{}
    bird.Move() // Output: Flying

    bird = Penguin{}
    bird.Move() // Output: Swimming
}
```

**Explanation**: The `Bird` interface represents general behavior, and specific birds implement it in ways that don't break substitutability.

## Interface Segregation Principle (ISP)

**Definition**: Clients should not be forced to depend on methods they do not use.

Before ISP:

```go
type Worker interface {
    Work()
    Eat()
}

type HumanWorker struct{}

func (h HumanWorker) Work() {
    fmt.Println("Working...")
}

func (h HumanWorker) Eat() {
    fmt.Println("Eating lunch...")
}

type RobotWorker struct{}

func (r RobotWorker) Work() {
    fmt.Println("Working...")
}

func (r RobotWorker) Eat() {
    // Robots don't eat
    panic("Robots don't eat!")
}
```

After ISP:

```go
type Worker interface {
    Work()
}

type Eater interface {
    Eat()
}

type HumanWorker struct{}

func (h HumanWorker) Work() {
    fmt.Println("Working...")
}

func (h HumanWorker) Eat() {
    fmt.Println("Eating lunch...")
}

type RobotWorker struct{}

func (r RobotWorker) Work() {
    fmt.Println("Working...")
}

func main() {
    human := HumanWorker{}
    robot := RobotWorker{}

    human.Work() // Output: Working...
    human.Eat()  // Output: Eating lunch...

    robot.Work() // Output: Working...
    // robot.Eat() // Error: Robots don't eat!
}
```

**Explanation**:\
Interfaces are split based on specific needs, so `RobotWorker` doesn’t need to implement `Eat()`.

## Dependency Inversion Principle (DIP)

**Definition**: High-level modules should not depend on low-level modules. Both should depend on abstractions.

Before DIP:

```go
type MySQLDatabase struct{}

func (db MySQLDatabase) Connect() {
    fmt.Println("Connecting to MySQL...")
}

type Service struct {
    Database MySQLDatabase
}

func (s Service) PerformTask() {
    s.Database.Connect()
    fmt.Println("Performing task...")
}
```

After DIP:

```go
type Database interface {
    Connect()
}

type MySQLDatabase struct{}

func (db MySQLDatabase) Connect() {
    fmt.Println("Connecting to MySQL...")
}

type PostgreSQLDatabase struct{}

func (db PostgreSQLDatabase) Connect() {
    fmt.Println("Connecting to PostgreSQL...")
}

type Service struct {
    Database Database
}

func (s Service) PerformTask() {
    s.Database.Connect()
    fmt.Println("Performing task...")
}

func main() {
    mysql := MySQLDatabase{}
    postgres := PostgreSQLDatabase{}

    service := Service{Database: mysql}
    service.PerformTask() // Output: Connecting to MySQL... Performing task...

    service.Database = postgres
    service.PerformTask() // Output: Connecting to PostgreSQL... Performing task...
}
```

**Explanation**: The `Service` depends on the `Database` interface, not specific implementations. This makes it easy to switch databases.

## Summary

| Principle | Description                                           | Example                                            |
| --------- | ----------------------------------------------------- | -------------------------------------------------- |
| SRP       | One responsibility per class/module                   | Separate report generation and saving logic        |
| OCP       | Open for extension, closed for modification           | Add new shapes without changing the calculator     |
| LSP       | Subtypes replace base types without breaking behavior | Penguins swim instead of fly                       |
| ISP       | Split interfaces to avoid unused methods              | Separate `Work` and `Eat` interfaces               |
| DIP       | Depend on abstractions, not concretions               | Service uses `Database` interface, not specific DB |

These principles make code cleaner, more maintainable, and easier to test.
