- Chỉ ra vấn đề sử dụng cấu trúc hệ thống phức tạp không cần thiết dù số người dùng thực tế rất ít
- Đưa ra ví dụ về việc kết hợp bừa bãi nhiều công nghệ như Redis, MongoDB, Kubernetes, microservices
- Nhấn mạnh rằng trong tình huống này, chỉ cần một instance Postgres và cấu hình máy chủ đơn giản là đủ
- Nhấn mạnh rằng phức tạp không phải là phẩm chất đáng ca ngợi, và chỉ nên mở rộng khi nhu cầu đã được chứng minh
- Nhắc lại rằng startup và các nhóm phát triển cần tuân thủ nguyên tắc thiết kế đơn giản phù hợp với quy mô
Lạm dụng stack công nghệ không cần thiết
- Phê phán sự kết hợp công nghệ được chọn một cách ngẫu nhiên, chẳng hạn như dùng Redis và MongoDB cùng lúc
- Đặt ra các câu hỏi như: “Tại sao Redis lại đang nói chuyện với MongoDB?”, “Tại sao lại dùng MongoDB?”
- Chỉ ra việc áp dụng hệ thống phân tán dù số người dùng thực tế chỉ là 12 người (trong đó 6 là tài khoản thử nghiệm)
- Nêu đây là trường hợp chọn mở rộng quá mức dù chỉ một instance Postgres là đủ
Triển khai và hạ tầng bị làm quá mức
- Cấu hình hiện tại: 15 microservice, 8 cơ sở dữ liệu, cụm Kubernetes cho 3 môi trường, 4 hàng đợi thông điệp, service mesh, pipeline CI/CD mất 2 giờ
- Cấu hình cần thiết chỉ là một máy chủ đơn, Postgres, và cùng lắm là Redis để caching
- Đối chiếu rõ ràng sự phức tạp hạ tầng quá mức so với nhu cầu thực tế
Độ phức tạp hệ thống và khả năng giải thích
- Chỉ ra rằng nếu phải dùng một sơ đồ rối như mì spaghetti để giải thích hệ thống cho một lập trình viên junior thì đó là dấu hiệu có vấn đề
- Tóm tắt thông điệp cốt lõi bằng câu: Phức tạp không phải là phẩm chất đáng ca ngợi
- Nhấn mạnh cần bắt đầu đơn giản, và chỉ thêm độ phức tạp khi nhu cầu đã được chứng minh
Bài học cốt lõi
- Việc chọn công nghệ và thiết kế hệ thống cần được đơn giản hóa cho phù hợp với quy mô và mức sử dụng thực tế
- Mở rộng bừa bãi và đưa vào stack công nghệ quá mức sẽ làm giảm khả năng bảo trì và hiệu quả
- Điều quan trọng với startup hoặc nhóm nhỏ là giữ được “sự đơn giản phù hợp với quy mô”
1 bình luận
Ý kiến trên Hacker News
Đôi khi kiểu hành động này đơn giản giống như trì hoãn (procrastination)
Vì không muốn nói chuyện với khách hàng, nhà đầu tư hay đội pháp lý nên thay vào đó lại làm những việc “thú vị” dưới góc nhìn kỹ sư
Bề ngoài trông có vẻ năng suất nhưng thực ra chỉ đang giậm chân tại chỗ
Nếu mỗi ngày không cố tình làm một vài việc khó chịu thì con người sẽ dần thụt lùi, và về sau sẽ phải đối mặt với những vấn đề lớn lẽ ra có thể tránh được
Điều này không chỉ đúng với phần mềm mà còn đúng với cuộc sống nói chung
Tôi đã học được rằng muốn kiếm tiền thì phải làm đúng việc theo ưu tiên, chứ không phải việc thú vị
Hay là để thỏa mãn tham vọng về kiến trúc lý tưởng của những CTO hay VPE xa rời thực tế?
Tôi nhớ trước đây từng có những màn đấu trí trong phỏng vấn thiết kế hệ thống quanh chuyện monolithic vs microservices
Cuối cùng thì người có quyền lực thường đã rất rõ họ muốn đi theo hướng nào, và chống lại điều đó là đốt vốn chính trị của bản thân
Kiểu như liệt kê đầy tự hào: “Tôi đã nối ABC với XYZ”
Cũng có động cơ muốn làm cho CV trông hoành tráng hơn
Thực ra phần lớn dự án hoàn toàn có thể làm được bằng công nghệ từ thập niên 1990, nhưng chỉ cần có những từ như hệ thống phân tán thì nghe sẽ “ngầu” hơn rất nhiều
Vì văn hóa tuyển dụng lệch lạc của ngành, đầu bếp không được công nhận vì dùng dao giỏi mà phải dùng “đúng thương hiệu dao” mới được đánh giá cao
Ví dụ DuckDuckGo chỉ yêu cầu thuật toán và cấu trúc dữ liệu, rồi chỉ nói thêm “nhân tiện chúng tôi dùng Perl”
Stream cung cấp khóa học 10 tuần cho ứng viên chưa biết Go, và Jane Street cũng không yêu cầu kinh nghiệm với OCaml
bevuta IT GmbH nơi tôi làm việc cũng cho phép nhân viên học Clojure sau khi vào công ty
Cách tiếp cận này hoàn toàn khác với những tin tuyển dụng lỗi thời kiểu “10 năm kinh nghiệm Ruby on Rails”
Chỉ vì tôi muốn thử cái mới và muốn đem ra so sánh
Cuối cùng thực tế của ngành lại là ngồi bàn về sự phức tạp không cần thiết chỉ để phục vụ vài trăm người dùng
Câu “cache bằng Redis” xuất hiện quá thường xuyên, nhưng thật ra Postgres cũng đã đủ tốt
Việc cứ nhất quyết dùng Redis có vẻ cho thấy chính tác giả cũng không cưỡng lại được ham muốn overengineering
Khi quy mô còn nhỏ thì chưa cần cache, còn dữ liệu tạm thời thì đặt ở một hệ thống riêng sẽ hấp dẫn hơn
Phần lớn lớp trừu tượng cache trong framework cũng được thiết kế với Redis trong đầu
Tốt nhất là bắt đầu bằng cache in-memory, rồi khi cần hãy thêm Redis
Nhưng Redis/Valkey thì quá tay. memcached đơn giản và thực tế hơn nhiều
Vì nó không lưu trạng thái như Redis nên tránh được những mẫu thiết kế tệ phụ thuộc vào tính nhất quán của cache
Cache trong DB thì chậm vì phải đi qua file system
Việc viết query cho hiệu quả lại là một vấn đề hoàn toàn khác
Khi làm cho Postgres nhanh trở lại thì có thể bỏ Redis đi, nhưng thường người ta cứ để nguyên
Trong một web app chạy trên AWS Lambda, khi xử lý 1000 request mỗi giây thì Postgres khá vất vả còn Redis thì rất ổn
Nhờ sự đơn giản nên trong những trường hợp như vậy nó đáng để dùng
Điều thú vị là tác giả nói về “sự đơn giản” nhưng lại dựng trang bằng Tailwind + JS framework + bundler
Trong khi lẽ ra có thể làm bằng HTML thuần
Vì vậy tôi xin giới thiệu framework web đơn giản mà bạn có thể tự xây: MastroJS
Thực tế nó chỉ tạo ra CSS cho những utility class được dùng
Tweet gốc bắt nguồn từ tweet năm 2013 của Jeff Atwood
Hiện tại tôi cũng đang cân nhắc một quyết định tương tự
Nếu là sản phẩm chưa được thị trường kiểm chứng thì nên bắt đầu nhỏ và nhanh để tạo ra một MVP có thể pivot
Ngược lại, nếu cần cho nhà đầu tư hay doanh nghiệp lớn thấy năng lực thiết kế có thể mở rộng, thì nên chọn cấu trúc có khả năng scale ngay từ đầu
Nếu mô hình kinh doanh chỉ có thể tồn tại khi tăng trưởng đến mức một DB đơn lẻ không gánh nổi, thì về lâu dài sẽ có lợi hơn nếu đi theo kiến trúc có khả năng mở rộng ngay từ đầu
Với người đang làm việc giữa những cơn ác mộng về hạ tầng, “sự đơn giản” có thể nghe rất viển vông
Nhưng rất nhiều sự phức tạp tồn tại không hẳn vì kỹ thuật mà để giải quyết vấn đề tổ chức
Tự động hóa triển khai, dự phòng cho sự cố, CI pipeline, quản lý secret, caching... đều là những chốt an toàn để bảo vệ đội ngũ
Bỏ qua những thứ này sẽ rất rủi ro khi làm việc theo nhóm
SQLite cũng hoàn toàn dùng được trong production, nhưng định kiến “chỉ để test” vẫn lan rộng
Thiết lập mặc định của nhiều PaaS cũng phức tạp một cách không cần thiết
Hãy bắt đầu bằng quy trình build dựa trên checklist, rồi khi nó ổn định thì mở rộng sang tự động hóa
Tôi muốn thấy những trường hợp microservices thực sự cần thiết ở các dịch vụ không phải tầm FAANG
Mọi người bám theo tech stack tiêu chuẩn chỉ vì sợ phải tự suy nghĩ
Vấn đề là dùng Kafka, Mongo, Redis một cách không phê phán
Thực ra tự triển khai đúng những tính năng mình cần còn tốt hơn, và khả năng chọn ra tập thành phần tối thiểu mới là cốt lõi của một kỹ sư
Những thứ như Kafka nhiều khi chỉ là tiêu tiền vô ích
Câu “chỉ thêm độ phức tạp khi thực sự cần” là đúng, nhưng cũng có những trường hợp về sau rất khó bổ sung
Nếu thiết kế ban đầu sai thì có thể phải viết lại toàn bộ
Vì vậy trong thực tế cần những phương án dung hòa kiểu cấu hình k8s đơn giản
Gần đây trong một cuộc phỏng vấn tôi cũng có trải nghiệm tương tự
Trong 10 năm qua tôi tập trung vào việc đạt được PMF (Product-Market Fit) chứ không ám ảnh với khả năng mở rộng ngay từ đầu
Nếu sản phẩm phù hợp với thị trường thì có thể dùng tiền để giải quyết vấn đề scale
Nhưng trong phỏng vấn họ hỏi “làm sao scale một dịch vụ Django lên 10 triệu request mỗi ngày”
Tôi trả lời rằng “chỉ cần nâng cấu hình máy chủ lên”, và có vẻ họ không thấy thỏa mãn