Dependency Injection cơ bản
Dependency Injection (DI) — nói đơn giản là cách truyền dependency từ bên ngoài vào thay vì để class tự tạo.
Chương này giải thích tại sao DI quan trọng và khi nào nên (hoặc không nên) dùng Singleton.
1. Code thuần vs. DI Framework
Phần tiêu đề “1. Code thuần vs. DI Framework”Có hai trường phái chính:
Code thuần (Vanilla Code):
- Tự viết code để truyền dependency qua constructor.
- Ưu điểm: Rõ ràng, dễ debug, ai đọc cũng hiểu.
- Nhược điểm: Phải viết thêm boilerplate code.
Dùng DI Framework (Swinject, Koin, Hilt…)
- Ưu điểm: Giảm boilerplate, tự động resolve dependency.
- Nhược điểm: Magic ẩn sau annotation, khó debug khi sai.
Cuốn sách này ủng hộ code thuần. Đơn giản > phép thuật.
2. Tại sao cần DI?
Phần tiêu đề “2. Tại sao cần DI?”Xem xét ví dụ:
class CourseAPI { private let tutorAPI = TutorAPI() // Tự tạo — tight coupling private let todoList = TODOList() // Tự tạo — tight coupling}Vấn đề: CourseAPI bị tight coupling với TutorAPI và TODOList cụ thể. Không thể:
- Thay bằng mock khi test
- Đổi implementation (staging vs. production)
Giải pháp — DI:
class CourseAPI { private let tutorAPI: TutorAPI private let todoList: TODOList
init(tutorAPI: TutorAPI, todoList: TODOList) { self.tutorAPI = tutorAPI self.todoList = todoList }}Bây giờ ta truyền dependency từ ngoài vào → dễ test, dễ thay đổi.
3. Cạm bẫy của Singleton
Phần tiêu đề “3. Cạm bẫy của Singleton”Singleton là cách dễ nhất để tránh truyền dependency:
class TutorAPI { let api = API.shared // Global access}Tuy tiện, Singleton gây ra nhiều vấn đề:
Thread safety
Phần tiêu đề “Thread safety”Singleton là global state. Nhiều thread cùng đọc/ghi → race condition.
Ví dụ thực tế: Đang chuyển tiền thì user logout rồi login tài khoản khác. Nếu User là singleton, tiền có thể bị ghi nhầm tài khoản.
Cản trở modularization
Phần tiêu đề “Cản trở modularization”Muốn tách CourseAPI ra module riêng, nhưng nó dùng User.shared (singleton ở module App). Kết quả: circular dependency — không tách ra được.
Khó scale
Phần tiêu đề “Khó scale”“Cái này chỉ cần 1 instance” — cho đến khi product manager nói “Hỗ trợ multi-account”. Lúc đó refactor singleton thành DI rất tốn công.
4. Khi nào Singleton hợp lý?
Phần tiêu đề “4. Khi nào Singleton hợp lý?”Singleton không hoàn toàn xấu. Phù hợp cho:
- Logger: Write-only, ít rủi ro conflict.
- Database/Cache coordinator: Đảm bảo single access point tránh data corruption.
Kết luận: Mặc định dùng DI (truyền dependency qua constructor). Chỉ dùng Singleton khi có lý do rõ ràng. Code thuần > DI framework cho hầu hết trường hợp.