3 pontos por GN⁺ 5 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • YAGNI não é uma simples regra de economia do tipo “não escreva código que ainda não é necessário”, mas um princípio sobre o custo de antecipar a estrutura com base em suposições antes de a necessidade estar confirmada
  • O centro do problema não é o design em si, mas quando fazer o design; estruturar cedo demais pode ser tão arriscado quanto estruturar tarde demais
  • Estruturas antecipadas geram ao mesmo tempo o custo da opcionalidade, ao fechar possibilidades antes da chegada de novas informações, e o custo de NPV, ao antecipar gastos e adiar retornos
  • Mesmo que o custo de gerar código se aproxime de zero, o YAGNI não desaparece; na verdade, a geração barata pode tornar ainda mais fácil criar frameworks baseados em suposições
  • A conclusão de construir apenas quando necessário não vem do custo de escrever código, mas do fato de que o valor da opcionalidade não usada e do dinheiro não gasto ainda permanece

YAGNI não proíbe design

  • YAGNI é a sigla de “You Aren’t Gonna Need It” e não é uma desculpa para nunca projetar algo que não seja estritamente necessário
  • Se algo for necessário, pode ser construído; o ponto central, porém, é o timing
  • O ponto de partida é uma história recorrente em projetos: diante da ideia de que “daqui a 3 semanas uma implementação simples não vai bastar, então quero fazer algo mais complexo agora”, a resposta repetida era “You aren’t going to need it”
  • Esse princípio considera arriscado tanto criar estrutura cedo demais quanto tarde demais

O problema não é o custo de escrever código, mas a estrutura baseada em suposições

  • Uma interpretação comum vê o YAGNI como uma regra de economia: “não escreva código que ainda não é necessário porque ele é caro”
  • Mas o alvo do YAGNI não é o custo de produção do código, e sim a estrutura especulativa (speculative structure) criada antes de uma funcionalidade realmente exigir isso
  • Esse tipo de estrutura gera dois tipos de custo, em momentos e por razões diferentes

Primeiro custo: opcionalidade

  • Quando você cria uma estrutura antes de a funcionalidade chegar, acaba se comprometendo com base em suposições sobre requisitos que ainda não conhece
  • As funcionalidades para as quais você tentou se preparar de antemão geralmente diferem das que de fato chegam, e o resultado é pagar duas vezes
    • o custo de contornar uma estrutura com formato errado
    • o custo de desmontar essa estrutura depois
  • O problema não se resume a dizer apenas que “é difícil prever”
  • Mesmo que a suposição esteja correta, ainda há perda, porque você abre mão da opção de não se comprometer antes e construir a estrutura certa mais tarde
  • Esperar não é preguiça; é manter um ativo chamado opcionalidade

Segundo custo: NPV

  • Assim como o dinheiro tem valor no tempo, funcionalidades também têm valor temporal
  • Se você cria agora a estrutura para uma funcionalidade que só será necessária daqui a 3 meses, antecipa o custo e atrasa o lançamento da funcionalidade que de fato gera receita
  • Esse custo existe mesmo quando a suposição está correta
  • Nem uma previsão perfeita muda a ordem entre custo e retorno; a perda surge do intervalo em que os gastos são colocados antes dos ganhos
  • O custo da opcionalidade trata do problema “não se comprometa antes que a informação chegue”, e o custo de NPV trata do problema “não pague antes de precisar”
  • Mesmo a objeção de que “depois vai ficar caro demais corrigir” pode ser, por si só, outra previsão

Mesmo com geração de código barata, o YAGNI continua válido

  • Em nenhum dos dois custos entra o custo de digitar código
  • Se o custo de escrever código cair para quase zero, a interpretação econômica do YAGNI — “como o código ficou barato, então tudo bem construir antes” — desmorona
  • Mas como o YAGNI não é uma regra de economia, a geração barata de código não o invalida
  • O custo da opcionalidade não surge da quantidade de esforço, mas do compromisso que fecha escolhas futuras
  • O custo de NPV não surge do preço de produção, mas do timing do fluxo de caixa
  • Geração gratuita não enfraquece o YAGNI; ao contrário, pode facilitar ainda mais a criação de frameworks baseados em suposições
  • A estrutura gerada continua produzindo os dois custos e, por não ter sido escrita diretamente, pode até ser menos compreendida
  • A conclusão não é “espere porque código é caro”, mas sim: como a opcionalidade e o dinheiro valem mais quando ainda não foram usados, construa quando for necessário

1 comentários

 
GN⁺ 5 시간 전
Comentários no Hacker News
  • Acho que o custo de mudar a estrutura também caiu
    Graças à IA, diminuiu o custo de reforçar o comportamento com testes antes de mudar a estrutura, e o custo de implementar migrações sem downtime também caiu
    Um dos grandes motivos de Rust ter ganhado atenção, mesmo antes da IA, era justamente o baixo custo de mudar a estrutura interna da aplicação, e agora isso é ainda mais verdadeiro
    O custo de oportunidade de não conseguir mudar a estrutura com segurança aumentou bastante, e hoje a principal otimização é a capacidade de alterar partes grandes do código e do produto de forma rápida e segura

    • A capacidade de alterar partes grandes do código e do produto de forma rápida e segura já era algo bom e valioso, independentemente da chegada da codificação com IA
      Só que, antes da IA, mudanças estruturais levavam muito mais tempo; então dá até para argumentar que o valor do que se está tentando otimizar agora, na verdade, caiu
      Ainda é valioso, mas talvez um pouco menos do que antes
    • Acho difícil concordar
      Com o aumento dos testes gerados por IA e frágeis, o custo de mudar a estrutura ficou maior do que antes
      Organizar um conjunto de testes para verificar a essência do problema, e não decisões acidentais de design, ainda é algo em que a IA não é boa
    • Isso mesmo
      Mas também ficou fácil demais acabar com um conjunto de testes frágil mais ou menos 75% pronto
      Muita gente se satisfaz em tratar como melhoria objetiva a passagem de “alguns testes comuns e frágeis escritos por humanos” para “muitos testes comuns e frágeis escritos por IA”
      Concordo totalmente com usar a ferramenta dessa forma, mas isso não significa que dê para deixar de se preocupar com construir um castelo de cartas errado cedo demais
      Ainda é bem difícil projetar um contrato de testes perfeito que resista a refatorações
    • Isso lembra o princípio aberto-fechado, de “aberto para extensão, fechado para modificação”
      É como se algo antigo tivesse voltado a ser novo
      Da eficiência contextual de abordagens como DDD ou Clean Architecture até itens como esse, a IA não cria novos trade-offs; ela funciona como um amplificador
      Aumenta a produtividade das equipes que fazem direito e também aumenta a dívida das equipes com padrões fracos de qualidade de design e arquitetura
    • Parece que estão aumentando cada vez mais os movimentos em falso, apostando que a IA vai consertar depois
      O único ganho é não precisar pensar profundamente
      Pensar a fundo não custa tanto tempo nem esforço assim, então vão acabar ficando para trás de quem usa a IA do mesmo jeito, mas pensa o suficiente para não produzir esse tipo de movimento em falso
  • Kent Beck compara código ainda não escrito a uma opção financeira de comprar código por um certo preço
    Mas isso é só uma metáfora, e começa a ficar estranho quando levada longe demais
    Se nenhum código foi escrito, então as opções são infinitas? Mesmo sem tempo investido ainda, isso não parece correto
    Isso também pode virar justificativa para ficar na fase de planejamento e adiar indefinidamente a escrita de código para não fixar nada
    Ainda assim, se a metáfora funcionar, o custo pode estar na leitura do código
    Código não escrito não precisa ser lido e, se você usa agentes de codificação, também não polui o contexto com detalhes irrelevantes
    Código ainda não escrito também não precisa ser testado, e testes ainda não escritos também não consomem tempo de execução
    Por isso, é bom manter o projeto o menor possível, e adiar funcionalidades pode retardar ao máximo o crescimento da base de código
    Isso também significa que executar código de outras pessoas pode evitar muitos custos
    Se for possível usar uma API padrão, não é preciso entender a implementação em detalhes nem executar seus testes, embora adicionar dependências tenha seus riscos

    • Em “Tidy, First?”, Kent vê o software como algo que cria valor de duas formas: pelo que faz hoje e pelas possibilidades que pode abrir amanhã
      Código não escrito não tem valor
      Para que o código escrito hoje gere valor, ele precisa resolver uma solicitação ou problema de hoje, ou estar inclinado a tornar algo mais fácil amanhã
      Assumir dívida técnica com uma solução gambiarra ou desperdiçar tempo com algo que contraria o YAGNI não gera valor
      O importante não é o código não escrito, mas o código que será escrito daqui para frente e seu propósito
      É preciso fazer o trade-off certo entre resolver o ticket ou tarefa de hoje e não dar um tiro no próprio pé no futuro
      Escrever código é um compromisso, e o valor de hoje é visível, mas o valor de amanhã é mais uma estimativa
      Ainda assim, sempre haverá um custo a pagar depois, então acabamos estimando o que pode vir a ser necessário para tentar minimizar esse custo
  • Acho que não se fala o bastante sobre as boas práticas na era da IA, mas há um ponto que Kent deixa passar completamente
    Há bastante valor em descobrir mais rápido quais funcionalidades são necessárias
    Criar uma estrutura especulativa pode funcionar como um mecanismo de pressão para fixar requisitos e, pelo menos, começar a revelar como as falhas acontecem
    Como isso pode sair mais caro do que esperar, não se deve fazer isso para a maioria dos requisitos, mas às vezes pode ser a melhor opção
    O custo de construir a coisa errada agora é muito menor, e por isso o cálculo em torno do YAGNI muda
    Ainda assim, continua sendo necessário fazer esse cálculo, e agora cada equipe precisa descobrir por si mesma como isso mudou para ela

    • Se você transformar a estrutura especulativa em um spike e descartá-la depois, tudo bem
      Se não descartar, isso vira um mecanismo de pressão para produzir um resultado bagunçado
    • Eu diria que as funcionalidades necessárias já vêm dos requisitos e do design do sistema que atende esses requisitos
      YAGNI é o problema de construir algo que não está nos requisitos atuais, antecipando uma futura mudança de requisitos
      Isso é diferente de concretizar os requisitos e restrições atuais
      Essas coisas vêm principalmente de conversas com stakeholders, usuários e clientes, além de recursos e restrições e capacidades de engenharia
      Protótipos têm valor quando servem para conversar com stakeholders, criar um modelo de gestão do projeto ou fazer pesquisa de engenharia
      Fora disso, está tudo invertido
  • A abordagem de ver o software em execução como um ativo está correta
    Só que o custo de executá-lo e recriá-lo caiu bastante
    O custo que não caiu é o de quebrar a cadeia de confiança sobre resultados previsíveis
    Uma versão específica de um software em execução acumulou confiança ao longo do tempo, e reescrevê-lo do zero zera esse capital no momento do lançamento

  • Em algum momento, passei a pensar diferente
    Adio os concretos com YAGNI e escrevo, na medida do possível, uma versão abstrata
    Criar um UserStore? Isso parece o mais simples, mas talvez não seja necessário um formato específico de User
    Então crio um Store que guarda qualquer coisa que possa ser armazenada
    Se você não estiver acostumado, isso parece overengineering e uma salada de genéricos, mas, paradoxalmente, é a forma que menos promete a qualquer implementação concreta

    • Parece exatamente overengineering e uma salada de genéricos
      Não só você criou uma interface UserStore que provavelmente não seria necessária, como também acabou criando uma abstração generalizada de Store que com certeza não era necessária
      Na tentativa de não se comprometer com uma implementação concreta, você implementou camadas pegajosas desnecessárias e com grande chance de nunca virem a ser necessárias
      Se for uma abstração que não se baseia em necessidade real, mesmo que ela venha a ser necessária depois, é bem provável que tenha sido feita de forma errada
      No fim, o UserStore provavelmente será necessário, então era isso que deveria ter sido feito primeiro
  • Não concordo com a frase “não é uma afirmação de que prever é difícil, como se um arquiteto mais afiado pudesse evitar isso”
    Essa afirmação só se sustenta se partir da premissa de que prever é difícil

    • “Mesmo acertando o palpite, ainda fica pior do que não se comprometer” também me parece confuso
      Se você prepara com antecedência a base para uma funcionalidade muito provável e tudo se encaixa, consegue lançar mais rápido
      Também não há garantia de que a equipe necessariamente vá crescer ou sequer se manter, então me parece pior comemorar a contenção do que correr em cima da hora para fazer YAGNI caber no prazo
  • Recentemente precisei me desvencilhar funcionalmente de um codebase cheio de YAGNI acumulado, e foi um trabalho enorme, mesmo com agente
    Em um sistema distribuído, como saber o que realmente está em uso? Teve coisas que eu deixei passar e coisas que o agente deixou passar, e o processo inteiro demorou mais do que precisava
    Não foi só um porteamento 1:1; aproveitamos como oportunidade para simplificar, então era preciso entender completamente como o sistema antigo funcionava
    Até coisas que na prática não eram usadas entravam no escopo do que precisava ser entendido, se não fosse possível identificá-las como tal

  • No fim, acho que tudo se resume a explorar o problema e implementar a solução
    Sempre há custo em resolver o problema errado, e também há custo em implementar uma solução ruim para algo que nem era necessário
    Às vezes o desenvolvimento de software pode descambar para um simples tentativa e erro, em vez de pensar em quais estratégias e conjuntos de problemas explorar
    Há casos em que explorar um problema mais a fundo em certa direção do que o estritamente necessário ajuda no longo prazo, mas implementar soluções sem propósito nunca é algo bom
    Acho que o que Kent Beck realmente critica é a postura de implementar algo “vai que” só porque talvez seja necessário no futuro

  • Foi dito que “se você cria a estrutura antes de a funcionalidade chegar, está se comprometendo com um palpite”, mas eu diria que há palpite dos dois lados
    A funcionalidade pode ter alta probabilidade de chegar, mas não é certo
    Se você não criar a estrutura agora, haverá custo de refatoração; se criar cedo demais e a funcionalidade nunca vier, terá desperdiçado esforço
    Quais são os custos, probabilidades e trade-offs entre essas possibilidades? Claro que depende da situação
    O próprio YAGNI é uma grande generalização deliberada
    No fim, depende do contexto
    Em qualquer um dos lados, muitas vezes há muito palpite e explicação gestual, e isso se parece com o problema de estimativas de trabalho confiáveis
    Alguns desenvolvedores, que não lidam bem com um mundo incerto, tentam encontrar regras em preto e branco para tudo

  • Nunca vi nada nos textos de Kent Beck que parecesse útil para uma empresa de chips
    Numa empresa de chips, muitas pessoas precisam trabalhar por muito tempo, o cliente não pode ver nada até estar pronto, e, para ganhar dinheiro, é preciso vender em escala de milhões de unidades

    • Mas ele não é alguém que faz software e escreve sobre desenvolvimento de software?
      Hardware tem restrições fortes
      Aliás, foi justamente para escapar desse tipo de restrição que o software foi inventado
    • Não é necessariamente verdade que o cliente jamais possa ver algo antes de ficar pronto
      É verdade que muitas empresas de chips não compartilham o trabalho em andamento, mas é possível — e isso de fato acontece — compartilhar simulações, protótipos e amostras de engenharia
      Claro que normalmente isso vale para clientes grandes
      Percepções de um setor em que o custo de mudança é relativamente baixo não se aplicam facilmente a um setor em que o custo de mudança é alto, e o inverso também costuma ser verdadeiro
    • Interessante
      Como as empresas de chips planejam projetos assim? Usam ágil, cascata ou algum framework diferente do setor de software?