Lần theo luồng chạy là trả lời câu hỏi: khi người dùng bấm một nút, những hàm nào được gọi, theo thứ tự nào, đọc và ghi những dữ liệu gì. Với mã cũ, đây là cách nhanh nhất để hiểu thật một phần hệ thống, vì bạn đi theo đúng con đường mà dữ liệu đi chứ không đọc tràn lan từng thư mục. AI giúp ở chỗ đoán bước kế tiếp và giải thích từng chặng; còn việc xác nhận bước đó có thật hay không thì phải nhờ máy chạy thật.
Bài này đi qua một quy trình bảy chặng, kèm câu lệnh mẫu và các cách kiểm chứng, lấy ví dụ giả định là tính năng "gửi lại mã xác nhận qua email" trong một ứng dụng web viết bằng PHP. Nguyên tắc áp dụng y hệt cho Python, JavaScript hay Java.
Chọn tính năng và đặt câu hỏi đúng cỡ
Một luồng nên lần trong một buổi phải đủ nhỏ để đi trọn từ đầu tới cuối. "Đăng ký tài khoản" có thể quá lớn nếu nó gồm gửi thư, tạo dữ liệu mẫu, ghi nhật ký, tính hoa hồng giới thiệu. "Bấm nút gửi lại mã xác nhận" thì vừa: có một điểm bắt đầu rõ trên giao diện, một kết quả nhìn thấy được là thư đến hộp thư, và đi qua đủ các tầng của một ứng dụng web.
Trước khi hỏi AI, viết ra ba điều bạn đã biết: người dùng làm gì, kết quả mong đợi là gì, và triệu chứng nếu đang có lỗi. Ví dụ: người dùng bấm "Gửi lại mã" ở trang nhập mã, mong nhận thư mới trong vòng một phút, nhưng có người báo bấm nhiều lần không thấy thư. Viết như vậy giúp AI tập trung vào đúng nhánh mã liên quan, thay vì giảng cho bạn toàn bộ hệ thống thư của dự án. Nó cũng giúp chính bạn nhận ra lúc nào đã đi lạc khỏi câu hỏi ban đầu.
Bảy chặng của một luồng web điển hình
Phần lớn ứng dụng web cũ đi qua các chặng dưới đây, dù có khung hay viết tay. Mỗi chặng, bạn tìm đúng tệp và đúng hàm, rồi ghi lại.
- Giao diện. Nút bấm nằm ở tệp mẫu nào, gửi biểu mẫu hay gọi bằng JavaScript tới địa chỉ nào, mang theo tham số gì.
- Định tuyến. Địa chỉ đó được ánh xạ tới tệp hay hàm xử lý nào. Ứng dụng không có bộ định tuyến thì địa chỉ trỏ thẳng vào một tệp PHP.
- Lớp trung gian. Những gì chạy trước hàm xử lý: kiểm phiên đăng nhập, kiểm mã chống giả mạo biểu mẫu, giới hạn tần suất.
- Hàm xử lý. Đọc tham số, kiểm hợp lệ, quyết định nhánh nào chạy.
- Nghiệp vụ. Các hàm thật sự làm việc: tạo mã mới, huỷ mã cũ, chọn tài khoản gửi thư.
- Dữ liệu. Câu lệnh đọc và ghi vào bảng nào, cột nào.
- Tác dụng bên ngoài. Gửi thư, gọi dịch vụ khác, ghi tệp, đẩy việc vào hàng đợi.
Chặng thứ ba là nơi hay bị bỏ qua nhất khi đọc bằng mắt, vì nó thường nằm ở tệp dùng chung được nạp từ đầu. Khi hỏi AI, nói rõ: liệt kê cả những gì chạy trước hàm xử lý chính.
Hỏi AI từng chặng thay vì cả luồng một lần
Cách làm hiệu quả là đi tuần tự và đưa cho AI đúng tệp của chặng đang xét. Bắt đầu bằng tệp giao diện chứa nút bấm và câu hỏi: Nút "Gửi lại mã" trong tệp này gửi yêu cầu tới đâu, bằng phương thức gì, kèm tham số gì? Trích dòng làm căn cứ. Khi đã có địa chỉ, tìm tệp xử lý bằng lệnh tìm kiếm trong kho, ví dụ grep -rn "resend" --include=*.php ., rồi đưa tệp đó cho AI với câu hỏi tiếp theo.
Với tác tử AI tự đọc được kho mã, bạn có thể giao cả luồng nhưng bắt nó trả về dạng danh sách chặng có tên tệp và số dòng, chưa giải thích dài. Câu lệnh mẫu: Lần theo luồng khi người dùng bấm nút gửi lại mã ở trang xác nhận. Trả về danh sách có thứ tự, mỗi dòng gồm: tệp, hàm, việc hàm đó làm trong một câu. Đánh dấu chỗ nào bạn không chắc bước kế tiếp. Chưa sửa gì.
Danh sách ngắn kiểu này dễ kiểm hơn nhiều so với một bài giải thích ba trang. Bạn mở từng dòng, đọc hàm, gạch bỏ hoặc sửa. Những dòng AI đánh dấu không chắc thường là những chỗ gọi gián tiếp: hàm được gọi qua tên lưu trong cơ sở dữ liệu, qua sự kiện, qua móc nối của khung. Đó cũng chính là những chỗ người đọc bằng mắt hay lạc.
Những chỗ mã cũ làm AI lạc đường
Gọi hàm bằng chuỗi ghép. Kiểu tên hàm hay tên lớp được ghép từ tham số rồi gọi động. Tìm kiếm theo tên hàm sẽ không thấy lời gọi, AI cũng không thấy. Khi gặp, hỏi AI liệt kê mọi chỗ có gọi động trong vùng đang xét để bạn biết mình đang có điểm mù.
Mã trùng tên ở hai nơi. Dự án cũ hay có bản sao của cùng một tệp ở thư mục cũ và mới, chỉ một bản đang chạy. AI có thể giải thích bản không chạy. Kiểm bằng cách xem tệp nào thật sự được nạp, ví dụ đặt dòng ghi log tạm vào cả hai.
Hàm toàn cục và biến toàn cục. Giá trị được gán ở một tệp nạp từ đầu, dùng ở tệp khác rất xa. AI đọc riêng tệp sau sẽ không biết giá trị đó từ đâu ra; bạn cần đưa thêm tệp khởi tạo.
Tác vụ chạy sau. Hàm xử lý chỉ ghi một dòng vào bảng hàng đợi, còn thư được gửi bởi một tác vụ định kỳ chạy mỗi phút. Nếu bạn chỉ lần theo yêu cầu web, luồng dừng ở bước ghi bảng và trông như "không gửi thư". Hỏi AI: có tác vụ nền nào đọc bảng này không.
Cấu hình khác nhau giữa môi trường. Cùng một hàm nhưng trên máy chủ thật đọc tài khoản gửi thư từ cơ sở dữ liệu, trên máy bạn đọc từ tệp cấu hình. AI không biết máy chủ thật chạy nhánh nào.
Kiểm chứng bằng chạy thật: log tạm và trình gỡ lỗi
Bản đồ luồng do AI dựng là giả thuyết, máy chạy thật mới là bằng chứng. Cách rẻ nhất là thêm dòng ghi log tạm ở đầu mỗi hàm trong danh sách chặng, mỗi dòng in tên hàm và vài giá trị đầu vào đã che bớt, rồi chạy tính năng trên máy cá nhân. Thứ tự các dòng log xuất hiện chính là luồng thật. Có chặng nào không in ra nghĩa là bản đồ sai ở đó.
Cách thứ hai là trình gỡ lỗi với điểm dừng. Với PHP, phần mở rộng Xdebug kết hợp trình soạn thảo cho phép dừng ở một dòng và xem toàn bộ ngăn xếp lời gọi tại thời điểm đó; Python có sẵn pdb, gọi bằng hàm breakpoint() từ phiên bản 3.7; JavaScript chạy trên Node có thể gỡ lỗi qua công cụ của trình duyệt. Ngăn xếp lời gọi tại điểm dừng cho bạn biết chính xác ai gọi ai, kể cả những lời gọi động mà tìm kiếm văn bản bỏ sót.
Khi chạy thật, dùng dữ liệu thử và tài khoản thử. Tính năng gửi thư thì trỏ cấu hình thư về một hộp thư thử hoặc chế độ chỉ ghi ra log, để không gửi nhầm thư cho khách thật. Xong việc, gỡ hết dòng log tạm trước khi commit; một lệnh tìm kiếm theo tiền tố bạn đặt cho log tạm giúp không sót dòng nào.
Ghi lại luồng thành bảng để cả nhóm dùng
Kết quả cuối cùng nên là một bảng ngắn, đặt trong tài liệu dự án. Dưới đây là bảng mẫu cho ví dụ giả định "gửi lại mã xác nhận".
| Chặng | Tệp và hàm (ví dụ giả định) | Ghi chú đã kiểm |
|---|---|---|
| Giao diện | Trang nhập mã, nút gửi lại | Gửi biểu mẫu POST kèm địa chỉ email ẩn |
| Định tuyến | Tệp xử lý xác nhận, nhánh hành động gửi lại | Không có bộ định tuyến, tệp được gọi trực tiếp |
| Trung gian | Hàm kiểm mã chống giả mạo biểu mẫu | Sai mã thì quay lại trang, không báo lỗi |
| Nghiệp vụ | Hàm kiểm được gửi tiếp hay chưa, hàm tạo mã mới | Mã cũ bị huỷ khi tạo mã mới |
| Dữ liệu | Bảng mã xác nhận: cập nhật dòng cũ | Cập nhật chứ không thêm dòng, nên đếm theo dòng sẽ sai |
| Bên ngoài | Hàm gửi thư qua máy chủ thư | Gửi ngay trong yêu cầu, không qua hàng đợi |
Chính cột ghi chú là chỗ phát hiện lỗi. Trong ví dụ giả định này, việc cập nhật dòng cũ thay vì thêm dòng mới khiến bộ đếm giới hạn số lần gửi không bao giờ tăng. Lần theo luồng cẩn thận thường lộ ra lỗi trước cả khi bạn bắt đầu gỡ lỗi.
Sau khi lần xong: dùng bản đồ để sửa an toàn
Có bản đồ luồng rồi, bạn biết thay đổi sẽ chạm vào những chặng nào và chặng nào được dùng chung với tính năng khác. Hỏi AI thêm một câu trước khi sửa: Hàm [tên] còn được gọi từ những đâu khác ngoài luồng này? Liệt kê tệp và dòng. Rồi tự kiểm bằng tìm kiếm trong kho. Hàm dùng chung là nơi một sửa đổi nhỏ gây hỏng ở chỗ không ngờ.
Nếu vùng đó chưa có kiểm thử, viết một kiểm thử ghi lại hành vi hiện tại của luồng trước khi đổi gì. Danh mục này có bài riêng về kiểm thử đặc tả hành vi cho mã cũ. Cuối cùng, cập nhật bảng luồng sau khi sửa, để người kế tiếp không phải lần lại từ đầu. Sau vài tính năng, những bảng này ghép lại thành bản đồ của cả hệ thống, thứ mà dự án cũ hầu như không bao giờ có.
Một thói quen nhỏ giúp bản đồ không lỗi thời: mỗi khi yêu cầu gộp mã có đụng tới một chặng trong bảng, người rà mã hỏi thêm một câu là bảng luồng đã cập nhật chưa. Câu hỏi đó tốn mười giây, còn một bảng luồng sai có thể làm người sau mất cả buổi lần theo con đường không còn tồn tại.
Câu hỏi thường gặp
Lần theo luồng chạy khác gì đọc mã từ trên xuống?
Đọc từ trên xuống là đọc theo thứ tự tệp và thư mục, dễ lạc vào phần không liên quan. Lần theo luồng là đi theo đúng thứ tự máy thực thi cho một hành động cụ thể, nên bạn chỉ đọc những gì thật sự chạy và hiểu được dữ liệu biến đổi qua từng chặng.
Tác tử AI có tự lần theo luồng chính xác được không?
Nó lần được phần lớn các lời gọi trực tiếp và làm nhanh hơn người. Phần dễ sai là lời gọi động, sự kiện, tác vụ nền và cấu hình riêng của máy chủ. Vì vậy luôn coi kết quả là giả thuyết và kiểm bằng log tạm hoặc trình gỡ lỗi.
Dán log từ máy chủ thật cho AI có an toàn không?
Chỉ sau khi che hết email, số điện thoại, mã phiên, khoá API, mật khẩu và mọi thông tin định danh khách hàng. Tốt hơn là tái hiện trên máy cá nhân bằng dữ liệu thử rồi dán log đó. Kiểm quy định của công ty về việc đưa log ra công cụ ngoài.
Ứng dụng không có bộ định tuyến thì tìm điểm vào thế nào?
Địa chỉ trên trình duyệt thường trỏ thẳng tới một tệp. Xem thuộc tính action của biểu mẫu hoặc địa chỉ trong lời gọi JavaScript, rồi tìm tệp cùng tên. Kiểm thêm cấu hình máy chủ web như tệp quy tắc viết lại địa chỉ, vì nó có thể chuyển hướng ngầm.
Lần theo luồng có giúp gỡ lỗi không, hay chỉ để hiểu?
Cả hai. Rất nhiều lỗi trong mã cũ lộ ra ngay khi bạn ghi lại dữ liệu đi qua từng chặng, ví dụ một bước cập nhật thay vì thêm mới, một nhánh không bao giờ chạy. Danh mục gỡ lỗi của trang đi sâu vào quy trình chẩn đoán khi đã biết có lỗi.