Qualidade de código: Validações usando padrão Result ou Exceções no C#?
Atuando em diversos projetos .NET muitas vezes vi projetos onde ao encontrar erros, eram utilizadas implementações que lançavam exceções em validações, outras vezes as validações devolviam um result indicando o problema encontrado sem lançar exceções.
Como boa prática, tenho visto muitos posts defendendo o uso de padrão Result em detrimento de exceções, mas aqui vou colocar os dois casos e seus prós e contras !
Abordagem 1: Retornar um Tipo Result
public Result<Entity> ValidateEntity(int id)
{
if (id <= 0)
return Result.Fail("ID deve ser maior que zero");
var entity = _repository.GetById(id);
if (entity == null)
return Result.Fail("Código não encontrado");
return Result.Ok(entity);
}Prós Ampliados:
- Alinhamento com RFC 7807:
- Pode encapsular naturalmente todos os campos do Problem Details:
public class Result<T> {
public string Type { get; } // URI identificando o tipo de erro (ex: "https://example.com/errors/invalid-id")
public string Title { get; } // Título genérico do erro
public int Status { get; } // Código HTTP
public string Detail { get; } // Descrição específica
public string Instance { get; }// URI do request específico
}- Permite mapeamento direto para respostas HTTP padronizadas
2. Semântica Rica:
- Pode diferenciar tipos de falhas (validação, não encontrado, conflito)
- Suporta múltiplos erros simultâneos (útil para validações de formulários)
3. Contrato Explícito:
- Força o cliente a lidar com possíveis falhas (ao contrário de exceções não documentadas)
4. Performance:
- Evita custo de construção de stack traces (até 1000x mais rápido que exceções em cenários de alta frequência)
5. Consistência:
- Uniformiza o tratamento de erros esperados vs inesperados
Contras Revisados:
- Propagação Manual:
- Requer verificação explícita em cada camada (if (!result.IsSuccess))
2. Duplicação com HTTP:
- Pode criar redundância se já usando RFC 7807 na camada API
3. Curva de Aprendizado:
- Padrão menos intuitivo para desenvolvedores acostumados com exceções
4. Interoperabilidade:
- Requer adaptação para integrar com bibliotecas que esperam exceções
Abordagem 2: Lançar Exceções
public Entity ValidateEntity(int id)
{
if (id <= 0)
throw new ArgumentException("ID deve ser maior que zero");
var entity = _repository.GetById(id);
if (entity == null)
throw new ArgumentException("Código não encontrado");
return entity;
}Prós Ampliados:
- Integração Nativa:
- Suportada automaticamente por frameworks (ASP.NET Core já converte para Problem Details)
2. Fluxo Automático:
- Propagação automática através das camadas sem código boilerplate
3. Padrão Dominante:
- Melhor documentação e suporte em ferramentas (debuggers, logging)
Contras Revisados:
- Máquina de Problemas para APIs:
- Sem tratamento adequado, gera respostas não padronizadas (violando RFC 7807)
2. Custo de Desempenho:
- Criar exceções com stack traces pode consumir até 1MB de memória cada
3. Abuso Semântico:
- Uso indiscriminado para fluxos normais de negócio (ex: “usuário não encontrado”)
4. Dificuldade de Rastreamento:
- Erros de validação se perdem em meio a exceções técnicas
Recomendação Final (Contextualizada)
- Use
Resultquando estiver:
- Construindo APIs que precisam seguir estritamente RFC 7807
- Validando entidades de domínio (DDD)
- Em cenários de alta performance (microserviços, processamento em lote)
2. Prefira Exceções quando:
- Desenvolvendo APIs REST com ASP.NET Core (que já trata bem Problem Details)
- Para falhas verdadeiramente excepcionais (banco offline, etc)
- Integrando com bibliotecas que esperam exceções
3. Híbrido (Melhor dos Mundos):
Podemos lançar mão de uma outra abordagem, lançando exceções apenas quando temos de fato um problema e tratando situações comuns como validações com o retorno adequado, como no exemplo abaixo:
// Na camada de aplicação:
try {
var result = _service.ValidarEntidade(id);
if (!result.IsSuccess) {
return ProblemDetailsFromResult(result); // Mapeia para RFC 7807
}
return Ok(result.Value);
}
catch (Exception ex) {
return ProblemDetailsFromException(ex); // Converte exceção inesperada
}Conclusão
Utilizar o padrão Result dará maior qualidade nas comunicação entre as diversas camadas da aplicação e permitirá trazer respostas mais conclusivas para identificar e corrigir problemas de execução dos sitemas.
O uso de exceções consome mais memória e prejudica a performance das aplicações !
Gostou do artigo? clique no ícone👏e me siga para ver as próximas publicações !! Quer ver mais conteúdos, acesse minhas redes através do Linktree: https://linktree.com/nizzola
