Xử lý lỗi - Nếu chương trình bị lỗi hoặc âm thầm bỏ qua chúng


20

Tôi đang viết một chương trình nhỏ đơn giản để truyền MIDI qua mạng. Tôi biết rằng chương trình sẽ gặp phải sự cố truyền và / hoặc các tình huống ngoại lệ khác mà tôi không thể dự đoán được.

Đối với việc xử lý ngoại lệ, tôi thấy hai cách tiếp cận. Tôi có nên viết chương trình để nó:

  • thất bại với một tiếng nổ khi có sự cố hoặc
  • Có nên bỏ qua lỗi và tiếp tục, với chi phí toàn vẹn dữ liệu?

Cách tiếp cận nào người dùng sẽ mong đợi một cách hợp lý?
Có cách nào tốt hơn để xử lý các trường hợp ngoại lệ?

Ngoài ra, liệu quyết định của tôi về việc xử lý các trường hợp ngoại lệ có bị ảnh hưởng bởi liệu tôi có đang xử lý kết nối mạng hay không (nghĩa là một cái gì đó mà tôi có thể mong đợi có vấn đề xảy ra một cách hợp lý)?



Có cách nào để chỉnh sửa +1 không? ;) Oh, đợi đã, tôi theo bạn. Chắc chắn, sẽ làm :)
Arlen Beiler

2
"Cách tiếp cận nào người dùng sẽ mong đợi một cách hợp lý?". Bạn đã thử hỏi một trong những người dùng của bạn chưa? Kiểm tra khả năng sử dụng hành lang có thể có hiệu quả đáng kể. Xem blog.openhallway.com/?p=146
Bryan Oakley

Tôi không có bất kỳ người dùng nào :)
Arlen Beiler

Câu trả lời:


34

Không bao giờ bạn nên bỏ qua một lỗi mà chương trình của bạn gặp phải. Ở mức tối thiểu, bạn nên đăng nhập nó vào một tập tin hoặc một số cơ chế khác để thông báo. Có thể đôi khi bạn sẽ muốn bỏ qua một lỗi nhưng ghi lại nó! Đừng viết một catchkhối trống mà không có bất kỳ bình luận nào giải thích tại sao nó trống.

Chương trình có nên thất bại hay không phụ thuộc rất nhiều vào bối cảnh. Nếu bạn có thể xử lý lỗi một cách duyên dáng, hãy tìm nó. Nếu đó là một lỗi không mong muốn, thì chương trình của bạn sẽ bị sập. Đó là khá nhiều cơ bản của xử lý ngoại lệ.


18
Không đủ để đảm bảo -1, nhưng "không bao giờ" là một từ mạnh mẽ và có những tình huống bỏ qua lỗi là hướng hành động đúng đắn. Ví dụ, phần mềm để giải mã truyền phát HDTV. Khi bạn gặp phải một số lỗi mà bạn thường gặp phải, tất cả những gì bạn có thể làm là bỏ qua nó và tiếp tục giải mã những gì xảy ra sau đó.
whatsisname

1
@whatsisname: đúng, nhưng bạn nên ghi rõ lý do tại sao bạn lại bỏ qua nó. Cập nhật câu trả lời để xem xét nhận xét của bạn.
marco-fiset

1
@ marco-fiset tôi không đồng ý. Phá vỡ toàn bộ chương trình chỉ là giải pháp nếu đó là tình huống khởi động lại nó sẽ khắc phục vấn đề. Điều này không phải lúc nào cũng đúng, vì vậy việc phá vỡ nó thường là vô nghĩa và mặc định rằng hành vi đó là ngu ngốc. Tại sao bạn muốn tạm dừng toàn bộ hoạt động của mình vì lỗi cục bộ? Điều đó không có ý nghĩa. Hầu hết các ứng dụng làm điều đó và, vì một số lý do, các lập trình viên hoàn toàn ổn với điều đó.
MaiaVictor

@Dokkat: vấn đề là không tiếp tục với các giá trị sai, điều này sẽ đưa ra một giải pháp sai (rác vào, rác ra). Sự cố không khắc phục được sự cố: nó buộc người dùng phải cung cấp các đầu vào khác nhau hoặc khiến nhà phát triển sửa lỗi chương trình của họ;)
André Paramés 15/03/13

1
@whatsisname Tôi nghĩ bạn có thể muốn nghĩ về định nghĩa "lỗi" của mình trong trường hợp đó. Lỗi trong dữ liệu nhận được không giống như lỗi trong cấu trúc và thực thi chương trình phần mềm.
joshin4colours

18

Bạn không bao giờ nên âm thầm bỏ qua các lỗi, bởi vì chương trình của bạn được xây dựng dựa trên một loạt các hành động hoàn toàn phụ thuộc vào mọi thứ đã xảy ra trước khi chúng đi đúng. Nếu có lỗi xảy ra ở bước 3 và bạn cố gắng tiếp tục sang bước 4, bước 4 sẽ bắt đầu dựa trên các giả định không hợp lệ, điều này có nhiều khả năng nó cũng sẽ gây ra lỗi. (Và nếu bạn cũng bỏ qua điều đó, thì bước 5 sẽ xuất hiện lỗi và mọi thứ bắt đầu từ quả cầu tuyết từ đó.)

Vấn đề là, khi các lỗi chồng chất, cuối cùng bạn sẽ gặp phải một số lỗi lớn đến mức bạn không thể bỏ qua nó, bởi vì nó sẽ bao gồm một cái gì đó được trao cho người dùng và rằng một cái gì đó sẽ hoàn toàn sai. Sau đó, bạn có người dùng phàn nàn về chương trình của bạn không hoạt động đúng và bạn phải sửa nó. Và nếu phần "đưa thứ gì đó cho người dùng" ở bước 28 và bạn không biết rằng lỗi ban đầu gây ra tất cả sự lộn xộn này là ở bước 3 vì bạn đã bỏ qua lỗi ở bước 3, bạn sẽ có một lỗi một thời gian gỡ lỗi vấn đề!

Mặt khác, nếu lỗi đó ở bước 3 làm cho mọi thứ nổ tung trong khuôn mặt của người dùng và tạo ra một lỗi nói SOMETHING WENT BADLY WRONG IN STEP 3!(hoặc tương đương về mặt kỹ thuật của nó, dấu vết ngăn xếp), thì kết quả là như nhau - người dùng phàn nàn về bạn chương trình không hoạt động đúng - nhưng lần này bạn biết chính xác nơi bắt đầu tìm kiếm khi bạn đi sửa nó .

EDIT: Đáp lại các bình luận, nếu có sự cố xảy ra mà bạn dự đoán và biết cách xử lý, điều đó khác. Ví dụ: trong trường hợp nhận được tin nhắn không đúng định dạng, đó không phải là lỗi chương trình; đó là "người dùng cung cấp đầu vào xấu mà xác nhận không thành công." Câu trả lời thích hợp là nói với người dùng rằng anh ta cung cấp cho bạn đầu vào không hợp lệ, đó là những gì nghe giống như bạn đang làm. Không cần phải sụp đổ và tạo ra một dấu vết ngăn xếp trong trường hợp như vậy.


Làm thế nào về việc trở lại vị trí tốt được biết đến cuối cùng, hoặc trong trường hợp của một vòng lặp nhận, chỉ cần bỏ thông điệp đó và đi đến vị trí tiếp theo.
Arlen Beiler

@Arlen: Thậm chí đó có thể là một ý tưởng tồi. Lỗi xảy ra vì điều gì đó đã xảy ra mà bạn không lường trước được khi bạn mã hóa nó . Điều này có nghĩa là tất cả các giả định của bạn đã đi ra ngoài cửa sổ. Rằng "vị trí tốt được biết đến cuối cùng" có thể sẽ không còn tốt nữa nếu bạn đang sửa đổi một số cấu trúc dữ liệu và bây giờ nó ở trạng thái không nhất quán, chẳng hạn.
Mason Wheeler

Điều gì sẽ xảy ra nếu tôi đang mong đợi nó, như các tin nhắn bị hỏng ngăn chặn quá trình khử lưu huỳnh. Trong một số trường hợp, tôi đã tuần tự hóa ngoại lệ và gửi lại qua dây. Ở đó, xem chỉnh sửa của tôi cho câu hỏi.
Arlen Beiler

@Arlen: Nếu bạn đã lường trước được điều đó và bạn chắc chắn rằng bạn biết tác động của lỗi là gì và chúng được chứa đúng cách, thì điều đó khác. Âm thanh với tôi như bạn đang xử lý lỗi và phản hồi thích hợp, không bỏ qua nó. Tôi đã nói về việc bỏ qua các lỗi không mong muốn , đó là những gì nghe có vẻ như bạn đang hỏi về.
Mason Wheeler

16

Có những lựa chọn khác giữa "nổ tung" và "bỏ qua."

Nếu lỗi có thể dự đoán và có thể tránh được, hãy thay đổi thiết kế hoặc cấu trúc lại mã của bạn để tránh lỗi đó.

Nếu lỗi có thể dự đoán được nhưng không thể tránh được, nhưng bạn biết phải làm gì khi xảy ra, sau đó bắt lỗi và xử lý tình huống. Nhưng hãy cẩn thận để tránh sử dụng ngoại lệ như kiểm soát dòng chảy. Và bạn có thể muốn ghi lại cảnh báo vào thời điểm này và có thể thông báo cho người dùng nếu có một số hành động họ có thể thực hiện để tránh tình huống này trong tương lai.

Nếu lỗi có thể dự đoán được, không thể tránh khỏi và khi xảy ra, bạn không thể làm gì để đảm bảo tính toàn vẹn dữ liệu, thì bạn cần phải ghi lại lỗi và trở về trạng thái an toàn (như những người khác đã nói, có thể có nghĩa là bị sập).

Nếu lỗi không phải là điều bạn dự đoán, thì bạn thực sự không thể chắc chắn rằng mình thậm chí có thể quay lại trạng thái an toàn, vì vậy tốt nhất là chỉ cần đăng nhập và gặp sự cố.

Theo nguyên tắc chung, đừng bắt bất kỳ ngoại lệ nào bạn không thể làm bất cứ điều gì, trừ khi bạn chỉ có kế hoạch đăng nhập và suy nghĩ lại. Và trong những trường hợp hiếm hoi không thể tránh khỏi việc thử bắt-bỏ qua, ít nhất hãy thêm một nhận xét trong khối bắt của bạn để giải thích lý do.

Xem bài viết xử lý ngoại lệ xuất sắc của Eric Lippert để biết thêm đề xuất về phân loại và xử lý ngoại lệ.


1
Câu trả lời tốt nhất cho đến nay, theo ý kiến ​​của tôi.
thứ năm

6

Đây là những quan điểm của tôi về câu hỏi:

Một nguyên tắc khởi đầu tốt là thất bại nhanh. Cụ thể, bạn không bao giờ nên viết mã xử lý lỗi cho bất kỳ lỗi nào mà bạn không biết nguyên nhân chính xác.

Sau khi áp dụng nguyên tắc này, bạn có thể thêm mã khôi phục cho các điều kiện lỗi cụ thể mà bạn gặp phải. Bạn cũng có thể giới thiệu một số "trạng thái an toàn" để quay lại. Hủy bỏ một chương trình hầu hết là an toàn, nhưng đôi khi bạn có thể muốn quay lại trạng thái tốt đã biết khác. Một ví dụ là cách một hệ điều hành hiện đại xử lý một chương trình vi phạm. Nó chỉ tắt chương trình, không phải toàn bộ hệ điều hành.

Bằng cách thất bại nhanh và chậm bao gồm các điều kiện lỗi cụ thể hơn và nhiều hơn, bạn không bao giờ ảnh hưởng đến tính toàn vẹn dữ liệu và dần dần tiến tới một chương trình ổn định hơn.

Nuốt lỗi, tức là cố gắng lập kế hoạch cho các lỗi mà bạn không biết nguyên nhân chính xác và do đó không có chiến lược khắc phục cụ thể nào, chỉ dẫn đến việc tăng mã lỗi và lách trong chương trình của bạn. Vì người ta không thể tin rằng dữ liệu trước đó đã được xử lý chính xác, bạn sẽ bắt đầu thấy các kiểm tra dàn trải cho dữ liệu không chính xác hoặc bị thiếu. Sự phức tạp chu kỳ của bạn sẽ xoắn ốc ra khỏi tầm tay và bạn sẽ kết thúc với một quả bóng bùn lớn.

Có hay không bạn nhận thức được các trường hợp thất bại là ít quan trọng. Nhưng nếu bạn đang xử lý một kết nối mạng mà bạn biết một số trạng thái lỗi nhất định, hãy hoãn việc thêm xử lý lỗi cho đến khi bạn cũng thêm mã khôi phục. Điều này phù hợp với các nguyên tắc được nêu ở trên.


6

Bạn không bao giờ nên âm thầm bỏ qua lỗi. Và đặc biệt không phải là chi phí của tính toàn vẹn dữ liệu .

Chương trình đang cố gắng làm một cái gì đó. Nếu thất bại, bạn phải đối mặt với thực tế và làm điều gì đó về nó. Điều gì đó sẽ được phụ thuộc vào rất nhiều thứ.

Cuối cùng, người dùng yêu cầu chương trình làm một cái gì đó và chương trình sẽ nói với họ rằng nó không thành công. Có nhiều cách làm thế nào nó có thể làm điều đó. Nó có thể dừng ngay lập tức, thậm chí có thể quay lại các bước đã hoàn thành hoặc mặt khác nó có thể tiếp tục và hoàn thành tất cả các bước có thể và hơn là cho người dùng biết rằng các bước này đã thành công và những bước khác đã thất bại.

Cách bạn chọn phụ thuộc vào mức độ liên quan của các bước có liên quan và liệu có khả năng lỗi sẽ xảy ra cho tất cả các bước trong tương lai hay không, điều này có thể lần lượt phụ thuộc vào lỗi chính xác. Nếu tính toàn vẹn dữ liệu mạnh là bắt buộc, bạn phải quay trở lại trạng thái nhất quán cuối cùng. Nếu bạn chỉ sao chép một loạt các tệp, bạn có thể bỏ qua một số và chỉ cần nói với người dùng ở cuối rằng các tệp đó không thể được sao chép. Bạn không nên âm thầm bỏ qua các tập tin và không nói gì với người dùng.

Chỉnh sửa quảng cáo, điểm khác biệt duy nhất là bạn nên xem xét thử lại một số lần trước khi từ bỏ và nói với người dùng rằng nó không hoạt động, vì mạng có thể có lỗi tạm thời sẽ không xảy ra nếu bạn thử lại.


Bạn có thực sự muốn đặt một dấu hỏi ở cuối dòng đầu tiên không?
một CVn

@ MichaelKjorling: Không. Lỗi sao chép-dán (sao chép công thức từ câu hỏi và bao gồm dấu chấm hỏi do nhầm lẫn).
Jan Hudec

4

Có một loại trường hợp bỏ qua lỗi là điều nên làm: Khi không có gì có thể được thực hiện về tình huống và khi kết quả kém và có thể không chính xác thì tốt hơn là không có kết quả.

Trường hợp giải mã luồng HDMI cho mục đích hiển thị là trường hợp như vậy. Nếu luồng không tốt thì nó sẽ tệ, hãy hét lên về việc nó sẽ không sửa được nó. Bạn làm những gì bạn có thể để hiển thị nó và để người xem quyết định xem nó có chấp nhận được hay không.


1

Tôi không tin rằng một chương trình nên âm thầm bỏ qua hoặc gây ra sự tàn phá bất cứ khi nào nó gặp sự cố.

Những gì tôi làm với phần mềm nội bộ tôi viết cho công ty của mình ...

Nó phụ thuộc vào lỗi, giả sử nếu đó là một chức năng quan trọng đang nhập dữ liệu vào MySQL, nó cần cho người dùng biết rằng nó bị lỗi. Trình xử lý lỗi nên cố gắng thu thập càng nhiều thông tin và cung cấp cho người dùng ý tưởng về cách tự sửa lỗi để họ có thể lưu dữ liệu. Tôi cũng muốn cung cấp một cách âm thầm gửi cho chúng tôi thông tin mà họ đang cố lưu để nếu tệ hơn trở nên tồi tệ hơn, chúng tôi có thể nhập thủ công sau khi sửa lỗi.

Nếu đó không phải là một chức năng quan trọng, một cái gì đó có thể lỗi và không ảnh hưởng đến kết quả cuối cùng của những gì họ đang cố gắng đạt được, tôi có thể không hiển thị cho họ một thông báo lỗi, nhưng hãy gửi email tự động chèn nó vào phần mềm theo dõi lỗi của chúng tôi hoặc một nhóm phân phối email thông báo cho tất cả các lập trình viên trong công ty để chúng tôi nhận ra lỗi, ngay cả khi người dùng không. Điều này cho phép chúng tôi sửa chữa mặt sau trong khi ở mặt trước không ai biết chuyện gì đang xảy ra.

Một trong những điều lớn nhất tôi cố gắng tránh là gặp sự cố chương trình sau lỗi - không thể khôi phục. Tôi luôn cố gắng cung cấp cho người dùng tùy chọn để tiếp tục mà không đóng ứng dụng.

Tôi tin rằng nếu không ai biết về lỗi - nó sẽ không bao giờ được sửa. Tôi cũng là một người tin tưởng vững chắc trong việc xử lý lỗi cho phép ứng dụng tiếp tục hoạt động sau khi phát hiện ra lỗi.

Nếu lỗi liên quan đến mạng - tại sao các chức năng không thực hiện kiểm tra giao tiếp mạng đơn giản trước khi thực hiện chức năng để tránh lỗi ở vị trí đầu tiên? Sau đó, chỉ cần thông báo cho người dùng rằng không có kết nối, vui lòng xác minh internet của bạn, v.v. và thử lại?


1
Cá nhân tôi thực hiện nhiều xác minh trước khi chạy các chức năng quan trọng để cố gắng hạn chế các lỗi mà tôi không hiểu đầy đủ và không thể cung cấp xử lý lỗi hữu ích trả về thông tin chi tiết. Nó không hoạt động 100% thời gian, nhưng tôi không thể nhớ lần cuối cùng tôi gặp lỗi khiến tôi mất hàng giờ.
Jeff

1

Chiến lược của riêng tôi là phân biệt giữa lỗi mã hóa (lỗi) và lỗi thời gian chạy , và, càng nhiều càng tốt, làm cho lỗi mã hóa khó tạo ra.

Lỗi cần được sửa càng sớm càng tốt, vì vậy phương pháp Thiết kế theo Hợp đồng là phù hợp. Trong C ++, tôi muốn kiểm tra tất cả các điều kiện tiên quyết (đầu vào) của mình với các xác nhận ở đầu hàm để phát hiện lỗi càng sớm càng tốt và giúp dễ dàng đính kèm trình gỡ lỗi và sửa lỗi. Nếu nhà phát triển hoặc người kiểm tra thay vì chọn tiếp tục chạy chương trình, thì bất kỳ sự mất toàn vẹn dữ liệu nào cũng trở thành vấn đề của họ.

Và tìm cách để ngăn chặn lỗi ở nơi đầu tiên. Nghiêm khắc với tính chính xác và chọn loại dữ liệu phù hợp với dữ liệu họ sẽ giữ là hai cách để gây khó khăn cho việc tạo lỗi. Fail-Fast cũng tốt ngoài mã quan trọng an toàn cần một cách để phục hồi.

Đối với các lỗi thời gian chạy có thể xảy ra với mã không có lỗi, chẳng hạn như lỗi giao tiếp mạng hoặc nối tiếp hoặc các tệp bị thiếu hoặc bị hỏng:

  1. Đăng nhập lỗi.
  2. (Tùy chọn) Cố gắng âm thầm thử lại hoặc phục hồi từ hoạt động.
  3. Nếu hoạt động tiếp tục không thành công hoặc không thể phục hồi, hãy báo cáo lỗi rõ ràng cho người dùng. Sau đó, như trên, người dùng có thể quyết định phải làm gì. Hãy nhớ Nguyên tắc ngạc nhiên tối thiểu , bởi vì việc mất tính toàn vẹn dữ liệu là đáng ngạc nhiên đối với người dùng trừ khi bạn đã cảnh báo họ trước thời hạn.

0

Thất bại là lựa chọn phù hợp khi bạn có lý do để nghĩ rằng trạng thái chung của chương trình không ổn định và điều gì đó xấu có thể xảy ra nếu bạn để nó chạy từ bây giờ. Một chút "bỏ qua" nó (nghĩa là, như những người khác đã chỉ ra, đăng nhập nó ở đâu đó hoặc hiển thị thông báo lỗi cho người dùng, sau đó tiếp tục) là ổn khi bạn biết rằng, chắc chắn, hoạt động hiện tại có thể được thực hiện, nhưng chương trình có thể được thực hiện tiếp tục chạy.

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.