Skip to main content

Command Palette

Search for a command to run...

SOLID Principles

Updated
β€’4 min read
B

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-else chaos)


βœ… 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)