System DesignEasy
Explain Single Responsibility Principle with a code example
SRP: a class should have one reason to change.
Violation — UserService doing too much:
public class UserService {
public void Register(string email, string password) {
// validate
if (!email.Contains("@")) throw new ArgumentException();
// hash password
var hash = BCrypt.HashPassword(password);
// persist
db.Users.Add(new User { Email = email, Hash = hash });
db.SaveChanges();
// send welcome email
smtp.Send(email, "Welcome", "Hi there");
// log
File.AppendAllText("audit.log", $"{DateTime.Now}: {email}\n");
}
}
Five reasons to change: validation rules, hashing algo, persistence, email content, audit format. Each touches the same file.
Refactored — each class owns one concern:
public class UserRegistration(
IEmailValidator validator,
IPasswordHasher hasher,
IUserRepository users,
IWelcomeEmailSender mailer,
IAuditLog audit)
{
public async Task RegisterAsync(string email, string password) {
validator.Validate(email);
var hash = hasher.Hash(password);
await users.AddAsync(new User { Email = email, Hash = hash });
await mailer.SendAsync(email);
await audit.LogAsync(AuditEvent.UserRegistered, email);
}
}
UserRegistration orchestrates. Each collaborator has one job. Changing the email content doesn't touch the registration class.
Useful test: if two different stakeholders (design, finance, security) edit the same class, you've violated SRP.