Think Like a Developer #12: Systems Thinking - "Bug Không Nằm Ở Chỗ Nó Nổ"
Bug Không Nằm Ở Chỗ Nó Nổ: Systems Thinking Khi Debug Với AI
App chậm.
Người mới nhìn vào API response time.
Sau đó prompt AI:
Optimize API này giúp tôi.
AI sẽ làm đúng thứ bạn yêu cầu. Nó đọc endpoint, nhìn vài đoạn code, có thể thêm cache, chỉnh query, memoize gì đó, hoặc refactor một phần handler.
Vấn đề là: API response time chỉ là nơi triệu chứng xuất hiện. Nó chưa chắc là nơi bệnh bắt đầu.
Đây là chỗ developer khác người mới.
Developer thường dừng lại một nhịp trước khi sửa. Không phải vì họ chậm hơn. Mà vì họ biết một sự thật khó chịu:
Chỗ đau không phải lúc nào cũng là chỗ bệnh.
Một Triệu Chứng, Nhiều Nguyên Nhân
API chậm có thể vì query SQL ngu.
Nhưng cũng có thể vì Redis miss.
Hoặc connection pool cạn.
Hoặc queue backlog.
Hoặc downstream service timeout.
Hoặc frontend spam 12 request vì render loop.
Hoặc CDN config sai.
Hoặc user upload ảnh 20MB mỗi lần.
Cùng một symptom: "app chậm".
Nhưng nguyên nhân có thể nằm ở database, cache, frontend, network, queue, storage, hoặc một service khác mà endpoint chỉ vô tình phải chờ.
Nếu bạn chỉ nhìn nơi nó nổ, bạn dễ sửa sai chỗ.
Sửa sai chỗ không chỉ mất thời gian. Nó còn làm hệ thống rối hơn, vì bạn thêm patch lên một symptom mà chưa hiểu root cause.
Fix Symptom Khác Với Hiểu System
Người mới thường debug theo điểm.
Lỗi hiện ở API thì sửa API.
Lỗi hiện ở UI thì sửa component.
Lỗi hiện ở upload thì tăng timeout.
Lỗi hiện ở button thì disable button.
Cách này đôi khi đúng. Với bug nhỏ, nguyên nhân nằm ngay ở điểm nổ, sửa vậy là đủ.
Nhưng với app thật, nhất là app đã có database, cache, auth, queue, background job, storage, payment, AI agent, hoặc nhiều service, bug thường không tử tế như vậy.
Developer debug theo hệ thống.
Họ hỏi:
· Cái gì upstream dẫn tới chuyện này?
· Cái gì downstream bị ảnh hưởng?
· Đây là nguyên nhân hay chỉ là hậu quả?
· Nếu sửa chỗ này thì chỗ khác vỡ không?
· Evidence nào chứng minh mình đang sửa đúng tầng?
Đó là systems thinking.
Không phải nghĩ cho phức tạp. Mà là nhìn đúng hình dạng của vấn đề trước khi đụng code.
Vì Sao Tư Duy Này Quan Trọng Khi Build Với AI
AI rất giỏi sửa cái bạn chỉ vào.
Bạn nói:
Page load chậm.
AI có thể optimize component.
Memoize.
Lazy load.
Refactor code.
Tách component.
Giảm render.
Những thứ đó có thể đúng. Nhưng nếu vấn đề thật là backend query N+1, hoặc API gọi vòng tròn, hoặc frontend đang bắn 12 request vì một effect dependency sai, thì tối ưu component chỉ là makeup cho một hệ thống đang bệnh.
Đây là lý do nhiều người có cảm giác:
AI code nhanh thật, nhưng app vẫn ngày càng rối.
Không phải lúc nào cũng vì AI dở.
Nhiều khi vì bạn đang dùng AI để debug theo điểm.
Bạn thấy chỗ nào đỏ thì bảo AI sửa chỗ đó.
AI làm rất nhanh, rất tự tin, và thường có vẻ hợp lý. Nhưng nếu mental model của bạn sai, AI chỉ giúp bạn đi sai nhanh hơn.
Ví Dụ: Upload Avatar Hay Fail
User than:
Upload avatar hay fail.
Người mới sửa timeout từ 30s lên 120s.
Nghe cũng hợp lý. Nếu upload fail vì timeout, tăng timeout có thể làm nó đỡ fail.
Nhưng developer sẽ hỏi thêm:
· File size limit đang là bao nhiêu?
· Có resize ảnh trước khi upload không?
· Ảnh đi thẳng lên app server hay direct lên S3/R2?
· Storage local hay object storage?
· Retry policy đang thế nào?
· Concurrent upload thì sao?
· Nếu user cancel giữa chừng, cleanup chưa?
· Queue xử lý ảnh có nghẽn không?
· Có log phân biệt upload fail ở network, storage, hay image processing không?
Một fix kéo timeout.
Một hướng debug nhìn cả flow.
Hai cách này khác nhau rất xa.
Nếu lỗi thật là user upload ảnh 20MB, tăng timeout chỉ làm request treo lâu hơn.
Nếu lỗi thật là queue resize ảnh nghẽn, tăng timeout upload không giải quyết gì.
Nếu lỗi thật là storage trả lỗi ngẫu nhiên, bạn cần retry/idempotency, không phải timeout dài hơn.
Nếu lỗi thật là app server nhận file quá lớn rồi hết memory, timeout chỉ che symptom.
Developer không hỏi nhiều vì thích làm khó.
Họ hỏi vì mỗi câu loại trừ một nhóm nguyên nhân.
Một Framework Debug Với AI
Trước khi bảo AI sửa code, yêu cầu nó phân tích hệ thống.
Prompt kém:
Upload avatar hay fail. Fix giúp tôi.
Prompt tốt hơn:
Upload avatar hay fail.
Đừng sửa code ngay.
Hãy phân tích flow upload avatar end-to-end:
1. User chọn file ở frontend
2. Frontend validate file
3. Request upload đi tới backend hoặc storage
4. Backend/storage nhận file
5. Ảnh được resize/process
6. URL được lưu vào database
7. UI hiển thị avatar mới
Với mỗi bước:
- failure mode có thể là gì?
- log/metric nào cần xem?
- nếu sửa sai tầng thì risk là gì?
- cách kiểm chứng nhanh nhất là gì?
Sau đó mới đề xuất fix nhỏ nhất.
Điểm khác biệt không nằm ở câu chữ dài hơn.
Điểm khác biệt là bạn bắt AI nhìn flow trước khi sửa.
AI rất hữu ích trong việc liệt kê failure mode, đọc code path, đối chiếu log, và tạo checklist kiểm chứng. Nhưng bạn phải yêu cầu nó làm việc đó.
Nếu bạn chỉ đưa symptom, nó thường sẽ nhảy thẳng vào patch.
Dấu Hiệu Bạn Đang Debug Theo Điểm
Bạn có thể đang debug theo điểm nếu:
· thấy API chậm là sửa API ngay
· thấy UI sai là sửa component ngay
· thấy timeout là tăng timeout ngay
· thấy test fail là sửa test ngay
· thấy log thiếu là thêm log lung tung
· thấy AI sửa xong pass là tin luôn
· thấy bug mới sinh ra thì lại prompt AI fix tiếp
Cách làm này tạo cảm giác tiến triển nhanh.
Nhưng nó thường làm codebase ngày càng có nhiều patch nhỏ, ít liên kết với nhau, và khó giải thích.
Đến một lúc bạn không còn biết behavior hiện tại là intentional hay accidental.
Đó là lúc app bắt đầu rối.
Dấu Hiệu Bạn Đang Debug Theo Hệ Thống
Bạn đang debug theo hệ thống nếu trước khi sửa, bạn có thể nói rõ:
· Symptom là gì?
· Symptom xuất hiện ở tầng nào?
· Upstream nào có thể gây ra nó?
· Downstream nào bị ảnh hưởng?
· Evidence nào đang có?
· Evidence nào còn thiếu?
· Fix nhỏ nhất để kiểm chứng giả thuyết là gì?
· Nếu giả thuyết sai, rollback thế nào?
Bạn không cần biến mọi bug thành nghiên cứu 3 ngày.
Nhưng bạn cần đủ mental model để không sửa mù.
Với bug nhỏ, mental model có thể rất nhanh:
Lỗi nằm trong một function, input/output rõ, test tái hiện được.
Với bug hệ thống, mental model phải rộng hơn:
Lỗi hiện ở UI nhưng có thể bắt đầu từ API cache, permission filter, hoặc data transform.
Sự khác biệt là biết lúc nào cần nhìn rộng.
AI Nên Làm Gì Trong Quá Trình Này?
AI không chỉ để viết code.
Trong debug, AI có thể hữu ích hơn nếu bạn dùng nó cho các việc trước khi code:
1. Tóm tắt flow hiện tại
Yêu cầu AI đọc code và mô tả request đi qua những module nào.
2. Liệt kê failure modes
Yêu cầu AI liệt kê các nguyên nhân có thể, phân nhóm theo frontend/backend/database/cache/network/storage.
3. Tìm evidence cần xem
Yêu cầu AI nói log nào, metric nào, query nào, trace nào cần kiểm tra.
4. Đề xuất thứ tự kiểm chứng
Không phải fix nào trước, mà là kiểm chứng giả thuyết nào trước.
5. Đề xuất patch nhỏ nhất
Sau khi có evidence, yêu cầu AI sửa trong scope hẹp.
6. Review regression risk
Yêu cầu AI đọc diff và trả lời: sửa này có thể làm vỡ gì?
Đây là cách dùng AI như một debugging partner, không phải một máy vá symptom.
Một Prompt Mẫu Cho Systems Thinking
Bạn có thể dùng prompt này trước khi cho AI sửa bug:
Bug: [mô tả symptom]
Không sửa code ngay.
Hãy phân tích theo systems thinking:
1. Symptom đang xuất hiện ở tầng nào?
2. Upstream nào có thể gây ra symptom này?
3. Downstream nào có thể bị ảnh hưởng?
4. Đây có thể là root cause hay chỉ là hậu quả?
5. Cần xem evidence nào trước khi sửa?
6. Có những giả thuyết nào? Xếp theo xác suất.
7. Cách kiểm chứng từng giả thuyết là gì?
8. Nếu phải sửa, patch nhỏ nhất là gì?
9. Risk/regression của patch đó là gì?
10. Test hoặc log nào chứng minh fix đúng?
Sau đó mới cho AI sửa.
Nếu AI nhảy vào sửa ngay, bắt nó dừng lại.
Nếu AI đưa 1 nguyên nhân duy nhất quá sớm, bắt nó liệt kê alternative hypotheses.
Nếu AI không có evidence, đừng tin.
Kết Luận
Developer không chỉ viết code.
Developer build mental model.
Khi AI viết code ngày càng nhanh, thứ tạo khác biệt không còn là tốc độ gõ.
Là khả năng nhìn thấy hệ thống phía sau cái bug.
AI có thể giúp bạn sửa nhanh hơn.
Nhưng nếu bạn chỉ nhìn nơi bug nổ, bạn sẽ sửa nhanh vào sai chỗ.
Think like a developer.
Đừng chỉ nhìn nơi nó nổ.
Hãy nhìn thứ dẫn tới vụ nổ.
Nếu bạn đang build app bằng AI và muốn app dùng được thật, hãy bắt đầu từ systems thinking trước khi bắt đầu từ prompt.