Sự cố 2 giờ sáng và cái kết từ hàm input()
Đúng 2 giờ sáng, điện thoại mình rung bần bật. Một script automation quan trọng trên production bỗng dưng “đứng hình”, kéo theo hàng loạt task phía sau bị delay. Sau 15 phút kiểm tra log, mình phát hiện nguyên nhân cực kỳ ngớ ngẩn: Một đồng nghiệp mới đã dùng hàm input() cơ bản để yêu cầu nhập thông số cấu hình.
Lúc chạy terminal, người trực lỡ tay gõ nhầm ký tự lạ vào ô số lượng. Thay vì báo lỗi, script “ngây thơ” crash thẳng vì ValueError. Giao diện lúc đó chỉ là một đống text trắng xóa, không hướng dẫn, không menu, khiến người vận hành phải tự đoán mình cần làm gì tiếp theo.
Khoảnh khắc đó mình nhận ra, nếu cứ bám víu vào mấy hàm nhập liệu mặc định, hệ thống sớm muộn cũng sẽ “toang” vì lỗi typo của con người.
Tại sao input() truyền thống lại dễ gây họa?
Nếu bạn chỉ viết script chạy cá nhân, input() có lẽ là đủ. Tuy nhiên, khi đưa công cụ cho người khác dùng hoặc chạy trên server thực tế, nó bộc lộ 3 điểm yếu chết người:
- Thiếu khả năng kiểm soát (Validation): Bạn phải viết hàng chục dòng
if-elsechỉ để check xem người dùng có nhập đúng định dạng email hay số nguyên không. Theo kinh nghiệm của mình, code validation thủ công có thể chiếm tới 40% logic script CLI. - Trải nghiệm người dùng (UX) nghèo nàn: Không có mũi tên chọn, không có checkbox. Chỉ cần sai một dấu cách là hỏng việc.
- Code rối như tơ vò: Càng nhiều câu hỏi, code càng giống một đống “spaghetti” với các vòng lặp
while Truelồng nhau vô tận.
Giải pháp: Từ thủ công đến thư viện chuyên dụng
Ban đầu, mình cố gắng chữa cháy bằng cách viết các hàm wrapper. Ví dụ như thế này:
def get_integer_input(prompt):
while True:
try:
return int(input(prompt))
except ValueError:
print("Lỗi! Bạn phải nhập số nguyên.")
Cách này cứu script khỏi crash nhưng nhìn vẫn rất nghiệp dư. Mình từng thử qua argparse hay click. Chúng rất mạnh để bắt tham số (flags), nhưng lại thiếu sự linh hoạt trong tương tác hỏi-đáp từng bước.
Cuối cùng, mình tìm thấy Questionary. Đây là thư viện xây dựng trên nền prompt_toolkit, giúp biến script Python khô khan thành bộ công cụ CLI thực thụ với menu và checkbox cực mượt.
Questionary – Cứu cánh cho CLI hiện đại
Cài đặt cực nhanh chỉ với một dòng lệnh:
pip install questionary
Dưới đây là 3 cách mình thường dùng để thay thế hàm input() cũ kỹ.
1. Tạo Menu chọn lựa (Select)
Thay vì bắt người dùng gõ “1”, “2” hay “Yes/No”, hãy cho họ chọn bằng phím mũi tên. Điều này triệt tiêu hoàn toàn lỗi typo.
import questionary
action = questionary.select(
"Chọn thao tác bạn muốn thực hiện:",
choices=[
"Kiểm tra trạng thái server",
"Backup dữ liệu",
"Restart service",
"Thoát"
]
).ask()
print(f"Thực thi: {action}")
2. Chọn nhiều mục cùng lúc (Checkbox)
Tính năng này cực kỳ hữu ích khi cần cấu hình nhiều option. Người dùng chỉ cần dùng phím Space để đánh dấu và Enter để xác nhận.
features = questionary.checkbox(
"Chọn các module cần cài đặt:",
choices=["Nginx", "PostgreSQL", "Redis", "Docker"]
).ask()
print(f"Sẽ cài đặt: {', '.join(features)}")
3. Ràng buộc dữ liệu ngay lập tức (Validation)
Đây là tính năng “đáng tiền” nhất. Questionary cho phép kiểm tra dữ liệu ngay khi người dùng đang gõ. Nếu sai định dạng, họ không thể nhấn Enter và sẽ nhận được thông báo lỗi ngay lập tức.
import re
def validate_ip(text):
pattern = r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$"
if re.match(pattern, text):
return True
return "IP không hợp lệ! (VD đúng: 192.168.1.1)"
ip_address = questionary.text(
"Nhập IP server mục tiêu:",
validate=validate_ip
).ask()
Mẹo nhỏ cho anh em: Khi cần test nhanh các regex phức tạp, mình thường dùng regex tester tại toolcraft.app để kiểm tra logic trước khi đưa vào code.
Ứng dụng thực tế: Script quản trị Server
Hãy xem sức mạnh của Questionary khi kết hợp vào một script quản lý thực tế. Mình sẽ thêm chút màu sắc cho chuyên nghiệp hơn.
import questionary
from prompt_toolkit.styles import Style
custom_style = Style([
('qmark', 'fg:#673ab7 bold'),
('question', 'bold'),
('answer', 'fg:#f44336 bold'),
('pointer', 'fg:#673ab7 bold'),
('highlighted', 'fg:#673ab7 bold'),
('selected', 'fg:#cc5454'),
])
def main():
print("--- HỆ THỐNG QUẢN TRỊ V1.0 ---")
env = questionary.select(
"Chọn môi trường:",
choices=["Staging", "Production", "Local"],
style=custom_style
).ask()
if env == "Production":
sure = questionary.confirm(
"CẢNH BÁO: Bạn đang tác động vào Production. Tiếp tục?",
default=False
).ask()
if not sure: return
service_name = questionary.text(
"Tên Service (ví dụ: nginx):",
validate=lambda text: True if len(text) > 0 else "Không được để trống!"
).ask()
task = questionary.select(
f"Hành động với {service_name}:",
choices=["Restart", "Stop", "Status"]
).ask()
print(f"\n[OK] Đang xử lý {task} cho {service_name} trên {env}...")
if __name__ == "__main__":
main()
Góc nhìn từ phòng kỹ thuật
Từ khi chuyển sang dùng Questionary, mình không còn bị dựng dậy lúc nửa đêm vì những lỗi input ngớ ngẩn. Team vận hành cũng hào hứng hơn vì giao diện CLI giờ nhìn “xịn” và dễ dùng như một phần mềm thực thụ.
Bài học rút ra là: Đừng bao giờ tin tưởng tuyệt đối vào dữ liệu người dùng nhập vào. Hãy giới hạn lựa chọn của họ bằng menu và validate mọi thứ có thể. Questionary không chỉ giúp code sạch hơn mà còn là lớp bảo hiểm vững chắc cho hệ thống của bạn.
Nếu bạn đang xây dựng công cụ automation hay tool nội bộ, hãy thử tích hợp Questionary ngay. Hiệu quả mang lại chắc chắn sẽ khiến bạn bất ngờ.

