Os erros mais vergonhosos da minha carreira como programador (no momento)


Como diz o ditado, se você não tem vergonha do seu código antigo, não cresce como programador - e eu concordo com essa opinião. Comecei a programar para entretenimento há mais de 40 anos e há 30 anos profissionalmente, por isso cometi muitos erros. Como professor de ciência da computação, ensino meus alunos a aprender com os erros - deles, meus, estranhos. Acho que é hora de falar sobre meus erros para não perder a modéstia. Espero que alguém ache útil.

Terceiro lugar - compilador Microsoft C


Meu professor da escola acreditava que “Romeu e Julieta” não pode ser considerado uma tragédia, porque os heróis não tinham culpa trágica - eles apenas se comportavam estupidamente, como deveriam os adolescentes. Então não concordei com ele, mas agora vejo na sua opinião um núcleo racional - especialmente em relação à programação.

Quando terminei meu segundo ano no MIT, eu era jovem e inexperiente, tanto na vida quanto na programação. No verão, pratiquei na Microsoft, na equipe do compilador C. No início, participei de uma rotina como o suporte a criação de perfil e, em seguida, fui encarregado do trabalho da parte mais divertida (como eu pensava) da otimização de compilador - back-end. Em particular, eu tive que melhorar o código x86 para instruções de ramificação.

Determinado a escrever o código de máquina ideal para todos os casos possíveis, corri para a piscina com a cabeça. Se a densidade de distribuição dos valores era alta, eu os inseri na tabela de transição . Se eles tivessem um divisor comum, eu o usava para tornar a tabela mais densa (mas apenas se a divisão pudesse ser feita usando um deslocamento de bit ). Quando todos os valores eram potências de dois, realizei outra otimização. Se o conjunto de valores não atender às minhas condições, divido-o em vários casos otimizáveis ​​e usei o código já otimizado.

Foi um pesadelo. Depois de muitos anos, eles me disseram que o programador que herdou meu código me odiava.


Lição aprendida


Como David Patterson e John Hennessy escrevem no livro Computer Architecture and Computer Systems Design, um dos principais princípios da arquitetura e do desenvolvimento é que, em geral, tudo funciona o mais rápido possível.

Acelerar casos comuns aumentará a produtividade com mais eficiência do que otimizar casos raros. Ironicamente, casos comuns são geralmente mais simples que raros. Esse conselho lógico implica que você saiba qual caso considerar comum - e isso só é possível através de testes e medições cuidadosas.

Em minha defesa, posso dizer que tentei descobrir como eram os operadores de ramificação na prática (por exemplo, quantas ramificações existiam e como constantes eram distribuídas), mas em 1988 essas informações não estavam disponíveis. No entanto, eu não deveria ter adicionado casos especiais sempre que o compilador atual não pudesse gerar o código ideal para o exemplo artificial que eu criei.

Eu precisava ligar para um desenvolvedor experiente e com ele para pensar quais eram os casos comuns e lidar especificamente com eles. Eu escreveria menos código, mas isso é bom. Como escreveu Jeff Atwood, fundador do Stack Overflow, o pior inimigo do programador é o programador:

Eu sei que você tem as melhores intenções, como todos nós temos. Criamos programas e adoramos escrever código. Então, estamos dispostos. Achamos que qualquer problema pode ser resolvido com fita adesiva, uma muleta caseira e uma pitada de código. Não importa o quão doloroso seja para os codificadores admitirem isso, o melhor código é aquele que não existe. Cada nova linha precisa de depuração e suporte, precisa ser entendida. Ao adicionar novo código, você deve fazê-lo com relutância e nojo, porque todas as outras opções foram esgotadas. Muitos programadores escrevem muito código, tornando-o nosso inimigo.

Se eu escrevesse um código mais simples que abordasse casos comuns, seria muito mais fácil atualizar se necessário. Deixei uma bagunça que ninguém queria mexer.


Segundo lugar: publicidade em mídia social


Quando trabalhei no Google em publicidade em mídia social (lembra do Myspace?), Escrevi em C ++ algo como isto:

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 deve ser j, não i. O teste de unidade não revelou um erro, nem meu revisor percebeu. Foi feito um lançamento e uma noite meu código foi para o servidor e travou todos os computadores no data center.

Nada terrível aconteceu. Nenhum deles quebrou, porque antes do lançamento global, o código era testado no mesmo data center. A menos que os engenheiros do SRE parem de jogar bilhar por um tempo e façam uma pequena reversão. Na manhã seguinte, recebi um email com um despejo de memória, corrigi o código e adicionei testes de unidade que revelariam um erro. Desde que segui o protocolo - caso contrário, meu código simplesmente não seria executado - não havia outros problemas.


Lição aprendida


Muitos estão convencidos de que um erro tão grande é necessariamente o culpado da demissão, mas não é assim: primeiro, todos os programadores estão errados e, segundo, raramente cometem um erro duas vezes.

Na verdade, eu tenho um programador familiar - um engenheiro brilhante, que foi demitido por um único erro. Depois disso, ele foi contratado pelo Google (e logo promovido) - ele falou honestamente sobre o erro cometido na entrevista, e ela não foi considerada fatal.

Eis o que Thomas Watson, o lendário chefe da IBM, tem a dizer:

Foi anunciada uma ordem do governo no valor de um milhão de dólares. A IBM Corporation - ou melhor, pessoalmente, Thomas Watson Sr. - realmente queria obtê-lo. Infelizmente, o representante de vendas não pôde fazer isso e a IBM perdeu a licitação. No dia seguinte, esse oficial veio ao escritório de Watson e colocou um envelope em sua mesa. Watson nem olhou para ele - ele estava esperando um funcionário e sabia que era uma carta de demissão.

Watson perguntou o que deu errado.

O representante de vendas descreveu detalhadamente o andamento da licitação. Ele chamou os erros que poderiam ter sido evitados. Por fim, ele disse: “Sr. Watson, obrigado por me deixar explicar. Eu sei o quanto precisávamos dessa ordem. Eu sei o quão importante ele era ”e estava prestes a sair.

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

Eu tenho uma camiseta que diz: "Se você realmente aprende com os erros, já sou mestre." De fato, no que diz respeito aos erros, sou doutor em ciências.

Primeiro lugar: API do App Inventor


Erros verdadeiramente assustadores afetam um grande número de usuários, se tornam públicos, são corrigidos e cometidos por aqueles que não os permitiam. Meu maior erro satisfaz todos esses critérios.

Quanto pior melhor


Eu li o ensaio de Richard Gabriel sobre essa abordagem nos anos 90 como estudante de graduação e gosto tanto que peço aos meus alunos. Se você não se lembra bem, atualize sua memória, ela é pequena. Neste ensaio, o desejo de "fazer o certo" e a abordagem "quanto pior, melhor" são contrastados de várias maneiras, incluindo a simplicidade.

Como deveria: o design deve ser fácil de implementar e fazer interface. A simplicidade da interface é mais importante que a simplicidade de implementação.

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

Esqueça por um momento. Infelizmente, esqueci-me disso por muitos anos.

Inventor de aplicativos


Enquanto estava no Google, fiz parte da equipe do App Inventor , um ambiente de desenvolvimento on-line com suporte ao arrastar e soltar para desenvolvedores iniciantes do Android. Era 2009 e estávamos com pressa de lançar a versão alfa a tempo, para que, no verão, pudéssemos dar aulas de mestrado para professores que pudessem usar o ambiente de aprendizado no outono. Ofereci-me para implementar sprites, nostálgicos pela forma como costumava escrever jogos na TI-99/4. Para quem não conhece: um sprite é um objeto gráfico bidimensional que pode se mover e interagir com outros elementos do programa. Exemplos de sprites são naves espaciais, asteróides, bolas e raquetes.

Implementamos o App Inventor orientado a objetos em Java, portanto, existem apenas alguns objetos. Como bolas e sprites se comportam de maneira muito semelhante, criei uma classe abstrata de sprites com propriedades (campos) X, Y, Velocidade (velocidade) e Direção (direção). Eles tinham os mesmos métodos para detectar colisões, quicar na borda da tela etc.

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


Quando os sprites começaram a funcionar, decidi que você poderia implementar objetos de bola com muito pouco código. O único problema foi que eu segui o caminho mais simples (do ponto de vista do implementador), indicando as coordenadas x e y do canto superior esquerdo do contorno ao redor da bola.


De fato, era necessário indicar as coordenadas x e y do centro do círculo, como ensinam qualquer livro didático de matemática e qualquer outra fonte que mencione os círculos.


Ao contrário dos meus erros anteriores, não apenas meus colegas, mas também milhões de usuários do App Inventor sofreram com isso. Muitos deles eram crianças ou completamente novos em programação. Eles tiveram que executar muitas ações desnecessárias ao trabalhar em cada aplicativo em que a bola estava presente. Se o resto dos meus erros me lembro com uma risada, então isso me deixa suada hoje.

Finalmente consertei esse erro apenas recentemente, dez anos depois. "Remendado", mas não "corrigido", porque, como Joshua Bloch diz, as APIs são eternas. Não é possível fazer alterações que afetariam os programas existentes, adicionamos a propriedade OriginAtCenter com false em programas antigos e true em todos os futuros. Os usuários podem fazer uma pergunta legítima a quem ocorreu a alguém localizar um ponto de referência em algum lugar que não seja o centro. Para quem? Um programador com preguiça de criar uma API normal há dez anos.

Lições aprendidas


Ao trabalhar em uma API (que quase todos os programadores às vezes precisam fazer), siga as melhores dicas descritas no vídeo de Joshua Bloch " Como criar uma boa API e por que ela é tão importante " ou nesta lista curta :

  • A API pode ser de grande benefício para você, além de causar grandes danos . Uma boa API cria clientes fiéis. O mal se torna seu pesadelo eterno.
  • APIs públicas, como diamantes, são eternas . Faça o seu melhor: não há outra chance de fazer tudo como deveria.
  • Os agendamentos para a API devem ser curtos - uma página com assinaturas e descrições de classe e método que não levam mais que uma linha. Isso permitirá que você reestruture facilmente a API, se a primeira vez que ela sair não for perfeita.
  • Descreva os cenários de uso antes de implementar a API e até trabalhar sua especificação. Dessa forma, você evita a implementação e a especificação de uma API totalmente não funcional.

Se eu escrevesse pelo menos uma pequena sinopse com um script artificial, provavelmente teria identificado um erro e o corrigido. Caso contrário, um dos meus colegas definitivamente o faria. Qualquer decisão que tenha conseqüências de longo alcance deve ser considerada pelo menos um dia (isso se aplica não apenas à programação).

O título do ensaio de Richard Gabriel, "O pior, o melhor", indica a vantagem que vem em primeiro lugar no mercado - mesmo com um produto imperfeito - enquanto outra pessoa persegue o ideal há séculos. Pensando no código do sprite, entendo que nem precisei escrever mais código para fazer tudo como deveria. Goste ou não, eu estava totalmente enganado.

Conclusão


Os programadores cometem erros todos os dias - seja escrevendo código com bugs ou não querendo tentar algo que aumentará sua habilidade e produtividade. Claro, você pode ser um programador e não permitir erros tão graves quanto eu. Mas tornar-se um bom programador sem perceber seus erros e não aprender com eles é impossível.

Eu sempre encontro alunos que pensam que cometem muitos erros e, portanto, não são projetados para programação. 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 - vergonhoso, engraçado e assustador. Ficarei surpreso e chateado se, no futuro, não tiver material suficiente para continuar o artigo.

Source: https://habr.com/ru/post/pt475662/


All Articles