1. Problem Statement — code evolution Quay lại ConfirmOrder (1.2). Khi đó ta tách Notifier ra sau interface — nhưng service vẫn gọi notifier. Giờ nghiệp vụ phình theo hướng khác: sau khi xác nhận đơn, cần thêm nhiều việc ăn theo:
// ❌ V1 — use case chính trở thành danh bạ của mọi bên quan tâm func (s *Service) ConfirmOrder(ctx context.Context, orderID string) error { /* ... load, confirm, save — NGHIỆP VỤ LÕI, 10 dòng ... */ // và cái đuôi mọc dài mãi: s.notifier.OrderConfirmed(ctx, o) // gửi mail s.loyalty.AddPoints(ctx, o.CustomerID, o.Total()) // cộng điểm s.analytics.Track(ctx, "order_confirmed", o) // sự kiện analytics s.recommender.InvalidateCache(ctx, o.CustomerID) // xóa cache gợi ý s.fraud.ReportSignal(ctx, o) // tín hiệu chống gian lận return nil } Quan sát bệnh sinh: mỗi bên quan tâm mới (team Loyalty, team Analytics…) = mở use case lõi ra sửa + thêm một dependency vào struct — trong khi nghiệp vụ “xác nhận đơn” không hề đổi. Mũi tên phụ thuộc trỏ sai chiều: module quan trọng nhất (order) phải biết mọi module ăn theo (analytics, recommender — những thứ đổi xoành xoạch). Vi phạm OCP theo trục “bên quan tâm”, vi phạm DIP về chiều ổn định. Và câu hỏi khó chịu bắt đầu xuất hiện: lỗi cộng điểm có nên làm hỏng việc xác nhận đơn không? — trong V1, có, dù chẳng ai chủ đích quyết như vậy.
...