SOLID Principles
Experienced Java/JavaScript full-stack developer over 6 years of extensive expertise serving key role on elite technical teams developing enterprise software for healthcare, apple ad-platform, banking, and e-commerce. Adaptable problem-solver with high levels of skill in Groovy, Java, Spring, Spring Boot, Hibernate, JavaScript, TypeScript, Angular, Node, Express, React, MongoDB, IBM DB2, Oracle, PL/SQL, Docker, Kubernetes, CI/CD pipelines, AWS, Micro-service and Agile/Scrum. Strong technical skills paired with business-savvy UI design expertise. Personable team player with experience collaborating with diverse cross-functional teams.
1οΈβ£ Single Responsibility Principle (SRP)
π₯ Definition
A class should have only one reason to change.
β Bad Example
class CreditCardService {
void processTransaction() { }
void calculateFees() { }
void saveTransaction() { }
void sendNotification() { }
}
β Why this is BAD
Multiple responsibilities in one class
Any change (fee logic, DB, notification) affects same class
Hard to test (everything tightly coupled)
High risk of bugs
β Good Example
class PaymentProcessor {
void processTransaction() { }
}
class FeeCalculator {
void calculateFees() { }
}
class TransactionRepository {
void saveTransaction() { }
}
class NotificationService {
void sendNotification() { }
}
β Why this is GOOD
Each class has single responsibility
Easy to modify one feature without breaking others
Easier unit testing
Cleaner architecture
2οΈβ£ Open/Closed Principle (OCP)
π₯ Definition
Open for extension, closed for modification.
β Bad Example
class FeeCalculator {
double calculate(String cardType, double amount) {
if (cardType.equals("BASIC")) return amount * 0.02;
if (cardType.equals("PREMIUM")) return amount * 0.01;
return 0;
}
}
β Why this is BAD
Every new card type requires modifying existing code
Violates stability (risk of breaking old logic)
Hard to scale (more
if-elsechaos)
β Good Example
interface FeeStrategy {
double calculate(double amount);
}
class BasicFee implements FeeStrategy {
public double calculate(double amount) {
return amount * 0.02;
}
}
class PremiumFee implements FeeStrategy {
public double calculate(double amount) {
return amount * 0.01;
}
}
β Why this is GOOD
New card types added without modifying existing code
Reduces risk of regression bugs
Follows plug-and-play design
3οΈβ£ Liskov Substitution Principle (LSP)
π₯ Definition
Subclasses should be replaceable without breaking behavior.
β Bad Example
abstract class CreditCard {
abstract void withdrawCash();
}
class RewardsCard extends CreditCard {
void withdrawCash() {
throw new RuntimeException("Not supported");
}
}
β Why this is BAD
Subclass breaks expected behavior
Causes runtime failures
Not all cards support withdrawal β bad abstraction
β Good Example
abstract class CreditCard {
abstract void makePayment(double amount);
}
interface CashWithdrawal {
void withdrawCash(double amount);
}
class BasicCard extends CreditCard implements CashWithdrawal {
public void makePayment(double amount) { }
public void withdrawCash(double amount) { }
}
class RewardsCard extends CreditCard {
public void makePayment(double amount) { }
}
β Why this is GOOD
No unexpected behavior
Safe substitution of subclasses
Models real-world constraints correctly
4οΈβ£ Interface Segregation Principle (ISP)
π₯ Definition
Do not force classes to implement methods they donβt use.
β Bad Example
interface CreditCardService {
void processPayment();
void calculateRewards();
void withdrawCash();
}
β Why this is BAD
Classes forced to implement unused methods
Leads to empty methods or exceptions
Hard to maintain
β Good Example
interface PaymentService {
void processPayment();
}
interface RewardService {
void calculateRewards();
}
interface CashService {
void withdrawCash();
}
β Why this is GOOD
Only required methods are implemented
Cleaner and flexible design
Easier to extend features
5οΈβ£ Dependency Inversion Principle (DIP)
π₯ Definition
Depend on abstractions, not concrete implementations.
β Bad Example
class CreditCardService {
private MySQLRepository repo = new MySQLRepository();
}
β Why this is BAD
Tight coupling to specific database
Hard to switch DB or test
Violates flexibility
β Good Example
interface TransactionRepository {
void save(double amount);
}
class CreditCardService {
private TransactionRepository repo;
CreditCardService(TransactionRepository repo) {
this.repo = repo;
}
}
β Why this is GOOD
Loose coupling
Easy to switch implementations (MySQL β MongoDB)
Better testability (mocking)