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:

Nem todos os problemas podem ser resolvidos da mesma forma. Nem toda ferramenta é apropriada para todo tipo de trabalho....
Na Guiando, os times já possuem certa maturidade com Scrum. Agora, com a adoção progressiva de princípios de Kanban estamos...
Neste post, compartilho um exemplo de implementação para um algoritmo extremamente famoso e importante: O algoritmo de Dijkstra. Trata-se de...
Superficialmente, direito e privilégio são conceitos que se aproximam e, eventualmente, se confundem. Mas, com um pouco de cuidado, ficam...
Conheci o poema maravilhoso da Viviane Mosé, transcrito abaixo, na interpretação de uma grande amiga. Quem tem olhos pra ver...
[tweet]Transformação Digital é sobre como o negócio será impactado (transformado) pela adoção de recursos digitais.[/tweet] Portanto, começando uma nova série...