Họ đang đo gì
Bạn có làm việc được với code không phải mình viết không — chiếm phần lớn công việc thật.
Trả lời ngắn~30 giây
Viết characterization test trước: cho hàm chạy với một loạt đầu vào thật, ghi lại đầu ra HIỆN TẠI làm kỳ vọng — kể cả khi bạn nghĩ nó sai. Mục tiêu không phải chứng minh code đúng mà là dựng một lưới an toàn để mọi thay đổi hành vi đều lộ ra. Sau đó mới tách dần từng phần ra, mỗi lần một bước nhỏ, chạy lại lưới đó sau mỗi bước.
Giải thích sâu
Việc ghi lại cả hành vi sai nghe phản trực giác nhưng là điểm mấu chốt: ở đâu đó có người đang phụ thuộc vào cái sai đó, và bạn cần BIẾT khi mình thay đổi nó, chứ không phải vô tình thay đổi rồi phát hiện qua ticket. Nếu quyết định sửa hành vi, bạn sửa test một cách có chủ đích và ghi lý do — đó là một thay đổi được ghi nhận, không phải một tác dụng phụ.
Khó khăn thực tế thường là hàm đó không gọi được trong test vì nó đọc thẳng từ database, gọi API, hoặc dùng new Date(). Kỹ thuật của Michael Feathers cho việc này là “seam”: tìm chỗ có thể thay đổi hành vi mà không sửa logic — bọc lời gọi vào một phương thức protected rồi override trong lớp test, hoặc tách tham số ra. Nó xấu về mặt thiết kế và tạm thời, và nó cho bạn cái lưới để dọn dẹp phần còn lại.
Câu hỏi tiếp theo họ sẽ hỏi
?Không có thời gian cho tất cả thì phủ phần nào trước?
Đúng những đường bạn sắp chạm vào, cộng những đường đắt nhất khi hỏng (tiền, quyền truy cập, mất dữ liệu). Đừng cố phủ cả 800 dòng — điều đó biến một thay đổi hai ngày thành một dự án hai tháng và thường bị huỷ giữa chừng.
Trả lời thế này là mất điểm
- Refactor trước, viết test sau. Không có lưới thì bạn không biết mình vừa đổi gì, và code cũ luôn có hành vi bạn không đoán được.
- Đề xuất viết lại từ đầu. Đôi khi đúng, nhưng nói ra trước khi hiểu code hiện tại là dấu hiệu chưa đọc nó.
Nguồn
- Michael Feathers — Working Effectively with Legacy Code (seam, characterization test)
- Martin Fowler — Refactoring: chỉ refactor khi đã có test xanh