Se você perguntar aos programadores por que eles devem escrever um código limpo, a resposta número um que você obtém é a manutenção. Enquanto estiver na minha lista, meu principal motivo é mais imediato e menos altruísta: não sei dizer se meu novo código está correto se estiver muito sujo. Acho que me concentrei tanto nas funções individuais e nas linhas de código que, quando termino o meu primeiro rascunho e passo para trás para olhar para o cenário geral novamente, às vezes não se encaixa muito bem. Passar uma ou duas horas refatorando para limpeza freqüentemente descobre erros de copiar / colar ou condições de contorno que eram muito difíceis de detectar no rascunho.
No entanto, algumas pessoas acham ocasionalmente aceitável fazer o check-in intencionalmente de códigos sujos no interesse do envio de software, com um plano para "limpá-lo mais tarde". Existe alguma técnica praticável que lhes dê confiança na correção de seu código quando a legibilidade for menor que o ideal? Vale a pena tentar desenvolver uma habilidade? Ou a falta de confiança no código é algo que algumas pessoas acham mais fácil de aceitar?
How do quick & dirty programmers know they got it right?
Porque ele funciona :)Respostas:
O código provavelmente não está certo.
No entanto, isso não importa.
Rápido e sujo pode ser o caminho certo a seguir em situações em que:
Às vezes, não é importante que o código seja robusto e lide com todas as entradas concebíveis. Às vezes, ele só precisa manipular os dados conhecidos que você tem em mãos.
Nessa situação, se os testes de unidade ajudarem você a escrever o código mais rapidamente (esse é o meu caso), use-os. Caso contrário, código rápido e sujo, faça o trabalho. Bugs que não disparam não importam. Os erros que você corrige ou soluciona em tempo real não importam.
O que é absolutamente vital é que você não faça um diagnóstico errado dessas situações. Se você codifica rápido e sujo porque o código será usado apenas uma vez, alguém decide reutilizar o código em algum projeto que mereça melhor código, esse código mereceu mais cuidado.
fonte
Eles não. Atualmente, estou trabalhando em uma base de código criada por programadores "rápidos e sujos" que "limpariam mais tarde". Eles se foram há muito tempo, e o código continua vivo, abrindo caminho para o esquecimento. Os codificadores de cowboy , em geral, simplesmente não entendem todos os modos de falha em potencial que seu software pode ter e não entendem os riscos aos quais estão expondo a empresa (e clientes).
fonte
Certo, correndo o risco de ser uma isca completa, vou "defender os diabos" da visão oposta.
Proponho que os desenvolvedores tendam a se preocupar demais com coisas como prática adequada e limpeza de código. Sugiro que, embora essas coisas sejam importantes, nada disso importa se você nunca enviar .
Qualquer pessoa que esteja neste ramo há algum tempo provavelmente concordaria que seria possível mexer com um pedaço de software mais ou menos indefinidamente. Duke Nukem Forever, meus amigos. Chega um momento em que esse recurso interessante ou, oh, que trabalho de refatoração tão urgente deveria ser deixado de lado e a coisa deveria ser chamada de CONCLUÍDA.
Eu lutei com meus colegas sobre isso muitas vezes. SEMPRE há mais um ajuste, outra coisa que "deveria" ser feita para que estivesse "certa". Você sempre pode encontrar isso. Em algum momento, no mundo real, o suficiente é suficiente. Nenhum software de remessa do mundo real é perfeito. Nenhum. Na melhor das hipóteses, é bom o suficiente.
fonte
Tais programadores quase nunca sabem que acertaram, apenas acreditam nisso . E a diferença pode não ser fácil de perceber.
Lembro-me de como costumava programar antes de aprender sobre o teste de unidade. E lembro-me daquele sentimento de confiança em um nível totalmente diferente depois de executar meu primeiro conjunto decente de testes de unidade. Eu não sabia que esse nível de confiança no meu código existia antes.
Para quem não tem essa experiência, é impossível explicar a diferença. Assim, eles podem continuar desenvolvendo-se no modo de codificar e orar por toda a vida, benevolente (e ignorantemente) acreditando que estão fazendo o melhor possível, considerando as circunstâncias.
Dito isto, de fato pode haver grandes programadores e casos excepcionais, quando alguém realmente consegue manter todo o espaço do problema em sua mente, em um estado completo de fluxo. Eu experimentei momentos raros como este, quando eu sabia perfeitamente o que escrever, o código simplesmente saiu de mim sem esforço, eu podia prever todos os casos especiais e condições de contorno, e o código resultante simplesmente funcionou . Não tenho dúvida de que existem gênios de programação por aí que podem permanecer nesse estado de fluxo por longos períodos ou até a maior parte do tempo, e o que eles produzem é um código bonito, aparentemente sem esforço. Acho que essas pessoas podem não ter necessidade de escrever testes de unidade insignificantes para verificar o que já sabem. E se você é realmente um gênio, pode ser bom (embora, mesmo assim, você não esteja presente nesse projeto para sempre e pense em seus sucessores ...). Mas se não ...
E vamos ser sinceros, é provável que você não esteja. Eu, por mim, sei que não sou. Eu tive alguns raros momentos de fluxo - e inúmeras horas de tristeza e tristeza, geralmente causadas por meus próprios erros. É melhor ser honesto e realista. De fato, acredito que os maiores programadores estão plenamente conscientes de sua própria falibilidade e erros passados, portanto desenvolveram conscientemente o hábito de checar suas suposições e escrever esses pequenos testes de unidade, para se manterem seguros. ( "Eu não sou um grande programador - apenas um bom programador com bons hábitos." - Kent Beck.)
fonte
Testes unitários . É a única maneira de confiar em qualquer código (sujo ou não).
Em uma nota lateral;
fonte
É bom aprender a aceitar que nenhum sistema de software de complexidade razoável será perfeito, independentemente da quantidade de testes de unidade e ajustes de código. Algum grau de caos e vulnerabilidade ao inesperado sempre espreita dentro do código. Isso não significa que não se deva tentar produzir um bom código ou realizar testes de unidade. Estes são, obviamente, importantes. Há um equilíbrio que precisa ser buscado e isso varia de projeto para projeto.
A habilidade a ser desenvolvida é a compreensão de qual nível de 'perfeição' precisa ser usado para um projeto específico. Por exemplo, se você estiver escrevendo um aplicativo de registros médicos eletrônicos com um cronograma de projeto de 12 meses, dedicará muito mais tempo aos testes e garantirá a manutenção do seu código do que faria em um aplicativo Web de registro de conferência único que deve ser implantado até sexta-feira. Os problemas chegam quando alguém que faz o aplicativo EMR fica desleixado ou o aplicativo de registro não é implantado a tempo porque o programador está muito ocupado ajustando o código.
fonte
Rápido e sujo está perfeitamente bem dentro de um subsistema . Se você tem uma interface bem definida entre sua porcaria e o resto do sistema, e um bom conjunto de testes de unidade que verificam se seu código feio, rápido e sujo faz a coisa certa, pode ser perfeitamente adequado.
Por exemplo, talvez você tenha algum truque hediondo de expressões regulares e desvios de bytes para analisar alguns arquivos provenientes de terceiros. E suponha que você tenha um teste dizendo que o resultado obtido da análise de arquivos de exemplo é o que você espera. Você poderia limpar isso para poder ... Não sei, reagir mais rapidamente quando um terceiro alterar um formato de arquivo? Isso simplesmente não acontece com frequência suficiente. O mais provável é que eles mudem para uma API completamente nova e você jogará fora o analisador antigo e conectará um novo que esteja em conformidade com a mesma API e pronto, pronto.
Onde a rapidez e a sujeira se tornam um problema é quando sua arquitetura é rápida e suja. Seu objeto de domínio principal precisa ser bem pensado e suas interfaces, mas as bordas do seu sistema geralmente podem ser confusas sem precisar pagar o preço.
fonte
Aqui está uma história sobre um programador rápido e sujo que eu conheço.
Conheço uma pessoa que considera testes de unidade uma perda de tempo. Depois de muita discussão, ele finalmente escreveu uma. Consistia em um método longo polvilhado com && e || e retornou um booleano para assertTrue. A declaração abrange 20 linhas. Por outro lado, ele escreveu uma classe em que todo método tinha uma linha e o principal tinha mais de 1000 linhas sem espaços em branco. Era uma parede de texto. Quando revi seu código e inseri algumas novas linhas, ele perguntou 'por que'. Eu disse 'Por causa da legibilidade'. Ele suspirou e os apagou. Ele colocou um comentário no topo "Não toque, funciona!"
A última vez que conversei com ele, ele codificou um site para uma empresa. Ele estava tentando encontrar um bug. Ele passou os últimos 3 dias fazendo isso durante 8 horas por dia. Um pouco mais tarde, falei com ele novamente, e seu companheiro de equipe mudou o valor de um literal e não o atualizou em nenhum outro lugar. Não foi uma constante. Então ele mudou os outros literais também, para que seu bug fosse corrigido. Ele reclamou do código de espaguete de seu companheiro de equipe. Ele me disse: 'Haha, nem todos sabemos como é ficar acordado a noite toda com o depurador, sem dormir por causa de um bug desagradável "Ele acha que isso é algo realmente bom que os programadores fazem e realmente se sente bem com isso.
Além disso, ele acha que ler livros e blogs de programação é inútil. Ele diz: 'apenas comece a programar'. Ele faz isso há 12 anos e acha que é um excelente programador. / facepalm
Aqui está um pouco mais.
Outra vez, estávamos escrevendo uma classe DatabaseManager para nosso aplicativo Web. Ele colocou todas as chamadas de banco de dados nele. Era uma aula de Deus com mais de 50 métodos para todas as coisas imagináveis. Sugeri que dividíssemos em subclasses porque nem todo controlador precisa conhecer todos os métodos de banco de dados. Ele discordou, porque era 'fácil' ter apenas uma classe para todo o banco de dados e era 'rápido' adicionar um novo método sempre que precisávamos. No final, o DatabaseManager tinha mais de 100 métodos públicos, da autenticação do usuário à classificação dos locais arqueológicos.
fonte
Minha lição para evitar sujeira e rapidez foi quando eu tinha seis meses para entregar o que era estimado (subestimado) como um ano de trabalho. Decidi pesquisar metodologias antes de começar o trabalho. No final, investi três meses de pesquisa e consegui entregar nos três meses restantes.
Obtivemos grandes ganhos ao identificar funcionalidades comuns e construir as bibliotecas necessárias para lidar com esses requisitos. Ainda vejo codificadores escrevendo seu próprio código quando há rotinas de bibliotecas disponíveis. Esses codificadores geralmente reescrevem ou, na melhor das hipóteses, recortam e colam o mesmo código quando precisam resolver o mesmo problema posteriormente. As correções de erros invariavelmente capturam apenas algumas cópias do código.
Um desenvolvedor deu uma resposta reveladora quando lhe pedi para usar o código da biblioteca: "Isso não é trapaça? Eu tive que escrever todo o meu próprio código na escola".
fonte
Em alguns casos, acho que pode haver um grande conjunto de testes de regressão que encontrará "todos" erros e verificará o comportamento, permitindo assim uma técnica de codificação rápida e suja. Mas, principalmente, é apenas uma questão de planejamento ruim do projeto e um gerente que acha mais importante fazê-lo do que fazê-lo corretamente.
E esqueça "limpe depois", isso nunca acontece. Nos raros casos em que isso acontece, o programador terá esquecido a maior parte do código, tornando o trabalho muito mais caro do que se ele tivesse feito certo da primeira vez.
fonte
O produto é enviado.
O código não existe no vácuo. Sofri incontáveis lutas contra as conseqüências da codificação rápida, suja e de caubói. Mas, às vezes, terminar o produto é a prioridade, não descobrir como escrever o melhor código. Por fim, se o produto for enviado e funcionar bem o suficiente, os usuários e clientes não saberão nem se importarão com o quão "ruim" é o código, e admitirei que houve momentos em que não me importei em "obtê-lo". certo "desde que eu o peguei pela porta.
Sim, isso em uma questão organizacional e "nunca deve acontecer". Mas se você estiver escrevendo código em uma organização que é mal gerenciada e fortemente orientada por prazos, no nível do programador individual, as opções são limitadas.
fonte
Eu não acho que eles possam dizer honestamente que acertaram se não for fácil de manter. Se eles admitirem que precisam "limpá-lo mais tarde", provavelmente haverá algo que não tenham pensado o suficiente. Testá-lo completamente só descobrirá verdadeiramente quaisquer problemas com o código sujo.
Eu, pessoalmente, não pretendia desenvolver a habilidade de "escrever código sujo" e ter confiança em sua correção. Prefiro escrever o código adequado na primeira vez.
fonte
Como eles sabem que acertaram? Testar é a resposta simples.
Se o código deles tiver sido testado exaustivamente por uma boa equipe de controle de qualidade e for aprovado, eu diria que eles acertaram.
Escrever código rápido e sujo não é algo que deva ser feito como um hábito, mas ao mesmo tempo há ocasiões em que você pode gastar 20 minutos escrevendo código que pode ser classificado como sujo ou 4 horas refatorando muito código para fazê-lo corretamente. No mundo dos negócios, às vezes 20 minutos é tudo o que está disponível para fazer o trabalho e, quando você enfrenta prazos rápidos e sujos, pode ser a única opção.
Eu já estive nos dois extremos disso, tive que corrigir o código sujo e tive que escrever o meu para contornar as limitações de um sistema em que estava desenvolvendo. Diria que confiava no código que escrevi porque, embora estivesse sujo e um pouco hackeado, às vezes eu tinha certeza de que foi completamente testado e que havia um monte de manipulação de erros, por isso, se algo desse errado, não destruiria o resto do sistema.
Quando olhamos para esses programadores rápidos e sujos, precisamos lembrar de uma coisa: um cliente geralmente não paga até ter o produto, se ele for enviado e eles forem para o teste UAT e encontrarem os bugs do código rápido e sujo. muito menos provável que eles se soltem quando tiverem um produto quase funcionando na frente deles, mas se eles não tiverem nada e você estiver dizendo a eles "você o terá em breve, estamos apenas consertando x" ou "foi adiado porque tivemos que obter y funcionando perfeitamente ", é mais provável que desista e vá com um concorrente.
Obviamente, como esta imagem demonstra, ninguém deve subestimar o perigo de código rápido e sujo!
fonte
Acho que você nem deveria começar a seguir esse caminho. Rápido e sujo pode dar a você o benefício temporal de terminar mais rapidamente, mas você sempre paga dez vezes mais por fazer isso no final.
fonte
Na minha opinião, aprender a julgar o código de Q&D pela correção não é uma habilidade que vale a pena desenvolver, porque é apenas uma má prática. Aqui está o porquê:
Eu não acho que "rápido e sujo" e "melhores práticas" andem juntos. Muitos codificadores (inclusive eu) criaram códigos rápidos e sujos como resultado de uma distorção nas restrições triplas . Quando eu tive que fazer isso, geralmente era o resultado da fluência do escopo combinada com um prazo cada vez mais próximo. Eu sabia que o código que estava verificando era sugado, mas cuspia as saídas adequadas, dado um conjunto de entradas. Muito importante para as partes interessadas, enviamos a tempo.
Uma olhada no CHAOS Report original deixa bem claro que Q&D não é uma boa ideia e reduzirá o orçamento mais tarde (em manutenção ou durante a expansão). Aprender a julgar se o código de Q&D está correto é uma perda de tempo. Como Peter Drucker disse: "Não há nada tão inútil quanto fazer com eficiência aquilo que não deve ser feito".
fonte
"Sujo" significa coisas diferentes para pessoas diferentes. Para mim, significa principalmente confiar em coisas nas quais você sabe que provavelmente não deveria confiar, mas nas quais também sabe que pode esperar trabalhar no curto prazo. Exemplos: supondo que um botão tenha 20 pixels de altura em vez de calcular a altura; codificar permanentemente um endereço IP em vez de resolver um nome; contando com uma matriz a ser classificada porque você sabe que é, mesmo que o método que fornece a matriz não a garanta.
O código sujo é frágil - você pode testá-lo e saber que funciona agora , mas é uma aposta muito boa que ele quebre em algum momento no futuro (ou então force todos a andar com casca de ovo por medo de quebrá-lo).
fonte
Correndo o risco de parecer um pouco polêmico, eu argumentaria que ninguém SABE realmente que seu código é 100% correto e 100% sem erros. Mesmo quando você tem uma cobertura de teste realmente boa e aplica rigorosamente boas práticas de BDD / TDD, ainda é possível desenvolver código que contém erros e sim que podem até conter efeitos colaterais!
Escrever um código e supor que ele funcione implica em excesso de confiança por parte do senso do desenvolvedor sobre as próprias habilidades do desenvolvedor e que, quando surgirem problemas (o que inevitavelmente o farão), o esforço para depurar e manter o código será caro, especialmente se outro desenvolvedor precisar para manter o código posteriormente. A diferença real é feita aplicando boas práticas de engenharia de software, que garantem que você possa ter confiança real de que seu código provavelmente funcionará a maior parte do tempo e que, se encontrar um erro, é mais provável que seja mais fácil depurar e muito menos dispendioso para alterar e manter, independentemente da pessoa que trabalha nesse código posteriormente.
O ponto mais importante é que um código bem fatorado e testado permitirá que OUTROS tenham confiança em seu código, o que é, na maioria dos casos, mais importante que sua própria confiança.
fonte
Se o código sujo for bem testado, ele poderá ser confiável. O problema é que esse código sujo de teste de unidade geralmente é muito difícil e complicado. É por isso que TDD é tão bom; revela e remove a sujeira e os cheiros. Além disso, o teste de unidade geralmente é a primeira coisa a sofrer com o tempo gasto. Portanto, se o cara mais limpo já criou o código mais limpo que ele já fez, eu ainda não confiava nem um pouco, se ele omitisse os testes de unidade devido à presunção de tempo.
fonte
Bons programadores (Rápido e Sujo ou não) não têm a arrogância de assumir que estão certos. Eles assumem que todos os grandes sistemas têm bugs e falhas, mas que em algum momento podem ser testados e revisados o suficiente para ter um risco suficientemente baixo ou um custo de falha suficientemente baixo que o código possa fornecer.
Então, por que esses programadores, chamados de Quick & Dirty, existem? Minha hipótese é a seleção darwiniana. Os programadores que enviam códigos viáveis rapidamente, ocasionalmente enviam antes que a competição seja lançada, ou o orçamento acabe, ou a empresa vá à falência. Portanto, suas empresas ainda estão no negócio, empregando novos programadores para reclamar da bagunça que precisa ser limpa. Os chamados códigos limpos também são fornecidos, mas não diferentemente o suficiente para levar os codificadores Quick & Dirty à extinção.
fonte
Provavelmente, pode-se pensar que uma parte não ideal de um código não faria diferença, devido à curta vida útil, pouco impacto nos negócios ou pouco tempo para fazê-lo. A resposta correta é que você realmente não sabe. Toda vez que ouço alguém dizendo que "esse é um recurso pequeno" ou "vamos torná-lo o mais rápido e simples possível" e gasto tempo insuficiente pensando no design certo, as duas únicas coisas que realmente ocorrem estão:
1-) O projeto aumenta e a motivação da equipe diminui, trabalhando no código cheio de "pontos". Nesse caso, o projeto provavelmente passará rapidamente para o caos.
2-) O projeto se torna conhecido como uma solução não ótima e seu uso começa a ser desencorajado, em favor de uma nova solução ou de uma refatoração que é tão cara quanto uma nova solução.
Tente sempre fazer o melhor código possível. Se você não tiver tempo suficiente, explique por que precisa de mais. Não se arrisque com trabalhos mal feitos. Seja sempre um profissional melhor. Ninguém pode puni-lo por isso, se você for razoável. Se o fizerem, não é onde você deveria trabalhar.
fonte
Discuta com o idoso e avalie o impacto das falhas, se houver. Por exemplo, uma situação em que você pode corrigir problemas leva 1 dia e um código robusto requer alterações de design e arquitetura, que podem levar de 4 a 6 meses + tempo de validação adicional para validar completamente todos os fluxos de trabalho que foram impactados com a alteração de design.
Temos que tomar uma decisão com base no Tempo + Capacidade + Prioridades na lista também. Uma boa discussão na equipe com idosos ou pessoas com maior experiência pode ajudar a chegar a uma decisão que melhor se adapta à equipe e à sua entrega.
O código limpo é a primeira e principal abordagem em que, como código sujo, para salvar as escalações, decisões de aprovação / não aprovação dos clientes, exibição de rolhas, reputação da organização em jogo e muito mais, onde o código sujo entra no código limpo.
fonte