CodePark/ questions / SOLID
START PRACTICINGPRACTICE
Backend question · Software design & patterns › SOLID

Which SRP problems do you see in this service, and how would you split it?

class UserService {
  async register(dto: RegisterDto) {
    if (!dto.email.includes("@")) throw new Error("bad email");
    const hash = await bcrypt.hash(dto.password, 12);
    const user = await this.db.query("INSERT INTO users ...", [dto.email, hash]);
    await this.smtp.send(dto.email, "<h1>Welcome!</h1>");
    await this.db.query("INSERT INTO audit_log ...", [user.id]);
    return user;
  }
  async monthlySignupReportCsv() { /* SQL + CSV formatting */ }
}

This class has many reasons to change, so it breaks SRP. SRP (the Single Responsibility Principle) is about reasons to change. In Robert Martin's later wording, it is about the actor a module serves: the person or team who asks for changes.

This class changes when:

  • the email template changes (marketing)
  • the password policy changes (security)
  • the schema changes (DBA)
  • the audit rules change (compliance)
  • the report format changes (finance)

That is several actors in one class. A change for one actor can break the code another actor depends on.

Split the class along those lines:

  • input validation at the boundary (a DTO validator)
  • a PasswordHasher
  • a UserRepository for persistence (saving to the database)
  • a WelcomeMailer, or a listener on a UserRegistered event
  • an audit component
  • a separate SignupReportService

After the split, UserService.register only orchestrates the registration use case. It calls the other parts in the right order.

SRP does not mean one method per class. It means things that change together stay together. Things that change for different reasons are kept apart.

  • SRP means one reason to change, or one actor, not one method per class.
  • Find out who would ask for each change.
  • Move hashing, persistence, email, audit and reporting into their own parts.
  • The service keeps only the orchestration of the use case.