Áp dụng triết lý "Hệ thống Đơn giản và Tốt nhất Hiện tại" trong thiết kế phần mềm

Công nghệ07 tháng 5, 2026·8 phút đọc

Daniel Terhorst-North lập luận rằng việc phải lựa chọn giữa tích lũy nợ kỹ thuật hay trễ hạn giao dự án thực chất là một sự lựa chọn sai lầm. Các lập trình viên thường có xu hướng tổng quát hóa vấn đề thay vì giải quyết nhu cầu hiện tại, dẫn đến sự phức tạp không cần thiết. Ông đề xuất phương pháp "Hệ thống Đơn giản và Tốt nhất Hiện tại" (BSSN) để cân bằng giữa chất lượng và tiến độ.

Áp dụng triết lý "Hệ thống Đơn giản và Tốt nhất Hiện tại" trong thiết kế phần mềm

Tại hội nghị GOTO Copenhagen, Daniel Terhorst-North đã có một bài phát biểu mang tên "Best Simple System for Now" (Hệ thống Đơn giản và Tốt nhất Hiện tại), trong đó ông lập luận rằng việc lựa chọn giữa việc tích lũy nợ kỹ thuật hay trễ hạn giao dự án là một sự lựa chọn giả tạo. Nhiều lập trình viên thường yêu thích việc tổng quát hóa (generalize) thay vì giải quyết triệt để vấn đề ngay trước mắt, điều này vô tình làm cho những thay đổi trong tương lai trở nên khó khăn hơn. Thay vào đó, chúng ta cần xây dựng các kỹ năng và bản năng để giữ cho mọi thứ luôn đơn giản.

Sự đánh đổi không cần thiết

Nhiều lập trình viên nghĩ rằng họ liên tục phải đưa ra sự đánh đổi: hoặc là gánh nợ kỹ thuật để đáp ứng thời hạn, hoặc là trì hoãn thời hạn do bộ phận quản lý áp đặt để có thời gian "làm đúng cách".

Tuy nhiên, Terhorst-North cho rằng với những sự đánh đổi và quyết định thiết kế đúng đắn, bạn hoàn toàn có thể có một sản phẩm có thể xuất xưởng (shippable) mọi lúc, trong khi vẫn giữ cho chất lượng ở mức đủ cao.

Đặc điểm của BSSN

Phương pháp "Hệ thống Đơn giản và Tốt nhất Hiện tại" (BSSN) đáp ứng ba đặc điểm chính:

  • Đơn giản (Simple): Không có mã thừa hay mã mang tính phỏng đoán, chỉ bao gồm những thứ cần thiết cho lúc này. Thiết kế mang tính "tương lai" theo nghĩa là các thay đổi dễ dàng thực hiện nhờ sự đơn giản của nó, chứ không phải vì chúng ta đặt các điểm mở rộng ở khắp nơi nơi mà chúng ta nghĩ rằng có thể sẽ thay đổi.
  • Hiện tại (for Now): Đáp ứng tất cả các yêu cầu hiện tại, trong khi cố ý bỏ qua hoặc hoãn lại bất kỳ nhu cầu nào trong tương lai.
  • Tốt nhất (Best): Bất kỳ mã nào hiện có đều phải được viết theo một tiêu chuẩn phù hợp. Đối với mã sản phẩm (production code), điều này có nghĩa là có giám sát (telemetry), kiểm thử tự động, tài liệu API, quy trình triển khai tự động, v.v. Đối với các "bản phác thảo" nơi bạn đang khám phá ý tưởng, tiêu chuẩn có thể thấp hơn. Nhưng trong mọi trường hợp, không có lý do nào để biện minh cho việc đặt tên kém, sự phức tạp không cần thiết — các tệp nguồn quá lớn, các phương thức hoặc hàm cồng kềnh, cấu trúc tệp kém — mà những "thói quen tốt" không thể xử lý được.

Nhìn thẳng vào sự thật

Terhorst-North đã trích dẫn mô tả của Terry Pratchett trong cuốn tiểu thuyết giả tưởng Wintersmith về các kỹ năng mà một phù thủy cần có: "First Sight and Second Thoughts" (Nhìn thấy đầu tiên và Suy nghĩ thứ hai). Nhìn thấy đầu tiên để thấy những gì thực sự ở đó, và Suy nghĩ thứ hai để theo dõi Những suy nghĩ đầu tiên nhằm kiểm tra xem chúng có đang suy nghĩ đúng không.

Thiết kế cho "hiện tại" liên quan đến việc "nhìn thấy đầu tiên": nhìn thấy những gì thực sự ở đó.

"Chúng ta có cần một rules engine (công cụ quy tắc) không, hay đây chỉ là nửa tá câu lệnh if được ngụy trang? Azure-hosted Kubernetes có phải là nền tảng triển khai phù hợp cho ứng dụng web nội bộ của bạn với 10 người dùng không?"

Các lập trình viên yêu thích tổng quát hóa, điều này giới thiệu các lớp độ phức tạp mà chúng ta đã học cách bỏ qua. Chúng ta đã mất đi "nhìn thấy đầu tiên", Terhorst-North lập luận. Điều này có thể làm cho các thay đổi trong tương lai trở nên khó khăn, đặc biệt nếu chúng đi theo một hướng mà chúng ta không dự đoán trước.

Lời khuyên để giữ mọi thứ đơn giản

Lời khuyên của Terhorst-North để giữ mọi thứ đơn giản là hãy cứ thử làm, biết rằng bạn sẽ sai lần lượt. Bạn sẽ suy nghĩ quá nhiều, viết quá nhiều mã, và quá chú trọng vào một hướng này hay hướng khác trong khi xây dựng các kỹ năng và bản năng giữ cho mọi thứ trở nên đơn giản một cách phi lý.

Hầu hết các thói quen xấu và hành vi đã học được ngăn cản mọi người thiết kế các hệ thống đơn giản tập trung vào bản chất vấn đề.

"Là một lập trình viên với nhiều thập kỷ kinh nghiệm, tôi có cái tôi rất lớn và tôi tin rằng mình biết rất nhiều về lập trình, vì vậy tôi thấy khó khăn khi phải thừa nhận rằng mình sẽ gần đúng nhưng sai lầm mỗi khi cố gắng dự đoán hướng đi tương lai của một sản phẩm hoặc cơ sở mã."

Mặc dù ông cố gắng tuân thủ các thói quen BSSN bất cứ khi nào viết mã, ông vẫn thấy mình đang suy nghĩ quá mức hoặc thiết kế quá mức (over-engineering) một giải pháp "để phòng hờ".

"Cách duy nhất để vượt qua điều này mà tôi tìm thấy là thực hành, thực hành và thực hành! Trong trường hợp của tôi, tôi thấy mình trung thực hơn nhiều khi tôi lập cặp (pairing); người bạn lập cặp của tôi ngăn tôi mạ vàng (gold-plating) giải pháp, hoặc thách thức các giả định của tôi về nơi chúng ta sẽ đi tiếp theo, theo cách giúp tôi đi đúng hướng."

Phỏng vấn Daniel Terhorst-North

InfoQ: Tại sao ông lại khuyên không nên dự đoán tương lai theo bất kỳ cách nào?

Daniel Terhorst-North: Đây là điểm mấu chốt của việc thiết kế cho hiện tại. Một sản phẩm có thể thay đổi theo mọi cách vào bất kỳ lúc nào và vì bất kỳ lý do gì. Tôi gọi đây là "các chiều của thay đổi" (dimensions of change).

Dưới đây là một số ví dụ:

  • Nhiều loại báo cáo bổ sung nhưng chúng tôi đã chọn một công cụ báo cáo dành riêng cho miền (domain-specific) có tính linh hoạt rất lớn về miền nhưng không thể kết nối với tất cả các nguồn dữ liệu bổ sung này.
  • Nhiều biến thể của cùng một báo cáo, nhưng việc thêm một biến thể mới tốn kém và tốn thời gian vì chúng tôi đã khóa nó "vì lý do hiệu suất".
  • Độ phức tạp của báo cáo tăng lên vì tuân thủ cần nguồn gốc dữ liệu (data provenance), nhưng điều này sẽ làm chậm đáng kể việc tạo báo cáo vì chúng tôi đã tối ưu hóa cho quy mô thay vì chi tiết.
  • Chúng tôi muốn một bảng điều khiển (dashboard) thay thế, vì vậy "báo cáo" sẽ được đánh giá động.

Những điều này không phải là giả định; tất cả những điều này đã xảy ra với tôi! Bất kỳ tương lai nào trong số các khả năng này mà chúng ta dự đoán hoặc phòng ngừa trong thiết kế của mình, chúng ta đều đang đánh đổi với những cái khác và giới thiệu sự phức tạp hoàn toàn mang tính phỏng đoán.

Vị trí của tôi là chìa khóa thực sự cho sự "linh hoạt" và "khả năng mở rộng" là giữ mọi thứ càng đơn giản càng tốt để bạn có thể xoay trục (pivot) hướng tới thay đổi tiếp theo, bất kể nó là gì.

InfoQ: Có thể làm gì để giữ cho hệ thống của chúng ta đơn giản và tốt nhất?

Daniel Terhorst-North: Tôi ủng hộ việc "giả vờ cho đến khi bạn làm được" (fake it ’til you make it), hay đúng hơn là "hành động theo cách của bạn để đến một tư duy mới". Bạn không thể thuyết phục ai đó rằng việc liên tục giữ cho một hệ thống đơn giản là khả thi, cũng không thể thuyết phục họ rằng bất kỳ thay đổi tương lai nào sẽ dễ dàng hơn khi cơ sở mã đơn giản hơn; họ phải tự trải nghiệm điều đó nhiều lần. Một cách trớ trêu, kỹ sư càng có kinh nghiệm thì họ càng khó tin rằng họ không nên dự đoán chiều thay đổi tiếp theo. Sau tất cả, phải chăng đó là ý nghĩa của tất cả kinh nghiệm đó?

Tôi không còn ám ảnh về việc liệu mình có "đúng" thiết kế hay không. Tôi đủ tự tin vào các thói quen của mình — TDD, kiểm soát phiên bản, tái cấu trúc (refactoring), "phác thảo" mã — để biết rằng tôi có thể hoàn tác nhanh chóng bất kỳ quyết định tồi nào và đi theo một hướng khác. Tôi cũng đã tự dạy mình không tin vào độc thoại nội tâm khi nó nói với tôi rằng nó "biết" điều gì sẽ đến tiếp theo.

Chia sẻ:FacebookX
Nội dung tổng hợp bằng AI, mang tính tham khảo. Xem bài gốc ↗