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, IOSecurityException
loạ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. DivisionByZeroException
là 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 product
khô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 DivisionByZeroException
tưở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ể.