14 pontos por GN⁺ 2025-06-26 | 1 comentários | Compartilhar no WhatsApp
  • Em 1982, a equipe de software do Lisa da Apple introduziu uma política de rastrear o número de linhas de código semanais de cada desenvolvedor para lançar o software
  • Bill Atkinson defendia que linhas de código eram uma métrica equivocada de produtividade de software
  • Ele reescreveu completamente o motor de cálculo de regiões do Quickdraw, reduzindo cerca de 2.000 linhas de código e melhorando o desempenho em 6 vezes
  • Atkinson escreveu -2000 no formulário de gestão em que precisava reportar a quantidade de código
  • No fim, os gestores deixaram de exigir que Bill enviasse o formulário

A equipe de software do Lisa em 1982 e a política de rastreamento de linhas de código

  • No início de 1982, a equipe de software do Lisa começou a se concentrar na meta de lançar o software nos 6 meses seguintes
  • Alguns gestores decidiram que acompanhar o número de linhas de código escritas por cada engenheiro toda semana ajudaria no progresso
  • Para isso, foi introduzido um formulário no qual, toda sexta-feira, os engenheiros registravam e enviavam a quantidade de linhas de código escritas

A visão de Bill Atkinson sobre critérios de produtividade

  • Bill Atkinson, que projetou o Quickdraw e a interface do usuário, considerava que o número de linhas de código não podia ser um critério de produtividade de software
  • Ele enfatizava que o objetivo era tornar os programas o menores e mais rápidos possível
  • Havia a percepção de que medir linhas de código poderia, ao contrário, incentivar código bagunçado e ineficiente

Refatoração e otimização do motor de regiões do Quickdraw

  • Atkinson havia recentemente reescrito por completo o motor de cálculo de regiões do Quickdraw com um algoritmo mais simples e genérico
  • Como resultado da otimização, a velocidade das operações de região melhorou em até 6 vezes
  • Nesse processo, cerca de 2.000 linhas de código também foram naturalmente eliminadas

O relatório de -2000 linhas de código e a reação dos gestores

  • Ao preencher o formulário de gestão da primeira semana, Atkinson escreveu -2000 no campo referente ao número de linhas de código
  • Não está claro como os gestores reagiram a esse número
  • Algumas semanas depois, disseram a Bill que não precisava mais enviar o formulário, e ele recebeu isso com satisfação

1 comentários

 
GN⁺ 2025-06-26
Comentários do Hacker News
  • O commit de que mais me lembro como o meu melhor foi quando apaguei cerca de 60 mil linhas de código e substituí um “servidor” inteiro, que mantinha todo o estado em memória, por uma lógica enxuta de umas 5 mil linhas

    • Considero isso um feito algorítmico, porque o código ficou leve o bastante para ser integrado naturalmente a outros serviços e não precisava mais manter estado em memória
    • Foi o processo de descobrir que eu conseguia resolver um problema de isomorfismo guiado de subgrafo para uma árvore específica, e graças a isso pude percorrer um grafo bidirecional direcionado genérico uma única vez, acompanhando apenas os caminhos a partir da raiz inicial com uma pequena pilha, para construir o grafo de saída (árvore)
    • O “commit de -60.000 linhas” foi realmente um momento inesquecível, e desde então fico com a sensação meio melancólica de nunca mais ter feito algo tão impressionante do ponto de vista algorítmico
      • Eu programo bastante com scripts no trabalho e me considero um programador amador razoavelmente competente em algumas áreas, mas toda vez que ouço uma história dessas volto a sentir humildade ao perceber como o mundo que eu desconheço é enorme e como uma vida inteira ainda não basta para aprender tudo
      • Queria ouvir mais contexto. Essa técnica de transformar um programa que guardava estado em algo sem estado parece mágica, então tenho muita curiosidade de aprender
      • Sou matemático com formação em teoria dos grafos e algoritmos, e fico me perguntando se minhas habilidades poderiam se aplicar a esse tipo de trabalho no mundo real. Será que você poderia compartilhar mais detalhes?
      • Acho que o fato de o grafo-alvo ser uma árvore não parece tão importante. O ponto principal, na minha visão, é que a parte realmente "guiada" é o que tornou possível a travessia única
        • Parte-se de um nó específico no grafo original e assume-se que, se o isomorfismo existir, a raiz da árvore-alvo também necessariamente corresponderá àquele nó
        • A interpretação do problema seria algo como: percorrer o grafo original seguindo o padrão da árvore-alvo e, se houver incompatibilidade, retornar false; se tudo combinar, retornar true. Mesmo que não seja uma árvore, dá para inferir que esse método se aplicaria a qualquer subgrafo se o ponto de partida estiver claramente definido
      • Uma piada dizendo que talvez esse tipo de programador seja a origem das famosas questões de entrevista do tipo “inverta uma árvore binária”
        • Pedido de uma explicação fácil para um desenvolvedor comum que tem curiosidade sobre teoria dos grafos, mas acha a terminologia difícil
  • Na época da faculdade, trabalhei para uma empresa cuja política gerencial era a de que calouros conseguiam escrever bom código, e no fim eles acabaram virando um caso de fracasso não comprovado

    • Eu corrigia um bug no código, mas o mesmo bug continuava aparecendo; quando analisei, descobri que em vez de adicionar um parâmetro à função existente, faziam uma cópia dela e alteravam só um pouco. Como resultado, tive a experiência de apagar mais de 3/4 do codebase, milhares de linhas em Turbo Pascal
    • O cliente do projeto era o departamento de Energia, e era um programa de controle de inventário de material nuclear, então lembro de ter passado noites em claro
      • Comentário sarcástico de que as vantagens de copiar código existente seriam não prejudicar a estabilidade do código antigo e ainda atender à métrica de “contribuição” do gerente. E, de quebra, o revert também vira piada: é só apagar a cópia
      • Também temos um colega no nosso time que costuma duplicar código assim, e acho que isso virou um hábito para entregar resultado rápido diante de exigências urgentes ou de quem fala mais alto. No fundo, o problema é não querer investir tempo no que realmente seria necessário: refatorar para uma função compartilhada e testar bem
      • Desenvolvedores terceirizados com quem trabalhei no passado tinham um hábito parecido; quando apontei que isso podia gerar confusão, a resposta foi: “nessa hora é só usar Ctrl+F”
      • Curiosidade se esse caso aconteceu na região de Blacksburg
      • Minha experiência foi parecida: trabalhei numa empresa que operava portais quase idênticos em vários países do Sudeste Asiático. O código-fonte de cada portal ficava em um repositório Git separado, e qualquer recurso ou correção que precisasse ser aplicado a todos exigia backport manual em várias cópias do código
        • Perguntei se não dava para colocar tudo em um único repositório e usar feature flags para customizações por portal, mas me disseram que não era possível
        • No fim, em dois ou três meses, juntei o código de 4 ou 5 portais em um único repositório, apliquei feature flags e atualizei o framework; a implantação terminou sem atritos. Agora é possível corrigir bugs em todos os portais ao mesmo tempo, e a sensação de se livrar da dor do trabalho manual repetitivo foi libertadora
  • Sobre esse tema, alguém reuniu threads populares do Hacker News sobre “código de -2000 linhas” em um link

    • Observa-se que esse costume de repostar periodicamente grandes textos do passado é uma tradição benéfica tanto para usuários novos quanto para os antigos
      • Eu me assumo como um ser humano simples: se vejo “-2k lines of code”, dou voto positivo automaticamente
        • Costumo contar o caso do Atkinson para clientes que querem gerenciar medição de produtividade como uma métrica de um único eixo. A verdadeira medida de produtividade deveria ser utilidade, e se alguém conseguisse quantificar isso de verdade provavelmente mereceria concorrer ao Nobel de Economia
  • O projeto de web UI pelo qual fui responsável tinha 250 mil linhas de código, sem contar o backend

    • O desenvolvedor anterior era inteligente, mas estava começando em JS, então guardava todo o estado em atributos customizados do DOM e espalhava addEventListener por toda parte. Eu até brincava dizendo que “esse é o tipo de código que sai se você der a um monge um livro de JavaScript e dez anos de solitária”
    • Passei alguns meses convertendo a estrutura para web components e removi 50 mil linhas. Depois comecei uma reescrita completa, e hoje cheguei a algo como 80% da mesma funcionalidade, mas com um total enxuto de cerca de 17 mil linhas (sem contar bibliotecas como Vue/pinia)
    • Em breve devo ultrapassar 200 mil linhas apagadas, e provavelmente nunca mais vou viver algo maior do que isso; dá até vontade de me aposentar
      • Também tive uma experiência parecida: o autor original tinha habilidade praticamente de júnior, mas era o fundador da empresa e extremamente produtivo. Como desenvolveu sem experiência com trabalho em equipe nem colaboração sobre código de outras pessoas, a estrutura continha literalmente todos os code smells imagináveis
        • Explicação de que era um frontend da era PHP/Dojo, com funções de milhares de linhas, 10 níveis de switch/case/if/else/ternário aninhados, SQL misturado com JS/HTML/HTML embutido em JS, e zero testes automatizados
      • Observação de que a própria descrição “código enxuto com apenas 80% das funcionalidades implementadas” mostra a limitação desse tipo de comparação: se só parte das funcionalidades foi reimplementada, é natural que não sejam necessárias tantas linhas quanto no código original
  • Há uma tirinha do Dilbert sobre uma estrutura de recompensa infinita: o chefe do Dilbert promete recompensa em dinheiro para cada bug corrigido, e o Wally diz “acho que hoje vou programar pelo menos uma minivan!”

    • Esse tipo de situação é chamado de “Perverse incentive” e é explicado neste link de referência
    • Meu gerente também tinha essa tirinha ( imagem ) pregada na parede da sala de descanso
    • Surge então a curiosidade prática: o que exatamente significa “minivan” nessa fala?
  • Compartilhamento de um caso real de remoção de 64 mil linhas no repositório dotnet/runtime

    • A estrutura foi alterada para substituir o suporte embutido de interoperabilidade entre C# e WinRT por uma ferramenta de geração de código-fonte, uma mudança que exigiu decisão firme para fazer a transição de uma vez só. Ver o PR
  • Sempre que vejo estatísticas dizendo o quanto LLMs aumentaram a produtividade dos desenvolvedores, lembro dessa história clássica

    • Contra-argumento de que IA também é muito boa em apagar código, junto com um caso divertido da comunidade do Cursor em que “a IA apagou tudo”
    • Comentário de que hoje em dia “X% do nosso código novo é escrito por IA!” virou um bordão favorito da indústria
    • Sarcasmo de que, se incluirmos até o custo de construir e manter novas usinas nucleares, essas métricas de produtividade de desenvolvedor ficam ainda mais absurdamente infladas
  • Não sou formado em Ciência da Computação; aprendi tudo na prática, trabalhando

    • O objetivo do projeto em que trabalhamos é reconstruir objetos vivos de forma legível por humanos
      • A representação final exige muitos tipos bem complexos, enquanto a representação inicial é relativamente simples
      • Quando há nós de dados parecidos, era preciso compará-los e combiná-los — isto é, extrair métodos e descobrir parâmetros — para melhorar a legibilidade
        • No começo, fazíamos primeiro a conversão para os tipos finais e só depois a comparação, o que fez explodir a quantidade de combinações de tipos e levou a uma complexidade tão alta que, por anos, os engenheiros mal conseguiam entender a estrutura
      • Mais tarde, conheci uma abordagem baseada em hashmap, em que nós com o mesmo esqueleto são distinguidos por hash, comparados e combinados, e só depois convertidos para os tipos finais, num fluxo de duas etapas
      • Ao trocar a abstração baseada no estado dos tipos por uma abstração centrada nos dados, até hierarquias estranhas de classes passaram a ser fáceis de administrar como propriedades simples
      • Em resumo, era uma estrutura meio burra de decompilador em várias etapas, mas tive a experiência de ver grandes melhoras tanto em desempenho quanto em legibilidade. Não existe bala de prata universal, mas no nosso caso o problema central eram os “tipos”, e essa solução ajudou bastante
  • Ao olhar minhas estatísticas no monorepo interno da empresa antes da avaliação de fim de ano, descobri que eu tinha virado uma pessoa “negativa” em saldo líquido de código

    • Isso aconteceu por remover código e tipos gerados automaticamente de API e aposentar APIs legadas, mas havia algo estranhamente agradável na sensação de ir trabalhar todos os dias basicamente para apagar código
  • Há muito tempo, fiquei chocado com um caso lamentável de KPI em um grande projeto onde os líderes técnicos mantinham manualmente, offline, e colavam na parede a contagem de bugs por desenvolvedor (bugs corrigidos e bugs causados)

    • Eu escapei porque estava em um projeto relacionado, mas um colega, inspirado na história de Lars von Trier sendo expulso da “lista de autores” de um burocrata depois de recortar a parte da cruz da bandeira da Dinamarca e costurá-la de volta de modo a parecer uma bandeira comunista vermelha, cortou a linha da própria contagem de bugs, colou de volta e protestou publicamente. No dia seguinte, a lista sumiu para sempre, e essa continua sendo uma lembrança preciosa para mim
      • “Porque eu não quero estar nessa lista!” foi a resposta simples e direta do colega, resumindo perfeitamente toda a situação
      • Também foi compartilhada a dificuldade bem prática de imaginar como exatamente a bandeira e a lista foram visualmente alteradas