Pular para o conteúdo
Categoria: Fundamentos & Boas Práticas16 min de leitura

"YAGNI explicado: você não vai precisar disso"

Por Schematize Blog ·

Entenda o princípio You Aren't Gonna Need It, como ele combate o over-engineering, equilibra-se com DRY e SOLID e por que construir só o necessário hoje deixa o software mais ágil.

YAGNI é um daqueles princípios que parecem óbvios até você se pegar construindo uma camada de abstração para um requisito que ninguém pediu. A sigla resume uma disciplina difícil: resistir à tentação de antecipar o futuro no código de hoje. Neste artigo você vai entender de onde vem o YAGNI, por que ele economiza tempo e dinheiro, como ele se relaciona com outros princípios de design e como aplicá-lo sem usá-lo como desculpa para escrever código descuidado. No fim, há uma seção de perguntas frequentes para fechar as dúvidas mais comuns.

A tentação de "preparar o terreno" é especialmente forte para quem está construindo software com a ajuda de IA: pedir a um assistente que gere um sistema "flexível e extensível" quase sempre produz mais estrutura do que o problema exige. Entender YAGNI é, hoje, parte essencial de saber revisar o que a IA entrega.

O que é YAGNI

YAGNI é a sigla de You Aren't Gonna Need It — "você não vai precisar disso". O princípio surgiu na cultura do Extreme Programming, atribuído a Ron Jeffries e aos primeiros praticantes do XP, e diz, de forma direta: não implemente algo até que seja de fato necessário. Nada de adicionar funcionalidade, parâmetro de configuração ou ponto de extensão "porque um dia pode ser útil".

A lógica é simples. Quando você constrói algo para uma necessidade futura imaginada, três coisas podem acontecer, e duas são ruins:

    Como apostar certo é exceção, o saldo médio do "preparar para o futuro" é negativo. Repare que mesmo no melhor cenário (caso 3) o ganho é modesto: você economizou o tempo de adicionar a feature depois, mas pagou o custo de carregá-la durante todo o intervalo. Nos outros dois cenários, o prejuízo é claro e às vezes severo, porque desfazer uma abstração errada custa mais do que nunca tê-la criado.

    YAGNI é, no fundo, uma aposta estatística: na dúvida, escolha não construir, porque o valor esperado de adiar é maior que o de antecipar.

    A diferença entre código necessário e código especulativo

    A distinção central do YAGNI é entre o que o sistema precisa agora e o que ele talvez precise. Código especulativo carrega custos que muitas vezes ignoramos:

      Martin Fowler decompõe esse desperdício em quatro categorias: o custo de construir a feature que não era necessária; o custo de atraso das features que de fato importavam; o custo de carregar a complexidade extra enquanto a feature espera; e o custo de reparar, caso você precise desfazer a abstração errada (Fowler, 2015). Cada generalização não usada é peso morto que torna o sistema mais lento para evoluir.

      Há ainda um custo invisível: o custo cognitivo. Toda pessoa que ler o código no futuro precisará entender por que aquela hierarquia de classes existe, por que há três parâmetros que sempre recebem o mesmo valor, por que existe um ponto de extensão sem nenhuma extensão. Esse esforço de compreensão se repete a cada nova pessoa que toca o arquivo — multiplicando o desperdício original.

      YAGNI e o combate ao over-engineering

      Over-engineering é a doença que o YAGNI trata. Acontece quando resolvemos problemas que ainda não existem: o sistema de plugins para um app que tem um cliente, a camada de cache para uma tabela com cem linhas, o parâmetro genérico que só é chamado de um jeito.

      Frederick Brooks, em seu ensaio clássico No Silver Bullet, distingue a complexidade essencial — inerente ao problema que estamos resolvendo — da complexidade acidental, que nós mesmos introduzimos (Brooks, 1987). Over-engineering é a forma mais pura de complexidade acidental: estrutura criada não pelo problema, mas pela nossa ansiedade em relação ao futuro.

      YAGNI mantém o foco na complexidade essencial. Você resolve o problema que tem na mão, com a estrutura mínima que ele exige. Isso conversa diretamente com o KISS: o princípio Keep It Simple, Stupid no desenvolvimento de software: manter simples é, em grande parte, não adicionar o que não é necessário.

      Vale notar a sutil diferença de foco entre os dois princípios. KISS fala sobre como você escreve o que escreve — prefira a solução mais direta. YAGNI fala sobre se você deveria escrever aquilo — não escreva o que ninguém precisa ainda. Um trata da simplicidade da solução; o outro, da existência da solução. Juntos, formam a espinha dorsal do design enxuto.

      Um exemplo concreto

      Imagine que você precisa enviar um e-mail de boas-vindas quando um usuário se cadastra. O requisito é exatamente esse — um e-mail.

      A versão "preparada para o futuro" pode parecer assim:

      interface CanalNotificacao {
        enviar(destinatario: string, mensagem: string): Promise<void>;
      }
      
      class EmailChannel implements CanalNotificacao { /* ... */ }
      class SmsChannel implements CanalNotificacao { /* ... */ }
      class PushChannel implements CanalNotificacao { /* ... */ }
      class WhatsappChannel implements CanalNotificacao { /* ... */ }
      
      class GerenciadorNotificacoes {
        constructor(private canais: CanalNotificacao[]) {}
        async notificar(usuario: Usuario, tipo: string) {
          // roteamento por preferência, fallback, retry...
        }
      }

      Quatro canais, um gerenciador, roteamento, fallback — para enviar um e-mail. SMS, push e WhatsApp foram construídos para um futuro que talvez nunca chegue, e cada um precisa ser mantido e testado desde já.

      A versão YAGNI faz só o pedido:

      async function enviarBoasVindas(email: string, nome: string) {
        await servicoEmail.enviar({
          para: email,
          assunto: "Bem-vindo!",
          corpo: `Olá, ${nome}! Que bom ter você aqui.`,
        });
      }

      Direta, fácil de ler, fácil de mudar. Se um dia o requisito de SMS realmente aparecer, você introduz a abstração naquele momento — com informação real sobre como os canais precisam se comportar, em vez de um palpite. Esse momento de reorganizar a estrutura sob demanda é, justamente, O que é refatoração e quando aplicar.

      Repare na assimetria: a versão YAGNI não fecha portas. Quando o SMS chegar, refatorar de uma função simples para uma interface custa pouco — você extrai a abstração de duas implementações concretas que já entende. O contrário não é verdade: desmontar o gerenciador de quatro canais quando descobrir que a empresa só vai usar e-mail por mais dois anos é trabalho puro de demolição.

      O caso do parâmetro "só por garantia"

      Um exemplo ainda mais sorrateiro de over-engineering é o parâmetro especulativo. Veja esta função:

      def gerar_relatorio(usuario, formato="pdf", incluir_graficos=True,
                          idioma="pt-BR", compactar=False, marca_dagua=None):
          # ... mas o sistema só chama gerar_relatorio(usuario)
          ...

      Cinco parâmetros opcionais, e na prática todas as chamadas usam os valores padrão. Cada parâmetro é uma promessa de comportamento que precisa ser testada, documentada e mantida — para flexibilidade que ninguém usa. A versão YAGNI assume apenas o que o presente exige:

      def gerar_relatorio(usuario):
          # gera o PDF em pt-BR com gráficos, que é o único caso real
          ...

      Quando surgir o pedido real de um relatório em inglês ou sem gráficos, você adiciona o parâmetro com a certeza de que ele será usado — e com um exemplo concreto para guiar o design.

      YAGNI não é desculpa para código ruim

      Aqui está o mal-entendido mais perigoso. YAGNI diz para não adicionar funcionalidade especulativa — não para escrever código desleixado, pular testes ou ignorar bons nomes. Construir só o necessário e construir bem são coisas independentes.

      Algumas distinções úteis:

        A síntese é esta: YAGNI restringe o que você constrói, não a qualidade com que constrói. Um sistema YAGNI ideal faz pouquíssimas coisas, mas faz cada uma delas com clareza, testes e nomes honestos.

        O equilíbrio difícil: YAGNI versus abstração prematura

        O trade-off mais delicado do dia a dia é decidir o momento certo de abstrair. Abstrair cedo demais é over-engineering. Abstrair tarde demais é conviver com duplicação que esconde um conceito importante. Onde fica a fronteira?

        A heurística mais conhecida vem de Sandi Metz: "duplicação é muito mais barata do que a abstração errada" (Metz, 2016). A consequência prática é contraintuitiva — quando estiver em dúvida, prefira duplicar e espere. A duplicação fica visível, incomoda e ensina: com duas ou três cópias na sua frente, você enxerga qual parte realmente varia e qual é estável. Aí, e só aí, a abstração certa se revela quase sozinha.

        A "regra de três" de Martin Fowler captura o mesmo instinto: você tolera a primeira ocorrência, suporta a segunda com um leve incômodo e, na terceira, refatora para remover a duplicação (Fowler, 1999). Antes da terceira, você simplesmente não tem informação suficiente sobre o padrão para abstraí-lo bem.

        Por que a abstração errada é tão cara? Porque ela acopla coisas que pareciam iguais mas não eram. Quando o terceiro caso chega e não encaixa, o desenvolvedor seguinte tende a adicionar um parâmetro condicional em vez de desfazer a abstração — e a cada novo caso, mais um if. O resultado é uma função genérica cheia de bandeiras que serve a todos mal. Era melhor ter três funções simples e separadas.

        // Abstração prematura que apodrece:
        function processar(item, tipo, comDesconto, ehVip, modoLegado) {
          if (tipo === "A") { /* ... */ }
          else if (tipo === "B" && ehVip) { /* ... */ }
          else if (modoLegado) { /* ... */ }
          // cada novo caso adiciona mais uma flag
        }
        
        // Versus duplicação honesta que se mantém clara:
        function processarPedidoPadrao(item) { /* ... */ }
        function processarPedidoVip(item) { /* ... */ }

        A duplicação à direita parece "pior" porque repete linhas. Mas é honesta: cada função diz exatamente o que faz, e mudar uma não arrisca quebrar a outra. Esse é o YAGNI no nível da abstração — não generalize antes de a generalização estar madura.

        Como praticar YAGNI

        Algumas perguntas ajudam a manter a disciplina no dia a dia:

          A última pergunta revela a relação saudável entre YAGNI e bom design: você adia features não por preguiça, mas porque construiu um código tão limpo e desacoplado que adicionar a feature mais tarde será fácil. YAGNI funciona melhor em cima de um código bem cuidado.

          Um passo a passo para revisar uma proposta de implementação

          Quando você (ou um assistente de IA) propõe uma estrutura, vale rodar este filtro antes de aceitar:

            Esse ritual transforma YAGNI de uma intuição vaga em uma checagem repetível — especialmente útil ao revisar código gerado por IA, que tende a entregar generosamente mais estrutura do que o pedido.

            Erros comuns ao aplicar YAGNI

            Mesmo quem conhece o princípio escorrega. Os deslizes mais frequentes:

              Quando YAGNI não se aplica

              Como todo princípio, YAGNI tem limites. Há decisões caras de reverter mais tarde — e essas merecem reflexão antecipada:

                A regra de bolso: aplique YAGNI agressivamente a tudo que for barato de adicionar depois, e pense com cuidado naquilo que será caro de mudar. A maior parte do código cai na primeira categoria.

                Uma forma útil de pensar nisso é separar decisões reversíveis de irreversíveis. Para o reversível, YAGNI é quase sempre a resposta: faça o mínimo, e mude quando precisar, porque mudar é barato. Para o irreversível, vale investir mais análise antecipada, porque o custo de errar é alto. O erro comum é tratar tudo como irreversível — e assim justificar over-engineering em todo canto. Na prática, a maioria das decisões de código é reversível, e é por isso que YAGNI ganha tantas vezes.

                YAGNI no desenvolvimento com IA

                Quem constrói apps com assistentes de IA encontra um amplificador de over-engineering. Peça "um sistema de notificações" e o modelo entregará interfaces, fábricas e canais que você não pediu — porque foi treinado em código que tende a ser genérico e "completo". O resultado é tecnicamente impressionante e funcionalmente excessivo.

                A defesa é fazer do YAGNI uma instrução explícita e um critério de revisão:

                  YAGNI deixa de ser só um princípio de quem escreve código e passa a ser um princípio de quem revisa código — incluindo o que a máquina produz. Saber identificar e cortar o excesso é uma das habilidades mais valiosas do desenvolvedor moderno.

                  Perguntas frequentes

                  YAGNI significa que não devo planejar nada? Não. YAGNI corta a implementação especulativa, não o pensamento. Você ainda deve refletir sobre arquitetura, antecipar riscos e desenhar fronteiras — só não constrói código para necessidades que ainda não existem. Planejar é barato; implementar o que não se usa é caro.

                  E quando eu tenho quase certeza de que a feature vai ser pedida? "Quase certeza" sobre o futuro é exatamente o que o histórico mostra ser pouco confiável. Mesmo certo sobre o se, é difícil acertar o como. Se adicionar a feature depois for barato, espere — você a construirá com informação real. Reserve a antecipação para o que é caro de mudar depois.

                  YAGNI não entra em conflito com DRY? Eles se equilibram, não se contradizem. YAGNI diz para não abstrair cedo demais; DRY diz para não conviver com duplicação de conhecimento. A síntese, de Sandi Metz, é "prefira duplicação à abstração errada" — ou seja, tolere a repetição até o padrão ficar claro, e então aplique DRY.

                  Como explico YAGNI para um time que adora "deixar pronto para o futuro"? Mostre o custo concreto: features especulativas atrasam entregas reais e adicionam complexidade que todos precisam manter. Use a métrica de Fowler — custo de construir, de atrasar, de carregar e de reparar — para tornar o desperdício visível. Combine com a regra de três para dar um critério objetivo de quando abstrair.

                  YAGNI vale para testes também? Não da mesma forma. Testes do comportamento que já existe são necessidade presente, não especulação. O que YAGNI desencoraja é escrever testes para funcionalidades que você ainda não construiu por especulação — porque elas não deveriam existir ainda.

                  Conclusão

                  YAGNI é uma defesa contra a nossa própria ansiedade. Programadores adoram resolver problemas, e isso nos leva a resolver problemas que ainda não temos — gastando tempo, adicionando complexidade acidental e atrasando o que importa. O princípio nos lembra de uma verdade incômoda: a maioria das nossas previsões sobre o futuro está errada, então construir para elas é, no agregado, prejuízo.

                  Adotar YAGNI não significa programar mal nem ignorar design. Significa direcionar o esforço para o que é necessário agora, manter esse necessário limpo e flexível, equilibrar a tolerância à duplicação com a aplicação de DRY no momento certo, e confiar que, quando o futuro chegar de verdade, você o atenderá com informação real em mãos. No mundo do desenvolvimento assistido por IA, essa disciplina vira também a arte de revisar e enxugar o que a máquina gera generosamente demais. Construa o presente com cuidado — e deixe o futuro pagar pela própria complexidade.

                  Referências

                    Leituras relacionadas

                    Nenhum comentário ainda

                    Seja o primeiro a comentar.

                    Deixe seu comentário

                    Entre com sua conta Canverly para comentar. Você pode usar a mesma conta em qualquer site da rede.

                    Entrar com Canverly