Exceptions are too intrusive

In the previous post, I shared an example of how containers could help us to make the code clearer about what to expect as execution results.

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

But, what about exceptions?! The GetById method would throw an exception if something goes wrong (for example, if it is not possible to connect to the database), but there is nothing in the method signature about it.

The Either container

A much better approach would be:

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;
        }
    }
}

The Either Type is just a regular C# struct that provides implicit conversions and very basic functional operations. It allows us to return different type results. In this example, we are using this container to make explicit that this method could result in either an employee instance or an exception.

The Try container

I love the Either container, but I don’t think it is good enough! I have been working hard to make my code even clearer.

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));
}

The Try Type, as the Either type, is just a regular C# struct that provides implicit conversions and very basic functional operations. It allows us to return different type results for failure and success, explicitly.

The most interesting thing about this approach is that the EmployeeRepository users would be forced to handle exceptions.

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

Nice, right? Either and Try implementations are available on my github.

Compartilhe este insight:

Uma resposta

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:

Reduction operations are those that reduce a collection of values to a single value. In this post, I will share...
Você ainda acredita em estimativas? Nós, não. Embora aceitemos que ter uma boa ideia de esforço e prazo sejam diferenciais...
O ano era 2001 ou 2002. Não lembro ao certo. Eu era um jovem programador, pai recente, tentando “encontrar meu...
Não são raros os casos onde a distância entre um “desejo” e a “realização” é a “tentativa”. Ou seja, partindo...
Muitas vezes, em nossos sistemas, temos tarefas que demandam processamento de  longa duração ou possuem alta complexidade computacional. Na medida...
Que nível de otimizações podemos esperar do compilador do C# e do JIT? Neste post, compartilho um pequeno, mas esclarecedor...