Design Pattern Operation Result em C#
Tags: csharp, designpatterns, result
Published: 2024-06-18 18:34:09

O Operation Result Design Pattern é um ferramenta incrível para você ter nas bases do seu projeto. Isso ajuda a lidar de forma muito mais assertiva com os resultados de operações do seu sistema.

## O que é o Operation Result Design Pattern
Para começar, o Operation Result Design Pattern é utilizado para encapsular o resultado de operações de forma que permite uma estrutura consistente de retornar tanto o sucesso quanto a falha de alguma operação.
Ele também é uma alternativa ao disparos de exceções, ao invés de lidar com as exceções, você trabalha com um resultado.

## Alguns obejtivos ao utilizar o Operation Result
Ter um indicador de sucesso ou falha da operação;
Ter acesso ao motivo da falha se a operação tiver falhado ou o valor resultante da operação caso tenha sido sucedida.

## Criação da classe Resultado
A classe Resultado em si encpasula o resultado de alguma operação. Ela pode incluir um valor de retorno quando a operação for bem sucedida ou os detalhes de erros em operações que falharam.
Em C# podemos escrever a classe Resultado da seguinte maneira, assim conseguimos usar o Resultado para tipos diferentes de valores

```
public class Resultado<Tipo>
{
    public Resultado()
    {
        Erros = [];
    }

    public Resultado(params string[] erros)
    {
        Erros = erros.ToImmutableList();
    }

    public Tipo? Valor { get; init; }
    public bool TemErros() => Erros.Count > 0;
    public bool Sucesso => !TemErros();
    public IReadOnlyCollection<string> Erros { get; init; }
}
```

Com essa pequena implementação você já tem disponível a lista de erros, caso a operação tenha falhado, armazenadas em um objeto ImmutableList<string>, caso a operação tenha falhado, e consegue retornar como um IReadOnlyCollection<string>. Além disso consegue saber se a operação foi sucedida ou não e no caso do sucesso, trabalhar em cima do valor resultante.
Lendo um pouco mais a classe, conseguimos entender que a criação do objeto com o construtor vazio representa uma operação de sucesso e quando tem itens no construtor significa que a operação falhou.

## Adicionando a gravidade da mensagem!
Ao invés de retornar somente mensagens de erros quando houverem erros, você pode retornar mensagens e em cada mensagem disponibilizar um nível de gravidade, ou seja, a mensagem pode ser somente uma informação, quer seria o caso de sucesso, ou pior, ela pode ser um erro, que seria uma mensagem com maior gravidade.
Assim, podemos escrever uma nova classe para representar essas mensagens e um enum para representar os níveis

```
public class ResultadoMensagem
{
    public ResultadoMensagem(string menssagem, MensagemGravidade gravidade)
    {
        Mensagem = menssagem?? throw new ArgumentNullException(nameof(menssagem));
        Gravidade = gravidade;
    }

    public string Mensagem { get; }
    public MensagemGravidade Gravidade{ get; }
}

public enum MensagemGravidade
{
    Informacao = 0,
    Aviso = 1,
    Erro = 2,
}
```

Por fim vamos adaptar a classe de resultado ao novo padrão utilizando as mensagens com gravidade!

```
public class Resultado<Tipo>
{
    public Resultado()
    {
        Mensagens = [];
    }

    public Resultado(params ResultadoMensagem[] mensagens)
    {
        Mensagens = [.. mensagens];
    }

    public Tipo? Valor { get; init; }
    public bool TemErros() => Mensagens.Count > 0;
    public bool Sucesso => !TemErros();
    public IReadOnlyCollection<ResultadoMensagem> Mensagens { get; init; }
    public IEnumerable<ResultadoMensagem> ProcurarErros() 
        => Mensagens.Where(mensagem => mensagem.Gravidade == MensagemGravidade.Erro);
}
```

Espero que eu tenha ajudado de alguma forma, pode deixar um comentário caso tenha alguma dúvida sobre esse design pattern!