Trong thế giới phần mềm, nơi mỗi dòng code đều có thể là “hạt giống” cho một hệ thống vững chắc hoặc một “quả bom hẹn giờ” của lỗi lầm, chúng ta – những lập trình viên – cần hơn cả khả năng viết code chạy được . Chúng ta cần viết code có thể đọc được, dễ bảo trì, và không biến thành gánh nặng trong tương lai.
Ba nguyên tắc KISS, DRY, và YAGNI là bộ ba “kim chỉ nam” đã tồn tại và chứng minh giá trị qua hàng chục năm. Chúng không phải là những câu khẩu hiệu suông, mà là kết tinh của kinh nghiệm xương máu từ vô số dự án phần mềm thành công… và cả thất bại.
Trong bài viết này, chúng ta sẽ đi sâu vào ý nghĩa, tư duy đằng sau, và cách áp dụng thực tế của ba nguyên tắc này. Hãy coi đây không chỉ là kiến thức, mà là triết lý sống còn của lập trình viên.
1. Tổng quan
KISS, DRY và YAGNI thường được gọi chung là “nguyên tắc thiết kế phần mềm” (software design principles) hoặc cụ thể hơn là “nguyên tắc lập trình” (programming principles / coding principles).
Chúng thuộc nhóm “best practices” – tức các phương pháp, nguyên tắc được công nhận rộng rãi giúp code dễ bảo trì, dễ mở rộng và giảm lỗi.

Ngoài ba nguyên tắc này, các lập trình viên còn hay nhắc đến một số nguyên tắc khác như:
- SOLID – 5 nguyên tắc thiết kế hướng đối tượng.
- GRASP – Nguyên tắc phân bổ trách nhiệm trong OOP.
- SoC (Separation of Concerns) – Tách biệt các phần chức năng để dễ quản lý.
- SNE (Simple, Not Easy) – khá giống KISS nhưng tập trung vào “giản lược nhưng không đánh đổi chất lượng”.
- Occam’s Razor – Chọn giải pháp đơn giản nhất có thể mà vẫn đáp ứng yêu cầu.
- Fail Fast – Phát hiện lỗi càng sớm càng tốt để giảm chi phí sửa chữa.
Trong phạm vi bài viết này chúng ta sẽ tập trung tìm hiểu chính về KISS, DRY và YAGNI
2. KISS — Keep It Simple, Stupid

2.1 Định nghĩa & triết lý
KISS là lời nhắc nhở: Giữ mọi thứ đơn giản nhất có thể. Trong thiết kế hệ thống và viết code, “đơn giản” không phải là bỏ bớt tính năng, mà là tránh sự phức tạp không cần thiết.
Những hệ thống phức tạp thường nảy sinh từ sự tích lũy của những quyết định nhỏ nhưng không được kiểm soát. Một hàm ban đầu chỉ 10 dòng, sau vài lần “chắp vá” trở thành 200 dòng với nhiều nhánh rẽ, khiến người đọc phải mất hàng giờ để hiểu.
2.2 Vì sao KISS quan trọng?
- Tốc độ hiểu và bảo trì: Code đơn giản giúp lập trình viên mới vào dự án có thể nhanh chóng nắm bắt.
- Giảm rủi ro lỗi: Mỗi phần logic thừa là một cơ hội để bug xuất hiện.
- Tối ưu khả năng mở rộng: Một nền tảng đơn giản dễ dàng thêm tính năng hơn nền tảng rối rắm.
2.3 Nguyên tắc áp dụng
- Luôn hỏi: “Có cách nào ngắn gọn và rõ ràng hơn không?”
- Tránh “tối ưu sớm” (premature optimization).
- Sử dụng các cấu trúc và thư viện quen thuộc thay vì “sáng tạo” những thứ không ai hiểu.
2.4 Ví dụ
Bài toán: Tính tổng giá trị đơn hàng (có giảm giá và thuế)
Bạn có một danh sách các sản phẩm trong giỏ hàng, mỗi sản phẩm có:
price
: giáquantity
: số lượng- Có thể có
discount
(tùy chọn) - Thuế VAT là 10%
Mục tiêu: Tính tổng số tiền khách phải trả.
❌ Cách viết phức tạp, vi phạm KISS
def calculate_total(cart):
total = 0
for i in range(len(cart)):
product = cart[i]
price = product["price"]
quantity = product["quantity"]
discount = 0
if "discount" in product:
discount = product["discount"]
subtotal = price * quantity
if discount > 0:
subtotal = subtotal - (subtotal * discount)
tax = subtotal * 0.1
subtotal = subtotal + tax
total = total + subtotal
return total
Vấn đề:
- Nhiều biến tạm không cần thiết.
- Quá nhiều bước tuần tự, khó nhìn ra “bức tranh tổng thể”.
- Vòng lặp dùng
range(len(cart))
không cần thiết. - Logic giảm giá và thuế tản mát, khó tái sử dụng.
✅ Cách viết KISS hơn
def calculate_total(cart):
def item_total(p):
subtotal = p["price"] * p["quantity"]
subtotal *= (1 - p.get("discount", 0))
return subtotal * 1.1 # cộng VAT 10%
return sum(item_total(product) for product in cart)
Tại sao đơn giản hơn?
- Rõ ý định: Nhìn vào là hiểu ngay “tính tổng từng sản phẩm rồi cộng lại”.
- Ít biến tạm: Không cần lưu từng giá trị trung gian nếu chỉ dùng một lần.
- Tách hàm nhỏ:
item_total
giúp đóng gói logic tính giá từng sản phẩm. - Dễ bảo trì: Nếu sau này thuế đổi từ 10% → 8%, chỉ cần sửa một chỗ.
Rút ra từ ví dụ này
- KISS không chỉ là “viết ít dòng hơn” mà là giữ cho ý tưởng trong code rõ ràng và dễ đọc.
- Người mới vào dự án đọc hàm KISS sẽ hiểu ngay mục đích và luồng xử lý, không phải “dịch” từng biến một.
- Code KISS thường ít bug hơn vì ít điểm rối loạn.
3. DRY — Don’t Repeat Yourself

3.1 Định nghĩa & triết lý
DRY kêu gọi: Không lặp lại chính mình. Nếu một logic xuất hiện ở nhiều nơi, bạn đang nhân đôi khối lượng công việc bảo trì và nhân đôi nguy cơ lỗi.
Triết lý DRY nằm ở chỗ: Mỗi ý tưởng, mỗi phần kiến thức trong hệ thống nên chỉ tồn tại ở một nơi duy nhất.
3.2 Vì sao DRY quan trọng?
- Bảo trì dễ dàng: Khi cần sửa đổi, bạn chỉ thay đổi một chỗ duy nhất.
- Giảm sai sót: Không lo sửa ở file này nhưng quên ở file khác.
- Tái sử dụng: Logic chung được gom lại thành function, module hoặc class, giúp dự án thống nhất.
3.3 Nguyên tắc áp dụng
- Khi thấy mình copy-paste code từ file này sang file khác, hãy dừng lại và nghĩ cách tách thành hàm hoặc module.
- Sử dụng inheritance hoặc composition trong OOP khi hợp lý.
- Dùng constant hoặc config file thay vì hard-code giá trị nhiều lần.
2.4 Ví dụ
Bài toán: Quản lý nhân viên và tính lương
Bạn cần viết một hệ thống nhỏ để:
- Lưu thông tin nhân viên.
- Tính lương thực nhận dựa trên lương cơ bản, thưởng và thuế.
❌ Cách viết vi phạm DRY (lặp code logic giống nhau ở nhiều chỗ)
def calculate_salary(emp):
gross_salary = emp["base_salary"] + emp["bonus"]
tax = gross_salary * 0.1
net_salary = gross_salary - tax
return net_salary
def print_salary(emp):
gross_salary = emp["base_salary"] + emp["bonus"]
tax = gross_salary * 0.1
net_salary = gross_salary - tax
print(f"{emp['name']} nhận {net_salary} VND")
Vấn đề:
- Logic tính lương (
gross_salary
,tax
,net_salary
) bị lặp lại ở cả hai hàm. - Nếu cần thay đổi thuế từ 10% → 8%, bạn phải sửa nhiều chỗ, dễ quên.
- Tăng khả năng bug khi cập nhật thiếu.
✅ Cách viết DRY (gom logic chung vào một chỗ)
def net_salary(emp):
"""Tính lương thực nhận (áp dụng DRY)"""
gross_salary = emp["base_salary"] + emp["bonus"]
tax = gross_salary * 0.1
return gross_salary - tax
def calculate_salary(emp):
return net_salary(emp)
def print_salary(emp):
print(f"{emp['name']} nhận {net_salary(emp)} VND")
Tại sao tốt hơn?
- Logic tính lương chỉ tồn tại ở một hàm duy nhất (
net_salary
). - Nếu thuế đổi, chỉ cần sửa một chỗ.
- Các hàm khác chỉ gọi lại hàm chung, không copy-paste.
Rút ra từ ví dụ này
- DRY không chỉ giúp code gọn hơn, mà bảo vệ bạn khỏi bug “update thiếu”.
- Nguyên tắc DRY đặc biệt quan trọng trong dự án lớn, nơi một đoạn logic có thể xuất hiện ở hàng chục file khác nhau.
- DRY = “Viết một lần, dùng nhiều lần” → vừa tiết kiệm thời gian, vừa giảm rủi ro.
4. YAGNI — You Aren’t Gonna Need It

4.1 Định nghĩa & triết lý
YAGNI là lời cảnh tỉnh: Đừng xây dựng những thứ bạn chưa cần. Nhiều lập trình viên có xu hướng “dự phòng” tính năng vì nghĩ rằng “sau này sẽ cần”, nhưng thực tế rất nhiều “tính năng dự phòng” không bao giờ được dùng.
4.2 Vì sao YAGNI quan trọng?
- Tiết kiệm thời gian: Tập trung làm những thứ hiện tại mang lại giá trị.
- Giảm rủi ro: Mỗi dòng code là một nơi tiềm ẩn bug, nếu chưa cần thì chưa nên viết.
- Tránh phức tạp hóa hệ thống: Tính năng dư thừa làm người khác khó hiểu code hơn.
4.3 Nguyên tắc áp dụng
- Chỉ triển khai tính năng khi có yêu cầu rõ ràng từ sản phẩm hoặc khách hàng.
- Nếu cần mở rộng sau này, hãy thiết kế code dễ mở rộng, thay vì viết sẵn mọi thứ.
- Tập trung vào MVP (Minimum Viable Product) trước.
4.4 Ví dụ
Bối cảnh
Giả sử bạn được giao nhiệm vụ viết một hàm để tính tổng các số nguyên trong một danh sách (list
).
Bạn dự đoán rằng tương lai có thể cần hỗ trợ thêm số thập phân, số phức, hoặc xử lý danh sách lồng nhau… nên bạn viết luôn một phiên bản “siêu đa năng” ngay từ đầu.
❌ Cách làm vi phạm YAGNI
def sum_list(lst, allow_float=False, allow_complex=False, recursive=False):
total = 0
for item in lst:
if isinstance(item, int):
total += item
elif allow_float and isinstance(item, float):
total += item
elif allow_complex and isinstance(item, complex):
total += item.real # giả sử chỉ cộng phần thực
elif recursive and isinstance(item, list):
total += sum_list(item, allow_float, allow_complex, recursive)
return total
# Hiện tại chỉ cần cộng số nguyên, nhưng viết quá phức tạp
print(sum_list([1, 2, 3])) # 6
Vấn đề:
- Bạn viết thêm nhiều tính năng chưa cần thiết (float, complex, recursive).
- Code khó đọc hơn, khó bảo trì hơn.
- Có khả năng phần mở rộng chưa bao giờ được dùng, gây lãng phí thời gian phát triển và kiểm thử.
✅ Cách làm theo đúng YAGNI
def sum_list(lst):
total = 0
for item in lst:
if isinstance(item, int):
total += item
return total
print(sum_list([1, 2, 3])) # 6
Giải thích:
- Bạn chỉ viết những gì cần thiết cho yêu cầu hiện tại.
- Nếu một ngày nào đó thật sự cần cộng thêm số thập phân hoặc danh sách lồng nhau, lúc đó mới mở rộng.
- Giúp code gọn gàng, dễ hiểu, và tiết kiệm thời gian phát triển.
Bài học từ YAGNI:
Đừng “tiên tri” cho tương lai khi viết code. Việc dự đoán quá nhiều nhu cầu có thể khiến phần mềm trở nên phức tạp, tốn thời gian mà chưa chắc đã dùng tới. Tập trung giải quyết đúng yêu cầu hiện tại, mở rộng khi cần thiết.
5. Mối liên hệ giữa KISS, DRY và YAGNI
Ba nguyên tắc này không tồn tại riêng lẻ, mà bổ trợ lẫn nhau:
- KISS giữ code đơn giản, giúp DRY và YAGNI dễ áp dụng.
- DRY giúp hệ thống gọn gàng, từ đó KISS được duy trì.
- YAGNI giữ cho codebase nhỏ gọn, làm KISS và DRY trở nên khả thi.
Nếu ví lập trình như xây nhà:
- KISS = bản thiết kế rõ ràng, không rối.
- DRY = dùng chung vật liệu và kỹ thuật thay vì làm mới hoàn toàn.
- YAGNI = không xây hồ bơi khi chưa ai muốn bơi.
6. Những sai lầm thường gặp khi áp dụng
- KISS nhưng quá giản lược
- Sai: Cắt bỏ tính năng quan trọng chỉ để code ngắn.
- Đúng: Giữ đủ tính năng, nhưng không thêm sự phức tạp không cần thiết.
- DRY nhưng áp dụng cực đoan
- Sai: Ép mọi thứ vào một hàm duy nhất, dẫn tới code khó đọc.
- Đúng: Gom những phần thật sự chung, giữ sự cân bằng.
- YAGNI nhưng bỏ qua tính toán mở rộng
- Sai: Không nghĩ tới khả năng mở rộng, khiến sau này phải viết lại từ đầu.
- Đúng: Thiết kế mở nhưng không code thừa.
7. Kết luận
Ba nguyên tắc KISS, DRY, và YAGNI là nền tảng của tư duy lập trình chuyên nghiệp.
- KISS nhắc bạn giữ mọi thứ rõ ràng, tránh phức tạp hóa.
- DRY đảm bảo bạn không lặp lại chính mình, giảm rủi ro và tăng khả năng bảo trì.
- YAGNI giúp bạn tập trung vào giá trị hiện tại, tránh lãng phí vào những thứ chưa chắc dùng.
Trước khi commit code, hãy tự hỏi:
- KISS — Có cách nào đơn giản hơn không?
- DRY — Mình có lặp lại ở đâu không?
- YAGNI — Mình có đang làm thừa không?
Lập trình không chỉ là “khiến máy tính chạy”, mà là viết code để con người hiểu và máy tính thực thi một cách hiệu quả. Ba nguyên tắc này chính là cầu nối giữa nghệ thuật và kỹ thuật trong lập trình.
Đọc thêm:
- SOLID là gì? Nguyên lý hoạt động và cách áp dụng vào thực tiễn
- Clean Code: Nghệ thuật viết mã sạch và bền vững trong phát triển phần mềm
Tài liệu tham khảo
- The Elements of Programming Style” – Brian W. Kernighan & P.J. Plauger
- “The Pragmatic Programmer” – Andrew Hunt & David Thomas (1999)
- “Extreme Programming Explained” – Kent Beck (1999)
- “DRY Principle” – ThoughtWorks Insights
- “YAGNI” – Martin Fowler