π§± SOLID Principles β
Five principles for writing maintainable object-oriented code.
S β Single Responsibility β
A class should have only one reason to change.
typescript
// BAD: UserService handles auth, profile, and notifications
class UserService {
login() { ... }
updateProfile() { ... }
sendWelcomeEmail() { ... }
}
// GOOD: Each class has one job
class AuthService { login() { ... } }
class ProfileService { updateProfile() { ... } }
class NotificationService { sendWelcomeEmail() { ... } }O β Open/Closed β
Open for extension, closed for modification.
Add new behavior by adding new code, not changing existing code. Use interfaces and composition instead of modifying existing classes.
L β Liskov Substitution β
Subtypes must be substitutable for their base types.
If Bird has a fly() method, Penguin extends Bird breaks the contract. Solution: restructure the hierarchy or use composition.
I β Interface Segregation β
Don't force clients to depend on methods they don't use.
typescript
// BAD: One fat interface
interface Worker {
code(): void
design(): void
manage(): void
}
// GOOD: Focused interfaces
interface Coder { code(): void }
interface Designer { design(): void }
interface Manager { manage(): void }D β Dependency Inversion β
Depend on abstractions, not concrete implementations.
typescript
// BAD: Directly depends on PostgreSQL
class UserService {
private db = new PostgresDatabase()
}
// GOOD: Depends on an interface
class UserService {
constructor(private db: Database) {}
}Practical application β
- Don't apply SOLID dogmatically β it's a guide, not law
- Most useful in large codebases with multiple contributors
- For small projects, KISS often trumps SOLID
- Start simple, refactor toward SOLID when complexity grows
- The goal is maintainability, not pattern purity