범위를 벗어난 의미있는 값의 경우 예외를 던지거나 직접 처리해야합니까?


42

위도 / 경도 좌표를 나타내는 구조체를 작성했습니다. 값은 경도의 경우 -180 ~ 180, 위도의 경우 90 ~ -90입니다.

해당 구조체의 사용자가 해당 범위를 벗어난 값을 제공하면 두 가지 옵션이 있습니다.

  1. 예외 발생 (범위를 벗어남)
  2. 값을 구속 조건으로 변환

-185의 좌표는 의미를 갖기 때문에 (극좌표이므로 +175로 매우 쉽게 변환 될 수 있음), 그것을 받아 변환 할 수 있습니다.

자신의 코드가 나에게 없어서는 안될 가치를 부여했다는 것을 사용자에게 알리기 위해 예외를 던지는 것이 낫습니까?

편집 : 또한 위도 / 경도와 좌표의 차이점을 알고 있지만 더 쉬운 토론을 위해 단순화하고 싶었습니다. 가장 밝은 아이디어는 아니 었습니다.


13
사용자가 범위를 벗어난 값을 삽입 할 수 있어야합니까? 대답이 아니오 인 경우 예외를 던지십시오. 규칙이 엄격하지 않은 경우 변환을 수행하지만 문서에 변환이 발생할 수 있음을 명시 적으로 명시하십시오. 또한 일부 언어에서는 예외 처리에 많은 비용이 소요됩니다.
Andy

C #, 문제가 되나요? 이것이 의미하는 경우 기본적으로 제약 조건을 지원하지 않습니다.
K. Gkinis

2
그것은 나에게 매우 분명한 것처럼 보입니다. 올바른 접근 방식은 사용자가 범위 밖의 것을 입력하고 입력 할 때 예외를 던지도록 다이얼 다운하고 있습니다 (표준에서 abs 값이 180보다 높아서는 안된다고 말하면 그보다 큰 값을 넣습니다) 명백한 위반). 그런데 C #은 실제로 예외가 상당히 많은 언어 중 하나이므로 예외적 인 상황에서만 예외를 사용하십시오. 예외적으로 잡히면 응용 프로그램을 깨뜨리지 않을 것입니다.
Andy

2
특정 매개 변수 값, 특히 내 코드에서 제공하지 않는 값을 전달하여 사용자가 무엇을 의미하는지에 대한 가정을 멀리하는 경향이 있습니다. 비슷한 경우처럼 들립니다.
JᴀʏMᴇᴇ

2
Web Mercator 좌표는 -180 ~ 180 및 -90 ~ 90 이 아닙니다. 위도 / 경도입니다 (그리고이를위한 여러 좌표계도 있음). 메르카토르 투영은 일반적으로 수십만 또는 수백만 개이며 "미터"단위 (각 단위의 길이가 극에 접근 할 때 실제 접지 거리가 증가하기 때문에 엄밀하지는 않음)가 아니라도 단위입니다. 각도의 관점에서도, 투영은 극에서 무한대로 넓어지기 때문에 ± 85.051129 도로 제한됩니다. (질문의 핵심이 아니기 때문에이를 수정하는 수정본을 제출했습니다.)
jpmc26

답변:


51

질문의 핵심이 이것이라면 ...

일부 클라이언트 코드가 내 데이터 구조가 모델링하는 것에 대해 값이 잘못된 인수를 전달하면 값을 거부하거나 합리적인 것으로 변환해야합니까?

... 일반적인 대답은 "거부"입니다. 이는 클라이언트 코드에서 실제로 잘못된 값이 프로그램에 나타나고 생성자에 도달하게하는 잠재적 인 버그에주의를 기울이는 데 도움이되기 때문입니다. 버그에주의를 기울이는 것은 최소한 개발 중에는 대부분의 시스템에서 일반적으로 원하는 속성입니다 (오류가 발생하는 경우 시스템의 장애물이되지 않는 한).

문제는 실제로 그 사건에 직면하고 있는지 여부 입니다.

  • 데이터 구조가 일반적으로 극좌표를 모델링하려는 경우 -180 및 +180 범위를 벗어난 각도가 실제로 유효하지 않기 때문에 값을 수락하십시오. 그것들은 완벽하게 유효하며 항상 -180과 +180의 범위 내에있는 동등한 것을 가지고 있습니다 (그리고 당신이 그 범위를 목표로 변환하고 싶다면 자유롭게 느끼십시오-클라이언트 코드는 일반적으로 신경 쓸 필요가 없습니다) .

  • 데이터 구조가 Web Mercator 좌표를 명시 적으로 모델링하는 경우 (초기 양식의 질문에 따라) 사양에 언급 된 규정을 따르는 것이 가장 좋습니다 (알지 못하므로 이에 대해 아무 말도하지 않습니다) . 모델링중인 항목 의 스펙에 일부 값이 유효하지 않다고 표시되면 거부하십시오. 그들이 합리적인 것으로 해석 될 수 있다고 말하면 (실제로 유효하다) 받아 들여라.

메커니즘 이 값 허용 여부되었는지 여부를 신호로 사용하는 언어, 그것의 일반적인 철학 및 성능 요구 사항의 기능에 따라 달라집니다. 따라서 (생성자에서) 예외를 던지거나 (개인 생성자를 호출하는 정적 메서드를 통해) nullable 버전의 구조체를 반환하거나 부울을 반환하고 구조체를 out매개 변수 로 호출자에게 전달할 수 있습니다 (다시 개인 생성자를 호출하는 정적 메소드 등).


12
-180에서 +180 범위를 벗어나는 경도는 허용 가능한 것으로 간주되지만 -90에서 +90 범위를 벗어난 위도는 의미가 없습니다. 일단 북극이나 남극에 도달하면 남북으로의 추가 이동은 정의되지 않습니다.
supercat 2019

4
@ supercat 나는 당신에게 동의하는 경향이 있지만 Web Mercator 사양에서 실제로 어떤 값이 유효하지 않은지 알 수 없으므로 어려운 결론을 내리려고하지 않습니다. OP는 나보다 문제 영역을 더 잘 알고 있습니다.
Theodoros Chatzigiannakis

1
@supercat : 자오선이 적도에 도달하는 곳에서 시작하십시오. 위도에 따라 자오선을 따라 이동합니다. 위도가 90보다 크면 동일한 큰 원을 따라 계속 진행하십시오. 문제 없어요. 문서화하고 나머지는 고객에게 맡기십시오.
kevin cline

4
@supercat 그것보다 나쁘다. Web Mercator 투영에서 실제로 ± 90은 무한 너비로 투영됩니다. 따라서 표준은 실제로 ± 85.051129에서 차단합니다. 또한 위도 / 경도! = 웹 메르카토르 좌표입니다. 메르카토르 좌표는 각도가 아닌 미터의 변형을 사용합니다. 극에 가까워 질수록 각 "미터"는 실제로 더 큰 접지 부분에 해당합니다. OP 좌표는 순전히 위도 / 경도입니다. Web Mercator는 Web Mercator 기본 맵 위에 표시 될 수있는 것 외에는 아무런 관련이 없으며 일부 공간 라이브러리가이를 지원합니다.
jpmc26

1
"± 85.051129에 해당"라고 말해야합니다. 실제 좌표가 아니기 때문입니다.
jpmc26

10

많이 다릅니다. 그러나 무언가를하고 문서화 하기결정 해야 합니다 .

코드에서 유일 하게 잘못된 것은 사용자 입력이 예상 범위를 벗어날 수 있다는 점을 잊고 실수로 동작이있는 코드를 작성하는 것입니다. 어떤 사람들은 코드가 어떻게 동작하는지에 대한 잘못된 가정을하고 버그를 일으킬 것입니다. 반면에 다른 사람들은 실수로 코드가하는 행동 에 따라 다른 행동을하게되므로 더 많은 버그가 발생할 수 있습니다. 나중에 문제를 해결할 때

이 경우 어느 쪽이든 인수를 볼 수 있습니다. 누군가가 175도에서 +10도를 여행하면 -175로 끝나야합니다. 항상 사용자 입력을 정규화하고 185를 -175와 동일하게 취급하면 클라이언트 코드 는 10도를 추가 할 때 잘못된 일을 할 수 없습니다 . 항상 올바른 효과가 있습니다. 185를 오류로 취급하면 클라이언트 코드가 상대 각도를 추가하여 정규화 논리에 넣을 때마다 (또는 적어도 정규화 절차를 호출해야 함) 강제로 발생합니다.버그 (빠르게 찌그러 질 버그를 잡기 쉽지만). 그러나 경도 숫자를 사용자가 입력하거나 문자 그대로 프로그램에 쓰거나 항상 [-180, 180)에있는 일부 절차를 통해 계산 한 경우 해당 범위 밖의 값은 오류를 나타낼 가능성이 매우 높습니다. "변환하면 문제가 숨겨 질 수 있습니다.

이 경우 가장 이상적인 것은 올바른 도메인을 나타내는 유형을 정의하는 것입니다. 추상 유형을 사용 (클라이언트 코드는 단순히 내부의 원료 번호에 액세스하지 않음) (소위 정규화 및 타당성을 검증하는 공장을 모두 제공하는 클라이언트가 트레이드 오프를 할 수 있습니다). 그러나이 유형의 값이 무엇이든간에 185는 공개 API를 통해 볼 때 -175와 구별 할 수 없어야합니다 (구성에서 변환되었는지 또는 어떻게 든 차이를 무시하는 평등, 접근 자 및 기타 작업을 제공하는지 여부는 중요하지 않음) .


3

하나의 솔루션을 선택하는 것이 실제로 중요하지 않은 경우 사용자가 결정하도록 할 수 있습니다.

구조체가 읽기 전용 값 객체이고 메서드 / 생성자에 의해 생성 된 경우 사용자가 가진 옵션에 따라 두 가지 오버로드를 제공 할 수 있습니다.

  • 예외 발생 (범위를 벗어남)
  • 값을 구속 조건으로 변환

또한 사용자에게 다른 메소드에 전달할 수있는 잘못된 구조체를 만들지 말고 작성시 바로 작성하십시오.

편집 : 의견에 따라 c #을 사용한다고 가정합니다.


입력 주셔서 감사합니다! 나는 그것을 던질 수 있다면 예외 던지기 생성자의 목적을 훼손 할까봐 두려워하지만 그것에 대해 생각할 것입니다. 그래도 흥미 롭습니다!
K. Gkinis

이 아이디어를 사용하려면 인터페이스를 정의하고 던지거나 변환하는 두 가지 구현 이있는 것이 좋습니다 . 설명 된대로 작동하기 위해 적절한 방식으로 생성자를 오버로드하는 것이 어려울 수 있습니다.

2
@ Snowman : 예, 동일한 인수 유형으로 생성자를 오버로드하는 것은 어렵지만 두 개의 정적 메소드와 개인 생성자를 갖는 것은 어렵지 않습니다.
wchargin

1
@ K.Gkinis : 예외 발생 생성자의 목적은 "응용 프로그램이 종료되었는지 확인"하는 것이 아니라 결국 클라이언트가 항상 catch예외를 처리 할 수 있다는 것입니다. 다른 사람들이 말했듯이, 원하는 경우 클라이언트가 스스로제한 하도록 허용합니다 . 당신은 실제로 아무것도 우회하지 않습니다.
wchargin

이 제안은 코드를 복잡하게 만들지 않습니다. 메소드가 유효하지 않은 입력을 변환하거나 변환하지 않아야합니다. 두 개의 과부하가 있으면 딜레마를 해결하지 않고도 코드가 더 복잡해집니다.
JacquesB

0

입력이 UI를 통해 사용자로부터 직접 온 것인지 아니면 시스템에서 온 것인지에 따라 다릅니다.

UI를 통한 입력

유효하지 않은 입력을 처리하는 방법은 사용자 경험 질문입니다. 특정 사례에 대해서는 잘 모르지만 일반적으로 몇 가지 옵션이 있습니다.

  • 계속 진행하기 전에 사용자에게 오류를 알리고 수정하도록합니다 (가장 일반적)
  • 유효한 범위로 자동 변환하지만 (가능한 경우) 변경 사항을 사용자에게 알리고 계속하기 전에 사용자가 확인할 수 있도록합니다.
  • 올바른 범위로 자동 변환하고 진행하십시오.

선택은 사용자의 기대치와 데이터의 중요도에 따라 다릅니다. 예를 들어 Google은 검색어의 철자를 자동으로 수정하지만, 도움이되지 않는 변경은 문제가 아니며 수정하기 쉬우므로 위험이 적습니다 (결과 페이지에서도 쿼리가 변경되었음을 알 수 있습니다). 반면에, 핵 미사일의 좌표를 입력하는 경우보다 엄격한 입력 유효성 검사를 원하고 잘못된 데이터의 자동 수정을 원하지 않을 수 있습니다. 따라서 보편적 인 대답은 없습니다.

가장 중요한 것은 입력을 수정하는 것이 사용자에게 이익이되는지도 고려해야합니다. 사용자가 유효하지 않은 데이터를 입력합니까? 누군가 철자 오류를 만드는 방법을 쉽게 알 수 있지만 왜 -185의 경도를 입력합니까? 사용자가 실제로 +175를 의미했다면 아마도 +175를 입력했을 것입니다. 나는 잘못된 경도가 단순히 입력 오류 일 가능성높으며 사용자는 -85 또는 다른 것을 의미한다고 생각합니다. 이 경우 자동 변환은 나쁘고 도움이되지 않습니다 . 앱에 가장 사용자 친화적 인 접근 방식은 사용자에게 잘못된 값을 알리고 사용자가 직접 수정하도록하는 것입니다.

API를 통한 입력

다른 시스템이나 서브 시스템에서 입력 한 경우에는 의문의 여지가 없습니다. 예외를 던져야합니다. 다른 시스템의 잘못된 입력은 시스템의 다른 곳에서 오류를 숨길 수 있으므로 자동으로 변환하지 않아야합니다. 입력이 "수정"되면 시스템 내부가 아닌 UI 계층에서 발생합니다.


0

예외를 던져야합니다.

185를 보내고 -175로 변환 한 예에서 경우에 따라 해당 기능을 제공하는 것이 편리 할 수 ​​있습니다. 하지만 발신자가 1 백만을 보내면 어떻게 될까요? 그들은 정말로 그것을 변환시키는 것을 의미합니까? 오류 일 가능성이 높습니다. 따라서 1,085에 대해서는 예외가 발생하지만 185에는 예외가 발생하지 않으면 예외를 발생시키기위한 임의의 임계 값을 결정해야합니다. 일부 호출 앱이 임계 값 주위로 값을 전송함에 따라 해당 임계 값이 언젠가 트립됩니다.

범위를 벗어난 값에 대한 예외를 던지는 것이 좋습니다.


-1

개발자에게 가장 편리한 옵션은 범위를 벗어난 값에 대해 플랫폼에서 컴파일 시간 오류 지원입니다. 이 경우, 범위는 매개 변수 유형과 마찬가지로 메소드 서명의 일부 여야합니다. 메소드 서명이 integer 를 취하도록 정의 된 경우 API 사용자가 문자열을 전달할 수없는 것과 동일한 방법으로 , 값이 메소드 서명에 지정된 범위 내에 있는지 확인하지 않고 값을 전달할 수 없어야합니다. 확인하지 않으면 컴파일 시간 오류가 발생하므로 런타임 오류를 피할 수 있습니다.

그러나 현재이 유형의 컴파일 시간 확인을 지원하는 컴파일러 / 플랫폼은 거의 없습니다. 개발자의 골치 거리입니다. 그러나 이상적으로는 지원되지 않는 값에 대해 의미있는 예외를 던져 명확하게 문서화해야합니다.

BTW, 난 정말 조 더피에 의해 제안 된 오차 모델 사랑 여기를 .


사용자 입력에 대한 컴파일 시간 오류를 어떻게 제공 하시겠습니까?
JacquesB

@JacquesB 실제 값이 범위 내에 있는지 여부 에 관계없이 사용자 입력이 삽입 후 범위 내에 있는지 확인하지 않으면 컴파일러에서 오류가 발생합니다 .
굴샨

그러나 입력을 거부하거나 유효한 범위로 변환할지 여부를 결정해야하므로 원래 질문에 대답하지 않습니다.
JacquesB

@JacquesB 나는 이것을 항상 말해야한다. 나는 항상 OP가 API를 개발하고 UI는 다른 사람에 의해 개발되어 API를 소비한다고 생각했다. 나는이 점에 대해 틀렸다. 방금 질문을 다시 읽고 깨달았습니다. 내가 말하려는 것은 API 소비자에서 유효성 검사를 수행해야하며 그렇지 않은 경우 컴파일러에서 오류를 발생시켜야합니다.
굴샨

입력을 포함하고 검증하는 새로운 클래스를 만들어야합니다. 원시 입력에서 클래스 객체를 구성 할 때 발생하는 문제는 무엇입니까? 예외를 던져? 조용히 통과? 당신은 문제를 움직입니다.
djechlin

-1

기본값은 예외를 발생시키는 것이어야합니다. strict=false플래그를 기반으로 옵션을 허용 하고 강제를 수행 할 수도 있습니다 strict=true. 물론 기본값은 기본값입니다. 이것은 매우 일반적입니다.


이로 인해 코드가 복잡해지지 않습니다.
JacquesB

@JacquesB는 기본적으로 예외를 던지거나 strict=false?
djechlin

@JacquesB 엄격하고 관대 한 모드를 지원하는 API 예제를 추가했습니다.
djechlin

-2

나에게 가장 좋은 방법은 사용자 입력을 변경하지 않는 것입니다. 내가 일반적으로 취하는 접근 방식은 유효성 검사와 실행을 분리하는 것입니다.

  • 주어진 매개 변수를 사용하는 간단한 클래스가 있습니다.
  • 데코레이터를 사용하여 실행 클래스에 영향을주지 않고 원하는대로 변경할 수있는 유효성 검사 계층을 제공하십시오 (또는이 방법이 너무 어려운 경우 유효성 검사기를 삽입하십시오).

질문이 말하는 "사용자"는 최종 사용자가 아닌 API를 사용하는 개발자입니다.
Jay Elston
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.