💡 Key Takeaways
- The $312 Million Bug That Changed How I Debug Forever
- Why Most Developers Debug Backwards
- The Foundation: Building Your Debugging Toolkit
- Step One: Define the Bug Precisely
Lỗi 312 triệu đô la đã thay đổi cách tôi gỡ lỗi mãi mãi
Tôi vẫn nhớ khoảnh khắc chính xác khi tôi nhận ra rằng toàn bộ phương pháp gỡ lỗi của tôi đã bị hỏng một cách cơ bản. Đó là 2:47 sáng vào một ngày thứ Ba năm 2011, và tôi đang ngồi trong phòng chiến tranh tại một công ty dịch vụ tài chính lớn nơi tôi làm việc với tư cách là kỹ sư phần mềm cấp cao. Chúng tôi vừa phát hiện một lỗi trong nền tảng giao dịch của mình, đã âm thầm tính toán sai các chuyển đổi tiền tệ trong ba tuần. Thiệt hại ước tính? 312 triệu đô la.
💡 Những Điều Quan Trọng
- Lỗi 312 triệu đô la đã thay đổi cách tôi gỡ lỗi mãi mãi
- Tại sao hầu hết các nhà phát triển gỡ lỗi ngược
- Nền tảng: Xây dựng bộ công cụ gỡ lỗi của bạn
- Bước Một: Xác định lỗi một cách chính xác
Phần tồi tệ nhất không phải là tiền—mặc dù điều đó chắc chắn đã đủ tồi tệ. Đó là sự nhận ra rằng tôi đã xem chính xác tệp chứa lỗi bốn lần trong quá trình điều tra của mình. Bốn lần. Tôi đã cuộn qua nó mà không để ý, tin rằng vấn đề phải ở đâu đó phức tạp hơn, thú vị hơn, xứng đáng với chuyên môn của tôi hơn. Tôi đã tìm kiếm một lỗi thuật toán tinh vi khi vấn đề thực tế chỉ đơn giản là một lỗi lệch một trong phép tính ngày tháng.
Tối hôm đó đã thay đổi cơ bản cách tôi tiếp cận gỡ lỗi. Trong suốt 18 năm qua với tư cách là kỹ sư phần mềm—12 trong số đó dành riêng cho việc gỡ lỗi các hệ thống phân tán phức tạp—tôi đã phát triển một phương pháp hệ thống giúp tôi tìm lỗi nhanh hơn 73% so với cách tiếp cận ad-hoc trước đây. Quan trọng hơn, hệ thống này đã giúp tôi tránh được cái bẫy mà tôi đã rơi vào tối hôm đó: giả định rằng lỗi phải phức tạp như hệ thống mà chúng đang tồn tại.
Ngày nay, tôi lãnh đạo một nhóm 15 kỹ sư tại một công ty hạ tầng đám mây, và tôi đã đào tạo hơn 200 nhà phát triển về các phương pháp gỡ lỗi có hệ thống. Những gì tôi đã học được là gỡ lỗi không phải là về việc thông minh—đó là về việc có phương pháp. Không phải là về trực giác—đó là về chứng cứ. Và chắc chắn không phải là về việc bạn có thể thức bao nhiêu giờ nhìn chằm chằm vào mã.
Tại sao hầu hết các nhà phát triển gỡ lỗi ngược
Trước khi chúng ta đi sâu vào phương pháp hệ thống, chúng ta cần hiểu tại sao việc gỡ lỗi lại khó khăn ngay từ đầu. Trong kinh nghiệm của tôi khi đào tạo các nhà phát triển, tôi đã xác định ba sai lầm cơ bản chịu trách nhiệm cho khoảng 80% thời gian lãng phí trong việc gỡ lỗi.
"Các lỗi tốn kém nhất không phải là những lỗi làm sập hệ thống của bạn—mà là những lỗi âm thầm hoạt động trong nhiều tuần, sản xuất ra các kết quả sai lệch nhẹ nhàng cộng dồn theo thời gian."
Sai lầm đầu tiên là điều tôi gọi là "gỡ lỗi giải pháp trước". Đây là khi bạn hình thành một giả thuyết về những gì sai trước khi bạn đã thu thập đủ chứng cứ. Bộ não của bạn bám vào một lý thuyết—có thể dựa trên một lỗi tương tự mà bạn đã thấy trước đó—và sau đó bạn dành hàng giờ để cố gắng chứng minh rằng lý thuyết đó là đúng. Tôi đã thấy các nhà phát triển dành cả ngày để điều tra vấn đề kết nối cơ sở dữ liệu chỉ vì họ từng thấy một triệu chứng tương tự, chỉ để phát hiện rằng vấn đề thực sự lại là một bộ cân bằng tải được cấu hình sai.
Sai lầm thứ hai là "gỡ lỗi đi lang thang ngẫu nhiên". Đây là phương pháp mà bạn thực hiện các thay đổi một cách bán ngẫu nhiên, hy vọng rằng điều gì đó sẽ hiệu quả. Bạn chú thích một dòng ở đây, thêm một câu lệnh ghi log ở đó, khởi động lại dịch vụ và xem điều gì xảy ra. Trong một nghiên cứu mà tôi thực hiện với nhóm của mình năm ngoái, chúng tôi thấy rằng các nhà phát triển sử dụng phương pháp này mất trung bình 4.7 giờ để giải quyết các lỗi mà các nhà gỡ lỗi có hệ thống giải quyết trong 1.3 giờ. Đó là một sự khác biệt 262% về hiệu suất.
Sai lầm thứ ba là điều tôi gọi là "gỡ lỗi theo cái tôi"—sự từ chối bắt đầu với những giải thích đơn giản vì chúng có vẻ thấp hơn trình độ kỹ năng của bạn. Đây chính xác là sai lầm của tôi với lỗi 312 triệu đô la. Tôi đã quá tin chắc rằng mình đang đối phó với một vấn đề tinh vi đến nỗi tôi đã phớt lờ điều hiển nhiên. Tôi đã thấy các kỹ sư cấp cao mất vài ngày để điều tra các điều kiện tranh chấp trong mã đa luồng khi vấn đề thực sự lại là một lỗi đánh máy trong biến môi trường.
Các sai lầm này có một nguyên nhân gốc chung: tất cả chúng đều là phản ứng cảm xúc chứ không phải là quy trình logic. Gỡ lỗi giải pháp trước phát xuất từ mong muốn thể hiện kiến thức. Gỡ lỗi đi lang thang ngẫu nhiên phát xuất từ sự thất vọng và thiếu kiên nhẫn. Gỡ lỗi theo cái tôi phát xuất từ niềm kiêu hãnh. Phương pháp hệ thống mà tôi sắp chia sẻ loại bỏ hoàn toàn cảm xúc khỏi phương trình.
Nền tảng: Xây dựng bộ công cụ gỡ lỗi của bạn
Trước khi bạn có thể gỡ lỗi một cách hệ thống, bạn cần có các công cụ phù hợp. Tôi không nói về phần mềm gỡ lỗi tinh vi—mặc dù điều đó giúp ích. Tôi đang nói về cơ sở hạ tầng tinh thần và thực hành mà làm cho việc gỡ lỗi có hệ thống trở nên khả thi.
| Phương pháp Gỡ lỗi | Thời gian hoàn thành | Tỷ lệ Thành công | Đặc điểm Chính |
|---|---|---|---|
| Săn Lỗi Ad-hoc | Thay đổi lớn (giờ đến ngày) | ~45% | Dựa vào trực giác và đoán mò |
| Gỡ Lỗi Câu Lệnh In | Hỗn hợp (2-6 giờ) | ~60% | Phản ứng, cần nhiều lần thử nghiệm |
| Phương Pháp Tìm Kiếm Nhị Phân | Nhanh (30 phút-2 giờ) | ~75% | Loại bỏ hệ thống các phần mã |
| Định Hướng Giả Thuyết | Rất nhanh (15 phút-1 giờ) | ~85% | Dựa trên chứng cứ, các giả thuyết có thể kiểm chứng |
| Phương Pháp Hệ Thống | Nhanh nhất (10-45 phút) | ~92% | Giá trị lặp lại, có tài liệu, có phương pháp |
Trước tiên, bạn cần một cách đáng tin cậy để tái tạo lỗi. Điều này nghe có vẻ hiển nhiên, nhưng trong kinh nghiệm của tôi, khoảng 40% thời gian gỡ lỗi bị lãng phí vì các nhà phát triển không có một trường hợp tái tạo nhất quán. Nếu bạn không thể tái tạo một lỗi một cách đáng tin cậy, bạn không thể gỡ lỗi nó một cách hệ thống. Thôi nào. Tôi đã từng dành ba ngày để theo dõi điều mà tôi nghĩ là một vấn đề đồng thời phức tạp, chỉ để phát hiện rằng tôi đang kiểm tra với các tập dữ liệu khác nhau mỗi lần, khiến lỗi xuất hiện không liên tục.
Trường hợp tái tạo của bạn nên được tối thiểu hóa càng nhiều càng tốt. Nếu lỗi xảy ra trong một quy trình người dùng phức tạp gồm 15 bước, nhiệm vụ đầu tiên của bạn là rút ngắn quy trình đó xuống chỉ còn phần nhỏ nhất có thể mà vẫn kích hoạt vấn đề. Tôi sử dụng cái mà tôi gọi là "phương pháp tìm kiếm nhị phân" để tái tạo: Tôi xóa một nửa các bước, kiểm tra, và lặp lại. Sử dụng phương pháp này, tôi đã giảm một trường hợp tái tạo 23 bước xuống chỉ còn 3 bước, điều này làm cho quá trình gỡ lỗi thực tế nhanh hơn 10 lần.
Thứ hai, bạn cần một cơ sở hạ tầng ghi log thích hợp. Tôi không nói về việc rắc rối các câu lệnh in khắp mã của bạn—tôi đang nói về ghi log có cấu trúc, có cấp bậc mà bạn có thể lọc và tìm kiếm một cách hiệu quả. Trong vai trò hiện tại của tôi, chúng tôi sử dụng một hệ thống ghi log tập trung cho phép tôi theo dõi một yêu cầu duy nhất qua 47 dịch vụ vi mô khác nhau. Cơ sở hạ tầng này đã giảm thời gian trung bình giải quyết vấn đề sản xuất của chúng tôi từ 6.2 giờ xuống còn 1.8 giờ.
Thứ ba, bạn cần một cuốn nhật ký giả thuyết. Đây chỉ đơn giản là một tài liệu nơi bạn ghi lại mọi giả thuyết bạn hình thành, chứng cứ ủng hộ hoặc bác bỏ nó, và các bài kiểm tra bạn thực hiện. Tôi sử dụng một tệp văn bản đơn giản với các dấu thời gian. Thói quen này mang lại hai lợi ích: nó ngăn bạn kiểm tra cùng một giả thuyết hai lần (điều mà tôi đã thấy các nhà phát triển làm nhiều lần hơn tôi có thể đếm được), và nó tạo ra một bản ghi.