Skip to main content

SOLID Principles — Five Rules for Extensible Object-Oriented Design

Five design principles that keep code open to extension without modification.

When to use

  • Designing classes/modules in any OO codebase
  • When adding features keeps breaking existing code
  • When tests require extensive mocking to isolate units

Tradeoffs

  • DIP adds indirection (more interfaces); overhead for simple scripts
  • Over-applying SRP creates class explosion
// SRP: one responsibility per type
type InvoicePrinter struct{}
func (p InvoicePrinter) Print(i Invoice) {}

// OCP: extend via interface, not modification
type Discounter interface{ Apply(price float64) float64 }

// LSP: subtypes must honour the contract
type ReadOnlyRepo interface{ Find(id int) Item }

// ISP: small, focused interfaces
type Writer interface{ Write([]byte) error }

// DIP: depend on abstraction
type OrderService struct{ repo OrderRepo }
func NewOrderService(r OrderRepo) *OrderService { return &OrderService{r} }

Gotcha: LSP violation is often a sign you need composition, not inheritance.