Os erros mais embaraçosos da minha carreira de programação (até agora)

Os erros mais embaraçosos da minha carreira de programação (até agora)
Como se costuma dizer, se você não tem vergonha do seu código antigo, então você não está crescendo como programador - e eu concordo com essa opinião. Comecei a programar por diversão há mais de 40 anos e profissionalmente há 30 anos, então cometo muitos erros. muito. Como professor de ciência da computação, ensino meus alunos a aprender com os erros – deles, meus e de outros. Acho que é hora de falar dos meus erros para não perder o pudor. Espero que sejam úteis para alguém.

Terceiro lugar - compilador Microsoft C

Minha professora acreditava que Romeu e Julieta não poderiam ser considerados uma tragédia porque os personagens não tinham culpa trágica - eles simplesmente se comportavam de maneira estúpida, como os adolescentes deveriam. Na época não concordei com ele, mas agora vejo um pouco de racionalidade em sua opinião, especialmente em relação à programação.

Quando terminei meu segundo ano no MIT, eu era jovem e inexperiente, tanto na vida quanto em programação. No verão, estagiei na Microsoft, na equipe do compilador C. No começo, fiz coisas rotineiras, como suporte a criação de perfil, e depois fui encarregado de trabalhar na parte mais divertida do compilador (como eu pensava) - otimização de back-end. Em particular, tive que melhorar o código x86 para instruções de ramificação.

Determinado a escrever o código de máquina ideal para cada caso possível, me joguei de cabeça na piscina. Se a densidade de distribuição dos valores fosse alta, eu os inseri tabela de transição. Se eles tivessem um divisor comum, eu o usava para deixar a tabela mais compacta (mas somente se a divisão pudesse ser feita usando mudança de bits). Quando todos os valores eram potências de dois, fiz outra otimização. Se um conjunto de valores não satisfizesse minhas condições, eu o dividia em vários casos otimizáveis ​​e usava o código já otimizado.

Foi um pesadelo. Muitos anos depois me disseram que o programador que herdou meu código me odiava.

Os erros mais embaraçosos da minha carreira de programação (até agora)

Lição aprendida

Como David Patterson e John Hennessy escrevem em Computer Architecture and Computer Systems Design, um dos principais princípios da arquitetura e do design é geralmente fazer as coisas funcionarem o mais rápido possível.

Acelerar casos comuns melhorará o desempenho de forma mais eficaz do que otimizar casos raros. Ironicamente, os casos comuns costumam ser mais simples do que os raros. Este conselho lógico pressupõe que você saiba qual caso é considerado comum – e isso só é possível através de um processo de testes e medições cuidadosos.

Em minha defesa, tentei descobrir como eram as instruções de ramificação na prática (como quantas ramificações havia e como as constantes eram distribuídas), mas em 1988 essa informação não estava disponível. No entanto, eu não deveria ter adicionado casos especiais sempre que o compilador atual não conseguisse gerar o código ideal para o exemplo artificial que criei.

Precisei ligar para um desenvolvedor experiente e, junto com ele, pensar quais eram os casos comuns e tratar deles especificamente. Eu escreveria menos código, mas isso é uma coisa boa. Como escreveu o fundador do Stack Overflow, Jeff Atwood, o pior inimigo de um programador é o próprio programador:

Eu sei que você tem as melhores intenções, assim como todos nós. Criamos programas e adoramos escrever código. É assim que somos feitos. Achamos que qualquer problema pode ser resolvido com fita adesiva, uma muleta caseira e uma pitada de código. Por mais que seja difícil para os programadores admitir isso, o melhor código é aquele que não existe. Cada nova linha precisa de depuração e suporte, precisa ser compreendida. Ao adicionar um novo código, você deve fazê-lo com relutância e repulsa, porque todas as outras opções foram esgotadas. Muitos programadores escrevem muito código, tornando-o nosso inimigo.

Se eu tivesse escrito um código mais simples que abrangesse casos comuns, teria sido muito mais fácil atualizar, se necessário. Deixei para trás uma bagunça com a qual ninguém queria lidar.

Os erros mais embaraçosos da minha carreira de programação (até agora)

Segundo lugar: publicidade nas redes sociais

Quando eu trabalhava no Google com publicidade em mídias sociais (lembra do MySpace?), escrevi algo assim em C++:

for (int i = 0; i < user->interests->length(); i++) {
  for (int j = 0; j < user->interests(i)->keywords.length(); j++) {
      keywords->add(user->interests(i)->keywords(i)) {
  }
}

Os programadores podem ver imediatamente o erro: o último argumento deveria ser j, não i. O teste de unidade não revelou o erro, nem meu revisor. O lançamento foi realizado e uma noite meu código foi para o servidor e travou todos os computadores do data center.

Nada de ruim aconteceu. Nada quebrou para ninguém, porque antes do lançamento global o código foi testado dentro de um data center. A menos que os engenheiros do SRE parassem de jogar bilhar por um tempo e fizessem uma pequena reversão. Na manhã seguinte, recebi um e-mail com um crash dump, corrigi o código e adicionei testes de unidade que detectariam o erro. Como segui o protocolo - caso contrário, meu código simplesmente não funcionaria - não houve outros problemas.

Os erros mais embaraçosos da minha carreira de programação (até agora)

Lição aprendida

Muitos têm certeza de que um erro tão grave certamente custará a demissão do culpado, mas não é assim: em primeiro lugar, todos os programadores cometem erros e, em segundo lugar, raramente cometem o mesmo erro duas vezes.

Na verdade, tenho um amigo programador que era um engenheiro brilhante e foi demitido por cometer um único erro. Depois disso, foi contratado pelo Google (e logo promovido) - falou honestamente sobre o erro que cometeu em uma entrevista, e não foi considerado fatal.

Veja o que contar sobre Thomas Watson, o lendário chefe da IBM:

Uma ordem governamental no valor de cerca de um milhão de dólares foi anunciada. A IBM Corporation - ou melhor, Thomas Watson Sr. pessoalmente - realmente queria consegui-lo. Infelizmente, o representante de vendas não conseguiu fazer isso e a IBM perdeu a licitação. No dia seguinte, esse funcionário foi ao escritório do Sr. Watson e colocou um envelope em sua mesa. O Sr. Watson nem se preocupou em olhar - ele estava esperando por um funcionário e sabia que era uma carta de demissão.

Watson perguntou o que deu errado.

O representante comercial falou detalhadamente sobre o andamento da licitação. Ele citou erros cometidos que poderiam ter sido evitados. Finalmente, ele disse: “Sr. Watson, obrigado por me deixar explicar. Eu sei o quanto precisávamos desse pedido. Eu sei o quanto ele foi importante”, e se preparou para sair.

Watson aproximou-se dele na porta, olhou-o nos olhos e devolveu o envelope com as palavras: “Como posso deixar você ir? Acabei de investir um milhão de dólares na sua educação.

Tenho uma camiseta que diz: “Se você realmente aprende com os erros, então já sou um mestre”. Na verdade, quando se trata de erros, sou doutor em ciências.

Primeiro lugar: API App Inventor

Erros verdadeiramente terríveis afetam um grande número de usuários, tornam-se de conhecimento público, demoram muito para serem corrigidos e são cometidos por aqueles que não poderiam tê-los cometido. Meu maior erro se enquadra em todos esses critérios.

Quanto pior melhor

Eu leio ensaio de Richard Gabriel sobre essa abordagem na década de XNUMX, quando era estudante de pós-graduação, e gosto tanto que pergunto isso aos meus alunos. Se você não se lembra bem, refresque a memória, é pequeno. Este ensaio contrasta o desejo de “fazer certo” e a abordagem “pior é melhor” de muitas maneiras, incluindo a simplicidade.

Como deveria ser: o design deve ser simples na implementação e na interface. A simplicidade da interface é mais importante do que a simplicidade de implementação.

Quanto pior, melhor: o design deve ser simples na implementação e na interface. A simplicidade de implementação é mais importante que a simplicidade da interface.

Vamos esquecer isso por um minuto. Infelizmente, esqueci disso por muitos anos.

Aplicativo Inventor

Enquanto trabalhava no Google, fiz parte da equipe Aplicativo Inventor, um ambiente de desenvolvimento on-line de arrastar e soltar para aspirantes a desenvolvedores Android. Era 2009 e estávamos com pressa de lançar a versão alfa a tempo para que no verão pudéssemos ministrar master classes para professores que pudessem usar o meio ambiente ao ensinar no outono. Ofereci-me para implementar sprites, nostálgico de como costumava escrever jogos na TI-99/4. Para quem não sabe, um sprite é um objeto gráfico bidimensional que pode se mover e interagir com outros elementos do software. Exemplos de sprites incluem naves espaciais, asteróides, bolinhas de gude e raquetes.

Implementamos o App Inventor orientado a objetos em Java, então há apenas um monte de objetos lá. Como bolas e sprites se comportam de maneira muito semelhante, criei uma classe abstrata de sprite com propriedades (campos) X, Y, Velocidade (velocidade) e Rumo (direção). Eles tinham os mesmos métodos para detectar colisões, ricochetear nas bordas da tela, etc.

A principal diferença entre uma bola e um sprite é exatamente o que é desenhado - um círculo preenchido ou uma varredura. Como implementei os sprites primeiro, era lógico especificar as coordenadas x e y do canto superior esquerdo de onde a imagem estava localizada.

Os erros mais embaraçosos da minha carreira de programação (até agora)
Depois que os sprites estavam funcionando, decidi que poderia implementar objetos bola com muito pouco código. O único problema foi que segui o caminho mais simples (do ponto de vista do implementador), indicando as coordenadas x e y do canto superior esquerdo do contorno que enquadra a bola.

Os erros mais embaraçosos da minha carreira de programação (até agora)
Na verdade, era necessário indicar as coordenadas x e y do centro do círculo, como ensinado em qualquer livro didático de matemática e em qualquer outra fonte que mencione círculos.

Os erros mais embaraçosos da minha carreira de programação (até agora)
Ao contrário dos meus erros anteriores, este afetou não apenas meus colegas, mas também milhões de usuários do App Inventor. Muitos deles eram crianças ou completamente novos em programação. Eles tiveram que realizar muitas etapas desnecessárias ao trabalhar em cada aplicação em que a bola estava presente. Se me lembro dos meus outros erros com risadas, então este me faz suar até hoje.

Finalmente corrigi esse bug recentemente, dez anos depois. “Corrigido”, não “consertado”, porque como diz Joshua Bloch, APIs são eternas. Incapazes de fazer alterações que afetariam os programas existentes, adicionamos a propriedade OriginAtCenter com o valor false em programas antigos e true em todos os futuros. Os usuários podem fazer uma pergunta lógica: quem pensou em colocar o ponto de partida em algum lugar diferente do centro. A quem? Para um programador que estava com preguiça de criar uma API normal há dez anos.

Lições aprendidas

Ao trabalhar em APIs (o que quase todo programador às vezes precisa fazer), você deve seguir os melhores conselhos descritos no vídeo de Joshua Bloch "Como criar uma boa API e por que ela é tão importante" ou nesta pequena lista:

  • Uma API pode trazer grandes benefícios e grandes danos.. Uma boa API cria clientes recorrentes. O ruim se torna seu eterno pesadelo.
  • APIs públicas, como diamantes, duram para sempre. Dê tudo de si: nunca haverá outra chance de fazer tudo certo.
  • Os esboços da API devem ser breves — uma página com assinaturas e descrições de classes e métodos, ocupando no máximo uma linha. Isso permitirá que você reestruture facilmente a API caso ela não fique perfeita na primeira vez.
  • Descrever casos de usoantes de implementar a API ou mesmo trabalhar em sua especificação. Dessa forma, você evitará implementar e especificar uma API completamente não funcional.

Se eu tivesse escrito pelo menos uma breve sinopse com um roteiro artificial, provavelmente teria identificado o erro e corrigido. Caso contrário, um dos meus colegas definitivamente o faria. Qualquer decisão que tenha consequências de longo alcance precisa ser pensada durante pelo menos um dia (isto não se aplica apenas à programação).

O título do ensaio de Richard Gabriel, "Pior é melhor", refere-se à vantagem de ser o primeiro a chegar ao mercado - mesmo com um produto imperfeito - enquanto outra pessoa passa uma eternidade perseguindo o produto perfeito. Refletindo sobre o código do sprite, percebo que nem precisei escrever mais código para acertar. O que quer que se diga, eu estava redondamente enganado.

Conclusão

Os programadores cometem erros todos os dias, seja escrevendo códigos com bugs ou não querendo tentar algo que melhore suas habilidades e produtividade. Claro, você pode ser um programador sem cometer erros tão graves como eu cometi. Mas é impossível se tornar um bom programador sem reconhecer os seus erros e aprender com eles.

Constantemente encontro alunos que sentem que cometem muitos erros e, portanto, não estão preparados para programar. Eu sei o quão comum é a síndrome do impostor em TI. Espero que você aprenda as lições que listei - mas lembre-se da principal: cada um de nós comete erros - embaraçosos, engraçados, terríveis. Ficarei surpreso e chateado se no futuro não tiver material suficiente para continuar o artigo.

Fonte: habr.com

Adicionar um comentário