“Chỉ sửa một luật kiểm tra thôi.” Câu nói nghe rất gọn, cho đến khi người làm phải mở controller, service, formatter, một helper dùng chung và cả test fixture mà chẳng ai còn nhớ thuộc về phần nào. Thay đổi vẫn làm được, nhưng đường đi qua codebase giống một mặt bàn nơi mọi sợi cáp đã quấn chặt vào nhau.
Phần lõi rối hiếm khi giơ biển báo “vấn đề kiến trúc”. Nó lộ ra bằng ma sát hằng ngày: một tính năng mất thêm vài ngày vì cùng một luật nằm ở ba chỗ; một bug fix khiến mọi người nín thở vì không biết side effect nào sẽ bật dậy; một đồng đội mới hỏi câu đơn giản nhưng nhận lại cả chuyến tham quan qua lịch sử, ngoại lệ và những deadline cũ.
Refactor để phần lõi rõ hơn không phải cuộc săn tìm thiết kế hoàn hảo. “Hoàn hảo” thường ngầm đòi một lần rewrite lớn và khoảng lặng mà công việc sản phẩm thật không cho phép. Câu hỏi thực tế hơn là: phần nào của hệ thống phải dễ tìm, dễ gọi tên và khó bị vô tình đi vòng qua?
Trước khi chuyển code, nên lần theo hành vi. Luật nghiệp vụ đi vào từ đâu, đổi hình dạng ở lớp nào, được lưu thế nào, và cuối cùng hiện ra trước người dùng ở đâu? Đường lần ấy biến cảm giác “chỗ này có vẻ rối” thành một bản đồ có thể kiểm tra. Không có bản đồ, refactor dễ thành tranh luận về gu; có bản đồ, cả nhóm nhìn được coupling nào đang tính phí cho mỗi thay đổi.
Một phần lõi tốt không cần biết mọi thứ. Nó không nên gánh từng màn hình, chi tiết transport hay tích hợp tạm thời. Phần rìa có thể chuyển đổi request, dựng response và nói chuyện với hạ tầng. Phần giữa giữ luật quan trọng bằng ngôn ngữ mà cả nhóm sử dụng, để người đến sau vẫn đọc được hành vi khi ký ức về áp lực ban đầu đã phai.
Cách an toàn thường là đi từng bước nhỏ: đổi tên một khái niệm cho khớp với cách product đang gọi; đặt một luật sau một boundary; viết test mô tả hành vi trước khi đổi cấu trúc; bỏ một helper mang tiếng “dùng chung” nhưng thực chất rải giả định của một tính năng sang nhiều nơi. Mỗi bước tốt phải làm cho bước kế tiếp dễ suy luận hơn, không chỉ làm diff hôm nay trông sạch.
Sự rõ ràng lấy thời gian trước rồi mới trả lại thời gian. Khi đang chạy deadline, cả nhóm có quyền hỏi vì sao một tính năng nhỏ lại cần thêm công sức. Không phải dòng code nào cũng đáng làm lễ. Nhưng có những vùng trở thành trạm thu phí cho mọi công việc về sau; nếu phần lõi khó hiểu, mỗi tính năng mới lại trả phí bằng thời gian dò đường và nỗi lo làm vỡ thứ khác.
Refactor tử tế cũng không biến code cũ thành bằng chứng kết tội người viết. Phần lớn code rối được tạo ra bởi những người đang cố giao hàng với thông tin chưa đủ. Việc cần làm không phải chứng minh quá khứ cẩu thả, mà là để lần sửa tiếp theo bớt phụ thuộc vào trí nhớ, may mắn và một người duy nhất còn biết lối tắt.
Một phần lõi rõ không làm codebase hết khó. Nó chỉ khiến những điều quan trọng trở nên thành thật và có địa chỉ. Khi luật trung tâm nằm ở nơi người mới có thể tìm thấy, cả nhóm nhận được nhiều hơn vài file gọn: họ bớt phải hỏi “ai còn nhớ đường?” trước mỗi thay đổi.