Lỗi lúc có lúc không là loại khó nhất, vì bước đầu tiên của mọi quy trình gỡ lỗi là tái hiện, mà lỗi này lại không chịu tái hiện theo ý bạn. Nó hỏng một lần trong hai mươi lần chạy, hỏng trên máy chủ mà không hỏng trên máy mình, hỏng vào sáng thứ hai rồi im cả tuần.
Tin tốt là lỗi chập chờn hiếm khi thật sự ngẫu nhiên. Đằng sau gần như luôn có một biến ẩn: thời điểm, thứ tự, dữ liệu, trạng thái còn sót lại từ lần chạy trước. Bài này liệt kê các nguồn hay gặp, cách biến lỗi chập chờn thành lỗi tái hiện được, và cách nhờ AI ở từng bước mà không để nó đoán mò.
Lỗi chập chờn hiếm khi ngẫu nhiên
Máy tính chạy cùng một mã với cùng đầu vào thì ra cùng kết quả. Khi kết quả khác nhau, nghĩa là có một đầu vào nào đó thay đổi mà bạn chưa nhận ra. Đầu vào đó có thể là thời gian hiện tại, thứ tự hai tiến trình chạy, nội dung bộ nhớ đệm, trạng thái cơ sở dữ liệu sau lần chạy trước, tốc độ mạng lúc đó, hay một giá trị sinh ngẫu nhiên.
Vì vậy, câu hỏi gỡ lỗi chuyển từ “lỗi ở đâu” sang “điều gì khác nhau giữa lần hỏng và lần không hỏng”. Đây cũng là câu hỏi nên đặt cho AI. Thay vì dán một lần lỗi và hỏi sửa thế nào, bạn thu thông tin của nhiều lần hỏng và nhiều lần không hỏng, rồi hỏi nó tìm điểm khác biệt.
Một thói quen nguy hiểm là chạy lại khi gặp lỗi chập chờn, thấy qua thì bỏ qua. Trong quy trình tích hợp liên tục, nhiều nhóm còn cấu hình tự chạy lại kiểm thử hỏng. Cách đó giúp công việc trôi, nhưng lỗi vẫn nằm đó và có thể là triệu chứng của một lỗi thật mà khách sẽ gặp. Ít nhất hãy ghi lại mỗi lần chạy lại mới qua để biết kiểm thử nào chập chờn nhiều.
Năm nguồn lỗi chập chờn hay gặp
Bảng dưới liệt kê các nguồn phổ biến, dấu hiệu gợi ý và cách thử tái hiện. Ví dụ đều là ví dụ giả định.
| Nguồn | Dấu hiệu gợi ý | Cách thử tái hiện |
|---|---|---|
| Tranh chấp đồng thời | Hỏng khi nhiều người dùng cùng lúc, hai đơn cùng lấy một mã giảm giá dùng một lần | Gửi nhiều yêu cầu song song cùng lúc bằng một đoạn mã nhỏ |
| Thứ tự kiểm thử | Kiểm thử qua khi chạy riêng, hỏng khi chạy cả bộ | Chạy cả bộ theo thứ tự ngẫu nhiên, hoặc chạy cặp hai kiểm thử nghi ngờ |
| Thời gian và múi giờ | Hỏng gần nửa đêm, ngày cuối tháng, ngày 29 tháng 2, hoặc chỉ trên máy chủ dùng UTC | Cố định thời gian hiện tại trong kiểm thử ở các mốc biên |
| Bộ nhớ đệm và trạng thái còn sót | Hỏng ở lần chạy thứ hai, hết khi xoá đệm hoặc khởi động lại | Chạy hai lần liên tiếp không dọn dẹp ở giữa |
| Mạng và dịch vụ ngoài | Hỏng khi dịch vụ ngoài chậm, quá thời gian chờ | Giả lập dịch vụ trả chậm hoặc trả lỗi trong kiểm thử |
Đi qua bảng này với lỗi của bạn, chọn một hai nguồn có dấu hiệu khớp nhất để thử trước. AI giúp được ở việc khớp dấu hiệu: mô tả khi nào lỗi xảy ra và khi nào không, hỏi nó xếp năm nguồn trên theo khả năng và giải thích lý do.
Biến lỗi chập chờn thành lỗi tái hiện được
Mục tiêu là làm lỗi xảy ra thường xuyên hơn, lý tưởng nhất là mỗi lần chạy. Khi đã tái hiện được, mọi kỹ thuật gỡ lỗi thông thường lại dùng được.
- Thu thập càng nhiều lần hỏng càng tốt: thời điểm, máy, dữ liệu vào, nhật ký đầy đủ. Một lần hỏng là giai thoại, mười lần hỏng là dữ liệu.
- Chạy lặp nhiều lần để đo tần suất. Ví dụ trong Bash: for i in $(seq 1 50); do python -m pytest tests/test_don_hang.py -q || break; done. Vòng lặp dừng ở lần hỏng đầu tiên để bạn đọc ngay nhật ký.
- Thay đổi từng yếu tố một và đo lại tần suất: chạy riêng hay chạy chung, chạy song song hay tuần tự, đổi múi giờ, xoá đệm giữa các lần.
- Khi một yếu tố làm tần suất tăng rõ, đó là hướng điều tra. Cố định yếu tố đó ở giá trị gây lỗi.
- Viết ca kiểm thử dựng đúng điều kiện đó, hỏng mỗi lần chạy. Đây là bước quyết định.
- Từ đây gỡ như lỗi thường, và giữ ca kiểm thử lại sau khi sửa.
AI làm tốt việc viết vòng lặp chạy nhiều lần, đoạn mã gửi yêu cầu song song, hay ca kiểm thử cố định thời gian, miễn bạn mô tả rõ điều kiện cần dựng. Hãy đọc kỹ các đoạn mã đó trước khi chạy, nhất là đoạn gửi nhiều yêu cầu, và chỉ chạy nhắm vào máy thử, không nhắm vào máy chủ đang phục vụ khách.
Tranh chấp đồng thời: lỗi của những thao tác tưởng là nguyên khối
Kiểm rồi mới ghi. Mã đọc số lượng tồn kho, thấy còn 1, rồi trừ đi 1 và ghi lại. Hai yêu cầu cùng đọc thấy 1 trước khi một trong hai kịp ghi, cả hai đều bán, tồn kho thành âm. Trên máy mình với một người dùng, lỗi này không bao giờ xảy ra.
Sửa ở tầng cơ sở dữ liệu. Cách sửa thường là đưa phép kiểm và phép ghi vào cùng một thao tác nguyên khối: câu cập nhật có điều kiện, giao dịch với khoá dòng, hoặc ràng buộc duy nhất để cơ sở dữ liệu tự từ chối bản ghi trùng. Cách cụ thể tuỳ hệ quản trị và khung làm việc, nên kiểm tài liệu.
Cẩn thận với cách sửa bằng chờ. AI đôi khi đề xuất thêm lệnh chờ một khoảng ngắn để tránh tranh chấp. Đó là che lỗi, không phải sửa: dưới tải cao hơn, khoảng chờ đó không còn đủ.
Mã bất đồng bộ cũng có tranh chấp. Trong JavaScript, hai lời gọi mạng gửi đi theo thứ tự nhưng có thể trả về ngược thứ tự. Ô tìm kiếm hiện kết quả của từ khoá cũ vì phản hồi cũ về sau phản hồi mới là ví dụ quen thuộc.
Khi hỏi AI, mô tả dòng thời gian. Viết rõ thao tác A làm gì, thao tác B làm gì, và thứ tự xen kẽ nào bạn nghi gây lỗi. AI phân tích dòng thời gian như vậy khá tốt và gợi ý được chỗ cần thao tác nguyên khối.
Thời gian, múi giờ và những ngày đặc biệt
Mã có dùng thời gian hiện tại là mã có đầu vào thay đổi mỗi giây. Kiểm thử viết vào buổi chiều có thể hỏng nếu chạy lúc 23 giờ 59, khi phép cộng một phút đẩy sang ngày hôm sau. Báo cáo theo tháng có thể hỏng vào ngày 31 nếu mã cộng một tháng vào một ngày không tồn tại ở tháng sau. Lỗi kiểu này thường được báo vào đúng những ngày đó, rồi biến mất trước khi kịp điều tra.
Múi giờ là nguồn lỗi riêng. Việt Nam dùng UTC+7 và không đổi giờ theo mùa, nhưng máy chủ thường đặt UTC, còn khách và đối tác có thể ở múi giờ có đổi giờ mùa hè. Thời gian không kèm múi giờ trong mã sẽ được hiểu theo múi giờ của máy đang chạy, nên cùng một mã cho kết quả khác nhau ở máy khác nhau.
Cách phòng bền vững là đưa thời gian hiện tại thành tham số thay vì gọi thẳng trong hàm, để kiểm thử truyền vào các mốc biên như cuối ngày, cuối tháng, ngày 29 tháng 2. Nhờ AI liệt kê các mốc thời gian biên cho một hàm cụ thể là việc nó làm nhanh và hữu ích, nhưng tự kiểm lại danh sách, vì quy tắc lịch và múi giờ là chỗ mô hình có thể nhầm chi tiết.
Đưa lỗi chập chờn cho AI thế nào
Với lỗi chập chờn, gói thông tin cho AI khác với lỗi thường. Trọng tâm là so sánh, không phải một lần hỏng.
- Mô tả tần suất đo được: hỏng khoảng mấy lần trên bao nhiêu lần chạy, trong điều kiện nào.
- Đặt cạnh nhau nhật ký của một lần hỏng và một lần không hỏng, đã che dữ liệu nhạy cảm.
- Liệt kê những yếu tố đã thử thay đổi và tần suất tương ứng, kể cả yếu tố không ảnh hưởng gì.
- Đoạn mã liên quan, đặc biệt các chỗ đọc thời gian, dùng bộ nhớ đệm, chạy song song, gọi dịch vụ ngoài.
- Câu hỏi: “Từ khác biệt giữa hai nhật ký và các thử nghiệm trên, nêu ba giả thuyết về biến ẩn gây lỗi, mỗi giả thuyết kèm cách làm cho lỗi xảy ra mỗi lần.”
- Ràng buộc: “Không đề xuất thêm lệnh chờ, chạy lại hay bắt lỗi để che lỗi.”
Câu ràng buộc cuối cùng cần thiết vì với lỗi chập chờn, cách sửa che lỗi dễ được chấp nhận nhất: chạy thử mười lần thấy qua cả mười, ai cũng tưởng xong. Chỉ ca kiểm thử dựng đúng điều kiện gây lỗi mới chứng minh được là đã sửa thật.
Sau khi sửa: chứng minh bằng số lần chạy
Với lỗi thường, chạy lại một lần thấy qua là đủ. Với lỗi chập chờn thì không. Nếu trước khi sửa lỗi xảy ra một lần trong hai mươi, chạy năm lần thấy qua chẳng chứng minh được gì. Chạy lặp đủ nhiều, ví dụ gấp vài lần số lần cần để thấy lỗi trước đây, với đúng điều kiện đã làm tăng tần suất.
Tốt nhất là có ca kiểm thử tái hiện ổn định: trước khi sửa hỏng mỗi lần, sau khi sửa qua mỗi lần. Ca này đi vào bộ kiểm thử chung và canh cho lỗi không quay lại. Ghi trong mô tả commit nguồn gốc lỗi, điều kiện tái hiện và tần suất trước, sau khi sửa, để người sau hiểu vì sao ca kiểm thử trông lạ như vậy.
Cuối cùng, theo dõi nhật ký trên máy chủ thật thêm một thời gian sau khi triển khai. Lỗi chập chờn đôi khi có hai nguyên nhân chồng nhau, sửa một thì tần suất giảm nhưng chưa về không. Nếu sau một tuần vẫn thấy, quay lại bước thu thập với nhật ký mới, lần này đã loại được một nguồn.
Câu hỏi thường gặp
Kiểm thử lúc qua lúc hỏng có nên cho tự chạy lại không?
Cho chạy lại giúp quy trình không bị tắc, nhưng nên ghi lại mỗi lần chạy lại mới qua và định kỳ xử lý các kiểm thử chập chờn nhiều nhất. Kiểm thử chập chờn có thể đang báo một lỗi thật mà khách sẽ gặp dưới tải.
Làm sao biết kiểm thử hỏng do thứ tự chạy?
Chạy riêng kiểm thử đó nhiều lần, rồi chạy cả bộ nhiều lần. Nếu riêng thì luôn qua mà chung thì thỉnh thoảng hỏng, nghi ngay trạng thái còn sót do kiểm thử khác để lại, như dữ liệu trong cơ sở dữ liệu thử, biến toàn cục, tệp tạm.
Thêm lệnh chờ có sửa được lỗi tranh chấp không?
Không, chỉ làm lỗi hiếm hơn trong điều kiện hiện tại. Khi tải tăng hay máy chậm hơn, khoảng chờ không còn đủ và lỗi quay lại. Cách sửa đúng là làm phép kiểm và phép ghi thành một thao tác nguyên khối.
Có nên nhờ AI viết mã gửi nhiều yêu cầu song song để tái hiện lỗi không?
Được, đó là việc nó làm nhanh. Đọc kỹ đoạn mã trước khi chạy, giới hạn số yêu cầu, và chỉ nhắm vào máy thử của chính bạn, không nhắm vào máy chủ đang phục vụ khách hay hệ thống của người khác.
Vì sao lỗi chỉ xảy ra trên máy chủ mà không xảy ra trên máy mình?
Máy chủ có nhiều người dùng đồng thời, múi giờ khác, dữ liệu thật, mạng thật và bộ nhớ đệm chạy lâu ngày. Đó đều là các biến ẩn hay gây lỗi chập chờn. So nhật ký trên máy chủ giữa lần hỏng và lần không hỏng để tìm biến đó.
Sửa xong rồi chạy mười lần đều qua đã đủ chưa?
Tuỳ tần suất ban đầu. Nếu trước đây lỗi xảy ra một lần trong năm mươi, mười lần qua chưa nói lên gì. Cần chạy đủ nhiều trong đúng điều kiện gây lỗi, hoặc tốt hơn là có ca kiểm thử dựng điều kiện đó và hỏng mỗi lần trước khi sửa.