SOLID Principles — Engineering Decision Framework
SOLID is not just about writing “clean code” in isolation.
SOLID Principles — Engineering Decision Framework
SOLID is not just about writing “clean code” in isolation.
It is a set of corrective mechanisms applied when specific structural problems emerge in object-oriented systems.
Each principle answers one question:
“What kind of change is making this code fragile?”
Full story for non-members | E-Books on Java/Microservices/Springboot | Whatsapp Group

codefarm.in
1. System-Level View of SOLID
Before going principle-by-principle, understand this:

codefarm.in
You don’t “apply SOLID”. You detect violations and fix them.
2. Single Responsibility Principle (SRP)
A module should have one reason to change, where “reason” maps to a stakeholder or concern.
Trigger Conditions
Same class modified by:
- Business team (logic change)
- DB team (schema change)
- DevOps (logging/config)
- Large classes with unrelated methods
- Frequent merge conflicts
Example: Violation
class InvoiceService {
public void generateInvoice() { ... } // business logic
public void saveToDB() { ... } // persistence
public void sendEmail() { ... } // notification
}
Problem Analysis
This class changes when:
- Business rules change
- Database schema changes
- Notification mechanism changes
→ 3 reasons to change = SRP violation
Refactoring
class InvoiceService {
void generateInvoice() { ... }
}
class InvoiceRepository {
void save() { ... }
}
class NotificationService {
void send() { ... }
}
Engineering Outcome
- Reduced change impact radius
- Independent deployability (in microservices context)
- Improved test isolation
SRP is about axis of change, not “number of methods”.
3. Open/Closed Principle (OCP)
Software entities should be:
- Open for extension
- Closed for modification
Trigger Conditions
- Adding new feature requires modifying existing code
- Regression risk increases with every change
- Repeated branching logic
Example: Violation
double calculateDiscount(String type) {
if (type.equals("NEW")) return 10;
if (type.equals("PREMIUM")) return 20;
}
Problem
- Every new type → modify method
- Violates stability
Refactoring → Strategy
interface DiscountStrategy {
double apply();
}
class PremiumDiscount implements DiscountStrategy {
public double apply() { return 20; }
}
Usage
strategyMap.get(type).apply();
Engineering Outcome
- New feature = new class
- No modification of stable code
- Safer deployments
OCP is about protecting stable code from change.
4. Liskov Substitution Principle (LSP)
Subtypes must be substitutable for their base types without altering correctness.
Trigger Conditions
instanceofchecks- Runtime failures in subclasses
- Unexpected behavior overrides
Example: Violation
class Rectangle {
void setWidth(int w) {}
void setHeight(int h) {}
}
class Square extends Rectangle {
void setWidth(int w) {
super.setWidth(w);
super.setHeight(w);
}
}
Problem
- Square breaks expectations of Rectangle
- Behavioral inconsistency
Fix
Separate abstractions:
interface Shape {
int area();
}
Engineering Outcome
- Correct polymorphism
- No hidden side effects
LSP violations are semantic, not syntactic. Code compiles — but logic breaks.
5. Interface Segregation Principle (ISP)
Clients should not depend on interfaces they do not use.
Trigger Conditions
- Large interfaces
- Many empty or dummy implementations
- Low cohesion
Example: Violation
interface Machine {
void print();
void scan();
void fax();
}
Problem
Not all clients need all methods.
Refactoring
interface Printer { void print(); }
interface Scanner { void scan(); }
Engineering Outcome
- Smaller, focused contracts
- Reduced implementation burden
ISP is about consumer-specific interfaces, not just splitting randomly.
6. Dependency Inversion Principle (DIP)
High-level modules should not depend on low-level modules. Both should depend on abstractions.
Trigger Conditions
- Direct object instantiation (
new) inside business logic - Hard-to-test code
- Tight coupling to implementations
Example: Violation
class OrderService {
PaymentGateway gateway = new StripeGateway();
}
Problem
- Cannot switch gateway easily
- Hard to mock
Refactoring
class OrderService {
private final PaymentGateway gateway;
OrderService(PaymentGateway gateway) {
this.gateway = gateway;
}
}
Engineering Outcome
- Loose coupling
- Testability
- Framework integration (Spring DI)
DIP is the foundation of Spring Boot’s dependency injection.
7. SOLID Interaction (How They Work Together)
These principles are not isolated.
They reinforce each other:
- SRP → enables OCP
- OCP → relies on abstraction (DIP)
- DIP → enables testability
- ISP → supports DIP
- LSP → ensures correctness
8. Practical Decision Flow
When designing or reviewing code, ask:
- Does this class change for multiple reasons? → SRP
- Am I modifying existing logic frequently? → OCP
- Are subclasses behaving incorrectly? → LSP
- Are interfaces too large? → ISP
- Are modules tightly coupled? → DIP
9. SOLID Decision Mind Map

created with https://codefarm.in/labs/mind-map
10. Final Engineering Takeaway
- SRP → limits impact
- OCP → prevents risk
- LSP → ensures correctness
- ISP → reduces noise
- DIP → decouples system
If no change pressure exists, applying SOLID blindly leads to over-engineering.
Liked this deep dive story? If Yes Please 👏 Clap(50) | 📤 Share | 🔔 Follow
Below is a collection of all related stories in one place
메타데이터
- post_id
- ec326a16bf84
- slug
- solid-principles-engineering-decision-framework-ec326a16bf84
- url
- https://medium.com/codefarm-java-ecosystem/solid-principles-engineering-decision-framework-ec326a16bf84
- canonical_url
- https://medium.com/codefarm-java-ecosystem/solid-principles-engineering-decision-framework-ec326a16bf84
- author_url
- https://medium.com/@codefarm0
- status
- ok
- fetched_at
- 2026-06-15 20:49:13