DEV Community

Cover image for Porque Evitar o Prefixo maybe_ em Funções Elixir
Luan Andryl
Luan Andryl

Posted on

1 1 1 1

Porque Evitar o Prefixo maybe_ em Funções Elixir

Em linguagens funcionais, conceitos como monads desempenham um papel crucial no gerenciamento de efeitos colaterais e no encadeamento seguro de operações. Um exemplo famoso é o tipo Maybe em Haskell, que abstrai cálculos opcionais e evita o tratamento explícito de valores ausentes. Entretanto, Elixir, uma linguagem funcional moderna construída sobre a BEAM (a máquina virtual do Erlang), segue um caminho diferente no design de linguagem.

Essa escolha tem implicações diretas na forma como lidamos com cenários similares e explica por que o uso do prefixo maybe_ em funções não é uma prática recomendada. Vamos explorar as razões técnicas e de design por trás dessa decisão e como Elixir oferece alternativas alinhadas aos seus objetivos.

O Papel das Monads e o Tipo Maybe

Monads, em linguagens como Haskell, são estruturas abstratas que permitem encadear operações enquanto lidam de maneira transparente com efeitos colaterais ou valores ausentes. O tipo Maybe, por exemplo, representa valores opcionais e encapsula dois casos: Just (um valor presente) ou Nothing (ausência de valor).

Isso é poderoso porque evita que desenvolvedores escrevam condicionais explícitos para cada caso onde um valor pode ou não existir. Veja este exemplo em Haskell:

safeDivide :: Int -> Int -> Maybe Int
safeDivide _ 0 = Nothing
safeDivide x y = Just (x `div` y)

result = Just 10 >>= (`safeDivide` 2) >>= (`safeDivide` 5)
-- Resultado: Just 1

Enter fullscreen mode Exit fullscreen mode

Aqui, o operador >>= permite encadear chamadas que respeitam as regras do tipo Maybe. Se qualquer etapa retornar Nothing, as subsequentes serão ignoradas automaticamente.

Por que Elixir Não Adota Monads?

Elixir, apesar de ser funcional, não implementa monads diretamente, e isso é uma escolha consciente. O design da linguagem privilegia simplicidade e desempenho na BEAM. Há algumas razões principais para essa decisão:

  1. Semântica Simples e Explícita: Monads, embora elegantes, podem introduzir complexidade conceitual para quem não está familiarizado com o paradigma funcional. Em Elixir, o objetivo é manter a linguagem acessível para um público amplo, inclusive desenvolvedores com histórico em linguagens imperativas.

  2. A BEAM Já Resolve Muitos Problemas: A BEAM oferece mecanismos robustos para lidar com falhas e concorrência, como links, supervisores e processos isolados. Isso reduz a necessidade de abstrações como monads para controle de fluxo ou propagação de erros.

  3. Alternativas Idiomáticas em Elixir: Construções como pattern matching, with e o uso de tuplas ({:ok, value} ou {:error, reason}) fornecem maneiras idiomáticas e explícitas de lidar com fluxos de dados opcionais ou falhas. Essas ferramentas já atendem às necessidades comuns sem introduzir uma camada extra de abstração.

O Problema do Prefixo maybe_

Quando usamos o prefixo maybe_ para nomear funções em Elixir, estamos implicitamente trazendo associações do tipo Maybe de linguagens como Haskell. Isso cria uma expectativa equivocada de que essas funções se comportem como uma monad, ou seja, que possam ser encadeadas automaticamente e que lidem com valores opcionais de maneira implícita. Contudo, em Elixir, qualquer controle de fluxo requer estruturas explícitas.

def maybe_divide(_, 0), do: nil
def maybe_divide(x, y), do: x / y
Enter fullscreen mode Exit fullscreen mode

Um nome como maybe_divide sugere que estamos lidando com uma abstração como o Maybe de Haskell, mas o resultado da função é apenas um nil em caso de falha. Para encadear essa função, é necessário criar lógica explícita:

result =
  case maybe_divide(10, 2) do
    nil -> nil
    value -> maybe_divide(value, 5)
  end
Enter fullscreen mode Exit fullscreen mode

Isso não reflete a elegância associada às monads e vai contra o espírito do design explícito e simples do Elixir.

A Solução Idiomática em Elixir: with

Elixir resolve o problema de controle de fluxo e propagação de falhas com a macro with. Essa construção permite encadear operações que podem falhar, mas mantém a clareza e a simplicidade.

Reescrevendo o exemplo anterior com with:

  def safe_divide(_, 0), do: {:error, :division_by_zero}
  def safe_divide(x, y), do: {:ok, x / y}

  with {:ok, value1} <- safe_divide(10, 2),
       {:ok, value2} <- safe_divide(value1, 5) do
         {:ok, value2}
  end
Enter fullscreen mode Exit fullscreen mode

O with elimina a necessidade de lógica explícita de case, simplifica o código e fornece um controle de fluxo elegante, sem depender de conceitos complexos como monads.

Conclusão: O Papel do Design do Elixir na Nomenclatura e no Tratamento de Fluxos

O prefixo maybe_ em funções Elixir não é bem-visto porque carrega associações enganosas com o conceito de monads, que não fazem parte do design da linguagem. Isso pode levar a confusão e expectativas errôneas, ao sugerir que há uma abstração implícita para lidar com valores opcionais, quando na verdade o Elixir se baseia em construções explícitas e diretas como tuplas ({:ok, valor} ou {:error, motivo}), pattern matching e a macro with. Essas ferramentas são mais do que suficientes para resolver problemas semelhantes, de forma clara e idiomática.

Além disso, nomes como try_algo ou maybe_algo também contradizem a filosofia subjacente ao Elixir e à BEAM, que adota o princípio "let it crash" ("deixe falhar"). Em Elixir, não tentamos fazer algo; simplesmente fazemos, e qualquer falha é tratada de forma explícita ou delegada ao sistema robusto de supervisão da BEAM. Essa abordagem elimina o excesso de condicionais defensivos, promovendo código limpo e alinhado ao design da linguagem.

Considere um exemplo simples:

# Não idiomático
def try_divide(_, 0), do: {:error, :division_by_zero}
def try_divide(x, y), do: {:ok, x / y}
Enter fullscreen mode Exit fullscreen mode

Neste caso, o nome try_divide não reflete a realidade do código nem a forma como a BEAM trata operações. Um nome mais claro e idiomático seria simplesmente:

def safe_divide(_, 0), do: {:error, :division_by_zero}
def safe_divide(x, y), do: {:ok, x / y}
Enter fullscreen mode Exit fullscreen mode

Com essa abordagem, o nome comunica exatamente o que a função faz: realiza uma divisão segura e retorna um erro se necessário. Isso está em harmonia com a simplicidade e a clareza esperadas no design de Elixir.

Por fim, ao evitar nomenclaturas como try_ e maybe_, garantimos que nosso código reflita os princípios fundamentais de Elixir: simplicidade, eficiência, resiliência e um alinhamento direto com os valores centrais da BEAM. A linguagem foi projetada para ser clara e explícita, e nossas escolhas de nomenclatura e design devem reforçar essa filosofia, promovendo código mais idiomático, legível e poderoso.

Image of Datadog

Create and maintain end-to-end frontend tests

Learn best practices on creating frontend tests, testing on-premise apps, integrating tests into your CI/CD pipeline, and using Datadog’s testing tunnel.

Download The Guide

Top comments (1)

Collapse
 
gissandrogama profile image
GISSANDRO M DANTAS GAMA

Concordo plenamente com os pontos apresentados no artigo. Em Elixir, o uso do prefixo maybe_ nas funções pode induzir a uma associação equivocada com o conceito de monads, especialmente o tipo Maybe de linguagens como Haskell. No entanto, Elixir não implementa monads diretamente, optando por uma abordagem mais explícita e direta no controle de fluxo. Ferramentas como pattern matching, tuplas {:ok, valor} ou {:error, motivo} e a macro with fornecem mecanismos claros e idiomáticos para lidar com operações que podem falhar ou retornar valores opcionais. Além disso, a filosofia "let it crash" da BEAM incentiva a escrita de código que lida com falhas de forma explícita, delegando a recuperação para sistemas de supervisão robustos. Portanto, evitar prefixos como maybe_ ou try_ nas funções ajuda a manter o código alinhado com os princípios de simplicidade e clareza do Elixir.

Image of Datadog

The Essential Toolkit for Front-end Developers

Take a user-centric approach to front-end monitoring that evolves alongside increasingly complex frameworks and single-page applications.

Get The Kit

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay