Topic 32. Configuration — Đừng Hard-code, Hãy Cấu Hình! (Pragmatic Programmer #32)
Chào mấy bạn! Mình lại tiếp tục hành trình The Pragmatic Programmer rồi đây. Hôm nay chúng ta tới Topic 32: Configuration — nằm trong Chapter 5: Bend, or Break (Uốn cong, hay là Gãy).
Ảnh: Godfrey Atima — Pexels
Mở đầu
Mấy bạn biết không, cuốn sách này đọc tới đoạn nào cũng thấy "đau đớn" nhận ra bao nhiêu lỗi mình từng mắc phải. Nhưng mà cái Topic 32 này thì khác — nó không phải là thứ "ồ, sao mình không nghĩ ra sớm hơn", mà là "trời ơi, sao hồi xưa mình ngu thế không chịu làm theo?" (cười).
Nói thiệt, hồi mới đi làm, mình từng viết cả đống code mà database connection string, API key, timeout value — toàn bộ hard-code hết trong source. Mỗi lần deploy lên môi trường khác là một cực hình. Có lần mình còn quên đổi connection string từ dev sang production, thế là cả team ngồi cày bug cả buổi chiều. Nghĩ lại vẫn thấy xấu hổ.
Topic 32 này là câu trả lời cho tất cả những nỗi đau đó. Nó dạy mình: đừng hard-code, hãy cấu hình.
Configuration — Cái gì, Tại sao, và Làm thế nào?
Ảnh: Bibek Ghosh — Pexels
Cốt lõi của Topic 32 chỉ vỏn vẹn một câu: "Put abstractions in code, details in metadata."
Tạm dịch: để logic trừu tượng trong code, còn chi tiết thì đưa ra ngoài (metadata / config). Nôm na là: code chỉ lo chuyện "làm thế nào", còn "làm với cái gì" thì để config lo.
Tại sao lại quan trọng đến thế?
Bởi vì ý tưởng thay đổi nhanh, nhưng code thì thay đổi chậm. Mỗi lần mở file code lên để sửa một cái URL, một cái port number, hay một cái threshold nào đó, bạn đang tự đặt mình vào nguy cơ: sửa nhầm, ảnh hưởng logic, hoặc quên không commit. Và tệ nhất là — mỗi lần sửa code đồng nghĩa với một lần build, test, deploy mới. Nếu config nằm riêng, bạn chỉ cần sửa file config, reload là xong.
Lợi ích thiết thực của Configuration
Để mình liệt kê vài cái lợi cụ thể mà mình thấy:
1. Dễ dàng thay đổi môi trường
Dev, staging, production — mỗi nơi một database, một API key, một log level. Nếu mọi thứ đều nằm trong config file, bạn chỉ cần đổi file (hoặc dùng biến môi trường) là xong. Không cần động vào code.
2. Feature Flags và A/B Testing
Muốn thử nghiệm tính năng mới với một nhóm nhỏ người dùng? Cho vào config. Muốn tắt tính năng khi có lỗi? Toggle cái config là xong, không cần rollback code. Đây là cách mà các công ty lớn như Facebook, Netflix vẫn làm hàng ngày.
3. Cho phép non-developers điều chỉnh
Có những thứ như rate limit, threshold, message template — bên business (Product Owner, Operation) có thể tự điều chỉnh nếu bạn expose config ra dashboard. Đỡ mất thời gian mỗi lần họ nhờ sửa hộ.
4. Code sạch hơn, ít "noise" hơn
Khi config ra ngoài, code của bạn chỉ còn logic thuần túy. Đọc code dễ hơn, maintain dễ hơn, và test cũng dễ hơn.
Các hình thức Configuration trong thực tế
Ảnh: Pixabay — Pexels
Có nhiều cách để đưa config ra khỏi code. Dưới đây là vài cách phổ biến:
a) Environment Variables (Env vars)
Cách đơn giản và phổ biến nhất. DATABASE_URL, REDIS_HOST, LOG_LEVEL — tất cả để trong .env file hoặc set trực tiếp trong OS. Dùng thư viện như python-dotenv hoặc dotenv (Node.js) để load lúc runtime. 12-Factor App khuyến nghị cách này.
b) Config Files (YAML / JSON / TOML)
Phù hợp cho config phức tạp hơn, có cấu trúc. Ví dụ: database config với nhiều connection pool, cache settings, v.v. Mấy file này thường để ở thư mục config/ riêng, và có version cho từng môi trường.
c) External Config Service (Consul, etcd, AWS AppConfig)
Khi hệ thống lớn, nhiều service, việc quản lý config file thủ công không còn hiệu quả. Các service như Consul hay AWS AppConfig cho phép quản lý config tập trung, có versioning, rollback, và push real-time.
d) Database-driven Configuration
Có những config cần thay đổi động ngay cả khi app đang chạy — ví dụ: tỉ lệ chiết khấu, nội dung quảng cáo, threshold báo động. Những thứ này nên để trong database, kèm theo cache để tránh query quá nhiều.
Nguyên tắc vàng khi thiết kế Configuration
Cuốn sách có đưa ra mấy nguyên tắc rất hay, mình ghi nhớ và áp dụng:
1. Default values luôn phải an toàn
Nếu config bị thiếu hoặc sai, hệ thống nên chạy với giá trị mặc định an toàn nhất, không crash. Đừng assume rằng config luôn đúng.
2. Validate config ngay khi khởi động
Không gì tệ hơn chạy app lên được 3 tiếng rồi mới vỡ lẽ config sai. Validate tất cả config ở startup phase, nếu sai thì fail fast.
3. Config phải có thể đọc được và document
Đừng đặt config với tên biến tối nghĩa. Mỗi config nên có comment giải thích nó dùng để làm gì, giá trị hợp lệ là gì.
4. Đừng hard-code default value trong code lẫn config
Nếu bạn có default value trong code, đừng ghi đè nó bằng config. Luôn ưu tiên config > environment variable > default trong code.
5. Tránh config quá mức
Cũng đừng điên cuồng config hóa mọi thứ. Chỉ config những gì thực sự cần thay đổi. Config mọi thứ cũng là một dạng over-engineering.
Cảm nhận của mình
Thú thật là hồi mới đọc topic này, mình nghĩ "ủa, đơn giản vậy thôi á?" Nhưng áp dụng rồi mới thấy nó thay đổi cách mình viết code hoàn toàn.
Có một lần mình làm project cho khách hàng, họ muốn thay đổi URL của external API mà họ dùng. Nếu mình hard-code URL đó trong controller, thì mỗi lần đổi, mình phải mở code, sửa, commit, build, test, deploy — mất ít nhất 30 phút. Nhưng mình để URL đó trong config YAML, họ chỉ cần vào server, sửa file, restart service — mất 2 phút. Khách hàng vui, mình cũng vui.
Cũng nhờ topic này, mình bắt đầu xây dựng một config module riêng cho mọi dự án. Một class/struct đọc config từ nhiều nguồn (env vars, file, arguments), validate ngay lúc khởi tạo, và expose các method type-safe. Nghe có vẻ tốn công, nhưng đỡ đau đầu về sau cực kỳ.
Điểm mình thích nhất ở topic này là: nó không chỉ dạy kỹ thuật, mà còn dạy tư duy — tư duy tách biệt giữa "cái gì thay đổi thường xuyên" và "cái gì ổn định". Khi nào code, khi nào config. Biết được ranh giới đó là dấu hiệu của một senior engineer.
Kết
Topic 32 — Configuration — tưởng đơn giản mà sâu sắc không ngờ. Nếu mấy bạn đang còn hard-code connection string, API key, hay bất cứ thứ gì dễ thay đổi, hãy dừng lại ngay. Bỏ config ra ngoài, cuộc sống sẽ dễ thở hơn nhiều.
Câu nói mình tâm đắc nhất trong bài này: "The details — the things that change — belong in metadata, not in code." — Chi tiết, những thứ thay đổi, thuộc về config, không thuộc về code.
Hẹn mấy bạn ở topic sau nha! 👋