Home/Learn/Low Level Design/Single Responsibility Principle

Single Responsibility Principle

Beginner
SOLID Principles in Practice

A class should have only one reason to change — it should do one thing and do it well.

Overview

SRP is about cohesion: grouping things that change for the same reason, and separating things that change for different reasons. A class that handles HTTP parsing, business logic, database access, and email sending has four reasons to change — it violates SRP. The practical test: "Can I describe this class's responsibility in one sentence without using 'and' or 'or'?" SRP applies at all levels: class, method, and module. Violations manifest as large classes (God classes), methods that do too much, and test files that need to mock dozens of dependencies.

SRP Violation and Refactoring

A UserService that handles registration, email sending, and PDF report generation has three reasons to change. Refactor by extracting each responsibility into its own class.

Java — SRP violation and refactoring
// ❌ SRP Violation: UserService does too many things
public class UserService {
    public void registerUser(String email, String password) {
        // 1. Validate
        if (!email.contains("@")) throw new IllegalArgumentException("Invalid email");
        // 2. Hash password
        String hashed = BCrypt.hashpw(password, BCrypt.gensalt());
        // 3. Save to database
        String sql = "INSERT INTO users (email, password) VALUES (?, ?)";
        jdbcTemplate.update(sql, email, hashed);
        // 4. Send welcome email
        MimeMessage msg = mailSender.createMimeMessage();
        // ... email setup ...
        mailSender.send(msg);
        // 5. Generate PDF welcome packet
        Document doc = new Document();
        PdfWriter.getInstance(doc, new FileOutputStream("welcome.pdf"));
        // ... PDF generation ...
    }
    // This class changes when: email template changes, PDF library upgrades,
    // DB schema changes, validation rules change, or password policy changes
}

// ✅ SRP Refactoring: one class, one responsibility
public class UserRegistrationService {   // orchestrates only
    private final UserRepository   userRepo;
    private final PasswordEncoder  encoder;
    private final EmailService     emailService;
    private final WelcomeDocService docService;

    public UserRegistrationService(UserRepository userRepo, PasswordEncoder encoder,
                                   EmailService emailService, WelcomeDocService docService) {
        this.userRepo     = userRepo;
        this.encoder      = encoder;
        this.emailService = emailService;
        this.docService   = docService;
    }

    public User registerUser(String email, String password) {
        User user = User.of(email, encoder.encode(password));
        userRepo.save(user);
        emailService.sendWelcome(user);
        docService.generateWelcomePacket(user);
        return user;
    }
}

// Each extracted class has one reason to change:
public class EmailService {
    public void sendWelcome(User user) { /* only email logic here */ }
}

public class WelcomeDocService {
    public void generateWelcomePacket(User user) { /* only PDF logic here */ }
}

public class UserRepository {
    public void save(User user) { /* only DB logic here */ }
}

SRP at Method Level

SRP applies to methods too. A method that fetches data, transforms it, validates it, and persists it violates SRP. Extract each concern into a named private method or separate class.

Java — SRP at method level
// ❌ Method SRP violation
public void processOrder(Order order) {
    // Fetch product details
    Product p = productRepo.findById(order.getProductId()).orElseThrow();
    // Apply discount
    double price = p.getPrice();
    if (order.hasPromoCode()) price *= 0.9;
    // Validate inventory
    if (p.getStock() < order.getQuantity()) throw new OutOfStockException();
    // Charge payment
    paymentGateway.charge(order.getUserId(), price * order.getQuantity());
    // Update inventory
    p.setStock(p.getStock() - order.getQuantity());
    productRepo.save(p);
    // Send email
    emailService.sendOrderConfirmation(order);
}

// ✅ SRP at method level — each step is named and testable
public void processOrder(Order order) {
    Product product  = fetchProduct(order);
    double  price    = applyDiscount(product.getPrice(), order);
    validateStock(product, order.getQuantity());
    chargeCustomer(order, price);
    deductStock(product, order.getQuantity());
    notifyCustomer(order);
}

private Product fetchProduct(Order order)          { return productRepo.findById(order.getProductId()).orElseThrow(); }
private double  applyDiscount(double p, Order o)   { return o.hasPromoCode() ? p * 0.9 : p; }
private void    validateStock(Product p, int qty)  { if (p.getStock() < qty) throw new OutOfStockException(); }
private void    chargeCustomer(Order o, double p)  { paymentGateway.charge(o.getUserId(), p * o.getQuantity()); }
private void    deductStock(Product p, int qty)    { p.setStock(p.getStock() - qty); productRepo.save(p); }
private void    notifyCustomer(Order o)            { emailService.sendOrderConfirmation(o); }

Key Points to Remember

  • 1A class should have one reason to change — one axis of variation, one responsibility.
  • 2God classes that do everything are the most common SRP violation.
  • 3SRP improves testability — small, focused classes are easier to unit test in isolation.
  • 4SRP applies at method level too — methods should do one thing, named as a verb-noun describing that one thing.
  • 5SRP and high cohesion are the same idea: group things that change together.

Interview Questions

Sign in to ask Aria
1

What does "one reason to change" mean in SRP?

EasyAmazon
2

How do you identify an SRP violation in a large codebase?

MediumGoogle
3

Can you have too much SRP? What is "over-engineering" in this context?

HardAtlassian
4

How does SRP relate to microservices architecture?

MediumNetflix

Ask Aria about Single Responsibility Principle

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…