Understanding SOLID Principles
1. Understanding Single Responsibility Principle
| Concept | Definition |
| SRP | One reason to change per class |
| Actor | Stakeholder driving change |
| Cohesion | High inside class |
Example: Split responsibilities
// BAD: Report does calc + format + persist
// GOOD:
class ReportCalculator { Report compute(Data d) { ... } }
class ReportFormatter { String toPdf(Report r) { ... } }
class ReportRepository { void save(Report r) { ... } }
2. Understanding Open-Closed Principle
| Aspect | Detail |
| Open for | Extension via new types |
| Closed for | Modification of existing code |
| Mechanism | Polymorphism, strategy, plugin |
Example: Strategy keeps it closed
interface DiscountPolicy { Money apply(Order o); }
class PricingService {
private final List<DiscountPolicy> policies;
Money price(Order o) {
return policies.stream().map(p -> p.apply(o)).reduce(o.total(), Money::minus);
}
}
3. Understanding Liskov Substitution Principle
| Rule | Constraint |
| Preconditions | Cannot strengthen in subtype |
| Postconditions | Cannot weaken in subtype |
| Invariants | Must preserve |
| Exceptions | Subtype throws same/narrower |
Warning: Classic violation: Square extends Rectangle breaks setWidth/setHeight contracts.
4. Understanding Interface Segregation Principle
| Smell | Fix |
| Fat interface | Split by client need |
| Forced empty impl | Separate interface |
| Unused method on client | Different role interface |
Example: Role interfaces
interface Reader<T> { T read(long id); }
interface Writer<T> { void write(T entity); }
// Read-only consumers depend on Reader only.
5. Understanding Dependency Inversion Principle
| Rule | Detail |
| High-level | Depends on abstractions |
| Low-level | Implements abstractions |
| Direction | Both depend on interface |
Example: Inverted dependency
// Domain owns the interface
package domain; interface NotificationPort { void send(Message m); }
// Infra implements it
package infra; class SmtpNotifier implements NotificationPort { ... }
6. Identifying SRP Violations
| Symptom | Diagnosis |
| "And" in class name | UserAndOrderService |
| Many imports | Touches many concerns |
| Mixed abstraction | HTTP + SQL in one class |
| High change frequency | Too many actors |
| Unrelated tests | Test classes cover disparate behaviors |
7. Applying SOLID in Domain Models
| Principle | Domain Application |
| SRP | One aggregate = one business concept |
| OCP | Extend via specifications, policies |
| LSP | Subtypes preserve invariants |
| ISP | Role interfaces per use case |
| DIP | Domain defines repository interfaces |
8. Applying SOLID in Service Layer Design
| Layer Concern | Approach |
| Workflow | One service per use case (SRP) |
| Extensibility | Inject strategies (OCP) |
| Substitutability | Interface-driven design (LSP/DIP) |
| Client API | Narrow service interfaces (ISP) |
9. Balancing SOLID with Pragmatism
Apply Strictly When
- Long-lived module
- Many collaborators
- Frequent change
- Public API
Relax When
- Throwaway script
- Single user, single use
- Prototype/spike
- Tiny utility
| Trade-off | Watch For |
| Over-abstraction | Indirection without value |
| Premature interface | Single implementer forever |
10. Refactoring to SOLID
Refactor Sequence
- Cover with characterization tests
- Extract methods (find responsibilities)
- Extract classes (split responsibilities — SRP)
- Introduce interfaces at seams (DIP)
- Replace conditionals with polymorphism (OCP)
- Split fat interfaces (ISP)
- Verify substitutability (LSP)
11. Understanding SOLID Trade-offs
| Principle | Cost | Benefit |
| SRP | More classes | Focused changes |
| OCP | Indirection | Stable core |
| LSP | Hierarchy discipline | Safe polymorphism |
| ISP | More interfaces | Decoupled clients |
| DIP | Wiring complexity | Testability, swappability |
12. Implementing SOLID in Legacy Code
| Step | Tool |
| Pin behavior | Approval/golden tests |
| Find seams | Sprout method/class |
| Break dependency | Extract interface, parameterize constructor |
| Rename safely | IDE refactoring |
| Strangle | Route new traffic through new design |