Exceptions são muito intrusivas

No post anterior, compartilhei um exemplo de como containers podem nos ajudar a deixar o código mais claro sobre os resultados de um método.

public interface IEmployeeRepository
{
  Option<Employee> GeyById(string id);
}
 
class EmployeeRepository : IEmployeeRepository
{
  public Option<Employee> GeyById(string id)
    =>; new DbContext().Find(id);
}

E o que temos sobre Exceptions?! O método GetById irá lançar uma exception se alguma coisa der errado (se não for possível conectar com o banco, por exemplo), mas não há nada sobre isso na assinatura do método.

Either

Uma abordagem superior seria:

public interface IEmployeeRepository
{
    Either<Exception, Option<Employee>> GeyById(string id);
}

class EmployeeRepository : IEmployeeRepository
{
    public Either<Exception, Option<Employee>> GeyById(string id)
    {
        try
        {
            return new DbContext().Find(id);
        }
        catch (Exception e)
        {
            return e;
        }
    }
}

O tipo Either é apenas uma struct comum com conversões implícitas e algumas operações funcionais. Ele permite diferentes tipos de retorno. Neste exemplo, estamos usando o container para tornar explícito que o método pode resultar tanto uma instância de Employee quanto uma exceção.

Try

Eu amo o Either, mas ele não é bom o suficiente! Eu tenho trabalhando bastante para tornar o meu código ainda mais claro.

public interface IEmployeeRepository
{
    Try<Exception, Option<Employee>> GeyById(string id);
}

class EmployeeRepository : IEmployeeRepository
{
    public Try<Exception, Option<Employee>> GeyById(string id)
        => Try.Run(return new DbContext().Find(id));
}

O tipo Try, assim como Either, é uma struct que provê conversões implícitas e algumas operações muito básicas. Ela permite que diferentes tipos de retorno para falha e para sucesso.

A coisa mais interessante sobre esta abordagem é que os programadores que consomem EmployeeRepository são agora forçados a tratar exceções.

public IActionResult Get(string id) => _repository.GetById(id).Match<IActionResult>(
  failure: _ => DatabaseError(),
  success: e => e .Match<IActionResult>(
    some: employee => Ok(employee),
    none: () => NotFound()
  ));

Implementações de Either e Try estão disponíveis no meu github.

Compartilhe este insight:

3 respostas

  1. Achei fantástica sua abordagem. Só não entendi como o programador pode ser forçado a tratar a exceção se ele ainda pode simplesmente chamar _repository.GetById(id) sem o Match()

  2. Elemar, lembro de um poste seu aonde você encadeava chamadas com o Try, porém não estou conseguindo achar no seu blog, parece que ele foi resetado rs, você teria ele ai ?

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Elemar Júnior

Sou fundador e CEO da EximiaCo e atuo como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

Elemar Júnior

Sou fundador e CEO da EximiaCo e atuo como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

Mais insights para o seu negócio

Veja mais alguns estudos e reflexões que podem gerar alguns insights para o seu negócio:

In these days, performance is a feature! So, you should start, right now, to refactor your code to achieve better...
No último post, solicitei uma explicação para o resultado da execução do código que segue: using System; using System.Threading.Tasks; using...
Ao utilizar recursos não gerenciados, em .NET, precisamos garantir que estes sejam devidamente liberados. Para isso, quando criamos classes que...
A EximiaCo não vende! Quando planejei a empresa decidi que ela não teria um departamento comercial. A estratégia é buscar...
Há tempos sou questionado e “assediado” quanto a possibilidade de ministrar cursos. Entre os temas mais frequentes estão “Arquitetura de...
No último post desta série, tratamos da “Lei do Retorno Acelerado”. Sabemos que negócios digitais tem crescimento potencialmente exponencial. Neste...
× Precisa de ajuda?