← SOLID Principles

Bài 1 · Vận dụng · 16 phút· Cập nhật 10/06/2026

Tổng Quan

Biên soạn bởi Nguyễn Anh Tuấn

SOLID là gì? Ưu nhược điểm. Khi nào nên áp dụng, và áp dụng tới mức nào để không bị over-engineering.

SOLID không ra đời để làm code trông "học thuật" hơn. Nó ra đời từ một nỗi đau rất thực dụng: phần mềm càng sống lâu, càng nhiều người sửa, càng dễ biến thành một khối khó đổi.

Lúc mới viết, code thường còn nhỏ. Sau vài tháng, một yêu cầu mới có thể kéo theo sửa nhiều module; sửa checkout lại vỡ email; đổi database lại ảnh hưởng nghiệp vụ; muốn viết test nhưng service kéo theo quá nhiều chi tiết hạ tầng. Đó là lúc team bắt đầu cần nguyên tắc thiết kế, không chỉ cần cú pháp.

  • Dự án càng sống lâu thì chi phí thay đổi càng quan trọng.
  • Team càng đông thì ranh giới trách nhiệm càng cần rõ.
  • Yêu cầu càng hay đổi thì dependency cứng càng dễ gây chậm và lỗi.

Các nguyên tắc đứng sau SOLID đến từ cộng đồng thiết kế hướng đối tượng (OOP) cuối thập niên 1990 và đầu thập niên 2000. Robert C. Martin, thường được biết tới với tên Uncle Bob, phổ biến chúng trong bài Design Principles and Design Patterns năm 2000 và các sách về Agile/OOP sau đó.

Ban đầu chúng là các nguyên tắc thiết kế lớp hướng đối tượng. Sau này Michael Feathers được ghi công vì đề xuất acronym SOLID, giúp 5 nguyên tắc dễ nhớ hơn:

SSingle Responsibility - một module nên có một trách nhiệm chính.
OOpen/Closed - mở để mở rộng, đóng để hạn chế sửa code ổn định.
LLiskov Substitution - biến thể thay được kiểu gốc mà không phá hành vi.
IInterface Segregation - interface nhỏ, đúng nhu cầu của client.
DDependency Inversion - module cấp cao phụ thuộc abstraction, không phụ thuộc chi tiết implementation.

Ghi công

Khoá này giữ các thuật ngữ như interface, implementation, abstraction, dependency bằng tiếng Anh khi dịch ra dễ gây nhầm. Mục tiêu là hiểu đúng khái niệm để đọc tài liệu và trao đổi trong team.

SOLID hữu ích nhất khi chi phí thay đổi bắt đầu lớn hơn chi phí thiết kế. Nói cách khác: nếu phần mềm còn sống lâu, còn đổi yêu cầu, còn nhiều người chạm vào, thì việc giảm coupling và tách trách nhiệm sẽ tiết kiệm công về sau.

Bối cảnhSOLID ít cầnSOLID đáng cân nhắc
Tuổi thọ dự ánScript một lần, prototype ngắnSản phẩm sống nhiều tháng hoặc nhiều năm
Mức đổi yêu cầuÍt đổi, phạm vi rõNhiều biến thể, khách hàng hay đổi luồng
Số người tham giaMột người, ít bàn giaoNhiều dev, nhiều review, cần chia module
Rủi ro khi sửa saiSai dễ xoá, dễ viết lạiSai ảnh hưởng dữ liệu, tiền, bảo mật, vận hành

Một hiểu lầm phổ biến là "đã học SOLID thì phải áp dụng đủ cả 5 nguyên tắc ở mọi nơi". Cách nghĩ đó dễ đẩy team vào over-engineering: nhiều class, nhiều interface, nhiều file, nhưng luồng nghiệp vụ lại khó đọc hơn.

  • SOLID là bộ câu hỏi thiết kế, không phải checklist để tích đủ.
  • Có module chỉ cần SRP: tách trách nhiệm cho dễ đọc và dễ test.
  • Có ranh giới I/O nên ưu tiên DIP: database, email, payment, API ngoài.
  • OCP, LSP, ISP đáng đầu tư hơn khi hệ thống có nhiều biến thể và nhiều client.

Trung thực

Nếu một abstraction chỉ có một implementation, không có kế hoạch thay thế, và làm người mới đọc code lâu hơn, đó có thể là chi phí chưa đáng trả. KISS và YAGNI vẫn phải đi cùng SOLID.

Áp dụng SOLID giống như trả một khoản chi phí thiết kế trước để giảm chi phí thay đổi sau này. Câu hỏi không phải "SOLID tốt hay xấu?", mà là "với dự án này, khoản chi đó có đáng không?"

Lợi ích thường thấy

  • Thay đổi ít lan ra ngoài module liên quan.
  • Test nghiệp vụ dễ hơn vì dependency có thể thay bằng fake hoặc mock data.
  • Thêm biến thể mới ít phải sửa code ổn định.
  • Ranh giới module rõ hơn, review dễ hơn.

Chi phí phải trả

  • Team cần học chung thuật ngữ và cách review.
  • Giai đoạn đầu có thể viết nhiều file hơn.
  • Abstraction sai chỗ làm code khó lần theo.
  • Legacy code cần test đỡ lưng trước khi refactor mạnh.

SOLID không chỉ là quyết định kỹ thuật. Nó là quyết định của team. Nếu team chưa cùng hiểu interface, dependency injection, unit test, refactor và code review, việc yêu cầu "áp dụng SOLID" có thể tạo ra 5 kiểu code khác nhau.

  • Team senior, có test và review đều: có thể áp dụng sâu ở module lõi và ranh giới hạ tầng.
  • Team hỗn hợp: chọn 1-2 nguyên tắc dễ thống nhất trước, viết guideline ngắn và review bằng ví dụ.
  • Team mới hoặc deadline gấp: ưu tiên đọc dễ, test được phần quan trọng, tránh coupling lộ rõ.
  • Team legacy: không refactor hàng loạt; chọn điểm đau, viết characterization test, cải thiện dần.

Câu hỏi nên hỏi trước khi áp dụng

Team có đủ thời gian học không? Có ai review được thiết kế không? Có test để bảo vệ refactor không? Phần nào của hệ thống đổi thường xuyên nhất? Nếu trả lời chưa rõ, hãy thử trên một module nhỏ trước.

Trước khi đưa SOLID vào một dự án, team có thể dùng khung 4 bước này trong buổi technical planning hoặc trước một đợt refactor:

  • Bước 1: chấm bối cảnh dự án - tuổi thọ, tần suất đổi yêu cầu, số người cùng sửa, rủi ro lỗi.
  • Bước 2: chấm năng lực team - OOP, interface, unit test, refactor, code review.
  • Bước 3: chọn mức áp dụng - nhẹ, vừa, hoặc mạnh; ghi rõ nguyên tắc nào ưu tiên trước.
  • Bước 4: đo lại sau 2-4 tuần - PR có dễ review hơn không, test có dễ viết hơn không, bug có giảm không.

Gợi ý mức áp dụng

Mức nhẹ: đặt tên rõ, tách trách nhiệm, hạn chế God class. Mức vừa: thêm interface ở ranh giới hay đổi, test nghiệp vụ bằng fake/mock. Mức mạnh: thiết kế plugin/strategy/module lõi theo abstraction rõ, có guideline và review nghiêm.

Bài tổng quan chỉ giúp bạn ra quyết định có nên học và áp dụng SOLID ở mức nào. Các bài sau mới đi vào từng nguyên tắc bằng ví dụ TypeScript trước/sau:

  • Bài 2: Single Responsibility - tách trách nhiệm để module chỉ có một lý do chính để đổi.
  • Bài 3: Open/Closed - mở rộng bằng đa hình, Strategy hoặc registry thay vì sửa nhánh if cũ.
  • Bài 4-6: LSP, ISP, DIP - giữ lời hứa kế thừa, chia interface nhỏ, đảo chiều phụ thuộc.
  • Bài 7-8: áp dụng tổng hợp và refactor một module legacy có test đỡ lưng.

Đi tiếp

Bài kế tiếp là S - Single Responsibility. Hãy đọc bài đó như một bước đầu nhẹ nhàng: tách trách nhiệm trước, rồi mới nói tới các abstraction phức tạp hơn.

Câu hỏi thường gặp

Không bắt buộc. Một team có thể bắt đầu từ SRP để tách trách nhiệm, DIP ở ranh giới I/O để dễ test, rồi học OCP/LSP/ISP khi gặp nhu cầu mở rộng. Áp dụng theo rủi ro và năng lực team tốt hơn làm đủ cho đẹp.

Có thể dùng ở mức nhẹ: đặt tên rõ, tách trách nhiệm rõ, tránh coupling quá lộ. Nhưng đừng tạo nhiều interface, factory, class trung gian nếu dự án chỉ vài file và ít khả năng đổi yêu cầu.

Đừng đưa thẳng vào deadline gấp. Hãy học chung thuật ngữ, review code mẫu, refactor một module nhỏ có test, rồi rút ra quy ước nội bộ. Mục tiêu là team hiểu cùng một cách, không phải mỗi người áp dụng theo một kiểu.

Không. Clean Code giúp code ở mức câu chữ, hàm, tên gọi dễ đọc. KISS và YAGNI nhắc team giữ thiết kế đơn giản, chưa cần thì chưa làm. SOLID bổ sung ở tầng thiết kế lớp, module và dependency.

Khi thay đổi quan trọng đã dễ test, ranh giới module đủ rõ, và việc tách thêm chỉ làm team mất thời gian đọc code. Thiết kế tốt là thiết kế giúp dự án đổi với chi phí thấp, không phải thiết kế có nhiều abstraction nhất.

Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.

Tick những điều em tự tin làm được sau khi học bài này. 0/6

Trả lời vài câu để chắc rằng em đã nắm bài.

Câu 1/3 Điểm: 0

Ai là người đúc kết & phổ biến 5 nguyên tắc SOLID?

Bài tập về nhà

  1. 1

    Thuộc 5 chữ cái

    Viết ra S-O-L-I-D, mỗi chữ một câu mô tả bằng lời của mèo con.

    ✅ Hoàn thành khi: Đủ 5 nguyên tắc; mỗi câu nêu đúng ý chính, không chép nguyên văn bảng trong bài.

  2. 2

    Kể lại lịch sử

    Viết đoạn 5-7 câu: SOLID xuất hiện trong bối cảnh nào, ai phổ biến, acronym do ai đề xuất, vì sao OOP cần các nguyên tắc này.

    ✅ Hoàn thành khi: Có mốc năm 2000, Robert C. Martin, Michael Feathers, và bối cảnh phần mềm cần dễ bảo trì.

  3. 3

    Chấm điểm dự án

    Chọn một dự án của mèo con. Chấm 1-5 cho bốn yếu tố: thời gian sống, tần suất đổi yêu cầu, số người cùng sửa, rủi ro khi sửa sai.

    ✅ Hoàn thành khi: Có điểm cho 4 yếu tố và kết luận dự án nên áp dụng SOLID nhẹ, vừa, hay mạnh.

  4. 4

    Đánh giá team

    Liệt kê kiến thức hiện có của team: OOP, interface, unit test, refactor, code review. Mỗi mục ghi: đã vững, đang học, hay chưa có.

    ✅ Hoàn thành khi: Có bảng đánh giá năng lực và ít nhất 2 việc cần chuẩn bị trước khi áp SOLID rộng.

  5. 5

    Cân thiệt hơn

    Chọn một nguyên tắc SOLID muốn áp dụng trước. Viết 2 lợi ích mong đợi và 2 chi phí hoặc rủi ro cho team.

    ✅ Hoàn thành khi: Lợi ích và chi phí gắn với bối cảnh dự án, không nói chung chung.

  6. 6

    Quy ước thử nghiệm

    Viết một quy ước 3 dòng cho team: áp dụng SOLID ở đâu, chưa áp dụng ở đâu, và tiêu chí xem lại sau 2 tuần.

    ✅ Hoàn thành khi: Quy ước đủ cụ thể để một pull request có thể được review theo đó.