sábado, 21 de agosto de 2010

Qualidade na Prática - Como Trabalhamos com Exceptions

Neste post vou mostrar como trabalhamos com Exceptions em nossos projetos. Pode parecer um assunto simples, e por este motivo, pode acontecer do desenvolvedor dar pouca ou nenhuma atenção às boas práticas relacionadas. Seguindo algumas regras, que vou expor aqui, podemos evitar muitos contratempos na manutenção.

Então vamos as regras que separei baseado no que li por aí e na minha experiência desenvolvendo sistemas:

  1. Nunca trate (lance ou capture) a super classe Exception. Alguém pode pensar: "Mas porque eu preciso me preocupar com quais exceções devo tratar, se com Exception trato todas?". Eu vejo dois motivos: O primeiro é a clareza. Tratar exceções pela classe Exception é XGH (eXtreme Go Horse), pois não é possível verificar apenas olhando o código, que tipos de exceções são lançadas pois Exception pode ser qualquer problema. O segundo motivo, na minha visão, está relacionado à segunda regra, que diz respeito a diferença conceitual entre algumas exceptions;
  2. Nunca lance uma exceção técnica para a camada de negócio. Trate a exceção técnica na camada onde ela pode ocorrer, como por exemplo uma SQLException em um DAO, e lance uma Custom Exception para o seu domínio, como um AcessoDadosException;
  3. Nunca, mas nunca mesmo, silencie uma exceção. Quem for manter a sua aplicação (podendo até ser você mesmo) agradece. Exceções silenciadas representam um desastre para o debug, e os motivos são óbvios.
Vamos usar como exemplo a aplicação em que estou envolvido no momento. Ela não possui nenhuma regra de negócio sigilosa, o que permite a exemplificação sem troca para dados fictícios. Nesta aplicação, precisamos lidar com dados de duas formas, o que torna este exemplo interessante.

A primeira fonte de dados é o Oracle e a segunda é utilizando a API do ALBPM. Quando estamos tratando diretamente com o Oracle, podemos receber ClassNotFoundException e SQLException. Quando estamos tratando com a API, as possibilidades são IOException, PortalException e RemoteException.

Dois testes que tenho em AdministrativoDeve são:
  • recuperarGruposPorParticipante(); - Oracle
  • adicionarParticipanteNoGrupo(); - via API
Uma das perguntas é: a classe Administrativo deve saber quando tratar RemoteException ou SQLException? Não, pois são exceções técnicas e Administrativo só precisa saber quando algo der errado no acesso aos dados. Isso me levou a criar AcessoDadosException.
No repositório de Grupos, temos os seguintes métodos:
  • public List recuperarGruposAtivosDe(Participante participante) throws AcessoDadosException;
  • public Integer adicionarUsuariosEm(Grupo group, List participantes) throws AcessoDadosException;
Dessa forma,  a classe Administrativo só precisa saber lidar com AcessoDadosException, que indica claramente o que aconteceu e tem um nome muito mais próximo do domínio que SQLException. Além da clareza, no caso desta aplicação, nem sempre vamos lidar com SQLException, o que reforça a justificativa para que a classe Administrativo só conheça problemas de AcessoDadosException.

Espero que o post tenha sido claro e fique a vontade se você trabalha de uma forma diferente e que também é eficiente para a sua equipe.

6 comentários:

  1. Excelente post.
    Interessante a idéia de criar uma Exception para o domínio.
    Falta material que trate de boas práticas de tratamento de Exceções.
    []'s

    ResponderExcluir
  2. Obrigado pelo elogio e pela participação Gabriel!

    ResponderExcluir
  3. Excelente post. Tenho uma pergunta:

    "Nunca lance uma exceção técnica para a camada de negócio. Trate a exceção técnica na camada onde ela pode ocorrer, como por exemplo uma SQLException em um DAO, e lance uma Custom Exception para o seu domínio, como um AcessoDadosException"

    ok entendi, porém não é um trabalho extra ? sabendo que é subententido que SQLException é uma exception de acesso a dados ? Considere que vc não está utilizando a segunda fonte, como a API...

    abraços

    ResponderExcluir
  4. @Renan obrigado pelo elogio.

    Quanto a sua pergunta, o acesso a dados também pela API foi dado como exemplo do porque não lançar a SQLException. Vamos dizer que hoje você não tenha uma segunda forma de acessar os dados. E se amanhã você tiver? Vai ter que mudar todas as outras camadas?

    Realmente é um trabalho extra, mas creio que necessário. O seu domínio não tem que saber se você está acessando dados via SQL, XML, API, sinal de fumaça, sei lá. O domínio precisa apenas saber que houve um problema de acesso a dados.

    Agora pensa no seu cliente. Ele, necessariamente, tem que saber o que é uma SQLException? Não fica mais claro para ele AcessoDadosException?

    Abraços

    ResponderExcluir
  5. Excelente explicação, muito obrigado. Sucesso

    ResponderExcluir
  6. @Renan
    Eu que agradeço a sua participação.
    Obrigado

    ResponderExcluir