Quá trình nào bạn thường sử dụng khi cố gắng gỡ lỗi một vấn đề / vấn đề / lỗi với phần mềm của bạn? [đóng cửa]


15

Hầu hết mọi người dường như coi việc gỡ lỗi là một nghệ thuật, hơn là một khoa học. Đối với những người ở đây coi nó như một khoa học, chứ không phải là một nghệ thuật - bạn thường sử dụng quy trình nào khi gặp phải một vấn đề / lỗi / vấn đề mới?

Câu trả lời:


13

Nói một cách rất chung chung, những gì tôi làm là:

  1. Cố gắng cô lập vấn đề. Hãy nghĩ về những gì đã thay đổi khi lỗi xuất hiện lần đầu tiên. Bạn đang làm việc ở đâu? Phần nào của mã bạn đã thay đổi? 99% lỗi của tôi được giải quyết theo cách này. Nó thường là một cái gì đó ngớ ngẩn.

  2. Nếu tôi có một dự đoán về vấn đề là ở đâu, hãy xem xét kỹ mã có vẻ là nguyên nhân. Đọc nó. Đọc to thậm chí Hãy tự hỏi: "Tôi đang cố gắng đạt được điều gì?". Đối với một số loại vấn đề: Nó có thể có một số tác dụng phụ hay nó có thể bị ảnh hưởng bởi mã ở một nơi khác theo cách mà tôi đã không nghĩ đến?

  3. Hãy thử theo nhiều cách khác nhau để phân tích những gì sai, ở đâu và khi nào (xem bên dưới).

  4. Nếu tôi vẫn không có manh mối, tôi kiểm tra xem một phiên bản cũ hơn của nguồn của tôi có cùng một vấn đề hay không, hãy thử tìm xem khi nào trong dòng thời gian phát triển của tôi, vấn đề xuất hiện lần đầu tiên. Để làm điều này, bạn cần phải làm việc với một hệ thống kiểm soát phiên bản tốt, chẳng hạn như git (git có một tính năng được gọi là bisect chính xác cho loại gỡ lỗi này).

  5. Nếu vẫn không có manh mối, hãy nghỉ ngơi .... nó thực sự thường giúp.

  6. Quay trở lại bảng vẽ - xem lại cách chương trình của bạn được cho là hoạt động và liệu điều đó có thực sự có ý nghĩa hay không.

Nó thực sự phụ thuộc vào loại vấn đề, nhưng giả sử tôi có một ý tưởng chung về vấn đề có thể xảy ra, thì:

  • Nếu tôi nghi ngờ vấn đề nằm ở một phần của mã / thay đổi gần đây, trước tiên tôi thử xóa / nhận xét / thay đổi hoặc bất cứ điều gì để lỗi biến mất bằng cách làm cho mã đơn giản hơn, sau đó đưa mã trở lại có vấn đề và lấy lại mã nhìn tốt về nó

  • Chạy trình gỡ lỗi với các điểm dừng (nếu có thể) và xem xét dữ liệu của tôi trông như thế nào khi cố gắng tìm kiếm khi nó bắt đầu hành động xấu, để hiểu rõ hơn về sự cố xảy ra.


1
+1 để nghỉ ngơi. Các vấn đề khó khăn nhất chỉ trở nên khó khăn hơn khi bạn thất vọng và trong giờ thứ 6 của bạn gỡ lỗi chúng. Biết khi nào nên nghỉ ngơi là một trong những kỹ năng sửa lỗi hữu ích nhất mà tôi có được.
Brad Gardner

Câu trả lời tuyệt vời. Tôi không thể làm tốt hơn.
EricBoersma

1
Giống như cách tiếp cận của tôi, nhưng bạn đã quên mất một chút khi bạn yêu cầu một đồng nghiệp đưa ra một cái nhìn nhanh và họ ngay lập tức nhận thấy lỗi chính tả ...
ChrisAnnODell

1
Câu trả lời tuyệt vời. Tôi chỉ muốn nói thêm rằng một ounce phòng ngừa đáng giá một pound thuốc chữa bệnh. Một phần lớn trong quá trình sửa lỗi của tôi là trong khi tôi đang mã hóa ở nơi đầu tiên, tôi chỉ thực hiện các thay đổi nhỏ, tăng dần và biên dịch, kiểm tra và cam kết cục bộ giữa mỗi lần. Theo cách đó, nếu một lỗi đột nhiên xuất hiện, danh sách nghi phạm có khả năng rất nhỏ và dễ nhìn thấy bằng một bzr qdifflệnh.
Karl Bielefeldt

8

Tôi cố gắng sử dụng phát triển dựa trên thử nghiệm ( TDD ). Tôi viết một bài kiểm tra sao chép lỗi, sau đó cố gắng để bài kiểm tra vượt qua. Đôi khi hành động viết bài kiểm tra giúp tìm ra lỗi.

Điều này giúp tôi tránh khỏi trình gỡ lỗi hầu hết thời gian và cung cấp các bài kiểm tra hồi quy để ngăn chặn việc giới thiệu lại lỗi.

Một số liên kết:


4
Tôi nghĩ rằng câu trả lời này là không đầy đủ. Tôi không hiểu nhiều upvote.
Alex

1
Nó chỉ nhận được nhiều upvote bởi vì nó bao gồm các từ viết tắt huyền diệu: TDD.
Bjarke Freund-Hansen

@Alex - Tôi đã thêm một số liên kết. Ví dụ: "Tìm một BUG, ​​Viết KIỂM TRA" có một ví dụ. Tôi có thể mở rộng về điều này, nhưng nó thực sự đơn giản.
TrueWill

7

Có một số định nghĩa cho từ khoa học, nhưng có vẻ như bạn có thể đang đề cập đến những gì có thể được gọi chính xác hơn là " phương pháp khoa học ". Phương pháp khoa học có thể được tóm tắt là quan sát một số hiện tượng (có thể là lỗi hoặc hành vi chương trình không mong muốn), hình thành một giả thuyết hoặc giả thuyết để giải thích hành vi và có khả năng thử nghiệm nhất để chứng minh điều đó (viết một bài kiểm tra tái tạo vấn đề một cách đáng tin cậy).

Các loại lỗi (hiện tượng) có thể xảy ra trên thực tế là vô tận và một số không nhất thiết đòi hỏi một quy trình được xác định rõ. Ví dụ, đôi khi bạn quan sát thấy một lỗi và ngay lập tức bạn biết nguyên nhân gây ra nó đơn giản vì bạn rất quen thuộc với mã. Lần khác, bạn biết rằng với một số đầu vào (hành động, chuỗi các bước, v.v.), kết quả không chính xác xảy ra (sự cố, đầu ra xấu, v.v.). Đối với những trường hợp đó, nó thường không đòi hỏi nhiều tư duy "khoa học". Một số suy nghĩ có thể giúp giảm không gian tìm kiếm, nhưng một phương pháp phổ biến chỉ đơn giản là bước qua mã trong trình gỡ lỗi và xem mọi thứ diễn ra như thế nào.

Mặc dù vậy, các tình huống mà tôi thấy thú vị nhất và có thể xứng đáng với một quy trình khoa học là nơi bạn được trao một số kết quả cuối cùng và được yêu cầu giải thích nó đã xảy ra như thế nào. Một ví dụ rõ ràng trong số này là một bãi chứa sự cố. Bạn có thể tải bãi chứa sự cố và quan sát trạng thái của hệ thống và công việc của bạn là giải thích cách thức hệ thống chuyển sang trạng thái đó. Kết xuất sự cố (hoặc lõi) có thể hiển thị ngoại lệ, bế tắc, lỗi nội bộ hoặc một số trạng thái "không mong muốn" như được xác định bởi người dùng (ví dụ: chậm chạp). Đối với những tình huống này, tôi thường làm theo các bước dọc theo các dòng sau:

  • Quan sát hẹp : Nghiên cứu thông tin trực tiếp xung quanh vấn đề cụ thể nếu có. Những điều rõ ràng ở đây là ngăn xếp cuộc gọi, các biến cục bộ nếu bạn có thể thấy chúng, các dòng mã xung quanh vấn đề. Loại nghiên cứu vị trí cụ thể này không phải lúc nào cũng được áp dụng. Ví dụ, nghiên cứu một hệ thống "chậm" có thể không có vị trí bắt đầu rõ ràng như thế này, nhưng một sự cố hoặc tình huống lỗi nội bộ có thể sẽ có một điểm quan tâm ngay lập tức và rõ ràng. Một bước cụ thể ở đây có thể là sử dụng các công cụ như Windbg (chạy! Phân tích -v trên một bãi chứa sự cố được tải và xem những gì nó nói với bạn).

  • Quan sát rộng : Nghiên cứu các phần khác của hệ thống. Kiểm tra trạng thái của tất cả các luồng trong hệ thống, xem xét bất kỳ thông tin toàn cầu nào (số lượng người dùng / hoạt động / mục, giao dịch / quy trình / widget đang hoạt động, v.v.), thông tin hệ thống (HĐH), v.v. Nếu người dùng cung cấp bất kỳ chi tiết bên ngoài nào , nghĩ về những người kết hợp với những gì bạn đã quan sát. Ví dụ, nếu họ nói với bạn rằng vấn đề xảy ra vào mỗi chiều thứ ba, hãy tự hỏi điều đó có nghĩa là gì.

  • Giả thuyết: Đây là phần thực sự thú vị (và tôi không tỏ ra lạc quan về việc nó vui vẻ). Nó thường đòi hỏi rất nhiều suy nghĩ logic ngược lại. Có thể rất thú vị khi nghĩ về cách hệ thống đi vào trạng thái hiện tại. Tôi nghi ngờ rằng đây là phần mà nhiều người nghĩ là một nghệ thuật. Và tôi cho rằng nó có thể là nếu lập trình viên chỉ bắt đầu ném ngẫu nhiên mọi thứ vào nó để xem những gì gậy. Nhưng với kinh nghiệm, đây có thể là một quá trình được xác định khá rõ. Nếu bạn nghĩ rất logic vào thời điểm này, thường có thể xác định các bộ đường dẫn có thể dẫn đến trạng thái đã cho. Tôi biết rằng chúng tôi đang ở trạng thái S5. Để điều đó xảy ra, S4a hoặc S4b cần phải xảy ra và có thể S3 trước S4a, v.v. Thông thường thì không, có thể có nhiều mục có thể dẫn đến một trạng thái nhất định. Đôi khi nó có thể giúp ghi lại trên bảng cào một sơ đồ trạng thái hoặc dòng chảy đơn giản hoặc một loạt các bước liên quan đến thời gian. Các quy trình thực tế ở đây sẽ thay đổi rất nhiều tùy thuộc vào tình huống, nhưng suy nghĩ nghiêm túc (và kiểm tra lại trong các bước trước) tại thời điểm này thường sẽ cung cấp một hoặc nhiều câu trả lời hợp lý. Cũng lưu ý rằng một phần cực kỳ quan trọng của bước này là loại bỏ những thứ không thể. Loại bỏ những điều không thể có thể giúp cắt bớt không gian giải pháp (hãy nhớ những gì Sherlock Holmes nói về những gì còn lại sau khi bạn loại bỏ những điều không thể). Cũng lưu ý rằng một phần cực kỳ quan trọng của bước này là loại bỏ những thứ không thể. Loại bỏ những điều không thể có thể giúp cắt bớt không gian giải pháp (hãy nhớ những gì Sherlock Holmes nói về những gì còn lại sau khi bạn loại bỏ những điều không thể). Cũng lưu ý rằng một phần cực kỳ quan trọng của bước này là loại bỏ những thứ không thể. Loại bỏ những điều không thể có thể giúp cắt bớt không gian giải pháp (hãy nhớ những gì Sherlock Holmes nói về những gì còn lại sau khi bạn loại bỏ những điều không thể).

  • Thử nghiệm : Trong giai đoạn này, cố gắng tái tạo vấn đề dựa trên các giả thuyết xuất phát ở bước trước. Nếu bạn đã suy nghĩ nghiêm túc trong bước trước, điều này sẽ rất đơn giản. Đôi khi tôi "gian lận" và sửa đổi cơ sở mã để giúp kiểm tra nhất định. Ví dụ, gần đây tôi đang điều tra một vụ tai nạn mà tôi kết luận là do tình trạng chủng tộc. Để xác minh nó, tôi chỉ cần đặt một chế độ Ngủ (500) giữa một vài dòng mã để cho phép một luồng khác thực hiện công cụ xấu của nó vào thời điểm "đúng". Tôi không biết nếu điều này được cho phép trong khoa học "thực sự", nhưng nó hoàn toàn hợp lý trong mã mà bạn sở hữu.

Nếu bạn thành công trong việc tái tạo nó, rất có thể bạn đã gần hoàn thành (tất cả những gì còn lại là bước đơn giản để sửa nó ... nhưng đó là cho một ngày khác). Hãy chắc chắn kiểm tra thử nghiệm mới vào hệ thống kiểm tra hồi quy. Và tôi nên chỉ ra rằng tôi dự định rằng tuyên bố trước đây về việc sửa nó trở nên đơn giản để nói thẳng. Việc tìm ra một giải pháp và thực hiện nó có thể đòi hỏi nhiều công việc. Theo ý kiến ​​của tôi, việc sửa lỗi không phải là một phần của quá trình sửa lỗi mà là sự phát triển. Và nếu sửa chữa hoàn toàn có liên quan, thì nó cần một số lượng thiết kế và xem xét.


Hầu hết các lỗi mà tôi thấy không thể tái tạo một cách đáng tin cậy và đối với tập hợp con, phần lớn vẫn yêu cầu công việc sửa lỗi đáng kể sau khi chúng được sao chép, trước khi mọi công việc khắc phục chúng có thể bắt đầu. Ngay cả khi thay vì nói "thành công trong việc tái tạo nó", bạn nói, "thành công trong việc thu hẹp một bài kiểm tra đơn vị rõ ràng thực hiện lỗi", tôi nói rằng công việc sửa lỗi chưa kết thúc. Đối với tôi, việc sửa lỗi đã kết thúc khi cả hai tôi đều có cách khắc phục Tôi có thể chứng minh khắc phục sự cố và tôi có bằng chứng đáng tin cậy rằng bản sửa lỗi của tôi là thứ thực sự khắc phục mọi thứ.
quả việt quất

Tôi đồng ý rằng nó có thể là khá nhiều công việc để sửa nó. Tôi thực sự đã sử dụng lời châm biếm trong lời nói "bước đơn giản để sửa nó", nhưng điều đó không thông qua rất tốt về loại hình.

4

Cố gắng giảm trường hợp thử nghiệm. Khi nó đủ nhỏ, thường sẽ dễ dàng hơn để xác định mã tương ứng gây ra sự cố.

Có khả năng việc đăng ký mới đang gây ra sự cố và bản dựng hàng ngày trước đó vẫn ổn. Trong trường hợp đó, nhật ký thay đổi của bạn từ kiểm soát nguồn sẽ giúp bạn quyết định bắt ai.

Ngoài ra, nếu bạn vào C / C ++, hãy cân nhắc việc chạy valgrind hoặc thanh lọc để cô lập các vấn đề liên quan đến bộ nhớ.


2

Phần khó nhất của việc gỡ lỗi là cách ly vấn đề, đặc biệt khi vấn đề được chôn vùi dưới nhiều lớp. Ở trường đại học tôi đã học ghi âm nhạc, và thật kỳ lạ là có một lớp Studio Electronics trực tiếp áp dụng ở đây. Tôi sẽ sử dụng gỡ lỗi một môi trường studio như một minh họa cho quá trình gỡ lỗi có hệ thống.

  1. Kiểm tra mét của bạn. Sử dụng âm kiểm tra ở điện áp hiệu chỉnh đã biết, đồng hồ đo phải đọc "U" (mức tăng đơn vị). Dịch: Nếu công cụ của bạn bị hỏng, bạn không thể sử dụng chúng để tìm ra điều gì khác là sai.
  2. Kiểm tra từng thành phần / giai đoạn đạt được làm việc ngược từ cuối. Sử dụng cùng một giai điệu thử nghiệm được áp dụng cho đầu vào của giai đoạn, sẽ không có thay đổi ở đầu ra của giai đoạn. Dịch: Bằng cách cách ly từng đối tượng từ đầu ra ngược, chúng tôi đang xây dựng niềm tin vào mã của mình cho đến khi chúng tôi tìm thấy vị trí mà nó gây rối. Nếu phải mất một vài lớp để các công cụ của bạn báo hiệu sự cố, bạn cần biết rằng các lớp ở giữa không đóng góp cho nó.

Mã gỡ lỗi thực sự không quá khác biệt. Gỡ lỗi dễ dàng hơn rất nhiều khi mã đang ném một ngoại lệ. Bạn có thể theo dõi ngược từ dấu vết ngăn xếp của ngoại lệ đó và đặt điểm dừng tại các vị trí quan trọng. Thông thường chỉ sau khi bạn đặt một biến hoặc trên dòng gọi phương thức ném ngoại lệ. Bạn có thể thấy rằng một hoặc nhiều giá trị không đúng. Nếu nó không đúng (không có giá trị khi không nên hoặc giá trị nằm ngoài phạm vi), thì đó là quá trình khám phá lý do tại sao nó không đúng. Điểm ngắt trong IDE tương đương với điểm kiểm tra điện tử (được thiết kế cho đầu dò của máy đo để kiểm tra mạch).

Bây giờ, một khi tôi đã trải qua phần khó khăn đó để khám phá vấn đề thực sự của mình ở đâu, tôi sẽ viết một số bài kiểm tra đơn vị để kiểm tra xem trong tương lai.


2

Với những con bọ khó chịu mà tôi phải vật lộn để theo dõi vào cuối buổi chiều, chiến lược hiệu quả nhất của tôi là đứng dậy và bỏ đi trong vài phút. Thông thường những ý tưởng mới về các nguồn lỗi có thể bắt đầu chảy vào chỉ sau 30 giây.


2

Đối với một aproach thực tế hơn:

  1. Nếu lỗi có liên quan đến một ngoại lệ chưa được xử lý - hãy nhìn vào dấu vết ngăn xếp. Không có tài liệu tham khảo, chỉ số ngoài giới hạn, v.v. và các trường hợp ngoại lệ được xác định của riêng bạn là phổ biến nhất, bạn có thể gán lỗi này cho một nhà phát triển cơ sở, nó có thể dễ dàng và là một điểm học tập tốt.

  2. Nếu nó không xảy ra trên mọi máy, thì đó có lẽ là một dạng của vấn đề về luồng / luồng. Đây là những siêu thú vị để theo dõi, đưa lập trình viên cao cấp nhàm chán của bạn vào nó. Rất nhiều đăng nhập, kiến ​​thức tốt và các công cụ tốt được thực hiện.

  3. Một loại lỗi lớn khác là khi nhóm thử nghiệm hoặc (các) khách hàng không thích một hành vi cụ thể. Ví dụ: họ không thích việc bạn quyết định hiển thị ID người dùng hoặc khi tìm kiếm bạn không tự động hoàn tất. Đây là những lỗi chính hãng, xem xét việc quản lý sản phẩm tốt hơn và nhà phát triển với tầm nhìn rộng hơn. Sẽ cần một nhà phát triển mất một thời gian tương đối ngắn để "khắc phục" điều này nếu anh ta xây dựng hệ thống với ý tưởng mở rộng.

  4. 80% tất cả các lỗi khác được giải quyết bằng cách có một hệ thống ghi nhật ký tốt và thu thập đủ thông tin để giải quyết chúng. Sử dụng theo dõi tích hợp với nhiều cấp, các hệ thống ghi nhật ký phức tạp như Log4Net / Log4J

  5. lỗi hiệu suất là một phạm trù của riêng họ, quy tắc táo bạo hơn ở đây là "đo lường trước, khắc phục sau!", và bạn sẽ ngạc nhiên khi thấy có bao nhiêu nhà phát triển chỉ đoán vấn đề ở đâu và đi vào ngay để khắc phục chỉ để xem sau đó chỉ giảm 3-4% trong thời gian đáp ứng.


Nếu tôi có thể +1 từng người trong số 5 người đó, tôi sẽ làm thế!
jmort253

1

Tôi có hai cách tiếp cận:

  1. Phân chia vấn đề được đưa ra trong các phần nhỏ hơn và sau đó chinh phục từng phần nhỏ hơn theo Divide and ConquerParadigm.
  2. Bất cứ khi nào tôi nghi ngờ về bất kỳ giá trị nào hơn là tôi chỉ in ra các giá trị của các biến để xem chính xác những gì đang đến và đi ra khỏi biến.

Cách tiếp cận này đã giúp tôi hầu hết thời gian.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.