Eu escrevi uma estrutura que representa coordenadas de latitude / longitude. Seus valores variam de -180 a 180 para longitudes e 90 a -90 para latitudes.
Se um usuário dessa estrutura me fornecer um valor fora desse intervalo, tenho 2 opções:
- Lançar uma exceção (argumento fora do intervalo)
- Converta o valor na restrição
Como uma coordenada de -185 tem significado (pode ser facilmente convertida em +175 por serem coordenadas polares), eu poderia aceitá-la e convertê-la.
É melhor lançar uma exceção para informar ao usuário que seu código me deu um valor que não deveria ter?
Edit: Também sei a diferença entre lat / lng e coordenadas, mas queria simplificar isso para facilitar a discussão - não era a mais brilhante das idéias
c#
exceptions
validation
K. Gkinis
fonte
fonte
Respostas:
Se o núcleo da sua pergunta é este ...
... então minha resposta geral seria "rejeitar", porque isso ajudará a chamar a atenção para possíveis erros no código do cliente que realmente estão fazendo com que o valor inválido apareça no programa e chegue ao seu construtor. Chamar a atenção para os bugs geralmente é uma propriedade desejada na maioria dos sistemas, pelo menos durante o desenvolvimento (a menos que seja uma propriedade desejada do seu sistema atrapalhar em caso de erros).
A questão é se você está realmente enfrentando esse caso .
Se sua estrutura de dados se destina a modelar coordenadas polares em geral, aceite o valor porque os ângulos fora do intervalo -180 e +180 não são realmente inválidos. Eles são perfeitamente válidos e sempre têm um equivalente no intervalo de -180 e +180 (e se você deseja convertê-los para atingir esse intervalo, fique à vontade - o código do cliente geralmente não precisa se importar) .
Se sua estrutura de dados estiver modelando explicitamente as coordenadas do Web Mercator (de acordo com a pergunta em sua forma inicial), é melhor seguir as disposições mencionadas na especificação (que eu não sei, por isso não vou falar nada sobre isso) . Se a especificação da coisa que você está modelando disser que alguns valores são inválidos, rejeite-os. Se diz que eles podem ser interpretados como algo sensível (e, portanto, são realmente válidos), aceite-os.
O mecanismo usado para sinalizar se os valores foram aceitos ou não depende dos recursos do seu idioma, de sua filosofia geral e de seus requisitos de desempenho. Portanto, você pode lançar uma exceção (no construtor) ou retornar uma versão anulável de sua estrutura (por meio de um método estático que chama um construtor privado) ou retornar um booleano e passar sua estrutura ao chamador como
out
parâmetro (novamente por meio de um método estático que chama um construtor privado) e assim por diante.fonte
Isso depende muito. Mas você deve decidir fazer algo e documentá-lo .
A única coisa definitivamente errada para o seu código é esquecer de considerar que a entrada do usuário pode estar fora do intervalo esperado e escrever um código que acidentalmente tenha algum comportamento. Porque então algumas pessoas fazem uma suposição incorreta sobre como seu código se comporta e isso causa bugs, enquanto outras acabam dependendo do comportamento que seu código acidentalmente tem (mesmo que esse comportamento seja completamente maluco) e, portanto, você causa mais bugs depois, quando você resolver o problema.
Nesse caso, posso ver argumentos de qualquer maneira. Se alguém viaja +10 graus a partir de 175 graus, deve terminar em -175. Se você sempre normaliza a entrada do usuário e trata 185 como equivalente a -175, o código do cliente não pode fazer a coisa errada quando adiciona 10 graus; sempre tem o efeito certo. Se você tratar 185 como um erro, forçar todos os casos em que o código do cliente estiver adicionando graus relativos para colocar na lógica de normalização (ou pelo menos lembre-se de chamar seu procedimento de normalização), você realmente causaráerros (embora esperemos que fáceis de capturar aqueles que serão rapidamente esmagados). Porém, se um número de longitude for inserido pelo usuário, gravado literalmente no programa ou calculado através de algum procedimento destinado a estar sempre em [-180, 180), é muito provável que um valor fora desse intervalo indique um erro, de modo "útil" "convertê-lo pode esconder problemas.
Meu ideal nesse caso provavelmente seria definir um tipo que represente o domínio correto. Use um tipo abstrato (não deixe o código do cliente simplesmente acessar os números brutos dentro dele) e forneça uma fábrica de normalização e validação (para que o cliente possa fazer a troca). Mas seja qual for o valor desse tipo, 185 deve ser indistinguível de -175 quando visto por meio de sua API pública (não importa se eles são convertidos em construção ou se você fornece igualdade, acessadores e outras operações que ignoram a diferença de alguma forma) .
fonte
Se realmente não importa para você escolher uma solução, você pode deixar o usuário decidir.
Como sua estrutura é um objeto de valor somente leitura e criada por um método / construtor, você pode fornecer duas sobrecargas com base nas opções que o usuário possui:
Além disso, nunca permita que o usuário tenha uma estrutura inválida para passar para seus outros métodos, corrija a criação.
Editar: com base nos comentários, suponho que você esteja usando c #.
fonte
catch
suas exceções. Como outros já disseram, é permitir que o cliente se restrinja, se assim o desejar. Você não está realmente contornando nada.Depende se a entrada é diretamente de um usuário por meio de alguma interface do usuário ou do sistema.
Entrada através de uma interface do usuário
É uma questão de experiência do usuário como lidar com entradas inválidas. Não conheço o seu caso específico, mas em geral existem algumas opções:
A escolha depende das expectativas dos usuários e da importância dos dados. Por exemplo, o Google corrige automaticamente a ortografia nas consultas, mas isso é de baixo risco, porque uma alteração inútil não é um problema e é fácil de corrigir (e mesmo assim fica claro na página de resultados que a consulta foi alterada). Por outro lado, se você estiver digitando coordenadas para um míssil nuclear, poderá querer uma validação de entrada mais rígida e nenhuma correção silenciosa de dados inválidos. Portanto, não há resposta universal.
Mais importante, você deve considerar se a correção de entrada tem um benefício para o usuário. Por que um usuário insere dados inválidos? É fácil ver como alguém pode cometer um erro de ortografia, mas por que alguém digitaria uma longitude de -185? Se o usuário realmente quisesse +175, provavelmente teria digitado +175. Eu acho que é mais provável que uma longitude inválida simplesmente seja um erro de digitação, e o usuário quis dizer -85 ou outra coisa. Nesse caso, a conversão silenciosa é ruim e inútil . A abordagem mais amigável para o seu aplicativo provavelmente seria alertar o usuário sobre o valor inválido e fazer com que o usuário corrija por conta própria.
Entrada através de uma API
Se a entrada for de outro sistema ou subsistema, não há dúvida. Você deve lançar uma exceção. Você nunca deve converter entradas inválidas de outro sistema em silêncio, pois isso pode mascarar erros em outras partes do sistema. Se a entrada for "corrigida", ela deverá ocorrer na camada da interface do usuário, não mais profundamente no sistema.
fonte
Você deve lançar uma exceção.
No exemplo que você deu, enviando 185 e convertendo para -175, pode ser útil, em alguns casos, fornecer essa funcionalidade. Mas e se o chamador enviar 1 milhão? Eles realmente querem converter isso? Parece mais provável que seja um erro. Portanto, se você precisar lançar uma exceção para 1.000.000, mas não para 185, precisará tomar uma decisão sobre um limite arbitrário para lançar uma exceção. Esse limite vai atrapalhá-lo em algum momento, já que algum aplicativo de chamada está enviando valores ao redor do limite.
Melhor lançar a exceção para valores fora do intervalo.
fonte
A opção mais conveniente para um desenvolvedor seria um suporte a erros de tempo de compilação na plataforma, para valores fora do intervalo. Nesse caso, o intervalo também deve fazer parte da assinatura do método, assim como o tipo dos parâmetros. Da mesma forma que o usuário da API não pode passar uma String se a assinatura do seu método estiver definida para receber um número inteiro , o usuário não deveria poder passar um valor sem verificar se o valor está dentro do intervalo fornecido na assinatura do método. Se não estiver marcado, ele deve receber um erro de tempo de compilação e, portanto, o erro de tempo de execução pode ser evitado.
Porém, atualmente, muito poucos compiladores / plataformas suportam esse tipo de verificação do tempo de compilação. Então, é uma dor de cabeça para os desenvolvedores. Mas, idealmente, seu método deve lançar uma exceção significativa para valores não suportados e documentá-lo claramente.
BTW, eu realmente amo o modelo de erro proposto por Joe Duffy aqui .
fonte
O padrão deve ser lançar uma exceção. Você também pode permitir uma opção como
strict=false
e fazer a coerção com base na bandeira, ondestrict=true
é claro que é o padrão. Isso é bastante comum:DateFormat
suporta branda .fonte
strict=false
?Para mim, a melhor prática é nunca alterar a entrada do usuário. A abordagem que eu costumo adotar é separar a validação da execução.
fonte