SOLID

Single Responsibility Principle (SRP)

A class should have ****only one reason to change—it should do only one job or have one responsibility.

Open/Closed Principle (OCP)

Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification. It minimizes changes to existing, tested code.

Tightly Coupled Code

type Shape struct {
    shapeType string
}

func (s Shape) Draw() {
    if s.shapeType == "circle" {
        fmt.Println("Drawing a Circle")
    } else if s.shapeType == "square" {
        fmt.Println("Drawing a Square")
    }
}

Extensible Code

New shapes can be added without modifying existing code

type Shape interface {
    Draw()
}

type Circle struct{}

func (c Circle) Draw() {
    fmt.Println("Drawing a Circle")
}

type Square struct{}

func (s Square) Draw() {
    fmt.Println("Drawing a Square")
}

Liskov Substitution Principle (LSP)

The LSP ensures that a subclass enhance or modify the base class behavior in a way that doesn't violate client expectations.

Violating LSP (Breaking Expected Behavior)

Bird base class or a Flyer interface that includes a Fly method suggests that all subclasses or implementers should be able to fly.

type Bird struct{}

func (b Bird) Fly() string {
    return "I can fly!"
}

type Penguin struct {
    Bird
}

func (p Penguin) Fly() string {
    return "I can't fly!"
}
type Flyer interface {
    Fly() string
}

type Bird struct{}

func (b Bird) Fly() string {
    return "I can fly!"
}

type Penguin struct {}

func (p Penguin) Fly() string {
    return "I can't fly!"
}

Complying LSP

Split the behaviors into distinct interfaces.

type Flyer interface {
    Fly() string
}

type Walker interface {
    Walk() string
}

type Bird struct{}

func (b Bird) Fly() string {
    return "I can fly!"
}

type Penguin struct {}

func (p Penguin) Walk() string {
    return "I can walk!"
}

Interface Segregation Principle (ISP)