1 pontos por GN⁺ 2024-03-25 | 1 comentários | Compartilhar no WhatsApp
  • No início de 1982, a equipe de software do Lisa estava sob pressão para lançar o produto em seis meses e tentou medir o progresso pelo número de linhas de código semanais por engenheiro
  • Bill Atkinson considerava que a contagem de linhas não mostrava corretamente a produtividade e também entrava em conflito com o objetivo de criar programas pequenos e rápidos
  • Ao reescrever o mecanismo de cálculo de regiões do QuickDraw com um algoritmo mais simples e geral, as operações de região ficaram quase 6 vezes mais rápidas e o código foi reduzido em cerca de 2.000 linhas
  • No primeiro formulário gerencial, no campo que perguntava quantas linhas de código ele havia escrito naquela semana, Bill escreveu -2000, expondo diretamente a falha desse método de medição
  • Algumas semanas depois, os gerentes deixaram de exigir esse formulário de Bill, e o episódio mostra como a gestão baseada em linhas de código pode deixar passar melhorias reais

Medição por linhas de código na equipe do Lisa

  • No início de 1982, a equipe de software do Lisa queria acelerar o ritmo de trabalho para lançar o software nos seis meses seguintes
  • Alguns gerentes tentaram acompanhar o progresso pelo número de linhas de código escritas por cada engenheiro a cada semana
  • Os engenheiros receberam um formulário para entregar toda sexta-feira, e nele havia um campo para informar quantas linhas de código haviam sido escritas naquela semana

O -2000 de Bill Atkinson

  • Bill Atkinson, autor do QuickDraw e principal designer de interface do usuário, desempenhava um papel importante na implementação do Lisa
  • Bill achava que a métrica de linhas de código não media corretamente a produtividade
    • Ele acreditava que o objetivo de um bom software era escrever programas o menor e mais rápidos possível
    • Uma métrica que incentiva aumentar o número de linhas pode estimular a escrita de código desleixado, inchado e quebrado
  • Na época, ele estava otimizando o mecanismo de cálculo de regiões do QuickDraw
    • Reescreveu completamente o mecanismo de regiões com um algoritmo mais simples e geral
    • Depois do ajuste, as operações de região ficaram quase 6 vezes mais rápidas
    • Ao mesmo tempo, o código foi reduzido em cerca de 2.000 linhas
  • Ao preencher o primeiro formulário gerencial, olhou por um instante para o campo de linhas de código e escreveu -2000
  • Não se sabe ao certo como os gerentes reagiram, mas algumas semanas depois deixaram de exigir que Bill enviasse o formulário

1 comentários

 
GN⁺ 2024-03-25
Opiniões no Hacker News
  • Isso me lembra o caso do conflito sobre número de linhas de código entre a Microsoft e a IBM
    Na série de TV da PBS baseada em Accidental Empires, de Bob Cringely, há uma cena em que Steve Ballmer descreve a experiência de desenvolver o OS/2 em conjunto com a IBM
    A Microsoft tinha uma atitude de empresa pequena, focada em fazer o trabalho acontecer, enquanto a IBM se concentrava em métricas internas, especialmente em medir a produtividade dos programadores em KLoC (mil linhas de código)
    Ballmer disse que “eles só se importavam com KLoC, KLoC e mais KLoC”, e parece que a IBM olhava mais para a quantidade de código do que para sua qualidade
    https://ubiquity.acm.org/article.cfm?id=1022357

    • A IBM não era a única. Alguns anos atrás, trabalhei em um grande projeto cujo contratante principal era uma grande consultoria internacional, e, quando a base de código passou de 1 milhão de linhas, fizeram uma festa para a equipe inteira
      Quem conhecia a situação recebeu aquela “comemoração” como se fosse um funeral
    • A série de TV mencionada aqui é Triumph of the Nerds, e continua excelente mesmo hoje. Talvez valha ainda mais a pena assistir agora
  • Contar linhas de código como métrica de produtividade é realmente uma tolice
    Já corrigi com uma única linha de código um bug de 20 anos que ninguém conseguia resolver, e lembro de ter resolvido um bug de 3 anos com um simples order by. Como medir o impacto de uma única linha de código? Pela minha experiência, programadores ruins escrevem muito mais código
    Também não dá para esquecer a história[1] de um desenvolvedor da Microsoft que reescreveu um código da IBM de 33 mil caracteres e o reduziu para 220. Como resultado, o volume de trabalho da Microsoft ficou “negativo”, e dizem que isso causou uma guerra
    [1] https://archive.org/details/bigbluesunmaking00carr/page/4/mode/2up página 101

    • Usar métricas de produtividade em si geralmente é uma tolice, e é uma forma fácil de fazer com que desenvolvedores passem a otimizar métricas em vez de fazer um bom trabalho
      Um exemplo atual são empresas que usam “impacto”, isto é, lançar novos produtos, como critério para promoção. Isso facilita o surgimento de um monte de produtos fracassados que ninguém mantém
    • Certamente há engenheiros que corrigem um bug crítico a cada poucos meses e geram milhões de dólares em valor, mas, em geral, bons engenheiros produzem bastante, e engenheiros que produzem pouco muitas vezes não são tão bons
    • No longo prazo, acho que há certa relação entre número de linhas de código e produção de engenharia
      Entre grandes cientistas da computação e engenheiros, há pessoas que tiveram uma produção enorme de código, e acredito que isso se converte diretamente em impacto de alguma forma. O problema é quando o número de linhas de código se torna a métrica de desempenho
      Aí se aplica a lei de Goodhart: “quando uma medida se torna uma meta, ela deixa de ser uma boa medida”
    • Como os exemplos mostram, um dos motivos pelos quais linhas de código são uma métrica ruim de produtividade é que elas representam muito bem o tamanho do fardo que os mantenedores da base de código terão de carregar
      Do ponto de vista de métricas de produtividade, o código é classificado como ativo; mas uma visão mais próxima da realidade é que a funcionalidade é o ativo, e o código em si é a dívida
  • Este tema aparece com frequência. Discussões anteriores incluem:
    https://news.ycombinator.com/item?id=33483165 (2022)
    https://news.ycombinator.com/item?id=26387179 (2021)
    https://news.ycombinator.com/item?id=10734815 (2015)
    https://news.ycombinator.com/item?id=7516671 (2014)
    https://news.ycombinator.com/item?id=4040082 (2012)
    https://news.ycombinator.com/item?id=1114223 (2010)
    https://news.ycombinator.com/item?id=1545452 (2010)

  • No início da minha carreira, otimizei um programa em C com mais de 10 mil linhas que eu havia herdado, reduzindo-o para menos de 500 linhas. Era um programa em C que fazia chamadas SQL a um banco de dados Sybase
    Não foi por algum grande insight, mas por uma suposição simples: era possível que meu antecessor não soubesse usar funções nem parâmetros para inserir dados variáveis em consultas SQL. De fato, a mesma instrução SQL aparecia inline várias vezes, mudando apenas alguns valores
    Reescrevi o código das chamadas SQL como chamadas de função e passei as variáveis de bind como parâmetros da função. O código inline repetido foi substituído por um loop que pegava os valores de bind variáveis de um array e chamava a função

  • O maior impacto às vezes vem de fazer uma pergunta simples como “Como vamos lidar com X?”, impedindo que algo sequer seja construído
    Se aquilo nem teria tido a chance de funcionar direito, você economizou o custo total de tentar construí-lo
    Esse tipo de coisa não só é impossível de medir com métricas numéricas, como também cria inimigos. Mesmo assim, aplaudo quem tem coragem de fazer isso

    • Por isso ensino aos recém-chegados a manter esse loop na cabeça e a não começar batendo rápido no teclado
      Pessoas que veem programação como algo parecido com digitação rápida mostram um paralelo interessante com LLMs. Escrevem todo o código mal pensado, apagam, depois escrevem de novo e apagam de novo
    • Quando eu gerenciava software em uma grande empresa, mantinha uma caixa de lápis sobre a mesa
      Cerca de metade das solicitações de informação que chegavam ao departamento eram sempre do tipo “é muito importante, precisamos disso agora, e pode render ou economizar muito dinheiro”, mas a resposta óbvia era: “Calculem com as informações que já têm. Vocês têm calculadora e planilha. Querem um lápis?”
      É melhor evitar do que fazer o sistema lidar com X. Um caso especial que talvez seja usado uma ou duas vezes infla o sistema, e ninguém sabe que esse caso especial ou programa existe, nem o que ele realmente faz. Mesmo quando a documentação é boa, ninguém gasta tempo aprendendo o que é possível. Por isso, a maioria desses recursos especiais acaba sendo, na prática, desperdício de tempo
  • Como experimento mental correspondente, dá para pensar na situação oposta. Se um gestor ler este texto e decidir medir simplesmente pelo número de linhas de código removidas, isso melhoraria ou pioraria as coisas?

    • Dependendo da empresa e da forma de medição, pode ser mais fácil de manipular. Basta mandar o llama gerar um código plausível, acrescentar um pouco de código para que ele não tenha efeito real, fazer o commit e depois removê-lo
      Esse tipo de medição é quase inútil, no geral, a menos que haja práticas sólidas de revisão de código. Ao contrário do que as pessoas aqui querem acreditar, essas práticas são raras. Mas, se houver boas revisões, elas também pegam baixa performance ou manipulação de métricas, então há menos motivo para introduzir esse tipo de métrica desde o início
    • Seria um pouco pior, mas talvez não tão catastrófico quanto parece. Isso porque já existe no setor um impulso míope parecido nessa direção
      Por exemplo, há a velha ideia de eliminar engenheiros de software e todo aquele texto de código obscuro, substituindo-os por gerentes de produto que desenham diagramas ou fluxogramas especiais para gerar resultados “low-code” ou “no-code”
    • Todas as métricas baseadas em número de linhas devem ser vistas com desconfiança, mas ΔSLOC talvez seja uma das menos ruins
      Eu contaria linhas adicionadas e removidas separadamente, de modo que um patch +50,-150 seria calculado como 200 ΔSLOC
      Isso não é uma boa medida de produtividade, especialmente sozinha. Ainda assim, é uma métrica razoável de conta de guardanapo para estimar aproximadamente o volume de mudanças. Se um desenvolvedor com ΔSLOC alto é mais produtivo do que um colega que fica 1 ou 2 semanas sem nenhum ΔSLOC depende do que esse colega está fazendo, mas é certo que, durante o período medido, o primeiro está alterando mais a base de código
    • Piora. Transformar a base de código inteira em objeto de code golf não é desejável
    • Com certeza não haveria novos recursos
      Se o produto estiver “pronto”, talvez fique igual ou até melhor. Caso contrário, mudanças negativas no número de linhas de código não chegariam à produção
      Mas a maioria dos produtos continua evoluindo. É por isso que podemos permanecer anos no mesmo projeto, e contribuições que apenas removem coisas acabam não acrescentando nada
  • A história real é que, quando se começa um projeto, às vezes não se sabe exatamente para onde ele vai
    À medida que se avança, entende-se muito melhor o problema e a resposta desejada, e então é possível arrancar grandes blocos e substituí-los por algo menor e melhor
    E não se deve esquecer que essas pessoas precisavam colocar tudo dentro de uma ROM de 64 KB, incluindo -2000 linhas de código, e até código assembly. A pressão para tornar tudo menor era enorme

  • É o Bill Atkinson, famoso pelo Atkinson Dither. https://beyondloom.com/blog/dither.html

    • Bill Atkinson criou o QuickDraw, a biblioteca gráfica que serviu de base para a UI do Lisa e do Mac, além do MacPaint e do HyperCard.
      Nesse processo, ele precisou continuar inventando novas formas de a interface de usuário funcionar e maneiras de escrever software para resolver isso. Ele otimizava ao mesmo tempo para “rodar rápido no hardware do Mac” e “oferecer uma ótima experiência de usuário”, e essa sinergia deixou sua marca em toda a estética dos antigos Macs em preto e branco. Aquele estilo de dithering também é outro exemplo da combinação de genialidade algorítmica com senso estético.
      Esse senso também aparece em coisas como a borda de seleção “marching ants” (https://en.wikipedia.org/wiki/Marching_ants). O mesmo vale para muito do feedback da UI clássica do Mac ter sido expresso por inversão de pixels. É o caso da seleção de texto, do destaque de menus, da forma como um botão aparece enquanto o botão do mouse está pressionado, das linhas de contorno ao arrastar uma janela etc.; desenhar por cima em modo XOR era uma maneira muito boa de criar esses efeitos.
      A forma como essas ferramentas foram combinadas no QuickDraw levou a famosa conversa sobre retângulos arredondados com Steve Jobs (https://www.folklore.org/Round_Rects_Are_Everywhere.html) a resultar, na prática, em tornar tão fácil desenhar retângulos arredondados no QuickDraw quanto retângulos comuns, fazendo com que eles aparecessem por todo o sistema operacional.
      O sucesso da UI do Mac não foi apenas por ela ser bonita. Em grande parte, foi porque Bill Atkinson criou um conjunto pequeno e inteligente de ferramentas que tornava fácil criar coisas bonitas.
      Os excelentes ícones de Susan Kare também não teriam sido lembrados com tanto carinho se Bill não tivesse criado ferramentas que facilitavam inserir bitmaps de máscara de 32x32 pixels na UI e invertê-los ao clicar.
  • A lição é que, mesmo sendo tão inteligente quanto Einstein, no fim você é funcionário, e precisa fazer o que deve fazer como funcionário.

    • Se Einstein tivesse sofrido pressão por métricas, provavelmente nunca teríamos ouvido seu nome.
  • Nunca entendi por que, quando as pessoas falam do número de linhas de código escritas, sempre calculam como “linhas adicionadas - linhas removidas”.
    Só porque eu fiz uma corrida de 10 km e voltei ao ponto de partida não quer dizer que corri 0 km.

    • Acho que em parte é porque ferramentas burras de diff podem registrar como uma grande diferença até linhas que foram apenas movidas de um lado para outro, embora a mudança funcional seja limitada.
      Por exemplo, transformar algo no formato if cond { ... return; } ... em if cond { ... return; } else { .... }.
      Ainda assim, essa explicação não cobre tudo.