bài viết ngẫu nhiên
Trong dự án thực tế, code thường phình ra theo kiểu “cần gì nhét đó”. Một service ban đầu chỉ có 50 dòng, sau vài tháng bỗng thành 1000 dòng với hàng chục trách nhiệm. Lúc đó, việc bảo trì sẽ thành ác mộng.
Đây chính là lúc nguyên tắc Single Responsibility Principle (SRP) lên tiếng.
Ngắn gọn: Một class hoặc module chỉ nên có một lý do để thay đổi.
Nếu một class vừa xử lý logic business, vừa nói chuyện với database, vừa gửi notification… thì nó đã vi phạm SRP.
Giả sử bạn đang viết UserService. Và vì tiện tay, bạn để luôn mọi thứ vào đây:
@Injectable()
export class UserService {
constructor(private readonly db: DatabaseService) {}
async createUser(data: any) {
// validate
if (!data.email.includes('@')) {
throw new Error('Invalid email');
}
// save to DB
const user = await this.db.user.create({ data });
// send welcome email
await this.sendWelcomeEmail(user.email);
return user;
}
private async sendWelcomeEmail(email: string) {
// giả lập gọi 1 email provider
console.log(`Sending welcome email to ${email}`);
}
}
Thoạt nhìn thì ổn, nhưng UserService đang làm ít nhất 3 việc khác nhau:
Nếu ngày mai bạn muốn đổi provider gửi email (từ Gmail → SendGrid), bạn phải sửa vào chính UserService. Nếu muốn tái sử dụng validation ở chỗ khác, lại phải copy code. Đây chính là vi phạm SRP.
Giải pháp: chia trách nhiệm ra những class/service riêng.
@Injectable()
export class UserValidator {
validate(data: any) {
if (!data.email.includes('@')) {
throw new Error('Invalid email');
}
}
}
@Injectable()
export class EmailService {
async sendWelcomeEmail(email: string) {
console.log(`Sending welcome email to ${email}`);
}
}
@Injectable()
export class UserService {
constructor(
private readonly db: DatabaseService,
private readonly validator: UserValidator,
private readonly emailService: EmailService,
) {}
async createUser(data: any) {
this.validator.validate(data);
const user = await this.db.user.create({ data });
await this.emailService.sendWelcomeEmail(user.email);
return user;
}
}
Giờ thì:
Nếu cần đổi provider email → chỉ sửa trong EmailService. Validation logic có thể tái sử dụng cho nhiều chỗ khác.
Tất nhiên, đừng quá “xé lẻ”. Nếu app của bạn nhỏ, gom 2–3 logic trong cùng một service cũng chẳng sao. SRP chỉ thật sự phát huy khi dự án lớn dần, team nhiều người, logic phức tạp.
Single Responsibility Principle giúp code trở nên trong sáng, gọn gàng và dễ mở rộng. Mỗi class chỉ cần trả lời được một câu hỏi: “Tôi tồn tại để làm một việc duy nhất, và tôi làm nó tốt nhất.?”