If the chef also had to serve, clean, AND handle money, one bad day could mess up EVERYTHING!
Simple Rule: If you describe your class and use the word “AND”, you might be breaking SRP!❌ “This class saves users AND sends emails AND logs activity”
✅ “This class saves users”
The hospital analogy: In a hospital, a surgeon operates, a pharmacist dispenses medication, and a radiologist reads scans. They all work on the same patient, but each has a distinct responsibility. If the surgeon also had to compound medications, a change in pharmaceutical regulations would force the surgeon to retrain — even though it has nothing to do with surgery. SRP works the same way: when one class has multiple responsibilities, a change in one area forces modifications that ripple into unrelated areas.
# Each class has ONE job!class UserRepository: """ONLY handles user data storage""" def __init__(self, db_connection): self.db = db_connection def create(self, user_data): self.db.execute("INSERT INTO users ...", user_data) def find_by_id(self, user_id): return self.db.query("SELECT * FROM users WHERE id = ?", user_id) def update(self, user_id, data): self.db.execute("UPDATE users SET ...", data) def delete(self, user_id): self.db.execute("DELETE FROM users WHERE id = ?", user_id)class PasswordService: """ONLY handles password operations""" def hash(self, password): import hashlib return hashlib.sha256(password.encode()).hexdigest() def verify(self, password, hashed): return self.hash(password) == hashedclass EmailService: """ONLY handles email sending""" def __init__(self, smtp_config): self.config = smtp_config def send(self, to, subject, body): # All email logic here print(f"📧 Sending '{subject}' to {to}") def send_welcome(self, user_email): self.send(user_email, "Welcome!", "Thanks for joining!") def send_password_reset(self, user_email, reset_link): self.send(user_email, "Reset Password", f"Click: {reset_link}")class ActivityLogger: """ONLY handles logging""" def __init__(self, log_file): self.log_file = log_file def log(self, user_id, action): with open(self.log_file, 'a') as f: from datetime import datetime timestamp = datetime.now().isoformat() f.write(f"[{timestamp}] User {user_id}: {action}\n")class UserReportGenerator: """ONLY generates reports""" def __init__(self, user_repository): self.repo = user_repository def generate_summary(self): users = self.repo.find_all() return { "total": len(users), "active": sum(1 for u in users if u.is_active) }# DESIGN REASONING: Now each class has ONE reason to change.# If the email provider switches from SMTP to SendGrid, only# EmailService changes. If the database schema evolves, only# UserRepository changes. The blast radius of any change is# contained to a single class.# The UserService coordinates them (this is called a "Facade"):class UserService: """Coordinates user operations using focused services. This class orchestrates but does not implement any single concern.""" def __init__(self): self.user_repo = UserRepository(db_connection) self.password_service = PasswordService() self.email_service = EmailService(smtp_config) self.logger = ActivityLogger('activity.log') def register_user(self, name, email, password): # Each service handles its own concern -- UserService just choreographs hashed_pw = self.password_service.hash(password) user = self.user_repo.create({'name': name, 'email': email, 'password': hashed_pw}) self.email_service.send_welcome(email) self.logger.log(user.id, 'registered') return user
SRP in LLD interviews: When you present a class diagram, interviewers mentally check if each class has a single, clear responsibility. The most common mistake candidates make is creating a “God class” — a BookingManager that handles reservation logic, payment processing, email notifications, and database persistence all in one. Instead, separate these into ReservationService, PaymentService, NotificationService, and BookingRepository. When the interviewer asks “what happens if we need to switch from email to push notifications?”, you can say “only the NotificationService changes.” That one sentence demonstrates SRP understanding. The rule of thumb: if a class name ends in “Manager” or “Handler” and has more than 5-6 methods, it probably violates SRP.