¿Debo lanzar una excepción en caso de un valor significativo fuera del rango o manejarlo yo mismo?

42

He escrito una estructura que representa las coordenadas de latitud / longitud. Sus valores van desde -180 a 180 para longtitudes y 90 a -90 para lattitudes.

Si un usuario de esa estructura me da un valor fuera de ese rango, tengo 2 opciones:

  1. Lanzar una excepción (argumento fuera de rango)
  2. Convierta el valor a la restricción

Debido a que una coordenada de -185 tiene un significado (se puede convertir fácilmente a +175 ya que son coordenadas polares), podría aceptarlo y convertirlo.

¿Es mejor lanzar una excepción para decirle al usuario que su código me ha dado un valor que no debería tener?

Edit: También sé la diferencia entre lat / lng y coordenadas, pero quería simplificar eso para facilitar la discusión, no fue la más brillante de las ideas

    
pregunta K. Gkinis 18.02.2016 - 12:11

8 respuestas

51

Si el núcleo de tu pregunta es esto ...

  

Si algún código de cliente pasa un argumento cuyo valor no es válido para lo que está modelando mi estructura de datos, ¿debo rechazar el valor o convertirlo en algo razonable?

... entonces mi respuesta general sería "rechazar", ya que esto ayudará a llamar la atención sobre posibles errores en el código del cliente que en realidad causan que el valor no válido aparezca en el programa y llegue a su constructor. En general, llamar la atención sobre los errores es una propiedad deseada en la mayoría de los sistemas, al menos durante el desarrollo (a menos que sea una propiedad deseada de su sistema para resolver en caso de errores).

La pregunta es si realmente estás enfrentando ese caso .

  • Si su estructura de datos está diseñada para modelar las coordenadas polares en general, entonces acepte el valor porque los ángulos fuera del rango de -180 y +180 no son realmente válidos. Son perfectamente válidos y siempre tienen un equivalente que está dentro del rango de -180 y +180 (y si desea convertirlos a ese rango, siéntase libre: el código del cliente no tiene por qué preocuparse) .

  • Si su estructura de datos está modelando explícitamente las coordenadas de Web Mercator (de acuerdo con la pregunta en su forma inicial), entonces es mejor seguir cualquier disposición mencionada en la especificación (que no sé, así que gané) No digas nada al respecto). Si la especificación de lo que estás modelando dice que algunos valores no son válidos, recházalos. Si dice que pueden interpretarse como algo sensato (y, por lo tanto, son válidos), acéptalos.

El mecanismo que utiliza para indicar si los valores se aceptaron o no depende de las características de su idioma, su filosofía general y sus requisitos de rendimiento. Por lo tanto, podría estar lanzando una excepción (en el constructor) o devolviendo una versión anulable de su estructura (a través de un método estático que invoca a un constructor privado) o devolviendo un booleano y pasando su estructura al llamante como un parámetro out ( de nuevo a través de un método estático que invoca a un constructor privado) y así sucesivamente.

    
respondido por el Theodoros Chatzigiannakis 18.02.2016 - 12:32
10

Depende mucho. Pero debes decidir hacer algo y documentarlo .

La única cosa definitivamente errónea que debe hacer su código es olvidarse de considerar que la entrada del usuario podría estar fuera del rango esperado, y escribir código que accidentalmente tenga algún comportamiento. Debido a que algunas personas harán una suposición incorrecta acerca de cómo se comporta su código y causará errores, mientras que otras terminarán dependiendo del comportamiento que accidentalmente tenga su código (incluso si ese comportamiento es completamente alocado) y así que causará más errores cuando más tarde solucione el problema.

En este caso puedo ver los argumentos de cualquier manera. Si alguien viaja +10 grados desde 175 grados, debe terminar en -175. Si siempre normaliza la entrada del usuario y, por lo tanto, trata a 185 como equivalente a -175, entonces el código del cliente no puede hacer lo incorrecto cuando agrega 10 grados; siempre tiene el efecto correcto. Si trata a 185 como un error, fuerza todos los casos en los que el código del cliente agrega grados relativos para poner en la lógica de normalización (o al menos recuerde llamar a su procedimiento de normalización), en realidad causa errores ( aunque es de esperar que sea fácil atrapar a los que serán aplastados rápidamente). Pero si se ingresa un número de longitud, se escribe literalmente en el programa, o se calcula a través de algún procedimiento destinado a estar siempre en [-180, 180), entonces es muy probable que un valor fuera de ese rango indique un error, por lo tanto "convertirlo podría ocultar problemas.

Mi ideal en este caso probablemente sería definir un tipo que represente el dominio correcto. Use un tipo abstracto (no permita que el código del cliente simplemente acceda a los números en bruto que contiene), y proporcione una fábrica de validación y normalización (para que el cliente pueda hacer la compensación). Pero sea cual sea el valor de este tipo, 185 debe ser indistinguible de -175 cuando se ve a través de su API pública (no importa si se convierten en construcción o si proporciona igualdad, accesores y otras operaciones que ignoran la diferencia de alguna manera) .

    
respondido por el Ben 19.02.2016 - 07:54
3

Si realmente no le importa elegir una solución, podría dejar que el usuario decida.

Dado que su estructura es un objeto de valor de solo lectura y creado por un método / constructor, podría proporcionar dos sobrecargas basadas en las opciones que tiene el usuario:

  • Lanzar una excepción (argumento fuera de rango)
  • Convierta el valor a la restricción

Además, nunca permita que el usuario tenga una estructura no válida para pasar a sus otros métodos, haga que sea correcto en la creación.

Editar: según los comentarios, asumo que estás usando c #.

    
respondido por el Filipe Borges 18.02.2016 - 13:22
0

Depende de si la entrada es directamente de un usuario a través de alguna interfaz de usuario o del sistema.

Entrada a través de una interfaz de usuario

Es una pregunta de experiencia del usuario cómo manejar una entrada no válida. No conozco su caso específico, pero en general hay algunas opciones:

  • Alerte al usuario del error y pídale que lo arregle antes de continuar (el más común)
  • Convierta automáticamente al rango válido (si es posible), pero alerte al usuario al cambio y permita que el usuario verifique antes de continuar.
  • Conviértete silenciosamente al rango válido y continúa.

La elección depende de las expectativas de sus usuarios y de la importancia de los datos. Por ejemplo, Google corrige automáticamente la ortografía de las consultas, pero esto conlleva un bajo riesgo porque un cambio inútil no es un problema y es fácil de corregir (e incluso entonces se deja claro en la página de resultados que se cambió la consulta). Por otro lado, si está ingresando coordenadas para un misil nuclear, es posible que desee una validación de entrada más rígida y que no haya soluciones silenciosas de datos no válidos. Así que no hay una respuesta universal.

Lo más importante es que debe considerar si la corrección de una entrada tiene un beneficio para el usuario. ¿Por qué un usuario ingresaría datos no válidos? Es fácil ver cómo alguien podría cometer un error de ortografía, pero ¿por qué alguien ingresaría una longitud de -185? Si el usuario realmente quisiera decir +175, probablemente habría escrito +175. Creo que es muy probable que una longitud no válida simplemente sea un error de escritura, y el usuario quiso decir -85 o algo más. En este caso, la conversión silenciosa es mala e inútil . El enfoque más fácil de usar para su aplicación probablemente sería alertar al usuario del valor no válido y hacer que el usuario lo corrija por sí mismo.

Entrada a través de una API

Si la entrada es de otro sistema o subsistema, no hay duda. Deberías lanzar una excepción. Nunca debe convertir en silencio la entrada no válida de otro sistema, ya que podría enmascarar errores en otras partes del sistema. Si la entrada se "corrige", debería ocurrir en la capa UI, no en el sistema.

    
respondido por el JacquesB 23.02.2016 - 08:31
0

Deberías lanzar una excepción.

En el ejemplo que dio, enviando 185 y convirtiéndolo a -175, en algunos casos podría ser útil proporcionar esa funcionalidad. Pero ¿y si la persona que llama envía 1 millón? ¿Realmente quieren convertir eso? Parece más probable que sea un error. Entonces, si necesita lanzar una excepción para 1,000,000 pero no para 185, entonces tiene que tomar una decisión sobre un umbral arbitrario para lanzar una excepción. Ese umbral lo hará tropezar en algún momento, ya que algunas aplicaciones de llamadas envían valores alrededor del umbral.

Es mejor lanzar la excepción para los valores fuera del rango.

    
respondido por el brendan 24.02.2016 - 08:16
-1

La opción más conveniente para un desarrollador sería un soporte de error de tiempo de compilación en la plataforma, para valores fuera de rango. En este caso, el rango también debe ser parte de la firma del método, al igual que el tipo de parámetros. De la misma manera que su usuario de API no puede pasar una Cadena si su firma de método está definida para tomar un entero , el usuario no debería haber pasado un valor sin verificar si el valor Está dentro del rango dado en la firma del método. Si no se marca, debería obtener un error de tiempo de compilación y, por lo tanto, podría evitarse el error de tiempo de ejecución.

Pero actualmente, muy pocos compiladores / plataformas soportan este tipo de verificación de tiempo de compilación. Por lo tanto, es un dolor de cabeza de los desarrolladores. Pero idealmente, su método debería lanzar una excepción significativa para los valores no compatibles y documentarlo claramente.

Por cierto, me encanta el modelo de error propuesto por Joe Duffy aquí .

    
respondido por el Gulshan 19.02.2016 - 06:35
-1

El predeterminado debería ser lanzar una excepción. También puede permitir una opción como strict=false y hacer la coacción en función de la bandera, donde, por supuesto, strict=true es la predeterminada. Esto es bastante común:

  • Java DateFormat admite lenient .
  • El analizador JSON de Gson también admite un lenient modo.
  • Etc.
respondido por el djechlin 19.02.2016 - 01:19
-2

Para mí, la mejor práctica es nunca cambiar la entrada del usuario. El enfoque que suelo adoptar es separar la validación de la ejecución.

  • Tenga una clase simple que solo use los parámetros dados.
  • Use un decorador para proporcionar una capa de validación que pueda modificarse a voluntad sin afectar la clase de ejecución (o inyecte un validador si este enfoque es demasiado difícil).
respondido por el David A 18.02.2016 - 18:28

Lea otras preguntas en las etiquetas