Sitemap

Qualidade de código: Validações usando padrão Result ou Exceções no C#?

3 min readAug 21, 2025
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:

  1. 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:

  1. 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:

  1. 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:

  1. 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)

  1. Use Result quando 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

--

--

Marcio Nizzola
Marcio Nizzola

Written by Marcio Nizzola

Microsoft MVP | Master Software Architect na CI&T | Prof. da Etec Itu | Membro Fundador da Comunidade Itu Developers.

Responses (1)