2 giờ sáng, điện thoại rung bần bật và bài học nhớ đời
Mình nhận được alert từ hệ thống monitoring: Production server sập toàn tập. Check log trên Grafana, lỗi hiện ra rành rành: ConnectionTimeout: Cannot connect to database at 192.168.1.50:5432.
Chuyện là team hạ tầng vừa đổi dải IP của cụm Database. Do mình lỡ tay hardcode địa chỉ IP cũ vào sâu trong code, hệ thống lập tức tê liệt. Mình phải ngồi lục tung hơn 20 file Python, sửa tay từng dòng rồi build lại Docker image ngay trong đêm.
Sau sự cố đó, mình rút ra quy tắc thép: Không bao giờ để thông số như IP, Port hay API Key nằm trực tiếp trong code. Tất cả phải được đưa ra Config File. Nếu bạn muốn ngủ ngon giấc, hãy cùng mình làm chủ YAML, TOML và INI ngay.
Tại sao phải tách biệt cấu hình?
Tách cấu hình ra khỏi mã nguồn không chỉ giúp code sạch hơn. Nó là yếu tố sống còn để bạn scale hệ thống.
- Thay đổi tức thì: Bạn đổi database port từ 5432 sang 6432? Chỉ cần sửa 1 dòng file text, không cần build lại code.
- Bảo mật: Đưa file cấu hình vào
.gitignoređể tránh lộ Secret Key hay Token lên GitHub. - Đa môi trường: Chạy script trên máy cá nhân (Dev) hay Server (Prod) chỉ bằng cách trỏ tới file config tương ứng.
Trong hệ sinh thái Python, chúng ta thường xoay quanh bộ ba: INI (cổ điển), YAML (chuẩn DevOps) và TOML (hiện đại).
1. INI – Đơn giản và không cần cài đặt
Định dạng INI cực kỳ phổ biến vì Python hỗ trợ sẵn thư viện configparser. Bạn không cần pip install thêm bất cứ thứ gì.
Ví dụ file config.ini:
[database]
host = 192.168.1.100
port = 5432
[server]
debug = true
Cách xử lý bằng Python:
import configparser
config = configparser.ConfigParser()
config.read('config.ini')
# Đọc giá trị và tự động convert kiểu dữ liệu
db_host = config['database']['host']
db_port = config.getint('database', 'port')
is_debug = config.getboolean('server', 'debug')
print(f"Kết nối đến {db_host}:{db_port}")
Điểm yếu: INI chỉ phù hợp với cấu hình phẳng. Nếu bạn có danh sách lồng nhau phức tạp, INI sẽ trở nên rất rối rắm.
2. YAML – Lựa chọn số 1 cho sự linh hoạt
Nếu bạn làm việc với Docker hay Kubernetes, YAML là ngôn ngữ bắt buộc phải biết. Nó hỗ trợ cấu trúc phân cấp cực tốt và rất dễ đọc. Để bắt đầu, hãy cài đặt PyYAML:
pip install pyyaml
File config.yaml thường dùng để quản lý danh sách các node:
database:
nodes:
- {host: "db-1.local", port: 5432}
- {host: "db-2.local", port: 5432}
timeout: 30
Code Python để đọc YAML:
import yaml
with open('config.yaml', 'r') as file:
# Luôn dùng SafeLoader để chặn các cuộc tấn công thực thi mã độc
config = yaml.load(file, Loader=yaml.SafeLoader)
print(f"Đang kết nối node: {config['database']['nodes'][0]['host']}")
Mẹo nhỏ: Đừng bao giờ dùng FullLoader cho các file config từ nguồn không tin cậy. Hacker có thể lợi dụng nó để chạy code Python trái phép trên máy bạn.
3. TOML – Tiêu chuẩn mới của giới Python
TOML (Tom’s Obvious, Minimal Language) đang dần thay thế YAML trong nhiều dự án Python nhờ tính tường minh. Nó không nhạy cảm với khoảng trắng như YAML, giúp giảm bớt các lỗi cú pháp ngớ ngẩn.
Từ Python 3.11, thư viện tomllib đã được tích hợp sẵn. Với các bản cũ hơn, bạn cần cài tomli.
import tomllib
# TOML yêu cầu mở file ở chế độ binary (rb)
with open("config.toml", "rb") as f:
config = tomllib.load(f)
print(f"Max connections: {config['database']['connection_max']}")
Kinh nghiệm thực tế: Nên chọn loại nào?
Thực tế làm dự án, mình thường chọn theo các tiêu chí sau:
- Dùng INI: Khi viết script nhỏ, cần chạy ngay trên mọi máy mà không muốn cài thêm thư viện ngoài.
- Dùng YAML: Khi làm việc với hệ thống lớn, CI/CD, hoặc cần cấu trúc lồng nhau nhiều lớp (Nested).
- Dùng TOML: Khi bạn muốn đi theo chuẩn hiện đại (giống
pyproject.toml) và ưu tiên sự rõ ràng.
Một bí kíp nữa là mình thường wrap file config vào một class Settings. Thay vì dùng config['db']['port'], mình gọi settings.DB_PORT. Cách này giúp IDE gợi ý code (IntelliSense) và hạn chế gõ sai tên key.
Quản lý cấu hình tốt là bước đầu tiên để trở thành một Senior Developer. Hãy thử áp dụng ngay vào dự án hiện tại, bạn sẽ thấy việc bảo trì hệ thống nhẹ nhàng hơn rất nhiều.

