Lỗi cú pháp thì trình biên dịch bắt được. Lỗi logic thì kiểm thử bắt được. Còn lại là những lỗi chỉ xuất hiện khi hệ thống chạy thật, nhiều thành phần cùng lúc, trong thời gian dài.
Điều kiện đua
Là gì. Hai luồng hoặc hai tiến trình truy cập cùng dữ liệu, và kết quả phụ thuộc thứ tự chúng chạy — mà thứ tự đó không xác định.
Vì sao khó tìm. Chỉ xảy ra khi thời điểm rơi đúng vào một khoảng rất hẹp. Có thể chạy hàng nghìn lần mới gặp một lần.
Triệu chứng. Lỗi ngẫu nhiên, không tái tạo được, xảy ra nhiều hơn khi hệ thống bận, và biến mất khi thêm lệnh in ra để gỡ lỗi.
Ví dụ trong robot. Vòng điều khiển đọc mục tiêu trong khi luồng khác đang ghi mục tiêu mới. Đọc được nửa giá trị cũ nửa giá trị mới.
Cách phòng. Bảo vệ mọi dữ liệu chia sẻ bằng cơ chế khoá hoặc dùng cấu trúc dữ liệu an toàn.
Cách phòng tốt hơn. Giảm tối đa dữ liệu chia sẻ. Truyền dữ liệu qua hàng đợi thay vì chia sẻ biến.
Cách tìm. Công cụ phát hiện điều kiện đua khi chạy. Chậm nhưng bắt được nhiều lỗi tiềm ẩn.
Kiểm bằng cách gây căng thẳng. Chạy với tải cao, nhiều luồng, thời gian dài. Điều kiện đua xuất hiện thường xuyên hơn.
Rò rỉ tài nguyên
Rò rỉ bộ nhớ. Cấp phát mà không giải phóng. Bộ nhớ tăng dần cho tới khi hết và chương trình bị kết thúc.
Triệu chứng. Hệ thống chạy tốt vài giờ rồi chậm dần và cuối cùng dừng. Khởi động lại thì hết, một thời gian.
Rò rỉ khác. Tệp mở không đóng, kết nối mạng không đóng, luồng tạo ra không kết thúc.
Vì sao robot dễ gặp. Hệ thống chạy liên tục nhiều ngày. Rò rỉ nhỏ mà thí nghiệm ngắn không thấy sẽ tích luỹ.
Cách phát hiện. Ghi lại mức sử dụng bộ nhớ theo thời gian. Đường tăng đều là dấu hiệu rõ ràng.
Cách tìm nguồn. Công cụ phân tích bộ nhớ chỉ ra nơi cấp phát mà không giải phóng.
Cách phòng. Dùng cơ chế tự quản lý vòng đời tài nguyên của ngôn ngữ. Tránh cấp phát trong vòng lặp chạy liên tục.
Kiểm bằng chạy dài. Để hệ thống chạy liên tục một tuần trước khi triển khai. Đây là bài kiểm duy nhất bắt được loại lỗi này.
Lỗi liên quan tới thời gian
Giả định về thứ tự đến. Dữ liệu từ hai cảm biến đến theo thứ tự khác dự kiến. Hiếm nhưng xảy ra.
Giả định về tần số. Mã giả định nhận được dữ liệu đều đặn. Khi mạng chậm hoặc hệ thống bận thì không.
Dữ liệu cũ dùng như dữ liệu mới. Không kiểm dấu thời gian nên tiếp tục dùng giá trị đã lỗi thời. Với robot đang di chuyển thì đây là sai số nghiêm trọng.
Tràn bộ đếm thời gian. Biến đếm thời gian chạy đủ lâu thì tràn về không. Lỗi xuất hiện sau nhiều ngày chạy liên tục và rất khó liên hệ với nguyên nhân.
Đồng hồ không đồng bộ. Giữa các máy. Dấu thời gian ở tương lai hoặc quá khứ gây hành vi kỳ lạ.
Đồng hồ nhảy. Khi hệ thống đồng bộ thời gian mạng. Mã tính khoảng thời gian bằng hiệu hai thời điểm sẽ ra giá trị âm hoặc rất lớn.
Cách phòng. Dùng đồng hồ đơn điệu cho việc đo khoảng thời gian, không dùng đồng hồ hệ thống.
Và luôn kiểm dấu thời gian. Dữ liệu quá cũ thì bỏ, không dùng.
Lỗi ở ranh giới giữa các thành phần
Vì sao hay xảy ra ở đây. Mỗi thành phần được viết và kiểm thử riêng. Giả định của bên này không khớp giả định của bên kia.
Nhầm đơn vị. Bên gửi dùng độ, bên nhận hiểu là radian.
Nhầm hệ toạ độ. Bên gửi theo hệ camera, bên nhận hiểu là hệ robot.
Nhầm quy ước. Chiều dương của góc, thứ tự các trục, gốc toạ độ ở đâu.
Xử lý trường hợp rỗng khác nhau. Bên gửi coi giá trị không là hợp lệ, bên nhận coi là chưa có dữ liệu.
Cách phòng — ghi rõ giao diện. Đơn vị, hệ toạ độ, quy ước, dải giá trị hợp lệ, ý nghĩa của giá trị đặc biệt. Viết ra chứ không giả định.
Cách phòng — kiểm tra ở biên. Mỗi thành phần kiểm dữ liệu vào có hợp lệ không trước khi dùng.
Cách tìm. Kiểm thử tích hợp và ghi lại dữ liệu trao đổi giữa các thành phần. Nhìn giá trị thật thường phát hiện ngay sự bất nhất.
Chiến lược tìm lỗi khó
Làm cho tái tạo được. Mục tiêu đầu tiên. Lỗi tái tạo được là lỗi sẽ sửa được. Tìm điều kiện làm nó xuất hiện thường xuyên hơn.
Thu hẹp bằng cách đơn giản hoá. Bỏ dần các phần không liên quan cho tới khi còn ví dụ nhỏ nhất vẫn tái tạo được lỗi.
Ghi nhiều hơn. Tăng mức chi tiết của nhật ký ở vùng nghi ngờ.
Nhưng cẩn thận. Thêm lệnh ghi có thể làm lỗi biến mất — đó chính là dấu hiệu của điều kiện đua.
Kiểm giả thuyết bằng thực nghiệm. Không dừng ở việc đọc mã. Sửa một chỗ và xem lỗi có đổi không.
Giải thích cho người khác. Kể lại vấn đề cho đồng nghiệp thường làm lộ ra chỗ mình đã bỏ qua. Hiệu quả kể cả khi người nghe không biết gì về hệ thống.
Nghỉ khi bế tắc. Sau vài giờ không tiến triển, làm việc khác. Rất nhiều lời giải đến khi không cố nghĩ về nó.
Ghi lại khi tìm ra. Loại lỗi này có xu hướng lặp lại trong các dự án khác, và ghi chép tiết kiệm rất nhiều lần sau.
Câu hỏi thường gặp
Dấu hiệu của điều kiện đua là gì?
Lỗi ngẫu nhiên không tái tạo được, xảy ra nhiều hơn khi hệ thống bận, và đặc biệt là biến mất khi thêm lệnh in ra để gỡ lỗi.
Vì sao robot dễ gặp rò rỉ bộ nhớ hơn ứng dụng khác?
Vì hệ thống chạy liên tục nhiều ngày, nên rò rỉ nhỏ mà thí nghiệm ngắn không thấy sẽ tích luỹ đủ để gây dừng máy.
Nên dùng đồng hồ nào để đo khoảng thời gian?
Đồng hồ đơn điệu, không dùng đồng hồ hệ thống. Đồng hồ hệ thống có thể nhảy khi đồng bộ thời gian mạng, cho ra khoảng thời gian âm hoặc rất lớn.
Mục tiêu đầu tiên khi gặp lỗi khó là gì?
Làm cho nó tái tạo được. Lỗi tái tạo được là lỗi sẽ sửa được, nên trước hết hãy tìm điều kiện làm nó xuất hiện thường xuyên hơn.
Đọc thêm trong Dự án tự làm và Hiệu chỉnh & căn chỉnh.