Executando verificação de segurança...
0

Exceções são apenas para casos excepcionais?

TLDR; Talvez não

Por muito tempo eu fui completamente desfavorável ao uso de exceptions no decorrer do código. Nunca entendi muito bem, mas sempre assimilei meio que como se fossem os famosos e pré-históricos GOTOs. Porém, hoje me ocorreu um estalo que mudou um pouco essa visão.

Pensamos em uma aplicação com camadas bem definidas. Vamos pegar a arquitetura limpa como exemplo já que na minha bolha anda em alta asuhaus.

Temos a camada de domínio e a camada de infraestrutura como principais atores. A camada de aplicação, ao meu entendimento é só um orquestrador tendo a camada de infraestrutura injetada e orquestrando a camada de negócio com base nisso.

Vamos navegar um pouco pelo caminho que eu via antes do estalo.

Nossa regra de negócio NUNCA poderia lançar uma exceção. Por que?! Basicamente tudo que receberíamos já deveria ser conhecido, ou seja, não deveria chegar valor inválido na nossa camada de domínio (volto nesse ponto mais pra frente).

As únicas exceções que teríamos realmente, seriam casos realmente excepcionais. Um banco de dados inacessível, uma api crítica fora do ar, um serviço com timeout e assim vai.

Com isso, apenas deveríamos nos preocupar em retornar valores válidos dessas camadas em caso de exceções. Banco secundário inacessível fora no momento de uma query? Sem problemas, devolve um valor conhecido e trata ele, devidamente registrando a exceção que ocorreu antes, obviamente.

Com isso, nossa camada de aplicação e domínio nunca precisaria se preocupar com exceções, porque, por mas que sejam situações excepcionais, elas são esperadas, podem ser de N tipos, mas sempre são (ou deveriam ser) esperadas.

A questão que fez com que acontecesse o estalo que fez com que eu mudasse de ideia foi: O que eu realmente preciso validar do dado inputado na camada de infraestrutura, como controller por exemplo?

A partir disso vi dois caminhos:

  • faço uma validação simples olhando se o dado é do tipo que espero e possui valor
  • faço uma validação complexa, para que meu domínio seja completamente blindado contra valores inesperados

Qual dos dois está certo? Diria que depende, mas como não sou sênior vou me contentar com um simples "talvez ambos" auehauhe.

Mas o que mais me fez pensar que talvez a segunda possibilidade fosse a MENOS adequada de se implementar na camada de infraestrutura foi, e só contextualizando um pouco, criar um objeto de valor na minha camada de domínio, e completamente no automático implementar uma validação lançando uma exceção de domínio, e depois disso instanciar ele direto na camada de infraestrutura apenas para validar se o dado inputado pelo usuário estava válido para ser passado para a camada de aplicação.

Nisso eu me dei de conta que eu estava usando um objeto de domínio que lançava uma exceção na camada de infraestrutura, para que se não lançasse eu passasse o valor inputado e não a instância do objeto de valor para dentro do meu caso de uso para que depois eu reinstanciasse ele novamente, sendo que eu havia acabado de fazer isso.

Foi nesse momento que eu percebi que o caminho que eu estava tomando como melhor até o momento, de evitar que o domínio lançasse exceção, não estava tão adequado. Eu estava implementando uma validação de regra de negócio no controlador (normalmente eu fazia diretamente no input e não instanciando um objeto de valor, isso foi totalmente por acaso) pois além disso enfraquecer o domínio, a regra de negócio estaria espalhada.

O domínio só pode existir em um estado válido, mas isso não significa que um valor inválido não possa tentar chegar até ele, e pra mitigar erros ele precisa saber qual é seu estado inválido, para que informe a quem precisar, que ele tentou ser instanciado com um valor que fere a regra.

A partir dali o estalo fez com que eu passasse a achar o primeiro caminho o ideal, pois só preciso saber que existe um valor que tente se encaixar na regra e que também seja do tipo esperado para compor o domínio e instanciar alguma entidade ou objeto de valor.

Carregando publicação patrocinada...
1

Veja:

goto não tem nada de pré-histórico e tem sua serventia. para quem sabe usar. O uso errado não invalida a ferramenta. E as pessoas usam ele o tempo todo com break e continue, nem vou falar com throw porque é o pior tipo de goto que existe, é um que sais da unidade de execução e vai para um lugar que você nem imagina qual é.

Exceção é um mecanismo errado e as linguagens mais modernas não adotam mais isso.

Então usamos por modinha, ou seja, porque todo mundo usa. E faz algum sentido, porque se a cultura de bibliotecas e frameworks e até códigos abertos de projetos usam exceções, e muitas vezes a linguagem não tem um mecanismo melhor, então é ela que devemos usar.

Ela em si nem é tão problemática se for usada para o que é mais que excepcional, ou seja, erro de programação. Se usar para mais uma coisa e for os casos de falhas que só podem ser percebidas em tempo de execução e tem como se recuperar disso, então é ok.

Mesmo isso em muitas linguagens é ter muitas exceções e poucas capturas. Embora difícil, o ideal seria ter apenas um try-catch. Vai com o mínimo possível.

Tem linguagens que só te dão essa opção para saber se algo falhou, então vai, e diga que não está sentindo falta de algo melhor.

Aproveito para mandar mais esta: https://pt.stackoverflow.com/q/441073/101, já que falou do assunto. Então talvez o erro já esteja aí, aí sai tudo errado. Hoje que mais se fala e se inventa de técnica ou tecnologia nova é para consertar alguma coisa errada que as pessoas começaram fazer e achavam uma boa ideia, em vez de consertar o erro original.

Por que o domínio não pode ter validação? E por que a validação tem que gerar uma exceção? Talvez aqui https://pt.stackoverflow.com/q/16089/101 explique melhor como uma API pode ser interessante de gerar uma exceção ou apenas indicar que não deu o resultado esperado.

Se você ler com atenção os links que passei dá uma ideia mais aprofundada.

S2


Farei algo que muitos pedem para aprender a programar corretamente, gratuitamente (não vendo nada, é retribuição na minha aposentadoria) (links aqui no perfil também).