it-swarm-vi.com

Làm thế nào để viết một thông điệp ngoại lệ tốt

Tôi hiện đang thực hiện đánh giá mã và một trong những điều tôi nhận thấy là số trường hợp ngoại lệ trong đó thông báo ngoại lệ dường như nhắc lại trong đó ngoại lệ xảy ra. ví dụ.

throw new Exception("BulletListControl: CreateChildControls failed.");

Tất cả ba mục trong tin nhắn này tôi có thể làm việc từ phần còn lại của ngoại lệ. Tôi biết lớp và phương thức từ dấu vết ngăn xếp và tôi biết nó thất bại (vì tôi có một ngoại lệ).

Nó khiến tôi suy nghĩ về những gì tôi đã gửi tin nhắn ngoại lệ. Đầu tiên tôi tạo một lớp ngoại lệ, nếu nó chưa tồn tại, vì lý do chung (ví dụ: PropertyNotFoundException - tại sao ) và sau đó khi tôi ném nó, thông báo cho biết điều gì đã sai (ví dụ: "Không thể tìm thấy thuộc tính 'IDontExist' trên Node 1234" - what ). Vị trí nằm trong StackTrace. khi có thể kết thúc trong nhật ký (nếu có). cách dành cho nhà phát triển để giải quyết (và sửa chữa)

Bạn có bất cứ lời khuyên khác để ném ngoại lệ? Cụ thể liên quan đến việc tạo các loại mới và thông báo ngoại lệ.

102
Colin Mackay

Tôi sẽ hướng câu trả lời của mình nhiều hơn đến những gì xảy ra sau một ngoại lệ: nó tốt cho cái gì và phần mềm nên ứng xử như thế nào, người dùng của bạn nên làm gì với ngoại lệ đó? Một kỹ thuật tuyệt vời tôi đã bắt đầu trong sự nghiệp của mình là luôn báo cáo các vấn đề và lỗi trong 3 phần: bối cảnh, vấn đề & giải pháp. Việc sử dụng dendsline này thay đổi rất nhiều việc xử lý lỗi và làm cho phần mềm tốt hơn rất nhiều cho các nhà khai thác sử dụng.

Dưới đây là một vài ví dụ.

Context: Saving connection pooling configuration changes to disk.
Problem: Write permission denied on file '/xxx/yyy'.
Solution: Grant write permission to the file.

Trong trường hợp này, người vận hành biết chính xác phải làm gì và tập tin nào phải bị ảnh hưởng. Họ cũng biết rằng những thay đổi tổng hợp kết nối đã không thực hiện và nên được lặp lại.

Context: Sending email to '[email protected]' regarding 'Blah'.
Problem: SMTP connection refused by server 'mail.xyz.com'.
Solution: Contact the mail server administrator to report a service problem.  The email will be sent later. You may want to tell '[email protected]' about this problem.

Tôi viết các hệ thống phía máy chủ và các nhà khai thác của tôi nói chung là những người am hiểu công nghệ hỗ trợ dòng đầu tiên. Tôi sẽ viết các thông báo khác nhau cho phần mềm máy tính để bàn có đối tượng khác nhau nhưng bao gồm cùng một thông tin.

Một số điều tuyệt vời xảy ra nếu một người sử dụng kỹ thuật này. Nhà phát triển phần mềm thường thích hợp nhất để biết cách giải quyết các vấn đề trong mã của họ, do đó, giải pháp mã hóa theo cách này khi bạn viết mã có lợi cho những người dùng cuối gặp bất lợi khi tìm giải pháp vì họ thường thiếu thông tin về chính xác những gì phần mềm đã làm. Bất cứ ai đã từng đọc một thông báo lỗi của Oracle sẽ biết ý tôi là gì.

Điều tuyệt vời thứ hai xuất hiện trong đầu bạn là khi bạn thấy mình đang cố gắng mô tả một giải pháp trong trường hợp ngoại lệ của bạn và bạn đang viết "Kiểm tra X và nếu A thì B khác C". Đây là một dấu hiệu rất rõ ràng và rõ ràng rằng ngoại lệ của bạn đang được kiểm tra sai vị trí. Bạn lập trình viên có khả năng so sánh mọi thứ trong mã vì vậy "if" các câu lệnh nên được chạy trong mã, tại sao lại liên quan đến người dùng trong một cái gì đó có thể được tự động hóa? Rất có thể là từ mã sâu hơn và ai đó đã thực hiện điều lười biếng và ném IOException từ bất kỳ phương thức nào và bắt lỗi tiềm ẩn từ tất cả chúng trong một khối mã gọi không thể mô tả đầy đủ những gì đã sai, điều gì bối cảnh cụ thể là và cách khắc phục. Điều này khuyến khích bạn viết các lỗi hạt nhỏ hơn, bắt và xử lý chúng ở đúng vị trí trong mã của bạn để bạn có thể nói rõ các bước mà người vận hành nên thực hiện.

Tại một công ty, chúng tôi đã có những nhà điều hành xuất sắc hàng đầu, những người hiểu rõ về phần mềm và giữ "cuốn sách chạy" của riêng họ, điều đó đã làm tăng các giải pháp báo cáo và đề xuất lỗi của chúng tôi. Để nhận ra điều này, phần mềm đã bắt đầu bao gồm các liên kết wiki đến sách chạy trong các trường hợp ngoại lệ để có giải thích cơ bản cũng như liên kết đến các cuộc thảo luận và quan sát nâng cao hơn của các nhà khai thác theo thời gian.

Nếu bạn đã có dendsline để thử kỹ thuật này, nó sẽ trở nên rõ ràng hơn nhiều về những gì bạn nên đặt tên ngoại lệ của mình trong mã khi tạo riêng của bạn. NonRecoverableConfigurationReadFailedException trở thành một chút tốc ký cho những gì bạn sắp mô tả đầy đủ hơn cho toán tử. Tôi thích được dài dòng và tôi nghĩ rằng sẽ dễ dàng hơn cho nhà phát triển tiếp theo chạm vào mã của tôi để giải thích.

72
Sir Wobin

Trong câu hỏi gần đây hơn này Tôi đã đưa ra quan điểm rằng các ngoại lệ không nên chứa một thông điệp nào cả. Theo tôi, việc họ làm là một quan niệm sai lầm rất lớn. Những gì tôi đang đề xuất là

"Thông điệp" của ngoại lệ là tên lớp (đủ điều kiện) của ngoại lệ.

Một ngoại lệ nên chứa trong các biến thành viên của chính nó càng nhiều chi tiết càng tốt về chính xác những gì đã xảy ra; ví dụ: một IndexOutOfRangeException nên chứa giá trị chỉ mục được coi là không hợp lệ, cũng như các giá trị trên và dưới có giá trị tại thời điểm ngoại lệ được ném. Bằng cách này, bằng cách sử dụng sự phản chiếu, bạn có thể có một thông điệp được xây dựng tự động, nó sẽ đọc như thế này: IndexOutOfRangeException: index = -1; min=0; max=5 và điều này, cùng với dấu vết ngăn xếp, phải là tất cả thông tin khách quan mà bạn cần để khắc phục sự cố. Định dạng nó thành một thông điệp đẹp như "index -1 không nằm trong khoảng từ 0 đến 5" không thêm bất kỳ giá trị nào.

Trong ví dụ cụ thể của bạn, lớp NodePropertyNotFoundException sẽ chứa tên của thuộc tính không tìm thấy và tham chiếu đến nút không chứa thuộc tính. Điều này rất quan trọng: nó nên không chứa tên của nút; nó nên chứa một tham chiếu đến nút thực tế. Trong trường hợp cụ thể của bạn, điều này có thể không cần thiết, nhưng đó là vấn đề nguyên tắc và cách suy nghĩ ưa thích: mối quan tâm chính khi xây dựng một ngoại lệ là nó phải có thể sử dụng được bằng mã có thể bắt được nó. Khả năng sử dụng của con người là một mối quan tâm quan trọng, nhưng chỉ là thứ yếu.

Điều này quan tâm đến tình huống rất bực bội mà bạn có thể đã chứng kiến ​​tại một thời điểm nào đó trong sự nghiệp của mình, nơi bạn có thể đã bắt gặp một ngoại lệ chứa thông tin quan trọng về những gì đã xảy ra trong văn bản tin nhắn, nhưng không phải trong các biến thành viên của nó, vì vậy bạn phải thực hiện phân tích chuỗi văn bản để tìm hiểu điều gì đã xảy ra, hy vọng rằng văn bản thông báo sẽ giữ nguyên trong các phiên bản tương lai của lớp bên dưới và cầu nguyện rằng văn bản thông báo sẽ không bằng tiếng nước ngoài khi chương trình của bạn chạy ở các nước khác.

Tất nhiên, vì tên lớp của ngoại lệ là thông điệp của ngoại lệ, (và các biến thành viên của ngoại lệ là các chi tiết cụ thể,) điều này có nghĩa là bạn cần rất nhiều ngoại lệ khác nhau để truyền tải tất cả các thông điệp khác nhau và đó là tốt.

Bây giờ, đôi khi, khi chúng ta viết mã, chúng ta gặp một tình huống sai lầm mà chúng ta chỉ muốn nhanh chóng mã hóa một câu lệnh throw và tiến hành viết mã của chúng ta thay vì phải làm gián đoạn những gì chúng ta đang làm để tạo ra một cái mới lớp ngoại lệ để chúng ta có thể ném nó ngay tại đó. Đối với những trường hợp này, tôi có một lớp GenericException trên thực tế chấp nhận một thông báo chuỗi là tham số thời gian xây dựng, nhưng hàm tạo của lớp ngoại lệ này được trang trí bằng một màu tím lớn rất lớn FIXME XXX TODO bình luận nói rằng mỗi lần khởi tạo của lớp này phải được thay thế bằng một khởi tạo của một lớp ngoại lệ chuyên biệt hơn trước khi hệ thống phần mềm được phát hành, tốt nhất là trước khi mã được cam kết.

23
Mike Nakis

Theo nguyên tắc chung, một ngoại lệ sẽ giúp nhà phát triển xác định nguyên nhân bằng cách cung cấp thông tin hữu ích (giá trị dự kiến, giá trị thực tế, nguyên nhân/giải pháp có thể, v.v.).

Các loại ngoại lệ mới sẽ được tạo khi không có loại tích hợp nào có ý nghĩa. Một loại cụ thể cho phép các nhà phát triển khác nắm bắt một ngoại lệ cụ thể và xử lý nó. Nếu nhà phát triển sẽ biết cách xử lý ngoại lệ của bạn nhưng loại là Exception, anh ta sẽ không thể xử lý đúng.

13
mbillard

Trong .NET đừng bao giờ throw new Exception("...") (giống như tác giả của câu hỏi đã hiển thị). Ngoại lệ là loại Ngoại lệ gốc và không được phép ném trực tiếp. Thay vào đó, ném một trong các loại ngoại lệ .NET dẫn xuất hoặc tạo ngoại lệ tùy chỉnh của riêng bạn xuất phát từ Ngoại lệ (hoặc loại ngoại lệ khác).

Tại sao không ném Ngoại lệ? Bởi vì ném Exception không có gì để mô tả ngoại lệ của bạn và buộc mã cuộc gọi của bạn viết mã như catch(Exception ex) { ... } thường không phải là một điều tốt! :-).

4
bytedev

Những thứ bạn muốn tìm kiếm để "thêm" vào ngoại lệ là những yếu tố dữ liệu không có trong ngoại lệ hoặc theo dõi ngăn xếp. Cho dù đó là một phần của "tin nhắn" hay cần được đính kèm khi đăng nhập là một câu hỏi thú vị.

Như bạn đã lưu ý, ngoại lệ có thể cho bạn biết điều gì, stacktrace có thể cho bạn biết nhưng "tại sao" có thể liên quan nhiều hơn (nên là, người ta sẽ hy vọng) hơn là chỉ nhìn ngang qua một hoặc hai dòng và nói " doh! Tất nhiên rồi ". Điều này thậm chí còn đúng hơn khi ghi nhật ký lỗi trong mã sản xuất - Tôi thường xuyên bị cắn bởi dữ liệu xấu được tìm thấy trong một hệ thống trực tiếp không tồn tại trong các hệ thống thử nghiệm của chúng tôi. Đôi khi đơn giản như việc biết ID của bản ghi trong cơ sở dữ liệu gây ra lỗi (hoặc đóng góp) cho lỗi có thể tiết kiệm đáng kể thời gian.

Vì vậy, ... Được liệt kê hoặc, đối với .NET, được thêm vào bộ sưu tập dữ liệu ngoại lệ được ghi lại (c.f. @Plip!):

  • Các tham số (điều này có thể có một chút thú vị - bạn không thể thêm vào bộ sưu tập dữ liệu nếu nó không được tuần tự hóa và đôi khi một tham số có thể phức tạp một cách đáng ngạc nhiên)
  • Dữ liệu bổ sung được trả về bởi ADO.NET hoặc Linq thành SQL hoặc tương tự (điều này cũng có thể có một chút thú vị!).
  • Bất cứ điều gì khác có thể không rõ ràng.

Tất nhiên, một số điều bạn sẽ không biết mình cần cho đến khi bạn không có chúng trong báo cáo/nhật ký lỗi ban đầu. Một số điều bạn không nhận ra mình có thể nhận được cho đến khi bạn thấy bạn cần chúng.

2
Murph

Ngoại lệ cho là gì?

(1) Nói với người dùng có gì đó không ổn?

Đây phải là giải pháp cuối cùng, bởi vì mã của bạn sẽ được can thiệp và hiển thị cho họ một cái gì đó "đẹp hơn" so với Ngoại lệ.

Thông báo "lỗi" phải nêu rõ ràng và ngắn gọn những gì đã sai và nếu có bất cứ điều gì, người dùng có thể làm gì phục hồi từ điều kiện lỗi.

ví dụ. "Xin đừng nhấn nút này lần nữa"

(2) Nói với một nhà phát triển khi gặp sự cố?

Đây là loại điều mà bạn đăng nhập vào một tệp để phân tích tiếp theo.
[.__.] Dấu vết ngăn xếp sẽ báo cho Nhà phát triển trong đó mã bị hỏng; một lần nữa, thông báo sẽ chỉ ra những gì đã sai.

(3) Nói với một trình xử lý ngoại lệ (tức là mã) rằng có điều gì đó không ổn?

Loại của Ngoại lệ sẽ quyết định trình xử lý ngoại lệ nào sẽ xem xét nó và thuộc tính được xác định trên đối tượng Ngoại lệ sẽ cho phép trình xử lý xử lý nó.

Thông báo của Ngoại lệ là hoàn toàn không liên quan .

0
Phill W.