Tôi có nên ném một ngoại lệ trong trường hợp giá trị có ý nghĩa nằm ngoài phạm vi hoặc tự xử lý nó không?


42

Tôi đã viết một cấu trúc đại diện cho tọa độ vĩ độ / kinh độ. Giá trị của chúng nằm trong khoảng từ -180 đến 180 đối với kinh độ dài và 90 đến -90 đối với mạng.

Nếu người dùng của cấu trúc đó cung cấp cho tôi một giá trị ngoài phạm vi đó, tôi có 2 tùy chọn:

  1. Ném một ngoại lệ (arg ra khỏi phạm vi)
  2. Chuyển đổi giá trị thành ràng buộc

Vì tọa độ -185 có ý nghĩa (nó có thể dễ dàng chuyển đổi thành +175 vì đây là tọa độ cực), tôi có thể chấp nhận và chuyển đổi nó.

Có phải tốt hơn để ném một ngoại lệ để nói với người dùng rằng mã của anh ta đã cho tôi một giá trị mà nó không nên có?

Chỉnh sửa: Ngoài ra tôi biết sự khác biệt giữa lat / lng và tọa độ, nhưng tôi muốn đơn giản hóa điều đó để thảo luận dễ dàng hơn - đó không phải là ý tưởng sáng giá nhất


13
Người dùng có nên được phép chèn một giá trị ra khỏi phạm vi không? Nếu câu trả lời là không, hãy ném một ngoại lệ. Nếu các quy tắc không nghiêm ngặt, hãy thực hiện chuyển đổi, nhưng nêu rõ trong tài liệu rằng việc chuyển đổi có thể xảy ra. Cũng cần lưu ý rằng trong một số ngôn ngữ, việc xử lý ngoại lệ khá tốn kém.
Andy

C #, có vấn đề gì không? Nó không thực sự hỗ trợ các ràng buộc nếu đây là những gì bạn muốn nói.
K. Gkinis

2
Sau đó, có vẻ như khá rõ ràng đối với tôi, cách tiếp cận chính xác là khiến người dùng nhập bất cứ thứ gì ngoài phạm vi và đưa ra một ngoại lệ khi họ làm như vậy (nếu tiêu chuẩn nói giá trị abs không được cao hơn 180, đặt giá trị lớn hơn mức đó vi phạm rõ ràng). Nhân tiện, C # thực sự là một trong những ngôn ngữ mà các trường hợp ngoại lệ khá tốn kém, vì vậy chỉ sử dụng chúng trong các tình huống đặc biệt, nghĩa là không nắm bắt được nó sẽ phá vỡ ứng dụng của bạn, như tình huống này.
Andy

2
Tôi có xu hướng tránh xa việc đưa ra các giả định về ý nghĩa của người dùng bằng cách chuyển các giá trị tham số cụ thể, đặc biệt là các mã mà mã của tôi không phục vụ. Âm thanh như một trường hợp tương tự.
JMᴇᴇ

2
Các tọa độ Web Mercator không nằm trong khoảng từ -180 đến 180 và -90 đến 90. Đó là vĩ độ / kinh độ (và thậm chí có một số hệ tọa độ cho điều đó). Các phép chiếu Mercator thường ở hàng trăm nghìn hoặc hàng triệu và có đơn vị "mét" (thậm chí không nghiêm ngặt, vì chiều dài của mỗi đơn vị bao gồm tăng khoảng cách mặt đất thực khi bạn tiếp cận các cực), không phải độ. Ngay cả về độ, nó bị giới hạn ở mức ± 85.051129 độ vì hình chiếu trở nên rộng vô hạn ở hai cực. (Tôi đã gửi một chỉnh sửa để sửa lỗi này, vì đó không phải là cốt lõi của câu hỏi.)
jpmc26

Câu trả lời:


51

Nếu cốt lõi của câu hỏi của bạn là ...

Nếu một số mã máy khách vượt qua một đối số có giá trị không hợp lệ đối với cấu trúc dữ liệu của tôi đang mô hình hóa, tôi có nên từ chối giá trị hoặc chuyển đổi nó thành thứ gì đó hợp lý không?

... thì câu trả lời chung của tôi sẽ là "từ chối", bởi vì điều này sẽ giúp thu hút sự chú ý đến các lỗi tiềm ẩn trong mã máy khách thực sự khiến giá trị không hợp lệ xuất hiện trong chương trình và tiếp cận với nhà xây dựng của bạn. Thu hút sự chú ý đến các lỗi nói chung là một thuộc tính mong muốn trong hầu hết các hệ thống, ít nhất là trong quá trình phát triển (trừ khi đó là một thuộc tính mong muốn của hệ thống của bạn để xử lý trong trường hợp có lỗi).

Câu hỏi là liệu bạn có thực sự phải đối mặt với trường hợp đó .

  • Nếu cấu trúc dữ liệu của bạn được dự định để mô hình tọa độ cực nói chung, thì hãy chấp nhận giá trị vì các góc ngoài phạm vi -180 và +180 không thực sự không hợp lệ. Chúng hoàn toàn hợp lệ và chúng chỉ luôn có một mức tương đương trong phạm vi -180 và +180 (và nếu bạn muốn chuyển đổi chúng để nhắm mục tiêu phạm vi đó, hãy thoải mái - mã khách hàng thường không cần quan tâm) .

  • Nếu cấu trúc dữ liệu của bạn mô hình hóa rõ ràng tọa độ Web Mercator (theo câu hỏi ở dạng ban đầu), thì tốt nhất bạn nên tuân theo bất kỳ quy định nào được đề cập trong thông số kỹ thuật (mà tôi không biết, vì vậy tôi sẽ không nói gì về nó) . Nếu đặc điểm kỹ thuật của điều bạn mô hình hóa nói rằng một số giá trị không hợp lệ, hãy từ chối chúng. Nếu nó nói rằng chúng có thể được hiểu là một cái gì đó hợp lý (và do đó chúng thực sự hợp lệ), hãy chấp nhận chúng.

chế bạn sử dụng để báo hiệu các giá trị có được chấp nhận hay không phụ thuộc vào các tính năng của ngôn ngữ, triết lý chung và yêu cầu về hiệu suất của bạn. Vì vậy, bạn có thể ném một ngoại lệ (trong hàm tạo) hoặc trả về một phiên bản nullable của struct của bạn (thông qua một phương thức tĩnh gọi hàm tạo riêng) hoặc trả về một boolean và chuyển cấu trúc của bạn cho người gọi dưới dạng outtham số (một lần nữa thông qua một phương thức tĩnh gọi một hàm tạo riêng), v.v.


12
Kinh độ ngoài phạm vi -180 đến +180 có thể được coi là chấp nhận được, nhưng vĩ độ ngoài phạm vi -90 đến +90 có vẻ vô nghĩa. Khi một người đến Bắc hoặc Nam Cực, việc đi tiếp về phía bắc hoặc phía nam là không xác định.
supercat

4
@supercat Tôi có xu hướng đồng ý với bạn, nhưng vì tôi không biết giá trị nào thực sự không hợp lệ trong thông số Web Mercator, tôi đang cố gắng không đưa ra bất kỳ kết luận khó khăn nào. OP biết miền vấn đề tốt hơn tôi.
Theodoros Chatzigiannakis 18/2/2016

1
@supercat: bắt đầu nơi kinh tuyến đến xích đạo. đi dọc theo kinh tuyến theo vĩ độ. Nếu vĩ độ> 90 thì chỉ cần tiếp tục đi theo cùng một vòng tròn lớn. Không vấn đề gì. Tài liệu nó và để lại phần còn lại cho khách hàng.
kevin cline

4
@supercat Tệ hơn thế. Trong phép chiếu Web Mercator, ± 90 thực sự được chiếu tới chiều rộng vô hạn. Vì vậy, tiêu chuẩn thực sự cắt nó ở ± 85.051129. Ngoài ra, lat / long! = Tọa độ web mercator. Tọa độ Mercator sử dụng một biến thể của mét, không phải độ. (Khi bạn đến gần các cực hơn, mỗi "mét" thực sự tương ứng với một mảnh đất lớn hơn và lớn hơn.) Các tọa độ OP hoàn toàn là lat / long. Web Mercator không liên quan gì đến họ, ngoài việc họ có thể hiển thị trên bản đồ cơ sở Web Mercator và một số thư viện không gian đang chiếu dưới mui xe cho họ.
jpmc26

1
Tôi nên nói "tương đương với ± 85.051129", vì đó không phải là tọa độ thực tế.
jpmc26

10

Nó phụ thuộc rất nhiều. Nhưng bạn nên quyết định làm một cái gì đó và tài liệu đó .

Điều sai lầm chắc chắn duy nhất cho mã của bạn phải làm là quên xem xét rằng đầu vào của người dùng có thể nằm ngoài phạm vi dự kiến ​​và viết mã vô tình có một số hành vi. Bởi vì sau đó một số người sẽ đưa ra một giả định không chính xác về cách mã của bạn hoạt động và nó sẽ gây ra lỗi, trong khi những người khác sẽ kết thúc tùy thuộc vào hành vi mà mã của bạn vô tình có (ngay cả khi hành vi đó hoàn toàn là bonkers) và do đó bạn sẽ gây ra nhiều lỗi hơn khi bạn sửa lỗi sau.

Trong trường hợp này tôi có thể thấy các đối số theo một trong hai cách. Nếu ai đó đi +10 độ từ 175 độ, họ sẽ kết thúc ở mức -175. Nếu bạn luôn bình thường hóa đầu vào của người dùng và vì vậy coi 185 tương đương với -175 thì mã máy khách không thể làm sai khi thêm 10 độ; nó luôn luôn có tác dụng đúng Nếu bạn coi 185 là một lỗi, bạn buộc mọi trường hợp trong đó mã khách hàng đang thêm độ tương đối để đưa vào logic chuẩn hóa (hoặc ít nhất là nhớ gọi thủ tục chuẩn hóa của bạn), bạn thực sự sẽ gây ralỗi (mặc dù hy vọng dễ dàng bắt được những con sẽ nhanh chóng bị nghiền nát). Nhưng nếu một số kinh độ được người dùng nhập vào, được viết theo nghĩa đen trong chương trình hoặc được tính thông qua một số thủ tục dự định luôn ở [-180, 180), thì một giá trị nằm ngoài phạm vi đó rất có thể chỉ ra lỗi, vì vậy "rất hữu ích "Chuyển đổi nó có thể che giấu vấn đề.

Lý tưởng của tôi trong trường hợp này có lẽ là xác định một loại đại diện cho tên miền chính xác. Sử dụng một loại trừu tượng (không để mã khách hàng chỉ cần truy cập vào các số thô bên trong nó) và cung cấp cả nhà máy chuẩn hóa và xác nhận hợp lệ (để khách hàng có thể thực hiện đánh đổi). Nhưng bất kể giá trị của loại này được tạo ra là bao nhiêu, 185 không thể phân biệt được với -175 khi nhìn qua API công khai của bạn (không quan trọng là chúng được chuyển đổi khi xây dựng hay bạn cung cấp sự bình đẳng, người truy cập và các hoạt động khác mà bỏ qua sự khác biệt nào đó) .


3

Nếu việc bạn chọn một giải pháp không thực sự quan trọng, bạn có thể để người dùng quyết định.

Do struct của bạn là đối tượng giá trị chỉ đọc và được tạo bởi một phương thức / hàm tạo, bạn có thể cung cấp hai tình trạng quá tải dựa trên các tùy chọn mà người dùng có:

  • Ném một ngoại lệ (arg ra khỏi phạm vi)
  • Chuyển đổi giá trị thành ràng buộc

Cũng không bao giờ để người dùng có cấu trúc không hợp lệ để chuyển sang các phương thức khác của bạn, làm cho nó đúng khi tạo.

Chỉnh sửa: dựa trên các nhận xét, tôi giả sử bạn đang sử dụng c #.


Cảm ơn các đầu vào! Tôi sẽ nghĩ về nó, mặc dù tôi sợ rằng nó sẽ làm suy yếu mục đích của người xây dựng ngoại lệ, nếu người ta có thể tránh nó. Mặc dù vậy, nó thật thú vị!
K. Gkinis

Nếu bạn định sử dụng ý tưởng này, sẽ tốt hơn nếu xác định một giao diện và có hai triển khai ném hoặc chuyển đổi. Sẽ rất khó để làm quá tải một nhà xây dựng theo cách hợp lý để làm việc như bạn mô tả.

2
@Snowman: Vâng, sẽ rất khó để làm quá tải một hàm tạo với cùng loại đối số, nhưng sẽ không khó để có hai phương thức tĩnh và hàm tạo riêng.
wchargein

1
@ K.Gkinis: Mục đích của hàm tạo ném ngoại lệ không phải là "đảm bảo ứng dụng chết". Sau tất cả, máy khách luôn có thể là catchngoại lệ của bạn. Như những người khác đã nói, nó cho phép khách hàng tự hạn chế nếu nó mong muốn. Bạn không thực sự phá vỡ bất cứ điều gì.
wchargein

Đề nghị này làm phức tạp mã không có lợi. Phương thức nên chuyển đổi đầu vào không hợp lệ hoặc không nên. Có hai quá tải làm cho mã phức tạp hơn mà không giải quyết được vấn đề nan giải.
JacquesB

0

Nó phụ thuộc nếu đầu vào trực tiếp từ người dùng thông qua một số UI hoặc nó là từ hệ thống.

Nhập thông qua một giao diện người dùng

Đó là một câu hỏi kinh nghiệm người dùng làm thế nào để xử lý đầu vào không hợp lệ. Tôi không biết về trường hợp cụ thể của bạn, nhưng nói chung có một vài lựa chọn:

  • Thông báo cho người dùng về lỗi và yêu cầu người dùng sửa lỗi trước khi tiếp tục (Phổ biến nhất)
  • Tự động chuyển đổi sang phạm vi hợp lệ (nếu có thể), nhưng cảnh báo người dùng về thay đổi và cho phép người dùng xác minh trước khi tiếp tục.
  • Âm thầm chuyển sang phạm vi hợp lệ và tiến hành.

Sự lựa chọn phụ thuộc vào sự mong đợi của người dùng và mức độ quan trọng của dữ liệu. Ví dụ: Google tự động sửa lỗi chính tả trong các truy vấn, nhưng điều này có rủi ro thấp vì một thay đổi không có ích không phải là vấn đề và rất dễ sửa (và thậm chí sau đó nó được làm rõ trên trang kết quả rằng truy vấn đã được thay đổi). Mặt khác, nếu bạn đang nhập tọa độ cho một tên lửa hạt nhân, bạn có thể muốn xác thực đầu vào cứng nhắc hơn và không có sửa chữa im lặng cho dữ liệu không hợp lệ. Vì vậy, không có câu trả lời phổ quát.

Quan trọng nhất, bạn nên xem xét nếu sửa lỗi đầu vào thậm chí có lợi cho người dùng. Tại sao người dùng nhập dữ liệu không hợp lệ? Thật dễ dàng để xem làm thế nào một người nào đó có thể mắc lỗi chính tả, nhưng tại sao mọi người sẽ nhập kinh độ -185? Nếu người dùng thực sự có nghĩa là +175 thì có lẽ họ đã gõ +175. Tôi nghĩ rằng rất có thể một kinh độ không hợp lệ chỉ đơn giản là một lỗi đánh máy và người dùng có nghĩa là -85 hoặc một cái gì đó khác. Trong trường hợp này âm thầm chuyển đổi là xấu và không có ích . Cách tiếp cận thân thiện với người dùng nhất cho ứng dụng của bạn có lẽ là cảnh báo người dùng về giá trị không hợp lệ và yêu cầu người dùng tự sửa nó.

Nhập thông qua API

Nếu đầu vào là từ một hệ thống hoặc hệ thống con khác, không có câu hỏi. Bạn nên ném một ngoại lệ. Bạn không bao giờ nên im lặng chuyển đổi đầu vào không hợp lệ từ một hệ thống khác, vì nó có thể che giấu các lỗi ở nơi khác trong hệ thống. Nếu đầu vào bị "sửa" thì nó sẽ xảy ra trong lớp UI, chứ không phải sâu hơn vào hệ thống.


0

Bạn nên ném một ngoại lệ.

Trong ví dụ bạn đã đưa ra, gửi 185 và chuyển đổi thành -175, trong một số trường hợp có thể có ích để cung cấp chức năng đó. Nhưng nếu người gọi gửi 1 triệu thì sao? Họ thực sự có nghĩa là để chuyển đổi điều đó? Có vẻ như đó là một lỗi. Vì vậy, nếu bạn cần ném một ngoại lệ cho 1.000.000 nhưng không phải là 185, thì bạn phải đưa ra quyết định về ngưỡng tùy ý cho việc ném ngoại lệ. Ngưỡng đó sẽ khiến bạn vấp ngã đôi khi vì một số ứng dụng gọi điện đang gửi các giá trị xung quanh ngưỡng đó.

Tốt hơn là ném ngoại lệ cho các giá trị ra khỏi phạm vi.


-1

Tùy chọn thuận tiện nhất cho nhà phát triển sẽ là hỗ trợ lỗi thời gian biên dịch trong nền tảng, cho các giá trị ngoài phạm vi. Trong trường hợp này, phạm vi cũng phải là một phần của chữ ký phương thức, giống như kiểu của các tham số. Giống như cách người dùng API của bạn không thể vượt qua Chuỗi nếu chữ ký phương thức của bạn được xác định để lấy số nguyên , người dùng sẽ không thể truyền giá trị mà không kiểm tra xem giá trị có nằm trong phạm vi được đưa ra trong chữ ký phương thức hay không. Nếu không được kiểm tra, anh ta sẽ nhận được một lỗi thời gian biên dịch và do đó, có thể tránh được lỗi thời gian chạy.

Nhưng hiện tại, rất ít trình biên dịch / nền tảng hỗ trợ loại kiểm tra thời gian biên dịch này. Vì vậy, đó là một nhà phát triển đau đầu. Nhưng lý tưởng nhất, phương pháp của bạn chỉ nên đưa ra một ngoại lệ có ý nghĩa cho các giá trị không được hỗ trợ và ghi lại rõ ràng.

BTW, tôi thực sự thích mô hình lỗi được đề xuất bởi Joe Duffy ở đây .


Làm thế nào bạn sẽ cung cấp lỗi thời gian biên dịch cho đầu vào của người dùng?
JacquesB

@JacquesB Trình biên dịch sẽ báo lỗi nếu đầu vào của người dùng không được kiểm tra trong phạm vi sau khi chèn, bất kể giá trị thực nằm trong phạm vi.
Gul Sơn

Nhưng sau đó, bạn vẫn phải quyết định xem bạn có muốn từ chối đầu vào hoặc chuyển đổi sang phạm vi hợp lệ hay không, vì vậy điều này không trả lời câu hỏi ban đầu.
JacquesB

@JacquesB Tôi nên nói điều này, lúc đầu- Tôi luôn nghĩ rằng, OP đang phát triển API và UI được phát triển bởi người khác, tiêu thụ API của anh ấy. Tôi đã sai về điểm này. Tôi chỉ đọc câu hỏi một lần nữa và nhận ra điều này. Tất cả những gì tôi đang cố gắng nói là, việc xác thực nên được thực hiện tại người tiêu dùng API và nếu không, trình biên dịch sẽ gây ra lỗi.
Gul Sơn

Vì vậy, ... bạn cần tạo một lớp mới chứa các đầu vào và xác nhận hợp lệ. Khi bạn xây dựng đối tượng lớp từ các đầu vào thô, điều gì xảy ra? Ném một ngoại lệ? Âm thầm vượt qua? Bạn chỉ cần di chuyển vấn đề.
djechlin

-1

Mặc định nên được ném một ngoại lệ. Bạn cũng có thể cho phép một tùy chọn thích strict=falsevà thực hiện cưỡng chế dựa trên cờ, trong đó tất nhiên strict=truelà mặc định. Điều này khá phổ biến:

  • Java DateFormathỗ trợ khoan hồng .
  • Trình phân tích cú pháp JSON của Gson cũng hỗ trợ chế độ khoan dung .
  • Vân vân.

Điều này làm phức tạp mã không có lợi.
JacquesB

@JacquesB ném ngoại lệ theo mặc định, hoặc cho phép strict=false?
djechlin

@JacquesB Tôi đã thêm một số ví dụ về API hỗ trợ các chế độ nghiêm ngặt và khoan dung, vui lòng xem qua.
djechlin

-2

Đối với tôi thực hành tốt nhất là không bao giờ thay đổi đầu vào của người dùng. Cách tiếp cận tôi thường làm là tách xác thực khỏi thực thi.

  • Có một lớp đơn giản chỉ sử dụng các tham số đã cho.
  • Sử dụng một trình trang trí để cung cấp một lớp xác nhận có thể được thay đổi theo ý muốn mà không ảnh hưởng đến lớp thực thi (hoặc nếu không thì tiêm trình xác nhận nếu cách tiếp cận này quá khó).

"Người dùng" mà câu hỏi đang đề cập đến là nhà phát triển sử dụng API, không phải người dùng cuối ...
Jay Elston
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.