Ai nên đọc Exception.Message nếu có?


27

Khi thiết kế ngoại lệ, tôi nên viết thông điệp mà người dùng hoặc nhà phát triển nên hiểu? Ai thực sự nên là người đọc tin nhắn ngoại lệ?

Tôi thấy tin nhắn ngoại lệ không hữu ích chút nào và tôi luôn gặp khó khăn khi viết chúng. Theo quy ước, loại ngoại lệ sẽ cho chúng ta biết lý do tại sao một cái gì đó không hoạt động và các thuộc tính tùy chỉnh có thể thêm nhiều thông tin hơn như tên tệp, chỉ mục, khóa, v.v ... vậy tại sao lại lặp lại nó trong thông điệp? Một thông điệp tự động cũng có thể làm và tất cả những gì nó phải chứa là tên của ngoại lệ với một danh sách các thuộc tính bổ sung. Điều này sẽ chính xác hữu ích như một văn bản viết tay.

Sẽ không tốt hơn nếu không viết tin nhắn mà thay vào đó có các trình kết xuất ngoại lệ đặc biệt quan tâm đến việc tạo các tin nhắn có ý nghĩa có thể bằng các ngôn ngữ khác nhau sau đó mã hóa chúng trong mã?


Tôi đã được hỏi liệu một trong những câu hỏi đó có cung cấp câu trả lời cho câu hỏi của tôi không:

Tôi đã đọc cả hai và tôi không hài lòng với câu trả lời của họ. Họ nói về người dùng nói chung và tập trung vào nội dung của tin nhắn hơn là vào người nhận và hóa ra có thể có ít nhất hai trong số họ: người dùng cuối và nhà phát triển. Tôi không bao giờ biết nên nói với ai khi viết tin nhắn ngoại lệ.

Tôi thậm chí nghĩ rằng thông điệp nổi tiếng hoàn toàn không có giá trị thực sự vì nó chỉ lặp lại tên của loại ngoại lệ bằng các từ khác nhau, vậy tại sao lại phải viết chúng? Tôi hoàn toàn có thể tạo ra chúng tự động.

Đối với tôi thông điệp ngoại lệ thiếu một sự khác biệt của độc giả của nó. Một ngoại lệ hoàn hảo sẽ cần cung cấp ít nhất hai phiên bản của thông báo: một cho người dùng cuối và một cho nhà phát triển. Gọi nó chỉ là một tin nhắn là quá chung chung. Một thông điệp dành cho nhà phát triển nên được viết bằng tiếng Anh nhưng tin nhắn của người dùng cuối có thể cần được dịch sang các ngôn ngữ khác. Không thể đạt được tất cả điều này chỉ với một tin nhắn nên một ngoại lệ sẽ cần cung cấp một số định danh cho tin nhắn của người dùng cuối mà như tôi vừa nói, có thể có sẵn bằng các ngôn ngữ khác nhau.

Khi tôi đọc tất cả các câu hỏi được liên kết khác, tôi có ấn tượng rằng một thông điệp ngoại lệ thực sự được đọc bởi người dùng cuối chứ không phải nhà phát triển ... một tin nhắn cũng giống như có một chiếc bánh và cũng ăn nó.


4
Có hai câu hỏi khác được đặt ra ở đây về các lập trình viên xuất hiện trong đầu. Tôi không chắc chúng có trùng lặp hay không, nhưng tôi nghĩ bạn nên đọc chúng và có lẽ chúng sẽ giải quyết một số hoặc thậm chí tất cả các mối quan tâm của bạn: Cách viết một tin nhắn ngoại lệ tốtTại sao nhiều tin nhắn ngoại lệ không chứa chi tiết hữu ích ?
Thomas Owens

2
@ThomasOwens Tôi đã đọc cả hai nhưng họ không đề cập đến người nhận cụ thể của một tin nhắn ngoại lệ. Họ nói về người dùng nói chung nhưng anh ta là ai? Có phải người dùng phần mềm hiện đã có ý tưởng về lập trình hoặc nhà phát triển nên phân tích những gì đã sai? Tôi không bao giờ chắc chắn tôi nên giải quyết ai khi viết tin nhắn.
t3chb0t

2
Tôi nghĩ rằng một câu trả lời tốt ở đây có thể đề cập đến một trong hai hoặc cả hai câu hỏi đó, nhưng chúng cách xa các bản sao.
Cuộc đua nhẹ nhàng với Monica

1
Tại sao trên trái đất này đã đóng cửa như là bản sao? Ngay cả khi đó là một bản sao của câu hỏi khác (mà không phải), câu hỏi này rõ ràng có câu trả lời tốt hơn, nó sẽ là câu hỏi khác được đánh dấu là trùng lặp.
Ben Aaronson

2
@MichaelT Tôi vẫn không thực sự thấy nhiều sự trùng lặp ở đó trừ khi bạn giả định rằng các thông báo Ngoại lệ dành cho người dùng
Ben Aaronson

Câu trả lời:


46

Những thông điệp này dành cho các nhà phát triển khác

Những thông điệp này dự kiến ​​sẽ được các nhà phát triển đọc để giúp họ gỡ lỗi ứng dụng. Điều này có thể có hai hình thức:

  • Chủ động gỡ lỗi. Bạn thực sự đang chạy một trình gỡ lỗi trong khi viết mã và cố gắng tìm hiểu điều gì sẽ xảy ra. Trong ngữ cảnh này, một ngoại lệ hữu ích sẽ hướng dẫn bạn bằng cách giúp bạn dễ hiểu những gì đang xảy ra hoặc cuối cùng đề xuất một cách giải quyết (mặc dù điều này là tùy chọn).

  • Gỡ lỗi thụ động. Mã chạy trong sản xuất và thất bại. Ngoại lệ được ghi lại, nhưng bạn chỉ nhận được thông báo và dấu vết ngăn xếp. Trong ngữ cảnh này, một thông báo ngoại lệ hữu ích sẽ giúp bạn nhanh chóng bản địa hóa lỗi.

    Vì các tin nhắn đó thường được ghi lại, điều đó cũng có nghĩa là bạn không nên bao gồm thông tin nhạy cảm ở đó (chẳng hạn như khóa riêng hoặc mật khẩu, ngay cả khi nó có thể hữu ích để gỡ lỗi ứng dụng).

Chẳng hạn, IOSecurityExceptionloại ngoại lệ được ném khi viết tệp không rõ ràng lắm về vấn đề: có phải vì chúng tôi không có quyền truy cập tệp? Hoặc có lẽ chúng ta có thể đọc nó, nhưng không viết? Hoặc có thể tệp không tồn tại và chúng tôi không có quyền tạo tệp ở đó? Hoặc có thể nó bị khóa (hy vọng, loại ngoại lệ sẽ khác trong trường hợp này, nhưng trong thực tế, các loại đôi khi có thể khó hiểu). Hoặc có thể Code Access Security ngăn chúng tôi thực hiện bất kỳ thao tác I / O nào?

Thay thế:

IOSecurityException: tệp đã được tìm thấy nhưng quyền đọc nội dung của nó đã bị từ chối.

rõ ràng hơn nhiều. Ở đây, chúng tôi biết ngay rằng các quyền trên thư mục được đặt chính xác (nếu không, chúng tôi sẽ không thể biết rằng tệp tồn tại), nhưng các quyền ở cấp tệp có vấn đề.

Điều này cũng có nghĩa là nếu bạn không thể cung cấp bất kỳ thông tin bổ sung nào chưa có trong loại ngoại lệ, bạn có thể giữ thông báo trống. DivisionByZeroExceptionlà một ví dụ tốt trong đó thông điệp là dư thừa. Mặt khác, thực tế là hầu hết các ngôn ngữ cho phép bạn đưa ra một ngoại lệ mà không chỉ định thông điệp của nó được thực hiện vì một lý do khác: vì thông điệp mặc định đã có sẵn hoặc vì nó sẽ được tạo sau nếu cần (và việc tạo ra điều này thông điệp được đính kèm trong loại ngoại lệ, có nghĩa hoàn hảo, nói "OOPly" ).

Lưu ý rằng vì lý do kỹ thuật (thường là hiệu suất), một số tin nhắn cuối cùng trở nên khó hiểu hơn nhiều so với mức cần thiết. .NET NullReferenceException:

Tham chiếu đối tượng không được đặt thành một thể hiện của một đối tượng.

là một ví dụ tuyệt vời của một thông điệp không hữu ích. Một thông điệp hữu ích sẽ là:

Tham chiếu đối tượng productkhông được đặt thành phiên bản của đối tượng khi được gọi trong product.Price.

Những tin nhắn không dành cho người dùng cuối!

Người dùng cuối sẽ không thấy các tin nhắn ngoại lệ. Không bao giờ. Mặc dù một số nhà phát triển cuối cùng hiển thị những thông báo đó cho người dùng, điều này dẫn đến trải nghiệm người dùng kém và thất vọng. Các thông điệp như:

Tham chiếu đối tượng không được đặt thành một thể hiện của một đối tượng.

có nghĩa là hoàn toàn không có gì với người dùng cuối và nên tránh bằng mọi giá.

Trường hợp xấu nhất là có một thử / bắt toàn cầu, ném ngoại lệ cho người dùng và thoát khỏi ứng dụng. Một ứng dụng quan tâm đến người dùng của nó:

  • Xử lý ngoại lệ ở nơi đầu tiên. Hầu hết những người có thể được xử lý mà không làm phiền người dùng. Mạng bị sập? Tại sao không đợi vài giây và thử lại?

  • Ngăn chặn người dùng dẫn ứng dụng đến một trường hợp đặc biệt. Nếu bạn yêu cầu người dùng nhập hai số và chia số đầu tiên cho số thứ hai, tại sao bạn lại để người dùng nhập số 0 trong trường hợp thứ hai để đổ lỗi cho anh ta vài giây sau? Điều gì về việc làm nổi bật hộp văn bản màu đỏ (với một mẹo công cụ hữu ích cho biết số đó phải khác 0) và vô hiệu hóa nút xác thực cho đến khi trường vẫn có màu đỏ?

  • Mời người dùng thực hiện một hành động ở dạng không phải là lỗi. Không có đủ quyền để truy cập một tập tin? Tại sao không yêu cầu người dùng cấp quyền quản trị hoặc chọn một tệp khác?

  • Nếu không có gì khác hoạt động, hiển thị một lỗi hữu ích, thân thiện được viết riêng để giảm bớt sự thất vọng của người dùng, giúp người dùng hiểu được những gì đã sai và cuối cùng giải quyết vấn đề, đồng thời giúp anh ta ngăn chặn lỗi trong tương lai (khi áp dụng).

    Trong câu hỏi của bạn, bạn đã đề xuất có hai thông báo ngoại lệ: một thông báo kỹ thuật cho nhà phát triển và một cho người dùng cuối. Mặc dù đây là một đề xuất hợp lệ trong một số trường hợp nhỏ, hầu hết các trường hợp ngoại lệ được tạo ra ở mức độ không thể tạo ra một thông điệp có ý nghĩa cho người dùng. Hãy DivisionByZeroExceptiontưởng tượng rằng chúng ta không thể ngăn chặn ngoại lệ xảy ra và không thể tự xử lý nó. Khi sự phân chia xảy ra, khung (vì đó là khung chứ không phải mã doanh nghiệp, sẽ ném ngoại lệ) có biết thông điệp hữu ích nào cho người dùng không? Tuyệt đối không:

    Sự phân chia bằng không xảy ra. [ĐƯỢC]

    Thay vào đó, người ta có thể để nó ném ngoại lệ, và sau đó nắm bắt nó ở cấp độ cao hơn nơi chúng ta biết bối cảnh kinh doanh và có thể hành động phù hợp để thực sự giúp đỡ người dùng cuối, do đó hiển thị một cái gì đó như:

    Trường D13 không thể có giá trị giống với giá trị trong trường E6, vì phép trừ của các giá trị đó được sử dụng làm ước số. [ĐƯỢC]

    hoặc có thể:

    Các giá trị được báo cáo bởi dịch vụ ATP không phù hợp với dữ liệu cục bộ. Điều này có thể được gây ra bởi dữ liệu cục bộ không đồng bộ. Bạn có muốn đồng bộ hóa thông tin vận chuyển và thử lại không? [Có không]

Những tin nhắn không phải để phân tích cú pháp

Các thông báo ngoại lệ dự kiến ​​sẽ không được phân tích cú pháp hoặc sử dụng theo chương trình. Nếu bạn nghĩ rằng người gọi có thể cần thêm thông tin, hãy đưa nó vào ngoại lệ bên cạnh tin nhắn. Điều này rất quan trọng, vì tin nhắn có thể thay đổi mà không cần thông báo trước. Loại là một phần của giao diện, nhưng thông báo thì không: không bao giờ dựa vào nó để xử lý ngoại lệ.

Hãy tưởng tượng thông báo ngoại lệ:

Kết nối với bộ nhớ đệm đã hết thời gian chờ sau khi chờ 500 ms. Tăng thời gian chờ hoặc kiểm tra giám sát hiệu suất để xác định hiệu suất máy chủ giảm. Thời gian chờ trung bình cho máy chủ bộ đệm là 6 ms. cho tháng trước, 4 ms. trong tuần qua và 377 ms. cho giờ cuối cùng

Bạn muốn trích xuất các giá trị của 500 500, thời điểm 6, thời gian và thời gian. Hãy suy nghĩ một chút về cách tiếp cận bạn sẽ sử dụng để thực hiện phân tích cú pháp và chỉ sau đó tiếp tục đọc.

Bạn có ý tưởng? Tuyệt quá.

Bây giờ, nhà phát triển ban đầu đã phát hiện ra một lỗi đánh máy:

Connecting to the caching sever timed out after waiting [...]

nên là:

                            ↓
Connecting to the caching server timed out after waiting [...]

Hơn nữa, nhà phát triển cho rằng tháng / tuần / một giờ không liên quan đặc biệt, vì vậy anh ta cũng thực hiện một thay đổi bổ sung:

Thời gian chờ trung bình cho máy chủ bộ đệm là 6 ms. cho tháng trước, 5 ms. trong 24 giờ qua và 377 ms. cho giờ cuối cùng

Điều gì xảy ra với phân tích cú pháp của bạn?

Thay vì phân tích cú pháp, bạn có thể sử dụng các thuộc tính ngoại lệ (có thể chứa bất cứ thứ gì bạn muốn, ngay khi dữ liệu có thể được tuần tự hóa):

{
    message: "Connecting to the caching [...]",
    properties: {
        "timeout": 500,
        "statistics": [
            { "timespan": 1, "unit": "month", "average-timeout": 6 },
            { "timespan": 7, "unit": "day", "average-timeout": 4 },
            { "timespan": 1, "unit": "hour", "average-timeout": 377 },
        ]
    }
}

Làm thế nào dễ dàng để sử dụng dữ liệu này bây giờ?

Đôi khi (chẳng hạn như trong .NET), tin nhắn thậm chí có thể được dịch sang ngôn ngữ của người dùng (IMHO, dịch các tin nhắn đó là hoàn toàn sai, vì bất kỳ nhà phát triển nào cũng có thể đọc được bằng tiếng Anh). Phân tích các tin nhắn như vậy là gần như không thể.


2
Điểm tốt về người dùng cuối. Tôi sẽ nói thêm rằng người dùng cuối cũng không nên xem các thông báo ngoại lệ vì lý do bảo mật. Biết bản chất chính xác của một lỗi đối với người dùng không phải là cư sĩ có thể trình bày một khai thác. Người dùng cuối chỉ nên biết lỗi trong bối cảnh những gì họ đang làm.
Neil

1
@Neil: đó là một chút quá lý thuyết. Trong thực tế, lợi ích từ việc ẩn các bản ghi từ người dùng là lớn hơn bởi sự phức tạp của việc đăng nhập trực tuyến. Không tính khía cạnh thân thiện với người dùng. Hãy tưởng tượng rằng bạn đang cài đặt Visual Studio trên Windows VM mới. Đột nhiên, cài đặt thất bại. Bạn có muốn tự mình đi đến nhật ký và tự chẩn đoán sự cố (với sự trợ giúp của Stack Exchange và blog) hay đợi cho đến khi Microsoft giải quyết vấn đề và xuất bản một hotfix?
Arseni Mourzenko

4
Tôi nghĩ rằng mọi người đều biết rằng thông điệp "tham chiếu đối tượng ..." là không có ích. Tuy nhiên, câu hỏi liên quan là mã máy nào bạn muốn jitter tạo ra để tạo ra thông điệp bạn muốn? Nếu bạn thực hiện bài tập này, bạn sẽ nhanh chóng phát hiện ra rằng thông điệp không thể dễ dàng được tạo ra mà không phải trả một khoản chi phí hiệu năng khổng lồ cho tất cả các trường hợp không đặc biệt . Lợi ích của việc làm cho một công việc của nhà phát triển bất cẩn trở nên dễ dàng hơn một chút không được trả cho hiệu suất của người dùng cuối.
Eric Lippert

7
Về ngoại lệ bảo mật: càng ít thông tin trong ngoại lệ càng tốt. Giai thoại yêu thích của tôi là trong phiên bản tiền beta của .NET 1.0, bạn có thể nhận được một thông báo ngoại lệ như "Bạn không có quyền xác định tên của tệp C: \ foo.txt". Tuyệt vời, cảm ơn vì thông điệp ngoại lệ chi tiết!
Eric Lippert

2
Tôi không đồng ý với việc không bao giờ hiển thị cho người dùng cuối một thông báo lỗi chi tiết. Nó đã xảy ra với tôi nhiều lần khi tôi nhận được một thông báo lỗi khó hiểu ngăn tôi khởi động trò chơi / phần mềm của mình, nhưng khi tôi google nó tôi phát hiện ra một cách giải quyết dễ dàng. Không có thông báo lỗi đó, sẽ không có cách nào để tìm cách giải quyết. Có lẽ tốt hơn là chỉ ẩn các chi tiết dưới nút "chi tiết hơn"?
BlueRaja - Daniel Pflughoeft

2

Câu trả lời cho điều này phụ thuộc hoàn toàn vào ngoại lệ.

Câu hỏi quan trọng nhất để hỏi là "ai có thể khắc phục vấn đề?" Nếu ngoại lệ là do lỗi hệ thống tệp trong khi bạn đang mở tệp, việc gửi thông báo đó cho người dùng cuối có thể có ý nghĩa. Thông báo có thể chứa thêm thông tin về cách sửa lỗi. Tôi có thể nghĩ về một trường hợp dứt khoát trong công việc của tôi khi tôi có một hệ thống plugin tải DLL. Nếu người dùng mắc lỗi đánh máy trên dòng lệnh để tải plugin sai, thông báo lỗi hệ thống cơ bản thực sự chứa thông tin hữu ích để cho phép họ khắc phục sự cố.

Tuy nhiên, hầu hết thời gian, người dùng không thể sửa lỗi ngoại lệ. Hầu hết trong số họ liên quan đến việc thay đổi mã. Trong những trường hợp này, người tiêu dùng của tin nhắn rõ ràng là một nhà phát triển.

Trường hợp ngoại lệ bị bắt phức tạp hơn vì bạn có cơ hội xử lý ngoại lệ đúng cách và ném một ngoại lệ thân thiện hơn. Một ngôn ngữ kịch bản tôi đã viết đã đưa ra các ngoại lệ có thông điệp rất rõ ràng dành cho nhà phát triển. Tuy nhiên, khi ngăn xếp ngăn chặn, tôi đã thêm dấu vết ngăn xếp có thể đọc được từ bên trong ngôn ngữ kịch bản. Người dùng của tôi rất hiếm khi có thể mò mẫm tin nhắn, nhưng họ có thể nhìn vào dấu vết ngăn xếp trong tập lệnh của họ và tìm hiểu điều gì đã xảy ra 95% thời gian. Đối với 5% còn lại, khi họ gọi cho tôi, chúng tôi không chỉ có dấu vết ngăn xếp mà còn có một thông báo sẵn sàng cho nhà phát triển để giúp tôi tìm ra điều gì sai.

Nói chung, tôi coi thông điệp Ngoại lệ là một nội dung không xác định. Một người nào đó ngược dòng, người biết nhiều hơn về việc triển khai, đã trao cho phần mềm của tôi một ngoại lệ. Đôi khi tôi có linh cảm rằng nội dung không xác định sẽ hữu ích cho người dùng cuối, đôi khi không.


1
"Nếu ngoại lệ là do lỗi hệ thống tệp trong khi bạn mở tệp, có thể có ý nghĩa khi gửi thông báo đó cho người dùng cuối": nhưng khi bạn ném lỗi hệ thống tệp, bạn không biết ngữ cảnh: đó có thể là hành động của người dùng hoặc một cái gì đó hoàn toàn không liên quan (như ứng dụng của bạn tạo bản sao lưu của một số cấu hình mà không cần người dùng nhận thấy nó). Điều này ngụ ý rằng bạn sẽ có một khối thử / bắt hiển thị thông báo lỗi , rất khác với hiển thị thông báo ngoại lệ trực tiếp.
Arseni Mourzenko

@MainMa Bạn có thể không biết rõ bối cảnh, nhưng có rất nhiều gợi ý. Ví dụ như, nếu họ đang trong quá trình mở tệp và ngoại lệ là "IOError: quyền bị từ chối", có khả năng người dùng có thể đặt 2 và 2 lại với nhau và tìm ra tệp đang nghi vấn. Trình soạn thảo yêu thích của tôi thực hiện điều này - nó chỉ xuất văn bản ngoại lệ trong hộp thoại, không có lông tơ. Mặt khác, nếu tôi đang tải ứng dụng của mình và bị "từ chối cấp phép" trong khi tải một loạt hình ảnh, sẽ không hợp lý hơn nhiều khi cho rằng người dùng có thể làm gì đó với thông tin.
Cort Ammon - Phục hồi Monica

Lập luận cho quan điểm của bạn, tôi chưa bao giờ thấy bất kỳ giá trị trong việc chỉ cho người dùng một NullReferenceException, trừ rằng hành động đơn thuần hiển thị rằng chương trình thông điệp rằng phần mềm của bạn không có một đầu mối làm thế nào để phục hồi! Thông báo ngoại lệ đó không bao giờ hữu ích cho người dùng cuối.
Cort Ammon - Phục hồi Monica
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.