Seu código tem forma de seta e ninguém quer admitir
Você já abriu um método, olhou pro lado direito da tela e viu aquilo? A indentação vai crescendo, crescendo, o código forma uma seta apontando pro canto, e lá no fundo, uns cinco níveis pra dentro, mora a linha que realmente importa.
A gente até tem nome carinhoso pra isso: arrow code (código seta). Ou, pros mais dramáticos, "a pirâmide da perdição".
O pior é que quase sempre esse método começou pequeno. Um if inocente. Aí veio uma validação, mais um caso, uma exceção pra tratar... e quando você percebe, precisa rolar o olho por seis linhas de fechamento de chave } só pra descobrir a qual if cada uma pertence.
O problema na prática
Olha esse método de processar um pedido. Parece inofensivo, mas repara na indentação:
public function processar(Order $order)
{
if ($order->isPago()) {
if ($order->itens->isNotEmpty()) {
if ($order->cliente->estaAtivo()) {
if (! $order->foiEnviado()) {
// finalmente, o código de verdade
$this->enviar($order);
return true;
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
}
return false;
}
Pra chegar na única linha que interessa ($this->enviar($order)), seu olho precisou atravessar quatro if e ainda torcer pra não confundir qual else fecha qual bloco. E se amanhã aparecer mais uma regra? Mais um nível pra dentro. A seta cresce.
Esse código não é difícil porque o problema é difícil. Ele é difícil porque tá escrito de trás pra frente.
O conceito: verifica o que dá errado primeiro
Early return (ou "cláusula de guarda", guard clause) é a ideia de tratar os casos de saída logo no começo do método e sair fora na hora. Em vez de aninhar o "caminho feliz" lá no fundo de um monte de if, você inverte a lógica:
"Não tá pago? Cai fora. Sem itens? Cai fora. Cliente inativo? Cai fora. Passou por tudo? Então executa."
O caminho feliz fica no nível principal do método, sem indentação nenhuma. As exceções ficam no topo, cada uma resolvida e esquecida. Você lê de cima pra baixo, uma condição de cada vez, sem precisar segurar nada na cabeça.
A solução: mesmo método, agora legível
public function processar(Order $order): bool
{
if (! $order->isPago()) {
return false;
}
if ($order->itens->isEmpty()) {
return false;
}
if (! $order->cliente->estaAtivo()) {
return false;
}
if ($order->foiEnviado()) {
return false;
}
// o caminho feliz, no nível principal, sem seta nenhuma
$this->enviar($order);
return true;
}
Zero else. Zero aninhamento. Cada if é uma pergunta simples: "tem algum motivo pra parar aqui?". Se tiver, para. Se chegou no fim, é porque passou por todos os filtros e agora pode fazer o trabalho de verdade com a consciência tranquila.
E o de bônus: adicionar uma regra nova amanhã é colar mais um bloco de guarda no meio. Não mexe na estrutura, não empurra nada pra dentro.
Como usar na prática
Lançando exceção em vez de retornar — funciona igualzinho, e é ótimo em Services e Actions:
public function reembolsar(Order $order): void
{
if (! $order->isPago()) {
throw new OrderException('Não dá pra reembolsar um pedido não pago.');
}
if ($order->foiReembolsado()) {
throw new OrderException('Esse pedido já foi reembolsado.');
}
$this->gateway->refund($order);
}
Saindo cedo dentro de um loop com continue — mesma filosofia, evita o if gigante envolvendo o corpo inteiro:
foreach ($usuarios as $usuario) {
if ($usuario->optOut) {
continue; // pula esse e segue
}
$this->notificar($usuario);
}
No Blade também, com @continue e @break, pra não aninhar a view inteira num @if.
A pegadinha: não é "return em todo canto"
Aqui vem o aviso, porque tem sempre alguém que lê isso e sai espalhando return no meio de qualquer função só pra parecer moderno.
Early return brilha quando as saídas são cláusulas de guarda de verdade: validações, pré-condições, casos de borda que impedem o fluxo principal. Aí ele reduz complexidade.
O que ele não é: desculpa pra ter dez return espalhados no meio da lógica principal, cada um saindo de um lugar diferente, sem ninguém entender por onde o método realmente termina. Isso não é early return, é fuga.
A régua é simples: os return de guarda ficam agrupados no topo, tratando o que dá errado. O return do caminho feliz fica sozinho no fim. Se seus returns estão espalhados feito confete no meio do código, você trocou um problema por outro.
Bônus: e agora?
Abre o arquivo com o método mais bagunçado do seu projeto — você já sabe qual é. Conta quantos níveis de indentação ele tem. Passou de dois ou três? Provavelmente dá pra inverter os if do topo em cláusulas de guarda e achatar aquilo em cinco minutos.
Uma dica: comece pelos else. Todo else que existe só pra retornar algo é um forte candidato a virar um early return e sumir.
Antes de você fechar a aba
Legibilidade não é frescura de quem gosta de código bonito. É você economizando o tempo do seu eu do futuro (ou do coitado que vai dar manutenção depois) na hora de entender o que aquele método faz.
E você, é time "trata o erro primeiro e cai fora" ou ainda tem carinho pela pirâmide de if? Conta nos comentários — e se conhece alguém que ama um else aninhado, marca lá. 😅
Top comments (0)