You are on page 1of 398
Série de Robert C. Martin ~~ Codigo Limpo Habilidades Praticas do Agile Software Prefacio Um de nossos doces favoritos aqui na Dinamarca é 0 Ga-Jol, cujos fortes vapores de licorice s4o um complemento perfeito para nosso clima timido e, geralmente, frio, Parte do charme do Ga-Jol, para nos dinamarqueses, séo os dizeres sabios impressos em cada caixa. Comprei dois pacotes dessa iguaria essa manhi e nela veio este antigo ditado dinamarqués: Erlighed i sma ting er ikke nogen lille ting. “Honestidade em pequenas coisas no é uma coisa pequena”. Era um bom pressagio para com 0 que eu ja descjava dizer aqui. Pequenas coisas so importantes. Este ¢ um livro sobre preocupagdes modestas cujos valores esto longe de ser pequenos. Deus est nos detalhes, disse o arquiteto Ludwig Mies van der Rohe. Essa citag%o retoma, argumentos com contemporancos sobre o papel da arquitctura no desenvolvimento de software, especialmente no mundo Agile. Bob ¢ eu, as vezes, acabavamos engajados entusiasmadamente debatendo sobre este assunto. E sim, Mies van der Rohe atentava para os utilitarios ¢ as formas imemoriais de construgdo que fundamentam uma étima arquitetura. Por outro lado, cle também selecionava pessoalmente cada maganeta para cada casa que ele projetava. Por qué? Por que pequenas coisas sdo importantes. Em nosso “debate” sobre Desenvolvimento dirigido a testes (TDD, sigla em inglés), Bob € eu descobrimos que concordamos que a arquitetura do software possuir um lugar importante no desenvolvimento, embora provavelmente tenhamos perspectivas diferentes do significado exato disso. Essas diferengas so relativamente irrelevantes contudo, pois podemos admitir que profissionais responsaveis dedicam algum tempo para pensar ¢ planejar o inicio de um projeto. As nogées de desenvolvimento dirigido apenas por testes ¢ por cOdigos do final da década de 1990 ja nao existem mais. Mesmo assim, a atengao aos detalhes é um fundamento de profissionalismo ‘ainda mais critico do que qualquer visio maior. Primeiro, € por meio da pratica em pequenos trabalhos que profissionais adquirem proficiéncia e confianga para se aventurar nos maiores. Segundo, a menor parte de uma construgao desleixada, a porta que nao fecha direito ou o azulejo levemente torto do chao, ou mesmo uma mesa desarrumada, retiram completamente o charme do todo. E sobre isso que se trata 0 cédigo limpo. Ainda assim, a arquitetura é apenas uma metéfora para o desenvolvimento de software, especialmente para a parte que entrega o produto inicial no mesmo sentido que um arquiteto entrega uma construgio imaculada, Nessa época do Scrum e do Agile, o foco esta em colocar 0 produto rapidamente no mercado. Desejamos que a indistria funcione em velocidade maxima na producao de software. Essas fabricas humanas: programadores que pensam ¢ sentem que trabalham a partir das pendéncias de um produto ou do user story para criar o produto, A metdfora da fabricago estd mais forte do que nunca no pensamento. Os aspectos da produg&o da manufatura japonesa de automéveis, de um mundo voltado para a linha de montagem, inspiraram grande parte do Scrum. Ainda assim, mesmo na indistria automobilistica, a maior parte do trabalho nao esta na fabricag&o, mas na manuten¢&o — ou na prevengdo. Em software, 80% ou mais do que fazemos é chamado de “manutengao”: 0 ato de reparar. Em vez de abragar o tipico foco ocidental sobre a produgdo de bons softwares, deveriamos pensar mais como um pedreiro que conserta casas na industria de construgdo, ou um mec4nico de automéveis na area automotiva. O que 0 gerenciamento japonés tem a dizer sobre isso? Por volta de 1951, uma abordagem qualitativa chamada Manutengao Produtiva Total (TPM) surgiu no cenario japonés. Seu foco era na manutenc&o em vez da produgao. Um dos maiores fundamentos da TPM €0 conjunto dos chamados 5S principios. 5S ¢€ uma série de disciplinas—uso aqui o termo “disciplina” para fins educativos, Os 5S principios, na verdade, sao os fundamentos do Lean — outro jargao no cenério ocidental, e cada vez mais conhecida no mundo dos softwares. Esses prineipios nao s’o uma op¢&o. Assim como Uncle Bob diz em suas preliminares, a pratica de um bom software requer tal disciplina: foco, presenga de espirito c pensamento. Nem sempre é sobre fazer, sobre pressionar os equipamentos da fabrica para produzir em velocidade maxima. A filosofia dos 5S inclui os seguintes conceitos: Seiri, ou organizacao (pense em “ordenar”). Saber onde esto as coisas — usar abordagens como nomes adequados — é crucial. Acha que dar nome a identificadores nao ¢ importante? Leia proximos capitulos. Seiton, ou arrumacdo (pense em “sistematizar”). Ha um antigo ditado americano que diz: “Um lugar para tudo, ¢ tudo em scu lugar”. Um pedago de cédigo deve estar onde voeé espera encontra-lo — caso ndo esteja, refatore ¢ o coloque la. Seiso, ou limpeza (pensem em “polir”): manter 0 local de trabalho livre de fios pendurados, gordura, migalhas ¢ lixo. O que os autores falam aqui sobre encher seu cédigo com comentarios ¢ linhas de cédigos como comentarios que informa o passado ou os desejos para o futuro? Livre- se deles. Seiketsu, ou padronizago: a equipe concorda em manter o local de trabalho limpo. Vocé acha que este livro fala algo sobre ter um estilo de programagao consistente e uma série de priticas dentro da equipe? De onde vém tais padrdes? Continue a leitura. ‘Shutsuke, ou disciplina (autodisciplina). Isso significa ter disciplina para seguir as praticas e refletir frequentemente isso no trabalho e estar disposto a mudar. Se aceitar 0 desafio — isso, 0 desafio — de ler e aplicar 0 que é aconselhado neste livro. yocé entendera e apreciard o ultimo item. Aqui estamos finalmente indo em direcao as raizes do profissionalismo responsavel numa profisso que deve se preocupar com o ciclo de vida de um produto. Conforme facamos a manutencao de automdveis e outras maquinas na TPM, a manutengdo corretiva — esperar que bugs aparegam — ¢ a excegao. Em vez disso, subimos um nivel: inspecionamos as méquinas todos os dias e consertamos as partes desgastadas antes de quebrarem, ou percorremos o equivalente aos famosos 16km antes da primeira troca de 6leo para testar 0 desgaste. No cédigo, a refatoragdo é impiedosa. Vocé ainda pode melhorar um nivel a mais com o advento do movimento da TPM ha 50 anos; construa maquinas que sejam passiveis de manutengio. Tornar seu cédigo legivel € téo importante quanto torna-lo executavel. A iltima pratica, adicionada 4 TPM em torno de 1960, é focar na incluso de maquinas inteiramente novas ou substituir as antigas. Como nos adverte Fred Brooks, proyavelmente devemos refazer partes principais do software a partir do zero a cada sete anos ou entao se livrar dos entulhos. Talvez devéssemos atualizar a constante de tempo de Fred para semanas, dias ou horas, em vez de anos. E ai onde ficam os detalhes. HA um grande poder nos detalhes, mesmo assim existe algo simples ¢ profundo sobre essa abordagem para a vida, como talvez esperemos de qualquer abordagem que afirme ter origem Japonesa. Mas essa nao é apenas uma visio ocidental de mundo sobre a vida; a sabedoria de ingleses e americanos também est cheia dessas adverténcias. A citag3o de Seiton mais acima veio da ponta da caneta de um ministro em Ohio que visualizou literalmente a organizagéo “como um remédio para todos os niveis de mal”. E Seiso? Deus ama a limpeza. Por mais bonita que uma casa seja, uma mesa desarrumada retira seu esplendor. E Shutsuke nessas pequenas questdes? Quem € fiel n0 pouco também € no muito, E que tal ficar ansioso para refatorar na hora certa, fortalecendo sua posigao para as “grandes” decisdes subsequentes, em vez de descarté-las? Um homem prevenido vale por dois. Deus ajuda a quem cedo madruga. Nao deixe para amanhf o que se pode fazer hoje. (Esse era o sentido original da frase “o ultimo momento de responsabilidade”, em Lean, até cair nas maos dos consultores de software). E que tal aplicar local de esforgos pequenos e individuais num grande todo? De grao em grio a galinha enche o papo. Ou que tal integrar um trabalho de prevencao no dia a dia? Antes prevenir do que remediat. O cédigo limpo honra as profundas raizes do conhecimento sob nossa cultura mais ampla, ou como ela fora um dia, ou deve ser, € podera vir a ser com a atengao correta aos detalhes, Mesmo na grande literatura na area de arquitetura encontramos visOes que remetem a esses supostos detalhes. Pense nas macanetas de Mies van der Rohe. Aquilo é seiri. E ficar atento a cada nome de varidvel. Deve-se escolher 0 nome de uma varidvel com cuidado, como se fosse eu primeiro filho. Como todo proprietério de uma casa sabe, tal cuidado e constante refinamento jamais acaba, O arquiteto Christopher Alexander — pai dos padrdes ¢ das linguagens de padrdes ~ enxerga cada o proprio design como um conserto pequeno e local. E ele enxerga a habilidade de uma boa estrutura como 0 Unico objetivo do arquiteto; pode-se deixar as formas maiores para os padrdes: © seus aplicativos para os moradores. O design é constante nao sé ao adicionarmos um novo cémodo a uma casa, mas ao nos atentarmos a repintura, a substituigao de carpetes gastos ou a melhoria da pia da cozinha. A maioria das artes reflete relacdes andlogas. Em nossa busca por outras pessoas que dizem que a casa de Deus foi feita nos minimos detalhes, encontramo-nos em boa companhia do autor francés Gustav Flaubert, do século XIX. O poeta francés Paul Valery nos informa que um poema nunca fica pronto e requer trabalho continuo, e parar de trabalhar nele seria abandona-lo. Tal preocupagao com os detalhes é comum a todos os encargos de exceléncia. Portanto, talvez haja pouca coisa nova aqui, mas ao ler este livro voeé serd desafiado a retomar a disciplina que vocé ha muito largou para a apatia ou um desejo pela espontaneidade ¢ apenas “respondia 4s mudangas”. Infelizmente, nfio costumamos enxergar essas questdes como pegas fundamentais da arte de programar. Abandonamos nosso cédigo antecipadamente, ndo porque ele ja esteja pronto, mas porque nosso sistema de valores se foca mais na aparéncia externa do que no contetido que entregamos. No final, essa falta de ateng%o nos custa: Dinheiro ruim sempre reaparece. Pesquisas, nem no mercado ¢ nem nas universidades, sAo humildes o bastante para se rebaixar ¢ manter 0 codigo limpo. Na época em que trabalhei na empresa Bell Labs Software Production Research (produgao, de fato!), ao ficarmos mexendo aqui e ali, nos deparamos com descobertas que sugeriam que 0 estilo consistente de endentacdo era um dos indicadores mais significantes estatisticamente da baixa incidéncia de bugs. Queriamos que a qualidade fosse produzida por essa ou aquela estrutura ou linguagem de programagio ou outra nogao de alto nivel; conforme as pessoas cujo suposto profissionalismo se di ao dominio de ferramentas e métodos de design grandioso, sentimo-nos ofendidos pelo valor que aquelas maquinas de fabricas, os codificadores, recebem devido a simples aplicagio consistente em um estilo de endentagao. Para citar meu préprio livro de 17 anos atras, tal estilo faz.a distingao entre exceléncia e mera competéncia. A visto de mundo japonesa entende o valor crucial do trabalhador diario e, além do mais, dos sistemas de desenvolvimento voltados para as aces simples c diarias desses trabalhadores. A qualidade € 0 resultado de um milhao de atos altruistas de importar-se — nao apenas um grande método qualquer que desga dos céus. Nao € porque esses atos sdo simples que eles sejam simplistas, « muito menos que sejam faccis. Eles so, ndo obstante, a fabrica de magnitude ¢. também, de beleza em qualquer esforyo humano. Ignord-los é nao ser ainda completamente humano. E claro que ainda defendo 0 conceito de um escopo mais amplo, e, especialmente, 0 do valor de abordagens arquiteténicas arraigadas profundamente no conhecimento do dominio ¢ de usabilidade do software. Este livro nao 6 sobre isso — ou, pelo menos, nao de modo direto. Mas ele passa uma mensagem mais sutil cuja esséncia nado deve ser subestimada. Ele se encaixa 4 maxima atual das pessoas que realmente se preocupam com o cédigo, como Peter Sommerlad, Kevlin Henney e Giovanni. “O cédigo 0 projeto” e “Cédigo simples” sao seus mantras. Enquanto devamos tentar nos lembrar de que a interface ¢ o programa, ¢ que suas estruturas dizem bastante sobre a estrutura de nosso programa, € crucial adotar a humilde postura de que o projeto vive no cédigo. E enquanto o retrabalho na metéfora da manufatura leva ao custo, 0 no projeto leva ao valor. Devemos ver nosso cédigo como a bela articulaga0 dos nobres esforgos do projeto — projeto como um processo, € nO uma meta estatica. E no cédige que ocorrem as medidas cstruturais de acoplamento € coesio. Se vocé vir a descrigao de Larry Constantine sobre esses dois fatores, ele os conccitua em termos de eédigo— e no em conceitos de alto nivel como se pode encontrar em UML. Richard Gabriel nos informa em seu artigo Abstraction Descant que a abstragao é maligna. O cédigo é antimaligno, ¢ talvez 0 cédigo limpo seja divino. Voltando a minha pequena embalagem de Ga-Jol, acho importante notar que a sabedoria dinamarquesa nos aconselha a nao s6 prestar atengdo a pequenas coisas, mas também a ser honesto em pequenas coisas. Isso significa ser honesto com o cédigo ¢ tanto com nossos colegas ¢, acima de tudo, com nés mesmos sobre o estado de nosso cédigo. Fizemos o Melhor para “deixar © local mais limpo do que como 0 encontramos"? Refatoramos nosso codigo antes de verificé- lo? Essas ndo sao preocupagdes externas, mas preocupagdes que esto no centro dos valores do Agile. Que a refatoragdo seja parte do conceito de “Pronto”, é uma pritica reeomendada no Scrum. Nem a arquitetura ¢ nem o cédigo limpo exigem perfeigao, apenas honestidade e que fagamos o melhor de nés. Errar é humano; perdoar ¢ divino. No Scrum, tornamos as coisas visiveis, Arejamos nossa roupa suja. Somos honestos sobre o estado de nosso cédigo porque © codigo nunca € perfeito. Tornamo-nos mais completamente humanos, mais merecedores do divino © mais proximos da magnitude dos detalhes. Em nossa profiss4o, precisamos desesperadamente de toda ajuda que conseguirmos. Se o piso de uma loja reduz os acidentes ¢ suas ferramentas bem organizadas aumentam a produtividade, entao sou totalmente a favor. E relagao a este livro, ele ¢ a melhor aplicagdo pragmatica dos principios de Lean ao software que jé vi. Eu no esperava nada mais deste pequeno grupo pratico de individuos que se esforcaram juntos por anos nao s6 para se aperfeigoarem, mas também para presentear com scus conhecimentos o mercado com obras como esta em suas maos agora. Isso deixa o mundo um pouco melhor do que quando 0 encontrei antes de Uncle Bob me enviar © manuscrito. Apés ter finalizado estes exercicios com conhecimentos tio sublimes, agora vou limpar minha mesa. James O. Coplien Mordrup, Dinamarca Introdu¢ao [he omy vAticl neaueenen oF code Quaciry: WTFs/ninure wrr Good code. BAA codle. Reproduzido com a gentil autorizagaio de Thom Holwerda. http:/Avww.osnews.com/story/19266/WTFs_m (c) 2008 Focus Shift Que porta representa seu cédigo? Que porta representa sua equipe ou sua companhia? Por que estamos naquela sala? E apenas uma revisdio normal de codigo ou encontramos uma série de problemas terriveis logo apés iniciarmos a apresentag’io? Estamos depurando em panico, lendo meticulosamente um cédigo que pensdvamos que funcionava? Os clientes estao indo embora aos bandos e estamos com os gerentes em nossos pescogos? Como podemos garantir que cheguemos atras da porta certa quando 0 caminho fica dificil? A resposta é: habilidade profissional Ha duas vertentes para se obter habilidade profissional: conhecimento e trabalho. Vocé deve adguirir 0 conhecimento dos principios, padrdes, priticas e heuristicas que um profissional habilidoso sabe, ¢ também esmiugar esse conhecimento com seus dedos, olhos corpo por meio do trabalho arduo ¢ da pratica Posso the ensinar a mecanica para se andar de bicicleta. Na verdade, a matemitica clissica € relativamente direta. Gravidade, atrito, momento angular. centro de massa, e assim por diante, podem ser demonstrados com menos de uma pagina cheia de equacdes. Dada essas formulas, eu poderia provar para vocé que ¢ pritico andar de bicicleta e Ihe dar todo o conhecimento necessario para que vocé consiga. E mesmo assim vocé caira na primeira vez que tentar. Programar nao ¢ diferente. Poderiamos pér no papel todos os principios necessarios para um cédigo limpo e, entio, confiar que vocé faré as tarefas (isto é, deixar vocé cair quando subir na bicicleta), mas que tipo de professores e de estudantes isso faria de nds? Nao. Essa no ¢ a forma que este livro seguira, Aprender a criar cédigos limpos é uma tarefa ardua e requer mais do que o simples conhecimento dos principios ¢ padrées. Vocé deve suar a camisa: praticar sozinho ¢ ver que cometeu erros; assistir a outros praticarem e errarem; vé-los tropegar e refazer seus passos; Vé- los agonizar para tomar decisdes e 0 prego que pagardo por as terem tomado da maneira errada. Esteja preparado para trabalhar duro enquanto ler este livro. Esse ndo ¢ um livro facil simples que vocé pode ler num aviao e terminar antes de aterrissar. Este livro Ihe fard trabalhar, ¢ trabalhar duro. Que tipo de trabalho vocé far? Vocé leré cddigos aqui, muitos cédigos. E vocé devera descobrir 0 que esta correto ¢ errado nos codigos. Vocé tera de seguir 0 raciocinio conforme dividirmos médulos e os unirmos novamente. Isso levari tempo ¢ esfor¢o, mas achamos que valerd a pena. Dividimos este livro em trés partes. Na primeira ha diversos capitulos que descrevem os principios, padrées ¢ priticas para criar um cédigo limpo. Ha um tanto de cédigos nessa parte. ¢ ser desafiador Ié-los. Eles Ihe prepararao para a se¢do seguinte. Se yocé deixar o livro de lado apés essa primeira parte. Bem, boa sorte! Na segunda parte entra o trabalho pesado que consiste em diversos estudos de caso de complexidade cada vez maior. Cada um é um exercicio para limpar um cédigo — resolver alguns problemas dele. O detalhamento nesta segdo ¢ intenso. Vocé terd de ir e voltar por entre as folhas de textos ¢ cédigos, c analisar ¢ entender 0 cédigo com o qual estamos trabalhando e captar nosso raciocinio para cada alteragao que fizermos. Reserve um tempo para essa parte, pois deveré levar dias. A terceira parte é a compensagao. E um tinico capitulo com uma lista de heuristicas e “odores” reunidos durante a criagao dos estudos de caso. Conforme progredirmos e limparmos os cédigos nos estudos de caso, documentaremos cada motivo para nossas agdes como uma heuristica ou um “odor”. Tentaremos entender nossas proprias reagdes em relag%io ao cédigo quando estivermos Iendo ou alterando-o, ¢ trabalharemos duro para captar por que nos sentimos de tal forma por que fizemos isso ou aquilo. O resultado sera um conhecimento base que descreve a forma como pensamos quando criamos, lemos e limpamos um eédigo. Este conhecimento base possui um valor limitado se vocé no ler com atengiio ao longo dos casos de estudo na segunda parte deste livro. Neles, anotamos cuidadosamente cada alteracio que fizemos com referéncias posteriores as heuristicas. Tais referencias aparecem em colchetes, assim: [H22]. Isso lhe permite ver 0 contexto no qual so aplicadas e escritas aquelas heuristicas! Essas. em si, nio sio téo valiosas, mas, sim, a relagao entre clas ¢ as diferentes decisdes que tomamos ao limpar o cédigo nos casos de estudo. A fim de lhe ajudar ainda mais com essas relagdes, colocamos no final do livro uma referéncia cruzada que mostra o nimero da pagina para cada referéncia, Vocé pode usd-la com um guia répido de consulta para saber onde uma determinada heuristica foi aplicada. Mesmo se vocé ler a primeira e a terceira segdes e pular para os casos de estudo, ainda assim teré lido um livro que satisfaz sobre a cria¢do de um bom software. Mas se no tiver pressa e explorar os casos de estudo, seguindo cada pequeno passo e cada minuto de decisao, se colocando em nosso lugar e se forgando a seguir a mesma linha de raciocinio que usamos, entdo vocé adquiriu um entendimento muito mais rico de todos aqueles principios, padrdes, priticas © heuristicas. Todo esse conhecimento ficara em cada fibra de seu corpo. Ele se tomnara parte de vocé da mesma forma que ao aprender a andar de bicicleta, cla se torna uma parte de sua vontade de pedalé-la. Agradecimentos Tlustracgées Meus agradecimentos a minhas duas artistas, Jeniffer Kohnke ¢ Angela Brooks. Jennifer ¢ a responsavel pelas maravilhosas e criativas figuras no inicio de cada capitulo ¢ também pelos retratos de Kent Beck, Ward Cunningham, Bjame Stroustrup, Ron Jeffries, Grady Booch, Dave Thomas, Michael Feathers e de mim mesmo. ‘Angela é a responsavel pelas figuras engenhosas que enfeitam os capitulos.Ao longo dos anos, ela criou bastantes imagens para mim, incluindo muitas das que est8o no livro Agile Software Develpment: Principles, Patterns, and Practices. Angela também é minha primogénita e de quem me sinto muito orgulhoso. Sobre a capa A imagem da capa se € a M104 — a Galaxia Sombrero ~, que fica na constclago de Virgem e esta a pouco menos de 30 milhdes de anos-luz de nés. Em seu centro hd um buraco negro supermassivo cujo peso equivale um bilhao de vezes a massa do sol. Aimagem Ihe faz lembrar da explosio da lua Praxis, de Klingon? Eu me recordo vividamente a cena de Jornada nas Estrelas VI que mostrava um anel equatorial de destrogos voando devido & explosdo. Desde essa cena, 0 anel equatorial se tornou um componente comum as explosdes em filmes de ficcao cientifica. Ele até foi adicionado & explosao de Alderaan nas iltimas versdes do filme Jomada nas Estrelas. O que causou a formagio desse anel em torno de M104? Por que ele possui um bojo 120 amplo ¢ um nileo tao minusculo ¢ brilhoso? Parece-me como se 0 buraco negro central perdeu sua graca e langou um buraco de 30,000 anos-luz no meio da galaxia, devastando quaisquer civilizagdes que estivessem no caminho daquele distarbio césmico. Buracos negros supermassivos engolem estrelas inteiras_no_almogo, convertendo_uma considerdvel fragaio de sua massa em energia. E = MC2 ja € bastante poténcia, mas quando M é uma massa estelar: Cuidado! Quantas estrelas cairam_ impetuosamente naquelas presas antes de o monstro ficar saciado? O tamanho do vao central poderia ser uma dica? ‘A imagem de M104 da capa é uma combinagao da famosa fotografia de luz visivel do Hubble (foto superior) com a recente imagem infravermelha do observatério espacial Spitzer (foto inferior). E essa segunda imagem que nos mostra claramente a natureza do anel da galaxi Na luz visivel, vemos apenas a extremidade frontal do anel como uma silhueta. O bojo central ofusca o resto do anel. ‘Mas no infravermelho, as particulas “quentes” — isto 6, altamente radioativas — no anel brilham através do bojo central. A combinagaio de ambas as imagens nos mostra uma visdo que ndo haviamos visto antes e indica que, ha muito tempo atras, la havia um inferno enfurecido de ativi ‘Cover mage: © Sper Space Telescope Cédigo Limpo HA duas razdes pelas quais voce esta lendo este livro: vocé é programador e deseja se tomar um ainda melhor. Otimo. Precisamos de programadores melhores. Capitulo 1: Cédigo Limpo Este livro fala sobre programagao ¢ est repleto de cédigos que examinaremos a partir de diferentes perspectivas: de baixo para cima, de cima para baixo e de dentro para fora. Ao terminarmos, teremos um amplo conhecimento sobre cédigos e seremos capazes de distinguir entre um cédigo bom ¢ um cédigo ruim. Saberemos como escrevet um bom cédigo e como tornar um ruim em um bom. O Cédigo Podem dizer que um livro sobre cédigos ¢, de certa forma, algo ultrapassado, que a programago deixou de ser uma preocupagio € que devemos nos preocupar com modelos ¢ requisitos. Outros até mesmo alegam que o fim do eédigo, ou seja, da programagio, esta proximo: que logo todo cédigo sera gerado, ¢ no mais escrito. E que nao precisarao mais de programadores, pois as pessoas criardio programas a partir de especificages. Bobagens! Nunca nos livraremos dos eédigos, pois eles representam os detalhes dos requisitos. Em certo nivel, no hé como ignorar ou abstrair esses detalhes; eles precisam ser especificados. E especificar requisitos detalhadamente de modo que uma maquina possa executé-los é programar ~¢ tal especificagao é 0 cédigo, Espero que 0 nivel de de nossas linguagens continue a aumentar © que 0 mimero de linguagens especificas a um dominio continue crescendo. Isso sera bom, mas no acabaré com a programagdo. De fato, todas as especificagées escritas nessas linguagens de niveis mais altos ¢ especificas a um dominio serdo cédigos! Eles precisardo ser minuciosos, exatos ¢ bastante formais ¢ detalhados para que uma maquina possa entendé-los ¢ executd-los. As pessoas que pensam que 0 codigo um dia desaparecera so como matemiticos que esperam algum dia descobrir uma matemitica que no precise ser formal. Elas esperam que um dia descubramos uma forma de criar maquinas que possam fazer o que desejamos em vez do que mandamos. Tais maquinas terdo de ser capazes de nos entender tio bem de modo que possam traduzir exigéncias vagamente especificadas em programas executaveis perfeitos para satisfazer nossas necessidades. so jamais acontecerd, Nem mesmo os seres humanos, com toda sua intuigo e criatividade, tém sido capazes de criar sistemas bem-sucedidos a partir das caréncias confusas de seus clientes. Na verdade, se a matéria sobre especificagio de requisitos ndo nos ensinou nada, € porque os requisitos bem especificados so to formais quanto os cédigos e podem agir como testes executaveis de tais cédigos! Lembre-se de que o cédigo é a linguagem na qual expressamos nossos requisitos. Podemos criar linguagens que sejam mais proximas a eles. Podemos criar ferramentas que nos ajudem a analisar a sintaxe ¢ unir tais requisitos em estruturas formais. Mas jamais climinaremos a preciso necessiria — portanto, sempre haverd um cédigo. Cédigo Ruim 3 Cédigo ruim Recentemente li o preficio do livro Implementation Patterns! de Kent Beck, no qual ele diz “... este livro bascia-se numa premissa fragil de que um bom cédigo importa...”. Uma premissa fragil? Nao concordo! Acho que essa premissa ¢ uma das mais robustas, apoiadas ¢ plenas do que todas as outras em nossa rea (¢ sei que Kent sabe disso). Estamos cientes de que um bom cédigo importa, pois tivemos de lidar com a falta dele por muito tempo. Lembro que no final da década de 1980 uma empresa criou um aplicativo extraordinario que se tornou muito- popular ¢ muitos profissionais 0 compraram € usaram. ‘Mas, entao, o intervalo entre os langamentos das novas distribuigdes comegou a aumentar. Os bugs ndo eram consertados na distribuicio seguinte. E 0 tempo de carregamento do aplicativo ¢ o ntimero de travamentos aumentaram. Lembro-me do dia em que, frustrado, fechei 0 programa ¢ nunca mais o usei. A empresa saiu do mercado logo depois. Duas décadas depois encontrei um dos funcionarios de tal empresa na época e o perguntei 0 que havia acontecido, e 0 que cu temia fora confirmado. Eles tiveram de apressar 0 langamento do produto ¢, devido a isso, o cédigo ficou uma zona. Entao, conforme foram adicionando mais € mais recursos, o cédigo piorava cada vez mais até que simplesmente nao era mais possivel gerencia-lo. Foi o cddigo ruim que acabou com a empresa. Alguma vez um cédigo ruim jé Ihe atrasou consideravelmente? Se vocé for um programador, independente de sua experiéncia, entdo jé se deparou varias vezes com esse obsticulo. Alids, ¢ como se caminhassemos penosamente por um lamacal de arbustos emaranhados com armadilhas ocultas.Isso é 0 que fazemos num cédigo ruim. Pelejamos para encontrar nosso caminho. esperando avistar alguma dica, alguma indicagdo do que esté acontecendo; mas tudo 0 que vemos é um cédigo cada vez mais sem sentido. E claro que um cédigo ruim ja lhe atrasou. Mas, enti, por que vocé o escreveu dessa forma? Estava tentando ser rapido? Estava com pressa? Provavelmente. Talvez vocé pensou que no tivesse tempo para fazer um bom trabalho; que seu chefe ficaria com raiva se vocé demorasse um pouco mais para limpar seu cédigo. Talvez vocé estava apenas cansado de trabalhar neste programa ¢ queria termina-lo logo. Ou verificou a lista de coisas que havia prometido fazer ¢ percebeu que precisava finalizar este médulo de uma vez, de modo que pudesse passar para o proximo. Todos jé fizemos isso, j4 vimos a bagunga que fizemos e, ent&o, optamos por arruma- las outro dia. Todos j4 nos sentimos aliviados ao vermos nosso programa confuso funcionar ¢ decidimos que uma bagunga que funciona ¢ melhor do que nada. Todos nos ja dissemos que revisariamos ¢ limpariamos o cédigo depois. E claro que naquela época nao conheciamos a lei de LeBlane: Nunca é tarde. 1. ecko) 4 Capitulo 1: Cédigo Limpo O Custo de Ter um Codigo Confuso Se vocé programador a mais de dois ou trés anos, provavelmente 0 cédigo confuso de outra pessoa ja fez com que vocé trabalhasse mais lentamente e provavelmente seu proprio cédigo jé Ihe trouxe problemas. © nivel de retardo pode ser significative. Ao longo de um ou dois anos, as equipes que trabalharam rapidamente no inicio de um projeto podem perceber mais tarde que esto indo a passos de tartaruga. Cada alteragdo feita no eédigo causa uma falha em outras duas ou trés partes do mesmo eédigo. Mudanca alguma ¢ trivial. Cada adiea0 ou modificagdo ao sistema exige que restauragdes, amarragées e remendos sejam “entendidas” de modo que outras possam ser incluidas. Com 0 tempo, a bagunga se tomna tao grande e profunda que nao da para arrumé-la. ‘Nao hé absolutamente solugiio alguma. Conforme a confusio aumenta, a produtividade da cquipe diminui, assintoticamente aproximando-se de zero. Com a redugo da produtividade, a geréncia faz a unica coisa que cla pode; adiciona mais membros ao projeto na esperanga de aumentar a produtividade. Mas esses novos membros néo conhecem o projeto do sistema, nao sabem a diferenga entre uma mudanga que altera o propésito do projeto ¢ aquela que o atrapalha. Ademais, cles, ¢ todo 0 resto da equipe, esto sobre tremenda pressio para aumentar a produtividade. Com isso todos criam mais € mais confuses, levando a produtividade mais perto ainda de zero (veja a Figura 1.1). co8 S888 Time Figura 1.1 Produtividade v. tempo O Custo de Ter um Cédigo Confuso 5 O Grande Replanejamento No final, a equipe se rebela. Todos informam a geréncia que nao conseguem mais trabalhar neste irritante cédigo-fonte e exigem um replanejamento do projeto. Apesar de a geréncia naio querer gastar recursos em uma nova remodelagdo, ela nfo pode negar que a produtividade esta péssima. No final das contas, ela acaba cedendo as exigéncias dos desenvolvedores ¢ autoriza o grande replanejamento desejado. F, entdo, formada uma nova equipe especializada. Por ser um projeto inteiramente novo, todos querem fazer parte dessa equipe. Eles desejam comegar do zero e criaralgo belo de verdade. Mas apenas os melhores e mais brilhantes sAo selecionados ¢ os outros deverao continuar na manutengao do sistema atual. ‘Agora ambos os times estao numa corrida. A nova equipe precisa construir um novo sistema que faca o mesmo que o antigo, além de ter de se manter atualizada em relagdo as mudangas feitas constantemente no sistema antigo. Este, a geréncia ndo substituira até que 0 nove possa fazer tudo também. Essa corrida pode durar um bom tempo. Jé vi umas levarem 10 anos, E, quando ela termina, ‘os membros originais da nova equipe j4 foram embora ha muito tempo, e os atuais exigem 0 replanejamento de um novo sistema, pois esta tudo uma zona novamente. Se vocé ja vivenciou pelo menos um pouco dessa situagéo, entio sabe que dedicar tempo para limpar seu cédigo nao ¢ apenas eficaz em termos de custo, mas uma questo de sobrevivéncia profissional. Atitude Vocé ja teve de trabalhar penosamente por uma confuséo tio grave que levou semanas 0 que deveria ter levado horas? Vocé ja presenciou o que deveria ser uma alteragao Gnica ¢ direta, mas que em vez disso foi feita em diversos médulos distintos? Todos esses sintomas so bastante comuns. Por que isso ocorre cm um cédigo? Por que um eédigo bom se decompée tio rapide em um ruim? Temos diversas explicagées para isso. Reclamamos que os requisitos mudaram de tal forma que estragaram o projeto original. Criticamos os prazos por serem curtos demais para fazermos as coisas certas. Resmungamos sobre gerentes tolos ¢ clientes intolerantes ¢ tipos de marketing iniiteis e téenicos de telefone. Mas 0 padrao, querido Dilbert", nao esti em nossas estrelas, mas sim em nés mesmos. Somes profissionais Isso pode ser algo dificil de engolir. Mas como poderia essa zona ser nossa culpa? E os requisitos? E 0 prazo? E os tolos gerentes ¢ tipos de marketing iniiteis? Eles no carregam alguma parcela da culpa? Nao. Os gerentes ¢ markeieiros buscam em nds as informagdes que precisam para fazer promessas ¢ firmarem compromissos; e mesmo quando no nos procuram, nfo devemos dar uma de timidos ao dizer-lhes nossa opinifio. Os usuarios esperam que validemos as maneiras pelas quais os requisitos se encaixarao no sistema. Os gerentes esperam que os ajudemos a cumprir 0 prazo. Nossa cumplicidade no planejamento do projeto é tamanha que compartilhamos de uma grande parcela da responsabilidade em caso de falhas: especialmente se estas forem em relag3o a um cédigo ruim. 6 Capitulo 1: Cédigo Limpo erei demitid “Mas, espere!”, voce di provavel que nao. ‘A maioria dos gerentes quer a verdade, mesmo que demonstrem o contrario. A maioria deles quer um cédigo bom, mesmo estourando o prazo. Eles podem proteger com paixao 0 prazo ¢ 03 requisitos, mas essa é a fungdio deles. A swa ¢ proteger o cédigo com essa mesma paixio. Para finalizar essa questo, e se vocé fosse médico e um paciente exigisse que vocé parasse com toda aquela lavagao das maos na preparacao para a cirurgia s6 porque isso leva muito tempo?” E obvio que 0 chefe neste caso ¢ 0 paciente; mas, mesmo assim, o médico deverd totalmente se recusar obedecé-lo, Por qué? Porque 0 médico sabe mais do que o paciente sobre os riscos de doengas e infecgées. Nao seria profissional (sem mencionar criminoso) que o médico obedecesse ao paciente neste cenério. Da mesma forma que nio é profissional que programadores cedam & vontade dos gerentes que nao entendem os riscos de se gerar cédigos confusos. . “E se eu nfo fizer 0 que meu gerente qui O Principal Dilema Os programadores se deparam com um dilema de valores basicos. Todos os desenvolvedores com alguns anos a mais de experiéncia sabem que bagungas antigas reduzem o rendimento. Mesmo assim todos eles se sentem pressionados a cometer essas bagungas para cumprir os prazos. Resumindo, eles nao se esforgam para. Os profissionais sérios sabem que a segunda parte do dilema esté errada, Vocé nfio cumprira © prazo se fizer bagunga no cédigo, De fato, tal desorganizacao reduzira instantaneamente sua velocidade de trabalho, ¢ vocé perdera o prazo. A winica maneira de isso nao acontecer — a unica maneira de ir mais rapido — é sempre manter o cédigo limpo. A Arte do Cédigo Limpo? Digamos que vocé acredite que um cédigo confuso seja um obstéculo relevante. Digamos que vocé accite que a tinica forma de trabalhar mais répido ¢ manter seu cédigo limpo. Entio, vocé deve se perguntar: “Como escrever um cédigo limpo?” Nao vale de nada tentar escrever um cédigo limpo se voce nao souber o que isso significa. As mis noticias so que escrever um cédigo limpo é como pintar um quadro. A maioria de nés sabe quando a figura foi bem ou mal pintada. Mas ser capaz de distinguir uma boa arte de uma ruim nao significa que vocé saiba pintar. Assim como saber distinguir um cédigo limpo de um ruim nao quer dizer que saibamos escrever um cédigo limpo. Escrever um cédigo limpo exige o uso disciplinado de uma mirfade de pequenas técnicas aplicadas por meio de uma sensibilidade meticulosamente adquirida sobre “limpeza”. A “sensibilidade ao codigo” é 0 segredo. Alguns de nds j4 nascemos com ela. Outros precisam se esforcar para adquiri-la. Ela nao so nos permite perceber se o cédigo é bom ou ruim, como também nos mostra a estratégia e disciplina de como transformar um cédigo ruim em um limpo. Um programador sem “sensibilidade ao c6digo” pode visualizar um médulo confuso & reconhecer a bagunga, mas nao sabera o que fazer a respeito dela. J4 um com essa sensibilidade olhara um médulo confuso ¢ vera alternativas. A “sensibilidade ao codigo” ajudara a esse +> tes 1847. qeamo lunar Sexureslorcis eumsiin pele ertmeira vex biveniom di woke, ala Soi nejeiteda, baasaado.se no Gato dé'que os méllicrs cram ctupades O Custo de Ter um Cédigo Confuso 7 programador a escolher a melhor alternativa ¢ 0 orientara na criagao de uma sequéncia de comportamentos para proteger as alteragées feitas aqui ¢ ali. Em suma, um programador que escreve um cédigo limpo ¢ um artista que pode pegar uma tela em branco ¢ submeté-la a uma série de transformagées até que se torne um sistema graciosamente programado, O que é um Cédigo Limpo? Provavelmente existem tantas definigdes como existem programadores. Portanto, perguntei a alguns programadores bem conhecidos ¢ com muita experiéneia o que achavam. Bjarne Stroustrup, criador do C++ e autor do livro A linguagem de programagao C++ Gosto do meu cédigo elegante ¢ eficiente. A logica deve ser direta para dificultar o encobrimento de bugs, ‘as dependéncias minimas para facilisar a mamutengao, 0 tratamento de erro completo de acordo com uma estratégia clara € 9 desempenko priximo do mais efielente de modo a néto incitar as pessoas a tornarem 0 cédigo confuso com otimizagbes sorrateiras, O cédiga impo faz bem apenas uma coisa. Bjame usa a palavra “elegante” — uma palavra e tanto! O diciondrio possui as seguintes definigdes: que se caracteriza pela naturalidade de harmonia, leveza, simplicidade; naturalidade no modo se dispor: requintado, fino, estiloso. Observe a énfase dada a palavra “naturalidade”. Aparentemente, Bjarne acha que um cédigo limpo proporciona uma leitura natural: ¢ lé-lo deve ser belo como ouvir uma misica num radio ou visualizar um carro de design magnifico. Bjarne também menciona duas vezes “eficiéncia”. Talvez isso nao devesse nos surpreender vindo do criador do C++, mas acho que ele quis dizer mais do que um simples desejo por agilidade. A repetigao de ciclos nao € elegante, nao é belo. E repare que Bjame usa a palavra “incitar” para descrever a consequéneia de tal desclegancia. A verdade aqui é que um cédigo ruim incita o crescimento do caos num cédigo. Quando outras pessoas alteram um cédigo ruim, elas tendem a piord-lo Pragmaticos, Dave Thomas ¢ Andy Hunt expressam isso de outra forma, Eles usam a metfora das janelas quebradas.’ Uma construgao com janelas quebradas parece que ninguém cuida dela. Dessa forma, outras pessoas deixam de se preocupar com ela também. Elas permitem que as outras janelas se quebrem também. No final das contas, as proprias pessoas as quebram. Elas estragam a fachada com pichagdes e deixam acumular lixo. Uma tinica janela inicia 0 proceso de degradagao. 5 Sas etna ai eas g Capitulo 1: Cédigo Limpo Bjarne também menciona que 0 tratamento de erro deva ser completo. Isso significa prestar atengiio nos detalhes. Um tratamento de erro reduzido € apenas uma das manciras pela qual os programadores deixam de notar os detalhes. Perdas de meméria e condigdes de corrida sao outras. Nomenclaturas inconsistentes so ainda outras. A conclusio é que um cédigo limpo requer bastante atengao aos detalhes. Bjarne conclui com a asseveragdo de que um cédigo limpo faz bem apenas uma coisa. Nao ¢ por acaso que ha intimeros principios de desenvolvimento de software que podem ser resumidos a essa simples afirmagio. Varios escritores j4 tentaram passar essa ideia, Um codigo ruim tenta fazer coisas demais, ele esta cheio de propésitos obscuros e ambiguos. O cédigo limpo é centralizado. Cada fungao, cada classe, cada médulo expe uma tinica tarefa que nunca sofre interferéncia de outros detalhes ou fica rodeada por eles. Grady Booch, autor do livro Object Oriented Analysis and Design with Applications Um cédigo limpo & simples e direto. Ele é tao bem legivel quanto uma prosa bem escrita. Ele jamais torna confuso 0 objetivo do desenvolvedor. em vez disso, ele esué repleto de abstragbes claras ¢ linhas de controle objetivas. Grady fala de alguns dos mesmos pontos que Bjame, voltando-se mais para questo da legibilidade. Eu, particularmente, gosto desse ponto de vista de que ler um cédigo limpo deve ser como ler uma prosa bem escrita. Pense num livro muito bom que voce j4 leu. Lembre-se de como as palavras eram substituidas por imagens! Era como assistir a um filme, nfo era? Melhor ainda, vocé via os personagens. auvia os sons, envolvia-se nas emogdes ¢ no humor. Ler um cédigo limpo jamais ser como ler O senhor dos anéis. Mesmo assim, a analogia com a literatura nao é ruim. Como um bom romance, um cédigo limpo deve expor claramente as questdes do problema a ser solucionado. Ele deve desenvolvé-las até um climax e, entao, dar ao leitor aquele “Aha! Mas é claro!”, como as questdes € 0s suspenses que so solucionados na revelagao de uma solugdo ébvia. ‘Acho que o uso que Grady faz da frase “abstragdes claras” ¢ um paradoxo fascinante! ‘Apesar de tudo, a palavra “clara” € praticamente um sindnimo para “explicit”. Meu dicionario MacBook tem a seguinte definigao para “claro(a)”: direto, decisivo, sem devaneios ou detalhes desnecessérios. Apesar desta justaposicao de significados, as palavras carregam uma mensagem poderosa. Nosso cédige deve ser decisivo, sem especulagdes. Ele deve conter apenas 0 necessirio. Nossos leitores devem assumir que fomos decisivos. © Custo de Ter um Cédigo Confuso 9 O “grande” Dave Thomas, fundador da OTI, o pai da estratégia Eclipse Além de seu eriador, wm desenvolvedor pode ler ¢ melhorar um cédigo limpo. Ele tem testes de unidade e de aceitagao, nomes significativas; ele oferece apenas unia maneira, € nao varias, de se fazer uma tarefa; possui poucas dependéncias, as quais sdo explicitamente declaradas ¢ oferecem um API minimo ¢ claro. O cédigo deve ser inteligivel ja que dependendo da linguagem, nem toda informagiia necessde pode expressa no cédigo em si. Dave compartilha do mesmo desejo de Grady pela legibilidade, mas com uma diferenga relevante. Dave afirma que um cédigo limpo facilita para que outras pessoas o melhorem, Pode parecer ébvio, mas nio se deve enfatizar muito isso. Ha, afinal de contas, uma diferenga entre um cddigo facil de ler e um facil de alterar. Dave associa limpeza a testes! Dez anos atrés, isso levantaria um ar de desconfianga. Mas 0 estudo do Desenvolvimento Dirigido a Testes teve grande impacto em nossa industria € se tornow uma de nossos campos de estudo mais essenciais. Dave esta certo. Um cédigo, sem testes, nio esta limpo. Nao importa 0 quao elegante, legivel ou acessivel esteja que, se ele no possuir testes, ele nao é limpo. Dave usa a palavra minima duas vezes. Aparentemente ele di preferéncia a um cédigo pequeno. De fato, esse tem sido uma citagdio comum na literatura computacional. Quando menor, melhor. Dave também diz que 0 cédigo deve ser inteligivel ~ referéncia esta a programacao inteligivel' (do livro Literate Programming) de Donald Knuth. A conclusao é que o cédigo deve * ser escrito de uma forma que scja inteligivel aos seres humanos. Michael Feathers, autor de Working Effectively with Legacy Code Eu poderia listar todas as qualidades que vejo em um eédigo Jimpo, mas hé uma predominante que leva a todas as outras. Um cédigo limpo sempre parece que foi escrito por alguém que se importava. Ndo hé nada de ébvio no que se pode facer para torné-lo melhor. Tudo foi pensado pelo autor do cédigo, € s@ tentar pensar em algumas meihoras, voee voltard ao inicio, ow seja, apreciando 0 cédigo deixado para voeé por alguém que se importa bastante com essa tarefa One word: care. E esse 0 assunto deste livro. Talvez, um subtitulo apropriado seria Como se importar |\- com o cédigo. a Michael bate na testa: um cédigo limpo é um eédigo que foi cuidado por alguém. Alguém que calmamente 4. [Reuth92], 10 Capitulo 1; Cédigo Limpo -manteve simples e organizado; alguém que prestou a atengao necesséria aos detalhes; alguém que se importou. Ron Jeffries, autor de Extreme Programming Installed and Extreme Programming Adventures in C# Ron iniciou sua carreira de programador em Fortran, no Strategic Air Command, ¢ criou cédigos em quase todas as linguagens ¢ maquinas. Vale a pena considerar suas palavras: Nestes anos reconies, comecel, ¢ quase finalizei, com as regras de Beck sobre cadigu simpies. Em ordem de prioridade, sto: + Efete todos os restes + Sem duplicagao de codigo; Expressa todas as ideias do proteto que estio no sistema, + Minimiza 0 mimero de entidades, como classes, métodos. funcdes e outras do tipo. Dessas quatro, foco-me mais na de duplicacdo. Quando a mesma coisa é feita repetidas vezes, é sinal de que ‘uma ideia em sua cabeca néo esté bem representada no cédigo. Tento descobrir o que é ¢, entéo, expressar aquela ideia com mais clareza. Expressividade para mim sdo nomes significatives ¢ costume mudar 0 nome das coisas varias vezes antes de Jfinalizar, Com ferramentas de programagao modernas, como a Eclipse, renomear é bastante facil, ¢ por isso ‘nlio me incomodo em fazer isso. Entretanio, a expressividade vat além de nomes. Também verifico se um métado ‘ou objeto faz mais de uma tarefa. Se for um objeto, provavelmente ele precisard ser dividido em dois ou mais. Se for um método, sempre uso a refatoragiia do Métode de Extracdo nele, resultando em um meétoda que expressa mais claramenie sua fungdo @ em outros mérodos que dizem como ela € feita. Duplicagdo e expressividade me levam ao que considero um cédigo limpo, ¢ methorar um codigo ruim com apenas esses dois conceitas na mente pode fazer uma grande diferenca. Hd, porém, uma outra coisa da qual estou ciente quando programo, que & um pouco mais dificid de explicar. ‘Apés anos de trabalho, parece-me que todos os programadores pensar tudo igual. Um exemplo é “encontrar coisas numa colecdo”. Tenhamos uma base de dados com registras de funciondrias ou wma tabela hash de chaves e valores ou um vetor de itens de algum tipo, geralmente procuramos um item especifico naquela colegdo. Quando percebo isso, costume implementar essa fungao em um método ou classe mats absiraio — 0 que me proporciona algumas vantagens interessantex Posso implemeniar a funcionalidade agora com algo mais simples, digamos uma tabela hash, mas como agora todas as referencias aquela busca estéo na minha classe ou método abstrato, posso alterar a implementagao sempre que desejar Posso ainda prosseguir rapidamente enquanto preservo a capacidade de alteracdo futwra. ‘Além disso, a de colegdes geralmente chama minha atencdo para o que realmente esti acontecendo, e impede que eu implemente funcionalidades arbitrarias em colegdes quando tuclo que eu preciso sao simples maneiras de encontrar o que desejo. Reducio de duplicacdo de codigo, alta expressividade ¢ eriagdo no inicio de abstracdes simples, E isso que torna para mim um cédigo limpo. Aqui, em alguns breves pardgrafos, Ron resumiu o conteiido deste livro. Sem duplicag4o, uma iarefa, expressividade, pequenas abstragBes. Tudo foi mencionado. O Custo de Ter um Cédigo Confuso ul Ward Cunningham, criador do conceito de “WikiWiki”, criador do Fit, co-criador da Programagao Extrema (eXtreme Programming). Incentivador dos Padrées de Projeto. Lider da Smalltalk e da OO. Pai de todos aqueles que se importam com 0 cédigo. Focé sabe que esté criando um cédigo limpo quando cada rotina que voe® leia se mostra como 0 que vocé esperava. Vacé pode chamar de cédigo belo quando ele também faz parecer que a g Iinguagem fot feita para o problema, DeclaragGes como essa sao caracteristicas de Ward. Vocé a 1g, coloca na sua cabeca e segue para a proxima. Parece tio racional, tio ébvio que raramente é memorizada como algo profundo, Vocé acha que basicamente ja pensava assim. Mas observemos mais atentamente. *.. 0 que voce esperava”. Qual foi a ltima vez que vocé viu um médulo como vocé o esperava que fosse? Nao é mais comum eles serem complexos, complicados, emaranhados? Interpretd-lo erroneamente nao é a regra? Vocé nao esta acostumado a se descontrolar ao tentar entender 0 raciocinio que gerou todo 0 sistema e associd-lo ao médulo que estés lendo? Quando foi a ultima vez que vocé leu um cédigo para o qual vocé assentiu com a cabega da mesma forma que fez com a declaragao de Ward? Este espera que ao ler um eédigo limpo nada Ihe surpreenda. De fato, nao sera nem preciso muito esforgo. Vocé ird lé-lo ¢ ser basicamente 0 que voce j4 esperava. O cédigo é dbvio, simples ¢ convincente. Cada médulo prepara o terreno para 0 seguinte. Cada um the diz como 0 proximo estaré escrito. Os programas que sao tao limpos e claros assim foram tio bem escritos que vocé nem pereebera. O programador o faz parecer super simples, como o é todo projeto extraordinario. E a nogo de beleza do Ward? Todos ja reclamamos do fato de nossas linguagens nao tiverem sido desenvolvidas para os nossos problemas. Mas a declaragio de Ward coloca novamente © peso sobre nds. Ele diz que um codigo belo faz parecer que a linguagem foi feita para o problema! Portanto, ¢ nossa tesponsabilidade fazer a linguagem parecer simples! Ha brigas por causa das linguagens em todo lugar, cuidado! Nao é a linguagem que faz os programas parecerem simples, é o programador! 12 Capitulo 1: Cédigo Limpo Escolas de Pensamento E eu (Tio Bob)? © que ¢ um cédigo limpo para mim? E isso 0 que este livro lhe dird em detalhes, o que eu ¢ meus compatriotas consideramos um cédigo limpo. Diremo-lhe o que consideramos como nomes limpos de varidveis, fungdes limpas, classes limpas etc. Apresentaremos nossos conceitos como verdades absolutas, e nao nos desculparemos por nos: austeridade. Para nés, a essa altura de nossa carreira, tais conceitos sdo absolutos. Séo nossa escola de pensamento acerca do que seja um cédigo limpo. Nem todos os mestres de artes marciais concordam com qual seria a melhor arte marcial de todas ou a melho técnica dentro de uma arte marcial especifica. Geralmente, cles criam suas proprias escolas de pensamento ¢ recrutam alunos para serem ensinados. Dessa forma, temos 0 Jiu Jitsu dos Gracie, criado e ensinado pela familia Gracie, no Brasil; 0 Jiu Jitsu de Hakkoryu, criado e ensinado por Okuyama Ryuho, em Téquio; ¢ o Jeet Kune Do, criado ¢ ensinado por Bruce Lee, nos EUA. Os estudantes se dedicam 4 doutrina ensinada por aquela determinada arte, e aprendem 0 que seus mestres ensinam, geralmente ignorando os ensinamentos de outros mestres. Depois, conforme os estudantes progridem, costuma-se mudar o mestre de modo que possam expandit seus conhecimentos e praticas. Alguns, no final, continuam a fim de refinar suas habilidades, descobrem novas téenicas e criam suas préprias escolas. ‘Nenhuma dessas escolas esté 100% ceria. Mesmo assim dentro de uma determinada escola agimos como os ensinamentos ¢ técnicas fossem os certos. Apesar de tudo, hé uma forma correta de praticar o Jiu Jitsu de Hakkoryu, ou Jeet Kune Do. Mas essa retidao dentro de uma escola no invalida as técnicas de outra. Considere este livro como uma descrigdo da Escola de Cédigo Limpo da Object Mentor. As técnicas e ensinamentos sao a mancira pela qual praticamos nossa arte. Estamos dispostos a alegar que se vocé seguir esses ensinamentos, desfrutar dos beneficios que também aproveitamos aprenderd a escrever cédigos limpos e profissionais. Mas nao pense vocé que nés estamos 100% “certos”, Provavelmente ha outras escolas ¢ mestres que tém tanto para oferecer quanto nés. O correto seria que vocé aprendesse com clas também. De fato, muitas das recomendagées neste livro séo contraditorias. Provavelmente vocé nao concordara com todas ¢ podera até mesmo discordar intensivamente com algumas. Tudo bem. No podemos querer ter a palavra final. Por outro lado, pensamos bastante ¢ por muito tempo sobre as recomendagées neste livro. As aprendemos ao longo de décadas de experiéncia e repetidos testes e erros. Portanto, concorde vocé ou nao, seria uma pena se vocé nao conseguisse enxergar nosso ponto de vista. Somos Autores B Somos Autores O campo @author de um Javadoc nos diz quem somos. Nos somos autores, ¢ todo autor tem leitores, com os quais uma boa comunicagao é de responsabilidade dos autores. Na proxima vez em que vocé escrever uma linha de cddigo, lembre-se de que vocé ¢ um autor, escrevendo para eitores que julgarao seus esforcos. Vocé talvez se pergunte: 0 quanto realmente se I¢ de um cédigo? A maioria do trabalho no é escrevé-lo? Vocé ja reproduziu uma sesso de edig&o? Nas décadas de 1980 ¢ 1990, tinhamos editores, como o Emacs, que mantinham um registro de cada tecla pressionada. Vocé podia trabalhar por horas e, entdo, reproduzir toda a sua sessiio de edigao como um filme passando em alta velocidade. Quando fiz isso, os resultados foram fascinantes. ‘A grande maioria da reprodugdo era rolamento de tela e navegacdo para outros médulos! Bob entra no modulo. Ele descia até a fungdo que precisava ser alterada. Ele para e pondera suas opgées. Oh, ele sobe para o inicio do médulo a fim de verificar a inicializagéo da varidvel. Agora ele desce novamente e comeca a digitar. Opa, ele esté: apagando 0 que digitou! Ele digita novamente. Ele apaga novamente. Ele digita a metade de algo eapaga! 4 Ele desce até outra fungdo que chama a que ele esté modificando para ver como ela é, chamada. Ele sobe novamente e digita o mesmo cédigo que acabara de digitar. Ele para. Ele apaga novamente! Ele abre uma outra janela e analisa uma subclasse. A fungao é anulada? Bem, vocé entendeu! Na verdade, a taxa de tempo gasto na leitura v. na escrita é de 10x1. Constantemente lemos um cédigo antigo quando estamos criando um novo. Devido A tamanha diferenga, desejamos que a leitura do cédigo seja facil, mesmo se sua criagao for ardua. E claro que nao ha como escrever um cédigo sem lé-lo, portanto torné-lo de facil leitura realmente facilita a escrita. Nao ha como escapar desta logica. Vocé nao pode eserever um cddigo se nao quiser ler as outras partes dele. O cddigo que vocé tenta eserever hoje sera de dificil ou facil leitura dependendo da facilidade de leitura da outra parte do cdigo. Sc quiser ser rapido. se quiser acabar logo, se quiser que seu codigo seja de facil escrita, tome-o de facil leitura. 4 Capitulo 1: Cédigo Limpo A Regra de Escoteiro Nao basta escrever um cédigo bom. Ele precisa ser mantido sempre limpo. Todos jé vimos cédigos estragarem e degradarem com o tempo. Portanto, precisamos assumir um papel ativo na prevengao da degradacao. ‘A Boy Scouts of America (maior organizagao de jovens escoteiros dos EUA) tem uma regra simples que podemos aplicar 4 nossa profissao, Deixe a érea do acampamenio mais limpa do que como vocé a enconirou.* Se todos deixdssemos nosso cédigo mais limpo do que quando 0 comecamos, ele simplesmente nao degradaria. A limpeza ndo precisa ser algo grande, Troque o nome de uma varidivel por um melhor, divida uma fungdo que esteja um pouco grande demais, climine um pouco de repeti¢ao de cédigo, reduza uma instrugo 4 £ aninhada. Consegue se imaginar trabalhando num projeto no qual 0 cédigo simplesmente melhorou com tempo? Vocé acredita que qualquer alternativa seja profissional? Na verdade, 0 aperfeigoamento continuo nao ¢ inerente ao profissionalismo? Prequela e Principios Em muitas maneiras este livro é uma “prequela” de outro que escrevi em 2002, chamado Agile Software Development: Principles. Patterns, and Practices (PPP). Ele fala sobre os prineipios do projeto orientado a objeto ¢ muitas das priticas utilizadas por desenvolvedores profissionais Se vocé ainda nao leu o PPP, talvez ache que € a continuagao deste livro. Se ja 0 leu, entao percebera que ele ¢ bastante parecido a esse em relacao aos codigos. Neste livro ha referencias esporddicas a diversos principios de projeto, dentre os quais esto Principio da Responsabilidade Unica (SRP, sigla em inglés), Principio de Aberto-Fechado (OCP, sigla emMinglés), Principio da Inversdo da Independéncia (DIP, sigla em inglés), dentre outros. Esses principios sao descritos detalhadamente no PPP. Conclusao Livros sobre arte ndo prometem Ihe tornar um artista. Tudo o que podem fazer ¢ Ihe oferecer algumas das ferramentas, técnicas ¢ linhas de pensamento que outros artistas usaram. Portanto, este livro no pode prometer Ihe tornar um bom programador. Ou the dar a “sensibilidade a0 cédigo”. Tudo o que ele pode fazer é Ihe mostrar a linha de pensamento de bons programadores cos truques, técnicas e ferramentas que eles usam. ‘Assim como um livro sobre arte, este esta cheio de detalhes. Ha muitos codigos. Vocé vera cédigos bons ¢ mains; cédigo ruim sendo transformado em bom: listas de heuristicas, orientagdes ¢ técnicas; ¢ também exemplo apds exemplo. Depois disso, ¢ por sua conta. que se perdeu no caminho para a apresentagao em Lembre-se daquela piada sobre o violinis eecceam: ein esacen eee: ronitinnmamtinne then mat wiih acai Bibliografia 15 um concerto? Ele aborda um senhor na esquina ¢ lhe pergunta como chegar ao Camnegie Hall. O senhor observa o violinista com scu violino debaixo dos bragos e diz “Pratique, filho. Pratique!”. Bibliografia [Beck07]: Jmplementation Patterns, Kent Beck, Addison-Wesley, 2007. [Knuth92]: Literate Programming, Donald E. Knuth, Center for the Study of Language and Information, Leland Stanford Junior University, 1992. 2 Nomes Significativos por Tim Ottinger Introducio Ha nomes por todos os lados em um software. Nomeamos nossas varidveis, fungdes, parimetros, classes e pacotes, assim como os arquivos-fonte € os diretérios que os possui. Nomeamos também nossos arquivos jar e war e ear. E nomeamos, nomeamos € nomeamos. Como fazemos muito isso, & melhor que o facamos bem. A seguir esto algumas regras simples para a criagdo de bons nomes. 18 Capitulo 2: Nomes Significativos Use Nomes que Revelem seu Propésito Dizer que os nomes devem demonstrar seu propésito € facil. Mas queremos que vocé saiba que estamos falando sério. Escolher bons nomes leva tempo, mas economiza mais. Portanto, cuide de seus nomes ¢ troque-os quando encontrar melhores. Todos que lerem seu codigo (incluindo vocé mesmo) ficardo agradecidos. © nome de uma variével, fungto ou classe deve responder a todas as grandes questies. Ele deve Ihe dizer porque existe, o que faz e como é usado. Se um nome requer um comentario, entio ele nao revela seu propésito. int d; // tempo decorrido em dias O nome d nao revela nada, Ele nao indica a ideia de tempo decorrido, nem de dias. Devemos escolher um nome que especifique seu uso para mensuragdo e a unidade usada int elapsedTimeInDays; int daysSinceCreation; int daysSi inceModification; int fileAgeInDays; Escolher nomes que revelem seu propdsito pode facilitar bastante o entendimento ea alteragao do cédigo. Qual o propésito deste cédigo? public List getThem() ( List listl = new ArrayList()7 for (int{] x : thebist) if (xf0] 4) Listl.add(x); return listl; } Por que € dificil dizer 0 que 0 eédigo faz? Nao ha expressdes complexas. espagamento ¢ a endentagao sao cabiveis. Sé hé trés variaveis € duas constantes, Nem mesmo ha classes refinadas ou métodos polimérficos. apenas uma lista de vetores (pelo menos & 0 que parece). O problema nao é a simplicidade do c6digo, mas seu aspecto implicito, isto é, 0 contexto nio est explicito no cédigo. Devido a isso, é necessario que saibamos as repostas para questdes como: 1. Que tipos de coisas esto em theList? 2. Qual a importancia de um item na posig&o zero na thelist? 3. Qual a importéncia do valor 4? 4, Como eu usaria a lista retornada? [As respostas para tais questdes nfo esto presentes no exemplo do cédigo, mas poderiam, Digamos que estejamos trabalhando num jogo do tipo “campo minado”. Perecbemos que 0 tabuleiro ¢ uma lista de células chamada thetist. Vamos renomeé-la para gameBoard. Eyite Informagoes Erradas 19 Cada quadrado no tabuleiro é representada por um vetor simples. Mais tarde, descobrimos que a posi¢ao zero ¢ armazena um valor de status e que o valor 4 significa “marcado com uma bandeirinha”. Ao dar esses nomes explicativos, podemos melhorar consideravelmente o cédigo: public List getFlaggedCells(} { List flaggedCells = new ArrayList(); for (int[] cell : gameBoard) if (cell[STATUS_VALUE] flaggedCells.add(cell); return flaggedCells; FLAGGED) } Note que a simplicidade do cédigo nao mudou. Ele ainda possui o mesmo mimero de operadores e constantes, com 0 mesmo numero de itens aninhados. Entretanto, 0 cédigo ficou muito mais explicito. Podemos continuar ¢ criar uma classe simples para as células, em vez de usar um vetor int S. Ela pode ter uma funcao com um nome revele seu propdsito (chamada isFlagged, ou seja “estd marcada com uma bandeirinha”) para ocultar os ntimeros magicos. O resultado ¢ uma nova ve! da fungao: public List getFlaggedCells() { List flaggedCells = new Arraybist(); for (Cell cell : gameBoard) if (cell.isFlaggedi)) flaggedCells.addicelb; return flaggedCells; Com essas simples alteragdes de nomes, nfo fica dificil entender o que esta acontecendo. Esse € o poder de escolher bons nomes. Evite Informagées Erradas Os programadores devem evitar passar dicas falsas que confundam o sentido do cédigo. Devemos evitar palavras cujos significados podem se desviar daquele que desejamos. Por exemplo, np, aix e sco seriam nomes ruins de varidveis, pois sio nomes de plataformas Unix ou variantes. Mesmo se estiver programando uma hipotenusa e hp parecer uma boa abreviagao, o nome pode ser mal interpretado. ‘Nao se refira a um grupo de contas como account List, a menos que realmente seja uma List. A palavra [ist (lista) significa algo especifico para programadores. Se o que armazena as contas nao for uma List de verdade, podera confundir os outros.' Portanto, accountGroup ou bunchOfAccounts ou apenas accounts seria melhor. Cuidado ao usar nomes muito parecidos. Fica dificil perceber a pequena diferenga entre xYZControllerForEfficientHandlingOfStrings em um méddulo e¢ xY¥ZControllerForEfficientStorageOfStrings em outro. Ambas as palavras sio muito semelhantes. 20 Capitulo 2: Nomes Significatives Usar conceitos similares para montar palavras ¢ informacdo. Usar formatos inconsistentes para palavras leva a uma ma interpretacdo. Com os ambientes Java de hoje dispomos do recurso de autocompletar palavras. Digitamos alguns caracteres de um nome ¢ pressionamos uma combinagao de teclas (se houver uma) e, entio, aparece uma lista de possiveis palavras que se iniciam com tais letras. Isso ¢ muito pratico se houver nomes muito parecidos organizados alfabeticamente num mesmo local e se as diferengas forem dbvias, pois ¢ mais provavel que o desenvolvedor escolha um objeto pelo nome, sem consultar seus comentérios ou mesmo a lista de métodos fornecidos por aquela classe. Um exemplo real de nomes que podem gerar confusio ¢ 0 uso da letra “I” miniscula ou da vogal “oO” maiiscula como nome de varidveis. O problema é que eles se parecem com 0 um € 0 zero, respectivamente. int a= 1; if (0 ) a 2°01: else 1 = 01; leitor pode achar que inventamos esse exemplo, mas jé vimos cédigos nos quais isso acontecia bastante, Uma vez, 0 autor do cédigo sugeriu 0 uso de fontes distintas de modo a realgar mais as diferengas, uma solugo que teria de ser repassada de forma oral ou escrita a todos os futuros desenvolvedores. Com uma simples troca de nome, 0 problema é resolvido com objetividade e sem precisar criar novas tarefas. Faca Distingées Significativas Os programadores criam problemas para si préprios quando criam um codigo voltado unicamente para um compilador ou interpretador. Por exemplo, como nao é possivel usar 0 mesmo nome para referir-se a duas coisas diferentes num mesmo escopo, voce pode decidir alterar o nome de maneira arbitraria, As vezes, isso é feito escrevendo um dos nomes errado, produzindo a uma situago na qual a correcao de erros de ortografia impossibilita a compilagao.* Nao basta adicionar nimeros ou palavras muito comuns, mesmo que o compilador fique satisfeito, Se os nomes precisam ser diferentes, ento também devem ter significados distintos. Usar ntimeros sequenciais em nomes (al, a2,...,aN) ¢ 0 oposto da selegao de nomes expressivos. Eles nao geram confusdo, simplesmente n8o oferecem informag3o alguma ou dica sobre a inten¢do de seu criador. Considere 0 seguinte: public static void copyCharsichar al[], char a2[]) { for (int i = 0; i < al.length; i++) { a2(i] = allil: } } Use Nomes Pronuncitiyeis Fica muito mais facil ler essa fung&o quando usam-se source ¢ destination como nomes de parémetros. Palavras muito comuns sio outra forma de distingdo que nada expressam. Imagine que vocé tenha uma classe Product. Se houver outra chamada ProductInfo ou ProductData, vocé usou nomes distintos que ndo revelam nada de diferente. Info e Data sao palavras muito comuns e vagas, como “um”, Observe que nao ha problema em usar prefixes como “um” e “a”, contanto que fagam uma distingao significativa, Por exemplo, vocé pode usar “um” para varidveis locais e “a” para todos os parametros de funges.’ © problema surge quando vocé decide chamar uma varidvel de aZork s6 porque ja existe outra chamada zork. Palavras muito comuns sao redundantes. O nome de uma variavel jamais deve conter a palavra “variavel”. O nome de uma tabela jamais deve conter a palavra tabela. Entio como ‘NameString é melhor do que Name? Um Name pode ser um numero do tipo ponto flutuante? Caso possa, estaria violando uma regra sobre passar informagoes incorretas. Imagine que vocé encontre uma classe Customer € outra CustomerObject. O que a diferenga nos nomes Ihe diz? Qual seria a melhor para possuir o historico de pagamento de um cliente? Conhecemos um aplicativo que ¢ assim. A fim de proteger seus desenvolvedores, trocamos ‘os nomes, mas abaixo est exatamente o tipo de erro: getActiveAccounti); getActiveAccounts(); getActiveAccount Info(); Como os programadores desse projeto poderiam saber qual das trés fungdes chamar? ‘Na auséncia de convencdes especificas, ndo ha como distinguir moneyAmount de money, customerInfo de customer, accountData de account ¢ theMMessage de message. Faga a distingao dos nomes de uma forma que o leitor compreenda as diferencas. Use Nomes Pronunciaveis Os ser humano é bom com as palavras. Uma parte consideravel de seu cérebro é responsivel pelo conceito das palavras. E, por definicao, as palavras so pronuncidveis. Seria uma ldstima nao tirar proveito dessa importante parte de nosso cérebro que evoluiu para lidar com a lingua falada.Sendo assim, crie nomes pronunc Se nao puder pronuncia-lo, nao tera como discutir sobre tal nome sem parecer um idiota. “Bem, aqui no bé cé erre trés cé ene té, temos um pé esse 76 que int, viram?”. Isso importa porque a programacao é uma atividade social. Conhego uma empresa que possui uma varidvel genymdhms (generation date, year, month, day, hour, minute e second) ¢ seus funcionarios sacm falando “gé dabliu eme dé aga eme esse”, Tenho um habito irritante de pronunciar tudo como esta escrito, portanto comecei a falar “gen-yah-muddahims”. Depois desenvolvedores € analistas estayam falando assim também, e ainda soava estiipido. Mas estévamos fazendo uma brincadeira e, por isso, foi divertido. Engragado ou nao, estamos tolerando nomeagdes de baixa qualidade. Novos desenvolvedores tiveram de pedir que Ihes explicassem as variaveis, e, entdo, em vez de usar termos existentes na lingua, inventavam palavras bobas ao pronuncié-las. Compare ‘eis. a 22 Capitulo 2: Nomes Significativos class DtaRerd102 { private Date genymdhms; private Date modymdhms; private final string pszgint = “102”; ce ue com class Customer { private Date generationTimestamp; private Date modificationTimestamp;; private final String recordId = *102*; 7* aa *F he Agora é possivel uma conversa inteligente: “Ei, Mikey, dé uma olhada este registro! A generation timestamp (“ctiago de marcago de horario”) esta marcada para amanha! Como pode?”. Use Nomes Passiveis de Busca ‘Nomes de uma s6 letra ou nimeros possuem um problema em particular por nao ser facil localiza- los ao longo de um texto. Pode-se usar facilmente 0 grep para MAX_CLASSES_PER_STUDENT, mas buscar o numero 7 poderia ser mais complicado, Nomes, definigdes de constantes e varias outras expressdes que possuam tal niimero, usado para outros propésitos podem ser resultados da busca. Pior ainda quando uma constante é um nimero grande e alguém talvez tenha trocado os digitos, eriando assim um bug ¢ ao mesmo tempo nfo sendo caplada pela busca efetuada. Damesma forma, onome*e” éuma escolharuim para qualquer variavela qual um programador talvez precise fazer uma busca. E uma letra muito comum e provavelmente aparecera em todo texto em qualquer programa. Devido a isso, nomes longos se sobressaem aos curtos, ¢ qualquer nome passivel de busca se sobressai a uma constante no cédigo., Particularmente. prefiro que nomes com uma tinica letra SO sejam usados como variaveis locais dentro de métodos pequenos. O tamanho de um nome deve ser proporcional ao tamanho do escopo. [NS]. Se uma varidvel ou constante pode ser vista ou usada em varios lugares dentro do cédigo. é imperativo atribui-la um nome facil para busca. Novamente, compare for (int j=0; 3<34; j++) ( s += (tI4]*4)/5; com int realDaysPerIdealDay = 4; const int WORK_DAYS_PER_WEEK = 5; int sum = 0; for (int j=0; j < NUMBER_OF_TASKS; j++) { int realTaskDays = taskEstimate[j] * realDaysPeridealDa: int realTaskWeeks = (realdays / WORK_DAYS_PER_WEEK); sum += realTaskWeeks; } Evite Codificacdes 23 Note que sum nao é um nome pritico, mas pelo menos é facil de procurar. © nome usado no cédigo serve para uma fungdo maior, mas pense como seria muito mais ficil encontrar WORK_ DAYS_PER_WEEK do que buscar em todos os lugares nos quais 0 5 aparece ¢, entfo, filtrar os resultados para exibir apenas as instdncias que vocé deseja. vite Codificagées Ja temos de lidar com bastante codificagéo ¢ nao precisamos acrescentar mais. Codificar informagdes do escopo ou tipos em nomes simplesmente adiciona uma tarefa extra de decifracao. Dificilmente parece logico contratar um novo funcionario para aprender outra “linguagem”™ codificadora além da atual usada no cédigo no qual se esta trabalhando. E uma sobrecarga mental desnecessaria ao tentar resolver um problema. Nomes codificados raramente so pronuncidveis, além de ser facil escrevé-los incorretamente. ANotacaéo Hingara Antigamente, quando trabalhavamos com linguagens com limite de tamanho para os nomes, violavamos essa regra quando necessério, com certo arrependimento. O Fortran forgava codificagdes, ao tomar a primeira letra uma indicag4o para o tipo. Versdes anteriores do BASIC sé permitiam uma letra mais um digito, A Notacdo Hingara (NH) inovou essas limitagdes. Na época da API em C do Windows, a NH era considerada muito importante, quando tudo era um inteiro owum ponteiro para um inteiro long de 32 bits ou um ponteiro do tipo void, ou uma das diversas implementagdes de “strings” (com finalidades e atributos diferentes). O compilador nao verificaya os tipos naquele tempo, entio os programadores precisavam de ajuda para lembrar dos upos. Em linguagens modemas, temos tipos muito melhores, ¢ os compiladores os reconhecem ¢ os tornam obrigatérios. Ademais. ha uma certa tendéncia para a criagdo de classes ¢ fungdes menores- de modo que as pessoas possam ver onde cada varidvel que esto usando foi declarada. Os programadores Java nao precisam definir o tipo. Os objetos ja so 0 priprio tipo, e a edigao de ambientes se tornou to avangada que detectam quando se usa inadequadamente um tipo antes mesmo da compilagao! Portanto, hoje em dia, a NH c outras formas de convengiio de tipos sao basicamente obstaculos. Eles dificultam a alterago do nome ou do tipo de uma varidvel, fungao ow classe; dificultam a leitura do cddigo; ¢ criam a possibilidade de que o sistema de codificagao induza o leitor ao erro. PhoneNumber phoneString; // 9 nome nao muda na alteracao do tipo! Prefixes de Variiveis Membro Vocé nao precisa mais colocar o prefixo m_em varidveis membro. Mas para isso, suas classes € fangdes devem ser pequenas. E vocé deve usar um ambiente de edigao que realce ou colore as varidveis membro de modo a distinguilas. public class Part { private String m_dsc; // Descricéo textual void setName(String name) ( 24 Capitulo lomes Significativos m_dsc = name; } ? public class Part { String description; void setDescription(String description) ( this.description = description; } t ‘Alem disso, as pessoas rapidamente aprendem a ignorar o prefixo (ou sufixo) para visualizar a parte significativa do nome. Quanto mais lemos 0 cédigo, menos prefixos enxergamos. No final, estes se tornam pares invisiveis e um indicative de cédigo velho. Interfaces e Implementagées ‘As vezes, hd casos especiais para codificagées. Por exemplo, digamos que vocé esteja construindo uma ABSTRACT FACTORY para criar formas. Essa factory sera uma interface, ¢ implementada por uma classe concreta. Como devemos nomed-la? IShapeFactory € ShapeFactory? Prefiro no enfeitar as interfaces. O “x” no inicio, tao comum no hoje em dia, é na melhor das hipdteses uma distragdo, e na pior so informagdes excessivas. Ndo quero que meus usuarios saibam que estou Ihes dando uma interface, e, sim, apenas uma ShapeFactory. Portanto, se eu devo codificar seja a interface ou a implementagao, escolho esta, Para codificar a interface. é preferivel chama-la de ShapeFactoryimp, ou mesmo de CShapeFactory. Evite o Mapeamento Mental Os leitores nfio devem ter de traduzir mentalmente os nomes que vocé escolheu por outros que eles conhegam. Essa questio costuma levar a decisdo de nfo usar os termos do dominio do problema e nem os da solugao. Este é um problema com nomes de varidveis de uma sé letra. Certamente um contador de iteragdes pode ser chamado de “i”, “j” ou “k” (mas nunca 1) ~ isso jd se tornou uma tradig’io — se seu escopo for muito pequeno ¢ ndo houver outros nomes que possam entrar em conflito com ele. Entretanto, na maioria dos contextos, um nome de uma sé letra é uma escolha ruim; é apenas um armazenador que o leitor devera mentalmente mapear de acordo com 0 conceito em uso. Nao hd razio pior do que usar o nome “c” s6 porque “a” e “b” jé esto sendo usados. De maneira geral, os programadores sao pessoas muito espertas. E esse tipo de pessoas gosta de se exibir mostrando suas habilidades mentais. Apesar de tudo, se vocé puder confiantemente se lembrar de que or” minusculo € uma versdo da url sem o host ¢ 0 contexto, entdo obviamente vocé é muito esperto. Uma diferenca entre um programador esperto e um programador profissional é que este entende que clareza é fundamental. Os profissionais usam seus poderes para o bem, e escrevem cédigos que outros possam entender. Nomes de Classes Classes € objetos devem ter nomes com substantivo(s), como Cliente, PaginaWiki, Conta e AnaliseEndereco. Evite palavras como Gerente, Processador, Dados ou Info no nome de uma classe, que também nao deve ser um verbo. Nomes de Métodos Os nomes de métodos devem ter verbos, como postarPagamento, excluirPagina ou salvar. Devem-se nomear métodos de acesso, alteragdo e autenticagAo segundo seus valores ¢ adicionar 0s prefixos get, set ou is de acordo com o padrio javabean.* string name = employee.getName(); customer.setName(*mike*); if (paycheck.isPosted()).. Quando os construtores estiverem sobrecarregados, use métodos factory estditicos com nomes que descrevam os parametros. Por exemplo, Complex fulerumPoint = Complex.FromRealNumber (23.0); € melhor do que Complex fulerumpoint = new Complex(23.0); Para forgar seu uso, torne os construtores correspondentes como privados. Nao dé uma de Espertinho Se os nomes forem muito “espertinhos”, apenas as pessoas que compartilhem do mesmo senso de humor que seu dono irao lembra-los, e sO enquanto se lembrarem da brincadcira. Eles saberio o que deve fazer a fungdo HolyHandGrenade? Claro, € engragado, mas talvez nesse caso DeleteTtems fique melhor. Opte por clareza no lugar de divertimento. Essas gracinhas em c6digos costumam aparecer na forma de coloquialismos e girias. Por exemplo, nao use firmar () para significar terminar(). Nao use piadas de baixo caldo, como cairFora para significar abortar (). Diga o que vocé quer expressar. Expresse 0 que vocé quer dizer. 26 Capitulo 2: Nomes Significativos Selecione uma Palayra por Conceito Escolha uma palavra por cada conceito abstrato e fique com ela. Por exemplo, é confuso ter pegar, recuperar ¢ obter como métodos equivalentes de classes diferentes, Como lembrar a qual método pertence cada classe? Infelizmente, vocé geralmente precisa se lembrar qual empresa, grupo ou pessoa criou a biblioteca ou a classe de modo a recordar qual termo foi usado. Caso contririo, vocé perde muito tempo vasculhando pelos cabegalhos e exemplos de cédigos antigos. Os ambientes modemos de edigdo. como o Eclipse ¢ o IntelliJ, oferecem dicas relacionadas a0 contexto, como a lista de métodos que vocé pode chamar em um determinado objeto. Mas. note que a lista geralmente no lhe oferece os comentarios que vocé escreveu em torno dos nomes de suas fungdes. Vocé tem sorte se receber 0 pardmetro nomes (names) das declaragdes das fungdes. Os nomes das fungdes tém de ficar sozinhos, e devem ser consistentes de modo que vocé possa selecionar 0 método correto sem qualquer busca extra. Da mesma forma, é confuso ter um controlador, um gerenciador ¢ um driver no mesmo c6digo-fonte. Qual a principal diferenga entre um GerenciadorDeDispositivo eum controlador-de-protocolo? Porque ambos nao sao controladores ougerenciadores? Ambos sao realmente drivers? O nome faz com que vocé espere dois objetos com tipos bem distintos, assim como ter classes diferentes. Um léxico consistente é uma grande vantagem aos programadores que precisem usar seu cédigo. Nao Faca Trocadilhos Evite usar a mesma palavra para dois propésitos. Usar o mesmo termo para duas ideias diferentes & basicamente um trocadilho. Se vocé seguir a regra “uma palavra por conceito”, vocé pode acabar ficando com muitas classes que possuam, por exemplo, um método add. Contanto que as listas de parametros e os valores retornados dos diversos métodos add sejam semanticamente equivalentes, tudo bem. Entretanto, uma pessoa pode decidir usar a palayra add por fins de “consisténcia” quando ela na verdade no aplica o mesmo sentido a todas, Digamos que tenhamos muitas classes nas quais add criara um novo valor por meio da adig&o e concatenagao de dois valores existentes. Agora, digamos que estejamos criando uma nova classe que possua um método que coloque seu Gnico parametro em uma colegdo. Deveriamos chamar este método de add? Por termos tantos outros meétodos add, isso pode parecer consistente. Mas, neste caso, a semantica & diferente. Portanto, deveriamos usar um nome como inscrir ou adicionar. Chamar este novo método de add seria um trocadilho. Nosso objetivo, como autores, € tornar a leitura de nosso eédigo o mais fiicil possivel. Desejamos que nosso cédigo seja de rapida leitura, e nao um estudo demorado. Queremos usar a linguagem de um livro popular no qual ¢ responsabilidade do autor ser claro, endo uma linguagem académica na qual a tarefa do estudioso é entender minuciosamente o que esta escrito. Use nomes a partir do Dominio da Solugio Lembre-se de que serdo programadores que lerao seu cédigo. Portanto, pode usar termos de Informatica, nomes de algoritmos, nomes de padrdes, termos matematicos ctc. Nao é prudente Adicione um Contexto Significativo 7 pensar num nome a partir do dominio do problema, pois ndo queremos que nossos companheiros de trabalho tenham de consultar o cliente toda hora para saber o significado de um nome o qual eles jé conhecem 0 conceito. s6 que por outro nome. © nome AccountVisitor (“conta do visitante”) significa o bastante para um programador familiarizado com o padrao VISITOR. Qual programador nao saberia o que € uma JobQueve (“fila de tarefas”)? HA muitas coisas técnicas que os programadores devem fazer. Selecionar nomes técnicos para tais coisas &. geralmente, 0 método mais adequado. Use nomes de Dominios do Problema Quando nao houver uma solugio “a la programador”, use o nome do dominio do problema. Pelo menos o programador que fizer a manutengao do seu eédigo poder perguntar a um especialista em tal dominio o que o nome significa. Distinguir os conceitos do dominio do problema dos do dominio da soluedo ¢ parte da tarefa de um bom programador e designer, O cédigo que tem mais a ver com os conceitos do dominio do problema tem nomes derivados de tal dominio. Adicione um Contexto Significativo Ha poucos nomes que so significativos por si s6—a maioria nao é. Por conta disso, vocé precisa usar nomes que fagam parte do contexto para o leitor. Para isso vocé os coloca em classes, fungdes e namespaces bem nomeados. Se nada disso funcionar, entao talvez. como tiltimo recurso seja necessério adicionar prefixos ao nome. Imagine que vocé tenha variaveis chamadas firstName, LastName, street, houseNumber, city, state e zipcode. Vistas juntas, fica bem claro que elas formam um enderego. Mas © se vocé s6 visse a varidvel state sozinha num método? Automaticamente yocé assumiria ser parte de um enderego? Podem-se usar prefixos para adicionar um contexto: addrFirstName, addrLastName, addr State etc. Pelo menos os leitores entenderao que esas varidveis so parte de uma estrutura maior. E claro que uma melhor solugdo seria criar uma classe chamada Address Ento, até o compilador sabe que as variiveis pertencem a um escopo maior. ‘Veja o método na Listagem 2.1. As variéveis precisam de um contexto mais significative? O nome da fungdo oferece apenas parte do contexto; o algoritmo apresenta o resto. Apés ter lido a fungao, voeé vé que trés varidveis, number, verb ¢ pluralModifier, fazem parte da mensagem de dedugo (guess statistics message). Infelizmente, 0 contexto deve ser inferido. Ao olhar pela primeira vez o método, o significado das variaveis nao esta claro. 28 Capitulo 2: Nomes Significativos Listagem 2-1 Variaveis com contexto obscuro private void printGuessstatistics(char candidate, int count) ( String number; String verb; String pluralModifier; if (count == 0) { number = “no”; verb = “Existem*; pluralModifier = "s"; else if (count == 1) ( number = “1"; verb = “Existe’; pluralModifier = * } else { number = Integer.toString(count); verb = “Existem’; pluralModifier = “s"; z String guessNessage = String. format ( “There ts $s %sts", verb, number, candidate, pluralModifier fe print (guessMessage) ; > A funcao ¢ um pouco extensa demais também ¢ as varidveis so bastante usadas. A fim de dividir a fun¢do em partes menores, precisamos criar uma classe GuessStatisticsMessage ¢ tornar as trés varidveis como campos desta classe. Isso oferecera um contexto mais claro para as trés varidveis. Elas so definitivamente parte da GuessStatisticsMessage. A melhora do contexto também permite ao algoritmo ficar muito mais claro ao dividi-lo em fungdes menores (veja a Listagem 2.2). Listagem 2-2 Variaveis possuem contexto public class GuessStatisticsMessage { private string number; private String verb; private String pluralModifier; public String make(char candidate, int count) ¢ createPluralDependentMessageParts (count return String. format ( “There ts %s ¢s%s verb, number, candidate, pluralModifier ): } private void createPluralDependentMessageParts(int count) { 4£ (count == 0) { thereAreNoLetters(); else if (count == 1} { thereTsOneLetter () } else ( Nao Adicione Contextos Desnecessirios 29 Listagem 2-2 (continuasao) variaveis possuem contexto thereAreManyLetters (count); ) d private void thereAreManyLetters(int count) { number = Integer.toString(count) ; verb = *Existem"; pluralModifier = ‘s"; ) private void thereTsOneLetter() { number = “1% verb = “Bxiste* pluralModifier = **: ) private void thereareNoetters() { number = “no”: verb = “Existem*; pluralModifier = "s*; N&o Adicione Contextos Desnecessarios Em um aplicativo ficticio chamado “Gas Station Deluxe” (GSD), seria uma péssima ideia adicionar prefixos a toda classe com Gsb. Para ser sineero, vocé estar4 trabalhando contra suas ferramentas. Vocé digita G e pressiona a tecla de autocompletar e recebe uma lista quilométrica de * cada classe no sistema. Isso ¢ inteligente? Para que dificultar a ajuda da IDE? Da mesma forma, digamos que vocé inventou uma classe MailingAddress no modulo de contabilidade do GSD e que o chamou de GSDAccount Address. Mais tarde. vocé precisa armazenar um enderego postal de seu cliente no aplicativo. Vocé usaria GSDAccountAddress? Parece que o nome € adequado? Dez dos 17 caracteres so redundantes ou irrelevantes. Nomes curtos geralmente sfio melhores contanto que sejam claros. Nao adicione mais contexto a um nome do que 0 necessario. Os nomes accountAddress ¢ customerAddress esti bons para instancias da classe ‘Address, mas seriam ruins para nomes de classes. Address esta bom para uma classe. Se precisar diferenciar entre enderecos MAC, enderegos de portas ¢ enderecos da Web, uma ideia seria Postaladdress, MAC € URT. Os nomes resultantes s4o mais precisos, motivo esse da tarefa de se atribuir nomes. Conclusao O mais dificil sobre escolher bons nomes é.a necessidade de se possuir boas habilidades de descri¢ao eum historico cultural compartilhado. Essa é uma questo de aprender, e nao técnica, gerencial ou cempresarial. Como consequéncia, muitas pessoas nessa érea néo aprendem essa tarefa muito bem. 30 Capitulo 2: Nomes Si Elas também tém receio de renomear as coisas por temer que outros desenvolvedores sejam contra, Nao compartilhamos desse medo e achamos que ficamos realmente agradecidos quando os nomes mudam (para melhor). Na maioria das vezes, no memorizamos os nomes de classes @ métodos. Mas usamos ferramentas modernas para lidar com detalhes de modo que possamos nos focalizar e ver se 0 c6digo é lido como paragrafos, frases, ou pelo menos como tabelas ¢ estruturas de dados (uma frase nem sempre é a melhor forma de se exibir dados). Provavelmente vocé acabaré surpreendendo alguém quando renomear algo. assim como qualquer outra melhoria no cédigo. Nao deixe que isso atrapalhe seu progresso. Siga alguma dessas regras e note se voce no melhorou a legibilidade de seu cédigo. Se estiver fazendo a manutencao do cédigo de outra pessoa, use ferramentas de refatoragao para ajudar a resolver essas questdes. Em pouco tempo valerd a pena, e continuard a vale em longo prazo. Nos primérdios da programagio, formavamos nossos sistemas com rotinas ¢ sub-rotinas. Ja na era do Fortran e do PL/1, usavamos programas, subprogramas ¢ fungdes. De tudo isso, apenas fungdo prevaleceu. As fungSes sio a primeira linha de organizagao em qualquer programa. Escrevé-las bem € o assunto deste capitulo. 32 Capitulo 3: Fungoes Veja o cédigo na Listagem 3.1. E dificil encontrar uma fungdo grande em FitNesse', mas procurando um pouco mais encontramos uma. Além de ser longo, seu codigo é repetido, hd diversas strings estranhas e muitos tipos de dados ¢ APIs esquisitos ¢ nada dbvios. Veja o quanto voeé consegue compreender nos préximos trés minutos. Listagem 3-1 Btmlutil a (FitNesse 20070619) bletical ( public static String te: PageData pagebata, boolean includesuires } throws Exception ( WikiFage wikiPage = rageData.getwikipage (|; StringBuft.~ buffer = new ScringBufter(!; Ca-hasAttribute(*Test")} { > PageCrawlerImp! .get InheritedPage i SuiteResponder. SUITE SETUP_NAME, wikiPage iteSetup != null) { WikiPageZath pagePath suiteSetup .cetPageCrawler!) .getPullPathisuitesetup) ; String pagePathNane = PathParser-render ipagePathi; buffer.appendi*!inelude -se Lo} -append (pageFat hlvame) append(*\n"): i ) Wikivage setup PageCrawler Imp: if (setup != null) { WikiPagePath setupPath - wiki Page. get PageCrawler () .gecFullpath (setup) ; String setupPathName = PachParser.render(setupPath) ; buffer-append(*!include -sevup .*) -append (setupPathName! -append(*\ nheritedPage(*Setup", wikiPage) ; buffer.append(pageData.aetContent (}); if (pageData.hasAttribute("Test*)} { WikiPage teardown PageCrawlerIncl.getInheritedPage(*TearDown", wikiPage’ ; if (teardown != null) { wikiPagePath tearDownPath wiki Page get PageCrawler (i .getPull Path (teardown) ; String tearDownfathName = PathPerser. render (tearDownEath) ; burfer.append(*\n") append("! include -teardewn .*| -append (tearDownPathwame! -append("\n"} 1.15 Mecermnitin de tenis dis chilean theme: wrereiiiiarerene:i- 33 20070619) if |includesuitesetup) kipage suiceTeardown = PageCraxleringl .get InheritedPage( ‘SuiteResponder. SUITE_TEARDONI_NAME, wikipage iteTeardewn != null [ PagePath pag ullpath (su jer (pagePath); pageData.setContent (buffer return pageData.getHtml (}; Conseguiu entender a fungio depois desses trés minutos estudando-a? Provavelmente nao. ‘Ha muita coisa acontecendo li em muitos niveis diferentes de . Ha strings estranhas e chamadas a fungées esquisitas misturadas com dois i £ aninhados controlados por flags. Entretanto, com umas poucas extragdes simples de métodos, algumas renomeagdes e um pouco de reestruturacao fui capaz de entender o propésito da fungdio nas nove linhas da Listagem 3.2. Veja se vocé consegue compreender também em trés minutos. Listagem 3-2 Htmlutil.java (refatorado) iTeardowns | string renderPageWichSetupsan isSuite public static PageData pa | throws Exception boolean isTestEage = pageData.hasAttribute(*Test"); if (igTestPage) { WikiPace testPage = pageData.getWikiPage(!; StringBuffer newEageContent = new ScringBuffer(); includeSecupPages|testPage, neweageContent, isSuite) ; newPageContent .append ipageData.getContent ())7 includeTeardownPages(testPage, newPageContent, isSuite): pageData.setContent (newPagecontent toString ()} + return pageData.getHtml (1; 34 Capitulo 3: Fungées ‘A menos que jé estivesse estudando o FitNesse, provavelmente vocé nao entendeu todos os detalhes. ‘Ainda assim vocé talvez tenha compreendido que essa fungao efetua a inclusao de algumas paginas SetUp e TearDown cm uma pagina de teste e, entio, exibir tal pagina em HTML. Se estiver familiarizado com o JUnit’, vocé ja deve ter perecbido que essa fungdo pertenca a algum tipo de framework de teste voltado para a Web. E vocé esta certo. Deduzir tal informagao da Listagem 3.2 € muito facil, mas cla esta bastante obscura na Listagem 3.1 Entdio, 0 que torna uma fungdo como a da Listagem 3.2 facil de ler e entender? Como fazer uma fungdo transmitir seu propésito? Quais atributos dar as nossas fungdes que permitirao um leitor comum deduzir o tipo do programa ali contido? Pequenas! ‘A primeira regra para fungdes € que elas devem ser pequenas. A segunda ¢ que precisam ser mais espertas do que isso. Nao tenho como justificar essa afirmagao. Nao tenho referéncias de pesquisas que mostrem que fungdes muito pequenas sio melhores. $6 posso dizer que por cerca de quatro décadas tenho criado fungdes de tamanhos variados. Jé eserevi diversos monstros de 3.000 linhas; bastantes fungdes de 100 a 300 linhas; e fungSes que tinham apenas de 20 a 30 linhas. Essa experiéncia me ensinou que, ao longo de muitas tentativas ¢ erros, as fungdes devem ser muito pequenas. Na década de 1980, costumavamos dizer que uma funcao nao deveria ser maior do que a tela. E claro que na época usavamos as telas VT100, de 24 linhas por 80 colunas, e nossos editores usavam 4 linhas para fins gerenciamento, Hoje em dia, com fontes reduzidas e um belo c grande monitor, vocé consegue colocar 150 caracteres em uma linha — nao se deve ultrapassar esse limite—e umas 100 linhas ou mais por tela—as fungdes nao devem chegar a isso tudo, elas devem ter no maximo 20 linhas. © quao pequena deve ser uma fung3o? Em 1999, fui visitar Kent Beck em sua casa, em Oregon, EUA. Sentamo-nos ¢ programamos um pouco juntos. Em certo ponto, ele me mostrou um simpatico programa de nome Java/Swing o qual ele chamava de Sparkle. Ele ptoduzia na tela um efeito visual similar a uma varinha magica da fada madrinha do filme da Cinderela, ‘Ao mover 0 mouse, faiscas (sparkles, em inglés) caiam do ponteiro do mouse com um belo cintilar até 0 fim da janela, como se houvesse gravidade na tela. Quando Kent me mostrou 0 cédigo, fiquei surpreso com tamanha pequeneza das fungdes. Eu estava acostumado a fungdes que seguiam por quilémetros em programas do Swing. Cada fungao neste programa tinha apenas duas, ou trés, ou quatro linhas. Esse deve ser o tamanho das suas fungdes’. © quato pequenas devem ser suas fungdes? Geralmente menores do que a da Listagem 3.2! Na verdade, a Listagem 3.2 deveria ser enxuta para a Listagem 3.3. 2. Ferramenta de codigo aberio de teste de unidade para va, WWW, junit.o Faga Apenas uma Coisa =) Listagem 3-3 Htmlutil.java (refatorado novamente) Fages (pagefiata, isSuite); etHtm () 2 Blocos e Endenta¢ao Aqui quero dizer que blocos dentro de instrugdes if, else, while ¢ outros devem ter apenas uma linha. Possivelmente uma chamada de fungdo. Além de manter a fungdo pequena, isso adiciona um valor significativo, pois a fun¢o chamada de dentro do bloco pode receber um nome descritivo. Isso também implica que as fungdes nao devem ser grandes ¢ ter estruturas aninhadas. Portanto, o nivel de endentagao de uma fung4o deve ser de, no maximo, um ou dois. Isso, é claro, facilita a leitura e compreensdo das fun¢des. Facga Apenas uma Coisa Deve ter ficado claro que a Listagem 3.1 faz muito mais de uma coisa. Ela cria buffers, pega paginas. busca por paginas herdadas, exibe caminhos, anexa strings estranhas e gera HTML, dentre outras coisas. A Listagem 3.1 vive ocupada fazendo diversas coisas diferentes. Por outro lado, a Listagem 3.3 faz apenas uma coisa simples. Ela inclui SetUp e TearDown em paginas de teste. O conselho a seguir tem aparecido de uma forma ou de outra por 30 anos ou mais. AS FUNCOES DEVEM FAZER UMA COISA. DEVEM FAZE-LA BEM. DEVEM FAZER APENAS ELA. © problema dessa declaragao é que € dificil saber o que é “uma coisa”, A Listagem 3.3 faz uma coisa? E facil dizer que ela faz trés: 1. Determina se a pagina ¢ de teste. 2. Se for, inclui SetUps e TearDowns. 3. Exibe a pagina em HTML. Entiio, uma ou trés coisas? Note que os trés passos da fungdo esto em um nivel de abaixo do nome da fungao. Podemos descrever a funcaio com um breve parigrafo TO": ‘$A Tingungem LOGO usava# palavma “TO” PARA") da mesma forma que Ruby ¢ Python usam “det”. Portano, toda fneae Comey com a palavra “TO”, 36 Capitulo 3: Fungées TO RenderPageWithSetupsAndTeardowns, verificamos se a pagina é de teste, se for. incluimos SetLips e TearDowns. Em ambos os casos, exibimos a pagina em HTML Se uma fungao faz apenas aqueles passos em um nivel abaixo do nome da fungao, entio ela esta fazendo uma s6 coisa. Apesar de tudo, 0 motivo de criarmos funglo é para decompor um conceito maior (em outras palavras, o nome da fun¢ao) em uma série de passos no proximo nivel de abstracao. Deve estar claro que a Listagem 3.1 contém passos em muitos niveis diferentes de . Portanto, obviamente ela faz mais de uma coisa. Mesmo a Listagem 3.2 possui dois niveis de abstrago , como comprovado pela nossa capacidade de redu¢do. Mas ficaria muito dificil reduzir a Listagem 3.3 de modo significative. Poderiamos colocar a instrugo if numa fungdo chamada ine ludeSetupsAndTeardownsIf?est Page, mas isso simplesmente reformula 0 eddigo, sem modificar 0 nivel de Portanto, outra forma de saber se uma fungdo faz mais de “uma coisa” é se vocé pode extrair outra fungdo dela a partir de seu nome que nao seja apenas uma reformulagdio de sua implementagao (G34). Segdes Dentro de Funcées Veja a Listagem 4.7 na pagina 71. Note que a fungao generatePrimes esti dividida em segdes, como declaracées, inicializagdes e selecdo. Esse & um indicio dbvio de estar fazendo mais de uma coisa. Nao da para, de forma significativa, dividir em segdes as funges que fazem apenas uma coisa. Um Nivel de Abstragao por Fungao A fim de confirmar se nossas fungées fazem sé “uma coisa”. Precisamos verificar se todas as instrugdes dentro da fungdo esto no mesmo nivel de abstragao. E facil ver como a Listagem 3.1 viola essa regra. Ha outros conceitos la que esto em um nivel de bem alto, como 0 get itm! (): outros que esto em um nivel intermedidrio, como String pagePathName = PathParser. render (pagePath); ¢ outros que estio em um nivel consideravelmente baixo, como -append(*\n"”). Varios niveis de dentro de uma fungao sempre geram confusio. Os leitores podem nao conseguir dizer se uma expresso determinada é um conceito essencial ou um mero detalhe. Pior, como janelas quebradas, uma vez misturados os detalhes aos conceitos, mais ¢ mais detalhes tendem a se agregar dentro da fungao. Estrutura Switch Ler o Cédigo de Cima para Baixo: Regra Decrescente Queremos que 0 cédigo seja lido de cima para baixo, como uma narrativa‘. Desejamos que cada fungdo seja seguida pelas outras no proximo nivel de de modo que possamos ler 0 programa descendo um nivel de de cada vez conforme percorremos a lista de fungoes. Chamamos isso de Regra Decrescente. Em outras palavras, queremos poder ler 0 programa como se fosse uma série de parigrafos 7O, cada um descrevendo 0 nivel atual de e fazendo referéncia aos paragrafos TO consecutivos no proximo nivel abaixo. Para incluir SetUps e TearDown: da pagina de teste e, entéio, adicionamos os segundos. Para incluir SetUps, ; incluimos os primeiros. depois 0 contetido adicionamos 0 suite setup, se este for uma colegio, incluimos o setup normal. Para incluir 0 suite setup, buscamos na hierarquia acima a pagina “SuiteSetUp” ¢ adicionamos uma instrucdo de inclusdo com o caminho aquela pagina. Para procurar na hierarquia acima.. ‘Acaba sendo muito dificil para os programadores aprenderem a seguir essa regra ¢ criar funcoes que fiquem em apenas um nivel de . Mas aprender esse truque ¢ também muito importante, pois ele ¢ 0 segredo para manter as fungdes curtas ¢ garantir que fagam apenas “uma coisa”. Fazer com que a leitura do cédigo possa ser feita de cima para baixo como uma série de pardigrafos 7O ¢ uma técnica eficiente para manter o nivel de consistente. Vejaa listagem 3.7 no final deste capitulo, Ela mostra toda a fungo testableHtm! refatorada de acordo com os principios descrito aqui, Note como cada fungdo indica a seguinte e como cada uma mantém um nivel consistente de . Estrutura Switch E dificil criar uma estrutura switch pequena’, pois mesmo uma com apenas dois cases é maior do que eu gostaria que fosse um bloco ou uma fungao. Também ¢ dificil construir uma que fala apenas uma coisa, Por padrao, as estruturas switch sempre fazem N coisas. Infelizmente, nem sempre conseguimos evitar 0 uso do switch, mas podemos gos certificar se cada um esta em uma classe de baixo nivel e munca € repetido, Para isso, usamos 0 polimorfismo. Veja a Listagem 3.4. Ela mostra apenas uma das operacdes que podem depender do tipo de funciondrio (employee, em inglés) 37 38 Capitulo 3: Fungées jagem 3-4 Payroll.java public Money calculatePay(Hnployee ej throws Invalidimployeelype { switch (e.type) { case COMMISSIONED: return calculateConmissionedPay (e) ; ‘case HOURLY: return calculateHourlyPay le); case SALARIED: return calculateSalariedPay le) ; default: throw new Tnval idemploy ypele. type); Esta fung&o tem varios problemas. Primeiro, ela ¢ grande, ¢ quando se adiciona novos tipos de funcionarios ela crescera mais ainda. Segundo, obviamente ela faz mais de uma coisa. Terceiro, ela viola o Principio da Responsabilidade Unica’ (SRP, sigla em inglés) por haver mais de um motivo para alteré-la. Quarto, ela viola o Principio de Aberto-Fechado* (OCP, sigla em inglés), pois precisa ser modificada sempre que novos tipos forem adicionados. Mas, provavelmente, 0 pior problema com essa fung&o é a quantidade ilimitada de outras fungdes que tero a mesma estrutura. Por exemplo, poderiamos ter isPayday(Employee e, Date date) ou deliverPay (Employee e, Money pay) ou um outro grupo. Todas teriam a mesma estrutura deletéria. A solugdo (veja a Listagem 3.5) é inserir a estrutura switch no fundo de uma ABSTRACT FACTORY’ e jamais deixar que alguém a veja. A factory usard o switch para criar instncias apropriadas derivadas de Employee, e as funcdes, como calculatePay. isPavday ¢ deliverPay, serio enviadas de forma poliférmica através da interface Employee. Minha regra geral para estruturas switch é que s4o aceitéveis se aparecerem apenas uma vez, como para a criagio de objetos poliférmicos, ¢ estiverem escondidas atris de uma relagao de heranga de modo que o resto do sistema nao possa enxerga-la [G23]. E claro que cada caso é um caso e haverd vezes que nao respeitarei uma ou mais partes dessa regra abstract class Employee { public abstract boolean isPayday(); public abstract Money calculatePay(); public abstract void deliverPay(Money pay); } sty pedia.org'witt/Single responsibility. principle Use Nomes Descritivos 39 Use Nomes Descritivos Na Listagem 3.7, eu mudei o nome do exemplo de nossa fungZo testablextml para SetupTeardownIncluder.render, que é bem melhor, pois descreve o que a fungao faz. Também dei a cada método privado nomes igualmente descritivos, como isTestable ou includeSetupandTeardownPages. E dificil superestimar o valor de bons nomes. Lembre-se do principio de Ward: “Vocé sabe que esté criando um codigo limpo quando cada rotina que voce Ié é como vocé esperava”’. Metade do esforgo para satisfazer esse principio ¢ escolher bons nomes para fungdes pequenas que fazem apenas uma coisa. Quando menor ¢ mais centralizada for a fungao, mais fécil seré pensar em um nome descritivo. Nao tenha medo de criar nomes extensos, pois eles sio melhores do que um pequeno e enigmitico, Um nome longo e descritivo é melhor do que um comentario extenso ¢ deseritivo. ‘Use uma convengo de nomenclatura que possibilite uma facil leitura de nomes de fungdes com varias palavras e, entio, use estas para dar 4 fungdo um nome que explique o que ela faz. Nao se preacupe com o tempo ao escolher um nome. Na verdade, vocé deve tentar varios nomes ¢, entao, ler © codigo com cada um deles. IDEs modernas, como Eclipse ou IntelliJ, facilita a troca de nomes. Utilize uma dessas IDEs ¢ experimente diversos nomes até encontrar um que seja bem descritivo. Selecionar nomes descritivos esclarecerd 0 modelo do médulo em sua mente ¢ Ihe ajudara a melhoré-lo. E comum que ao buscar nomes adequados resulte numa boa reestruturagao do cédigo. Seja consistente nos nomes. Use as mesmas frases, substantivos ¢ verbos nos nomes de fungdes de seu médulo. Considere, por exemplo, os nomes includeSetup-AndTeardownPages, includeSetupPages, includeSuiteSetupPage e includeSetupPage. A fraseologia nesses nomes permite uma sequéncia de facil dedugdo. Na verdade. se eu Ihe mostrasse apenas a série acima, vocé se perguntaria: “O que aconteceu com includeTeardownPages, includeSuiteTeardownPage € includeTeardownPage?”, como isso é “... como 0 que vocé esperava?”. Pardmetros de Fungées ‘A quantidade ideal de parémetros para uma fungao & zero (nulo). Depois vem um (ménade), seguido de dois (diade). Sempre que possivel devem-se cvitar trés parametros (triade). Para mais de trés deve-se ter um motivo muito especial (poliade) — mesmo assim nao devem ser usados. Parametros sio complicados. Eles requerem bastante conceito. E por isso que me livrei de quase todos no exemplo, Considere, por exemplo, © StringBuffer. Poderiamos té-lo _passado como parimetro em vez de instancié-lo como uma variavel, mas ento nossos leitores teriam de interpreti-lo sempre que o vissem. Ao ler a 40 Capitulo 3: Fungées estoria contada por pelo médulo, fica mais facil entender includesetupPage() do que includeSetupPageInto(newPage-Content). O pardmetro nao esta no nivel de que o nome fung&o, forgando-lhe reconhecer de um detalhe (ou seja, 0 StringBuffer) que nao seja importante particularmente naquele momento. Os parametros sao mais dificeis ainda a partir de um ponto de vista de testes. Imagine a dificuldade de escrever todos os casos de teste para se certificar de que todas as varias combinagdes de pardmetros funcionem adequadamente. Se nao houver pardmetros, essa tarefa € simples. Se houver um, nao ¢ tao dificil assim. Com dois, a situado fica um pouco mais desafiadora, Com mais de dois, pode ser desencorajador testar cada combinacdio de valores apropriados. Os parametros de safda so ainda mais dificeis de entender do que os de entrada. Quando lemos uma fungao, estamos acostumados 4 ideia de informagdes entrando na fungao através de parimetros e saindo através do valor retornado. Geralmente nao esperamos dados saindo através de parametros. Portanto, parametros de saida costumam nos deixar surpresos ¢ fazer com que leiamos novamente. Um parametro de entrada é a melhor coisa depois de zero pardmetro. E facil entender SetupTeardown-Includer. render (pageData). Esta ébvio que renderizemos os dados no objeto pageData Formas Ménades Comuns Hi duas razdes bastante comuns para se passar um unico parimetro a uma fang’o. Vocé pode estar fazendo uma pergunta sobre aquele parametro, como em boolean fileExists("MyFile”). Ou vocé pode trabalhar naquele parametro, transformando-o em outra coisa e retornando-o, Por exemplo, InputStream fileOpen("MyFile”) transforma a String do nome de um arquivo em um valor retornado por InputStream. Sao esses dois usos que 0s leitores esperam ver em uma fungao, ‘Vocé deve escolher nomes que tornem clara a distingdo, ¢ sempre use duas formas em um contexto consistente. (Veja a seguir Separacdo comando-consulia). Uma forma menos comum ‘mas ainda bastante vitil de um parimetro para uma fungdo é um evento. Nesta forma, hi um parimetro de entrada, mas nenhum de saida. O programa em si serve para interpretar a chamada da fungdo como um evento, ¢ usar 0 parimetro para alterar 0 estado do sistema, por exemplo, void passwordAttemptFailedNtimes(int attempts). Use esse tipo com cautela. Deve ficar claro para o leitor que se trata de um evento. Escolha os nomes ¢ 0s contextos com atengao. ‘Tente evitar fungdes ménades que nao sigam essas formas, por exemplo, void include SetupPageInto (StringBuffer pageText). Usar um parimetro de saida cm vez de um valor de retorno para uma modificagao fica confuso. Se uma fungdo vai transformar seu pardmetro de entrada, a alteracao deve aparecer como 0 valor retomado. De fato, StringBuffer transform(StringBuffer in) é melhor do que void’ transform-(StringBuffer out), mesmo que a implementagio do primeiro simplesmente retorne o parametro de entrada. Pelo menos ele ainda segue o formato de uma modificagao. Pardmetros Légicos Esses parfimetros so feios. Passar um booleano para uma fungdio certamente é uma pritica horrivel, pois ele complica imediatamente a assinatura do método, mostrando explicitamente que a fungo faz mais de uma coisa, Ela faz uma coisa se o valor for verdadeiro, ¢ outra se for falso! Use Pardimetros de Fungdes 41 Na Listagem 3.7, nao tinhamos alternativa, pois os chamadores jd estavam passando aquela flag (valor boolean) como pardmetro, e eu queria limitar 0 escopo da refatoragio a fung3o e para baixo. Mesmo assim, a chamada do método render (true) ¢ muito confusa para um leitor simples. Analisar a chamada e visualizar render (boolean isSuite) ajuda um pouco, mas nem tanto, Deveriamos dividir a fung2o em duas: renderForsuite() ¢ renderForSingleTest(). Fungées Diades Uma fangao com dois parametros ¢ mais dificil de entender do que uma com um (ménade). Por exemplo, ¢ mais facil compreender writeField(name) do que writeField(output- Stream, name)", Embora o significado de ambas esteja claro, a primeira apresenta seu propésito explicitamente quando a lemos, A segunda requer uma pequena pausa até aprendermos a ignorar 0 primeiro parametro. E isso, é claro, acaba resultando em problemas, pois nunca devemos ignorar qualquer parte do cédigo. O local que ignoramos é justamente aonde se esconderio os bugs. HA casos, é claro, em que dois pardmetros so necessdrios como, por exemplo, em Point. p = new Point (0,0). Os pontos de eixos cartesianos naturalmente recebem dois parametros, De fato, ficariamos surpresos se vissemos new Point (0). Entretanto, os dois parfimetros neste caso sdo componentes de um tinico valor! Enquanto que output-Stream e name néio so partes de um mesmo valor. Mesmo fungdes diades bvias, como assertEquals(expected, actual), sao problematicas. Quantas vezes vocé ja colocou actual onde deveria ser expected? Os dois pardmetros nao possuem uma ordem pré-determinada natural. A ordem expected, actual é uma convengao que requer prética para assimilé-la. Diades nao sao ruins, e vocé certamente teri de usé-las. Entretanto, deve-se estar ciente de que haverd um prego a pagar e, portanto, deve-se pensar em tirar proveito dos mecanismos disponiveis a vocé para converté-los em ménades. Por exemplo. vocé poderia tornar 0 método writeField um membro de output Stream de modo que pudesse dizer output StreamwriteField (name); tomar output Stream uma variével membro da classe em uso de modo que nao precisasse pass4-lo por parémetro; ou extrair uma nova classe, como FieldWriter, que receba 0 outputStream em construtor e possua um método write. Triades Fungées que recebem trés pardmetros so consideravelmente mais dificeis de entender do que as diades. A questo de ordenagao, pausa e ignoragdo afresentam mais do que 0 dobro de dificuldade. Sugiro que vocé pense bastante antes de criar uma triade. Por exemplo, considere a sobrecarga comum de assertEquals que recebe trés parimetros: assertEquals (message, expected, actual). Quantas yezes vocé precisou ler 0 parimetro message e deduzir o que ele carrega? Muitas vezes jd me deparei com essa triade em particular e tive de fazer uma pausa. Na verdade, toda vez que a vejo, tenho de ler novamente e, entao, a ignoro. 5 Seti a Sci wl wack Rink Hic csc i li eit Mh kn cc Use ParAmetros de Fungies B formato imbuimos os nomes dos pardmetros no nome da fungdo. Por exemplo, pode ser melhor escrever assertEquals do que assert Expect edEqualsActual (expected, actual),o que resolveria o problema de ter de lembrar a ordem dos parametros. Evite Efeitos Colaterais Efeitos colaterais sio mentiras. Sua fungdo promete fazer apenas uma coisa, mas ela também faz outras coisas escondida. As vezes, ela fara alteragdes inesperadas nas variaveis de sua propria classe. As vezes, ela adicionara as variveis aos parametros passados a fungao ou as globais do sistema. Em ambos os casos elas so “verdades” enganosas ¢ prejudiciais, que geralmente resultam em acoplamentos temporarios estranhos e dependéncias. Considere, por exemplo, a fungdo aparentemente inofensiva na Listagem 3.6. Ela usa um algoritmo padrao para comparar um userName (nome de usudrio) a um password (senha). Elaretorna true (verdadeiro) se forem iguais,e false {£also) caso contrario. Mas ha também um efeito colateral. Consegue identificd-lo? Listagem 3-6 Uservalidator.java public class Uservalidacor i private Cryptographer cryptographer; public boolean ch User user ssword(String userName, String password) [ UserGateway. findByName (userName) ; (user != User NULL) ( ring codedPhrase = user.getPhraseEncodedByPassword|) + String parace = cryptogvapher decrypt (codedPhrase, password] ; if ("Valid Password" equals (phrase) ) { tializei); Session. i return true; © efeito colateral é a chamada ao Session.initialize(), é claro. A fungio checkPassword, segundo seu nome, diz que verifica a senba. O nome nao indica que ela inicializa a sesso. Portanto, um chamador que acredita no que diz o nome da fungao corre 0 isco de apagar os dados da sessio existente quando ele decidir autenticar do usuario. Esse efeito colateral cria um acoplamento temporirio. Isto é, checkPassword s6 podera ser chamado em determinadas horas (em outras palavras, quando for seguro inicializar a sessio). Se for chamado fora de ordem, sem querer, os dados da sesstio poder ser perdidos. Os acoplamentos temporarios so confusos, especialmente quando sao um efeito colateral. Se for preciso esse tipo 44 Capitulo 3: Fungées de acoplamento, é preciso deixar claro no nome da fungio. Neste caso, poderiamos renomear a funcao para checkPasswordAndInitializeSession, embora isso certamente violaria 0 “fazer apenas uma timica coisa”. ParAmetros de Saida Os parametros so comumente interpretados como entradas de uma fungao. Se jd usa o programa ha alguns anos, estou certo de que vocé jé teve de voltar ¢ ler novamente um parametro que era, na verdade, de saida, e nao de entrada. Por exemplo: appendFooter(s); Essa fung&io anexa s como rodapé (Footer, em inglés) em algo? Ou anexa um rodapé as? sé uma entrada ou uma saida? Nao precisa olhar muito a assinatura da fungao para ver: public void appendFooter(StringBufier report) Isso esclarece a questo, mas a custa da verificagaio da declaraco da fung4o. Qualquer coisa que Ihe force a verificar a assinatura da fungdo é equivalente a uma relida. Isso é uma interrupgzo do raciocinio ¢ deve ser evitado. Antes do surgimento da programagao orientada a objeto, as vezes era preciso ter parametros de saida, Entretanto, grande parte dessa necessidade sumiu nas linguagens OO, pois seu propsito é servir como um parimetro de saida. Em outras palavras, seria melhor invocar appendrooter como: report .appendFooter |); De modo geral, devem-se evitar parametros de saida, Caso sua fungao precise alterar 0 estado de algo, faca-a mudar o estado do abjeto que a pertence. Separacgao comando-consulta ‘As fungdes devem fazer ou responder algo, mas no ambos. Sua fungio ou altera o estado de um objeto ou retoma informagdes sobre ele, Efetuar as duas tarefas costuma gerar confusdo. Considere, por exemplo, a fungio abaixo: public beolean set(String attribute, String value); Esta funcao define 0 valor de um dado atributo ¢ retorna tru (verdadeiro) se obtiver éxitoe false (falso) se tal atributo nao existir. Isso leva a instrugdes estranhas como: if (set(“username”, “unclebcob"))..- Imagine isso pelo ponto de vista do leitor. O que isso significa? Esta perguntando se 0 atributo “username” anteriormente recebeu 0 valor “unclebob”? Ou se “username” obteve éxito a0 receber 0 valor “unclebob™? E dificil adivinhar baseando-se na chamada, pois nao esta claro se a palavra “set” é um verbo ou um adjetivo. Prefira exceges a retorno de cédigos de erro 45 O intuito do autor era que set fosse um verbo, mas no contexto da estrutura if, parece um adjetivo. Portanto, a instrugdo 1é-se “Se o atributo username anteriormente recebeu o valor unclebob” endo “atribua 0 valor unc ebob ao atributo username, ese isso funcionar, entdo, Poderiamos tentar resolver isso renomeando a fung&o set para setAndCheckIfExists, mas nao ajudaria muito para a legibilidade da estrutura i. if (attributesxists(*username"}) ( setAttribute(*username", “unclebob*); Prefira excegées a retorno de cédigos de erro Fazer fungdes retornarem codigos de erros ¢ uma leve violagao da separagdo comando-consulta, pois os comandos sao usados como expresses de comparacao em estruturas i f. if (deletePage(pagei E_OK) O problema gerado aqui nao é a confusio verbo‘adjetivo, mas sim a criagao de estruturas aninhadas. ‘Ao retornar um cédigo de erro, vocé cria um problema para o chamador, que deverd lidar imediatamente com o erro. if (deletePage(page) E_OK) ( if (registry.deleteReference(page.name) == E_OK) { Lf (configkeys.deleteKey(page.name.makeKey()) == E_OK){ logger.log(*pagina excluida"); ‘ } else { logger.log(*configkey n&o foi excluida”}; } } else { logger.log(*deleteReference nado foi excluido do registro"); } } else ( logger.log(*a exclusdo falhou"); return E_ERROR; z Por outro lado, se vocé usar excegdes em vez de retomnar cédigos de erros, entéo 0 cédigo de tratamento de erro podera ficar separado do cédigo ¢ ser simplificado: try deletePage(page); registry.deleteReference(page.name); configkeys.deleteKey(page.name.makeKey()); ) catch (Exception e) { logger. log(e.getMessage()); } 46 Capitulo 3: Funges Extraia os blocos try/catch Esses blocos nao tém 0 direito de serem feios. Eles confundem a estrutura do cédigo e misturam © tratamento de erro com o processamento normal do cédigo. Portanto, é melhor colocar as estruturas try ¢ catch em suas préprias fungoes. public void delete(Page page) { try { deletePageAndAllReferences (page + catch (Exception e) { logError (ej; + a private void deletePageAndAllReferences(Page page) throws Exception t delet ePage(pagei; registry.deleteReference(page.name); configkeys.deleteKey (page.name.makeKey()); } private void logBrror(Exception e) { logger. log(e.getMessagei)); } A funcao delete acima sé faz tratamento de erro. E € facil entendé-la ¢ seguir adiante. A fungio deletepageAndAllReferences 86 trata de processos que excluem toda uma pagina. Pode-se ignorar o tratamento de erro. Isso oferece uma boa separagao que facilita a compreensao e alteracdio do cédigo. Tratamento de erro é uma coisa s6 As fungSes devem fazer uma coisa s6. Tratamento de erro é uma coisa s6. Portanto, uma fungaio que trata de erros nfio deve fazer mais nada. Isso implica (como no exemplo acima) que a palavra try esta dentro de uma fungao e deve ser a primeira instrugao ¢ nada mais deve vir apés os blocos catch/finally. Error.java, o chamariz 4 dependéncia Retomar cédigos de erro costuma implicar que ha classes ou enum nos quais esto definidos todos os cédigos de erro. 7 public enum Error { OK, INVALID, NO_SUCH, LOCKED, OUT_OF_RESOURCES, WAITING_FOR_EVENT; Programasio estruturada 47 Classes como esta so chamarizes & dependéncia, muitas outras classes devem importa-las e usé-las, Portanto, quando o enum da classe Error enum, é preciso recompilar todas as outras classes e redistribui-las". Isso coloca uma pressdo negativa na classe Error. Os programadores nao querem adicionar novos erros porque senao cles teriam de compilar e distribuir tudo novamente. Por isso, eles reutilizam cédigos de erros antigos em vez de adicionar novos. Quando se usam excegdes em vez de cédigos de etro, as novas excegbes s8o derivadas da classe de excegdes. Podem-se adiciona-las sem ter de recompilar ou redistribuir®. Evite repeticdo« Leia novamente com atengao a Listagem 3.1 ¢ notara que ha um algoritmo que se repete quatro vezes em quatro casos: SetUp, SuitesetUp, TearDown ¢ SuiteTearDown, Nao ¢ facil perceberessaduplicagao, pois as quatro instncias esto misturadas com outros cédigos e nao esto uniformemente repetidas, Mesmo assim, a duplicagao é um problema, pois ela amontoa 0 eddigo e serio necessérias quatro modificagdes se o algoritmo mudar. Além de serem quatro oportunidades para a omissdo de um erro. Sanou-se essa duplicagdo através dométodo include na Listagem 3.7. Leia estecédigonovamente note como a legibilidade do médulo inteiro foi melhorada com a retirada de tais repetigdes. ‘A duplicagao pode ser a raiz de todo o mal no software, Muitos principios e priticas tem sido criados com a finalidade de controla-la ou elimind-la. Considere, por exemplo, que todas as regras de normalizagio de bando de dados de Ted Codd servem para eliminar duplicagio" de dados. Considere também como a programacao orientada a objeto serve para centralizar o cédigo em classes-base que seriam outrora redundantes. Programagaio estruturada, Programagao Orientada a Aspecto ¢ Programagao Orientada a Componentes so todas, em parte, estratégias para eliminar duplicagao de cédigo. Parece que desde a invengdo da sub-rotina, inovagdes no desenvolvimento de software tém sido uma tentativa continua para eliminar a duplicagao de nossos cédigos-fonte. Programacao estruturada Alguns programadores seguem as regras programagiio estruturada de Edsger Dijkstra", que disse que cada fungao e bloco dentro de uma fungao deve fer uma entrada e uma saida. Cumprir essas regras significa que deveria haver apenas uma instrugdo return na fun¢do, nenbum break ou cont inue num loop ¢ jamais um goto. Enquanto somos solidarios com os objetivos e disciplinas da programago estruturada, tais regras oferecem pouca vantagem quando as fungées sao muito pequenas. Apenas em fungdes maiores tais regras proporcionam beneficios significativos. Portanto, se vocé mantiver suas fungGes pequenas, entio as varias instrugdes return, break ou continue casuais nao trardo problemas e poderao ser até mesmo mais expressivas do que Thess a kh enaiilbn dss clei Uti cecal eka '8 Acie pecveain. 48 Capitulo 3: Fungdes a simples regra de uma entrada e uma saida. Por outro lado, 0 goto s6 faz sentido em fungdes grandes, porianto ele deve-se evité-lo. Como escrever funcées como essa? Criar um software € como qualquer outro tipo de escrita. Ao escrever um artigo, vocé primeiro coloca seus pensamentos no papel ¢ depois os organiza de modo que fiquem ficeis de ler. O primeiro rascunho pode ficar desastroso ¢ desorganizado, entdo vocé o apare, reestrutura e refina até que ele fique como vocé deseja. Quando escrevo fungdes, elas come¢am longas ¢ complexas; hd muitas endentagdes ¢ loops aninhados; possuem longas listas de parametros; os nomes so arbitrarios; e ha duplicagao de cédigo. Mas eu também tenho uma colegio de testes de unidade que analisam cada uma dessas linhas desorganizadas do cddigo. Sendo assim, eu organizo e refino 0 cédigo, divido fungdes, troco os nomes, elimino a duplicagao, reduzo os métodos e os reorganizo. As vezes, desmonto classes inteiras, tudo com 05 testes em execugdio. No final, minhas fungdes seguem as regras que citei neste capitulo. Nao as aplico desde 0 inicio. Acho que isso nao seja possivel. Conclusao Cada sistema € construido a partir de uma linguagem especifica a um dominio desenvolvida por programadores para descrever o sistema. As fungdes sfio os verbos dessa linguagem, e classes os substantivos. Isso nado ¢ um tipo de retomada da antiga nogao de que substantivos e verbos nos requerimentos de um documento sejam os primeiros palpites das classes ¢ fungdes de um sistema. Mas sim uma verdade muito mais antiga. A arte de programar é, e sempre foi, a arte do projeto de linguagem. Programadores experientes veem os sistemas como historias a serem contadas em vez de programas a serem escritos, Eles usam 0s recursos da linguagem de programagao que escolhem para construir uma linguagem muito mais rica e expressiva do que a usada para contar a est6ria, Parte da linguagem especifica a um dominio ¢ a hierarquia de fungdes que descreve todas as agdes que ocorrem dentro daqucle sistema, Em um ato engenhoso, escrevem-se essas fungdes para usar a mesma linguagem especifica a um dominio que eles criaram para contar sua prépria parte da historia Este capitulo falou sobre a mecdinica de se escrever bem fungdes. Se seguir as regras aqui descritas, suas fungdes serao curtas, bem nomeadas e bem organizadas. Mas jamais se esqueca de que seu objetivo verdadciro é contar a histéria do sistema, e que as fungdes que vocé eserever precisam estar em perfeita sincronia ¢ formar uma linguagem clara e precisa para Ihe ajudar na narrago SetupTeardownIneluder SetupTeardownIncluder 49 Listagem 3-7 SetupTeardownIncluder.java package fitnesse. html; import fitnesse.responders.run.SuiteResponder; import fitnesse.wiki.*; public class SetupTeardoxntncluder { private PageData pageData; private boolean isSuite; private Wikipage testPage; private StringBuffer newPageContent; private PageCrawler pageCravler; public static String render (PageData pageData) throws Exception return render(pageData, false); } public static String render (PageDats pageData, boolean issuite) throws Exception { return new SetupTeardownIncluder (pageData) render (issuite) ; } private SetupTeardownIncluder (PageData pageData) | this.pageNata = pageData; cestPage = pageData.cetWikiPage|) : pageCrawler = testPage.getPageCrawler i) ; newPageContent = new StringBuffer|); } private String render (boolean isSuite) throws Exception { this.isSuite = isSuite; if (isTestPage|)) includegetupAndteardownPages (}; return pageData.get tml (); } private boolean isTestPage() throws Exception { return pageData.hasAttribute(*Test”); private void includeSetupandteardownPages() throws Exception { includesetupPages(); includePageContent () ; includeTeardownPages |) ; updatePageContent !) 50 Capitulo 3: Fungdes Listagem 3-7 (continuagiio SetupTeardownincluder. java private void includeSetupPages() throws Exception { if (issuite) includesuitesetupPage |) ; inclugeSetupPage() : , private void includesuitesetupPage() throws Exception { include(SuiteResponder.SUITE SETUP_NAME, *-secup" } private void includeSetupPageii throws Exception { include(*Settp", *-setup" + vate void includePageContent (} throws Exception [ newPageContent append (pageData.getContent (}) ; i private void includeTeardownPages(} throws Exception ( includeTeardownPage () : if (issuite) includeSuiteTeardownPage(); } private void includeTeardownPage() throws Exception { include (*TearDown", "-teardown"); } private void includesuiteTeardownpage() throws Exception { include (SuiteResponder.SUITE_TEARDOAN_NAME, *-teardown") + + private void updatePageContent() throws Exception { pageData, secContent (newPageContent . toString (1) ; private void includeiString pageName, String arg) throws Exception { WikiPage inheritedPage = findinheritedPage pageName! ; if iinheritedPage != null) { String pagePathName = get PathNameForPage |inheritedPage) ; buildIncludeDirective(pageFathName, arg) d } > private WikiPage findInheritedPage(String pageName) throws Exception { return PageCrawlerInp! get InheritedPage (pageName, test Page) ; private String getPathNameforPage(WikiPage page) throws Exception { wikiPagePath pagePath = pageCrawler.getFullPath (page) ; return PathParser.render (pagePath) ; + private void builaincludeDirecti newPageContent -append(*\n! include e(String pageFathName, String arg) ( 4 Comentarios 10 insira comentérios num cédigo ruim, reescreva-o””. —Brian W. Kernighan e’P. J. Plaugher' Nada pode ser to itil quanto um comentario bem colocado. Nada consegue amontoar um médulo mais do que comentarios dogmaticos e supérfluos. Nada pode ser tao prejudicial quanto um velho comentario mal feito que dissemina mentiras ¢ informagées incorretas. Comentarios nao si como a Lista de Schindler. Nao s4o 0 “bom puro”. De fato, eles so, no maximo, um mal necessirio. Se nossas linguagens de programagao fossem expressivas 0 suficiente ou se tivéssemos o talento para manipular com destreza tais linguagens de modo a expressar nossa intengo, ndo precisariamos de muitos comentarios, quicé nenhum. 34 Capitulo 4: Comentarios N © uso adequado de comentarios ¢ compensar nosso fracasso em nos expressar no cddigo. Observe que usei a palavra fracasso. F ¢ isso que eu quis dizer. Comentarios so sempre fracassos. Devemos usé-los porque nem sempre encontramos uma forma de nos expressar sem eles. mas seu uso nao € motivo para comemoragio. Entdo, quando vocé estiver numa situacao na qual precise criar um comentério, pense bem ¢ veja se nao hd como se expressar através do eédigo em si. Toda vez que vocé fizer isso, dé em si mesmo um tapinha de aprovagao nas costas. Toda vez que vocé escrever um comentario, faga uma careta e sinta o fracasso de sua capacidade de expresso. Por que sou ndo gosto de comentérios? Porque cles mentem. Nem sempre, ¢ nao intencionalmente, mas é muito comum. Quanto mais antigo um comentirio for e quanto mais longe estiver do cédigo 0 qual ele descreve, mais provavel sera que esteja errado. O motivo ¢ simples. Nao ¢ realistico que programadores consigam manté-los atualizados. Cédigos mudam e evoluem. Movem-se blocos para lé e para ca, que se bifurcam ese reproduzem ese unem novamente, formando monstros gigantescos. Infelizmente, os comentarios nem sempre os seguem —nem sempre ¢ possivel. E, muito frequentemente, os comentarios ficam longe do cédigo qual deserevem e se tornam dizeres érf¥0s com uma exatidao cada ver menor. Por exemplo. olhe ‘© que aconteceu com o comentirio abaixo ¢ a linha que ele procurava descrever: MockRequest request; private final String HTTP_DATE_REGEXP = * [SMTWF] [a-z] {2)\\,\\S [0-9] {2}\\s [J FMASOND] [2-2] {2}\\s"+ {0-9] (4}\\s [0-9] (2W\: [0-9] {2\\;: [0-91 {2]\\ SMT"; private Response response; private FitNesseContext context private FileResponder responder; private Locale saveLocale; V7 Exemplo: “Tue, 02 Apr 2003 22:18:49 GMT” Outras instancias de varidveis que provavelmente foram adicionadas posteriormente ficaram entre a constante HTTP_DATE_REGEXP e seu comentario descritivo. E possivel dizer que os programadores deveriam ser disciplinados o bastante para manter os comentarios em um elevado estado de atualizagio, relevancia e preciso. Concordo que deveriam. Mas eu preferiria que essa energia fosse direcionada para tornar o codigo tao claro ¢ descritivo que de inicio nem se precisaria de comentarios. Comentarios imprecisos so muito piores do que nenhum. Eles enganam e iludem; deixam expectativas que jamais sero cumpridas; citam regras antigas que nao precisariam mais, ou nao deveriam, ser seguidas. . 86 se pode encontrar a verdade em um lugar: no cédigo. S6 ele pode realmente the dizer o que cle faz. Ele éa tnica fonte de informagdes verdadeiramente precisas. Entretanto, embora ds vezes comentarios sejam necessirios, gastariamos energia consideravel para minimiza-los. Comentarios Compensam um Cédigo Ruim Uma das motivagées mais comuns para criar comentirios é um cédigo ruim. Construimos um médulo ¢ sabemos que esté confuso e desorganizado. Estamos cientes da bagunga. Nos mesmos dizemos “Oh, ¢ melhor inserir um comentario!” Nao! E melhor limpa-lo. = Comentarios Bons 55 Cédigos claros e expressivos com poucos comentarios sfo de longe superioresa um amontoado e complexo com muitos comentarios. Ao invés de gastar seu tempo criando comentarios para explicar a bagunca que voce fez, use-o para limpar essa zona. Explique-se no cédigo Certamente ha vezes em que nao € possivel se expressar direito no cédigo, Infelizmente, devido a isso, muitos programadores assumiram que o codigo raramente é, se é que possa ser, um bom meio para se explicar. Evidentemente isso € falso. O que vocé preferiria ver? Iss // Werifica se o funcionario tem direito a todos os beneficios if ((employee.flags & HOURLY_FLAG) && lemployee.age > 65)) Qu isso? if (employee.isHligibleForFullBenefits()) $6 6 preciso alguns segundos de pensamento para explicar a maioria de sua intengdo no e6digo. Em muitos casos, é simplemente uma questo de criar uma fung’o cujo nome diga a mesma coisa que vocé deseja colocar no comentirio. Comentarios Bons Certos comentarios so necessarios ou benéficos, Veremos alguns que considero valerem 03 bits que consumem. Tenha em mente, contudo, que 0 ‘anico comentario verdadeiramente bom é aquele em que vocé encontrou uma forma para nao escrevé-lo, Comentarios Leg: As vezes, nossos padrées de programagao corporativa nos forgam a escrever certos comentarios por questdes legais. Por exemplo, frases sobre direitos autorais ¢ autoria so informagdes necessirias ¢ logicas para se colocar no inicio de um arquivo fonte. Por exemplo, abaixo esta o comentario padrao de cabegalho que colocamos no inicio de todo arquivo fonte do FitNesse. Fico feliz em dizer que nossa IDE evita a unido automitica desse comentirio para que nao fique aglomerado // Direitos autorais (C) 2003,2004,2005 por Object Mentor,*Inc. Todos os direitos reservados j/ Distribuido sob 05 termos da vers&o 2 ou posterior da Licenca Publica Geral da GNU. Comentarios como esse nao devem ser contratos ou tomos legais. Onde for possivel, faga referéncia a uma licenga padrao ou outro documento externo em vez de colocar todos os termos ¢ condigdes no mesmo comentari 56 Capitulo 4: Comentarios Comentarios Informativos As vezes € pritico fornecer informagées basicas em um comentario. Por exemplo, considere 0 comentario abaixo que explica o valor retornado de um método abstrato: // Retorna uma instancia do Responder sendo testado. protected abstract Responder responderInstance(); Um comentario como este pode ser itil as vezes, mas, sempre que possivel, & melhor usar 0 nome da fungao para transmitir a informagao. Por exemplo, neste caso, 0 comentirio ficaria redundante se trocdssemos 0 nome da fung4o: responderBeingTested. Assim ficaria um pouco melhor: /¢ formato igual a kk:mm:ss EEE, MMM dd, aaaa Pattern timeMatcher = Pattern.compile(*\d*:\\d*:\\d* \\Ww*, Wwe \\dt, \\d*7); Neste caso, 0 comentario nos permite saber que a expresso regular deve combinar com uma hora e data formatadas com a fungao SimpleDateFormat.format usando a string especifica com 0 formato. Mesmo assim, teria ficado melhor e mais claro se esse cddigo tivesse sido colocado em uma classe especial para converter os formatos de datas e horas. Entdo, 0 comentario provavelmente seria supérfiuo. Explicagio da intencaio As vezes, um comentario vai além de ser apenas informagées uteis sobre a implementagao e fornece a intengao por tris de uma decistio, No caso a seguir, vemos uma decistio interessante documentada através de um comentirio. Ao comparar dois objctos, 0 autor decidiu que queria classificar como superiores os objetos de sua classe em relagao aos de outras. public int compareTo(Object 0) { if(o instanceof WikiPagePath) t WikiPagePath p = (WikiPagePath) o; String compressedNeme = StringUtiljoininames, **); string compressedArgumentName = StringUtil.icin(p.names, ""); return compressedName.compareTo(compressedArgumentName}; } Ps return 1; // somos superiores porque somos tipo certo. Abaixo esté um exemplo melhor ainda, Talvez voce discorde da solug&o do programador, mas pelo menos vocé sabe o que ele estava tentando fazer. public void testConcurrentAddWidgets() throws Exception { WidgetBuilder widgetBuilder = new WidgetBuilder(new Class{]{Boldwidget.class}); String text = "bold text!''"; Comentérios Bons 37 ParentWidget parent = new BoldWidget (new MockilidgetRoot(), *'/"bold text’’""); AtomicBoolean failFlag = new AtomicBoolean(); failPlag.set(false); “Essa e a nossa melhor tentativa para conseguir uma condicao de corrida. //Paxa isso criamos um grande numero de threads. for (int i i < 25000; it) { WidgetBuilderThread widgetBuilderThread = new WidgetBuilderThread(widgetBuilder, text, parent, failflag); Thread thread = new Thread(widgetBuilderthread); thread.start(); y assertEquals(false, failFlag.get()); J Esclarecimento As vezes é bom traduzir o significado de alguns pardmetros ou valores retornados obscuros para algo inteligivel. De modo geral, ¢ melhor encontrar uma forma de esclarecer tal parametro ou valor retornado por si s6, mas quando for parte da biblioteca padrao, ou de um cédigo que nao se possa alterar, entdo um comentario esclarecedor pode ser ttil. public void testCompareTo() throws Exception { WikiPagepath a = PathParser.parse("PageA"); WikiPagePath ab = PathParser.parse("PageA.PageB"); WikiPagePath b = PathParser.parse("PageB"); WikiPagePath aa = PathParser.parse("PageA.Pagea"); WikiPagePath bb = PathParser.parse("PageB.PageB"); Wikipagepath ba = PathParser.parse(*PageB.PageA"); assert True(a.compareTo(a) 0; /azsa assertTrue(a.compareTo(b) != 0); // a t= b assertTrue(ab.compareTo(ab) 0); ff ab assertTrue(a.compareTo(b) li ach assertTrue(aa.compareTo(ab) “1; /# aa < ab assertTrue(ba.compareTo(bb) 1); /f ba < bb assertTrue(b.compareTo(a) == 1); // b> a assertTrue(ab.compareTo(aa) 1); // ab > aa assertTrue(bb.compareTo(ba) 1): // bb > ba " ab + Hé um risco consideravel, é claro, de que um comentirio esclarecedor possa estar incorreto, Leia o exemplo anterior € veja como € dificil verificar se esto corretos. Isso explica tanto 0 porqué da necessidade do esclarecimento como seu risco. Portanto, antes de criar comentirios como esses, certifique-se de que nao hd outra saida melhor e, entdo, certifique-se ainda mais se estéo precisos. 58 _cL'pltulo 4: Comentirios Alerta Sobre Consequéncias As vezes € itil alertar outros programadores sobre certas consequéncias. Por exemplo, 0 comentario abaixo explica porque um caso de teste em particular esta desabilitado: // N&oN&o execute a menos que vocé #/ venha tempo disponivel. public void _testwithReallyBigFile() t writeLinesToFile(10000000); response.set8ody(testFile); response.readyToSend(this); String responseString = output tostring(); assertSubString("Content-Length: 1060000000", responseString); assertTrue(bytesSent > 1000000000); } Hoje em dia, desabilitariamos 0 teste de caso através do atributo @ignore com uma string explanatéria adequada: @ignore (“Leva muito tempo para executar"). Antes da chegada do JUnit4, uma convengao comum era colocar um trago inferior (underscore) no inicio do nome do método, O comentario, enquanto divertido, passa sua mensagem muito bem. Outro exemplo mais direto seria: public static SimpleDateFormat makeStandardHttpDateFormat () { //simpleDateFormat néo 6 uma thread segura, Wé preciso criar cada instancia independentemente. SimpleDateFormat df = new SimpleDateFormat(*EEE, dd MMM yyyy HH:mm:ss 2") df. setTimeZone(TimeZone.get TimeZone ("GMT*)); return df; } Talvez vocé reclame por haver melhores maneiras de resolver esse problema, Talvez cu concorde com vocé, mas 0 comentirio como foi feito ¢ perfeitamente Idgico. Ele evitard que um programador afoito use um inicializador estatico em prol da eficiéncia, Comentario TODO : As vezes € cabivel deixar notas “To Do” (‘Fazer’) em comentarios no formato / /'70D0. No caso a seguir, o comentario TODO explica por que a fungao tem uma implementagao degradante ¢ 0 que se deveria fazer com aquela fun¢ao. /1TODO-MGM essas néo séo necessérias // Bsperamos que isso nfo esteja mais aqui quando verificarmos o modelo protected Versioninfo makeversion() throws Exception 1 xeturn nul } ‘Comentérios Ruins 59 ‘opos sao tarefas que os programadores acham que devem ser efetuadas, mas, por alguma razio, nao podem no momento. Pode ser um lembrete para excluir uma instrugao desnecessaria ‘uum apelo para que alguém olhe o problema. Ou um pedido para que alguém pense em um nome melhor ou um lembrete para fazer uma alteragaio que ¢ dependente de um evento determinado. Seja qual for o TODO, cle ndo justifica deixar um cédigo ruim no sistema, Hoje em dia, a maioria das IDEs oferecem ferramentas € recursos para localizar todos os comentérios 7000; portanto, no é provavel que fiquem perdidos no eédigo. Mesmo assim, vocé no deseja que seu cédigo fique amontoado de TODOs, sendo assim, procure-os regularmente € climine os que puder. Destaque Pode-se usar um comentério para destacar a importancia de algo que talvez parega irrelevante. String listItemconcent = match.group(3).trim(); // a fungdo trim é muito importante. Ela remove os espacos “/ Ainiciais que poderiam fazer com que o item fosse // reconhecido como outra lista. new ListItemWidget(thia, listItemContent, this.level + 1); return buildList(text.substring(match.end(!)); Javadoes em APIs Publicas Nao ha nada de tio pratico ¢ satisfatério como uma API piblica em deserita. Os javadocs para a biblioteca Java padrdo sio um exemplo. No maximo, seria dificil escrever programas Java sem cles Se estiver criando uma API piblica, entdo vocé certamente deveria escrever bons javadocs para ela, Mas terha em mente os outros conselhos neste capitulo, Os javadoes podem ser to enganadores, nfio-locais ¢ desonestos como qualquer outro tipo de comentario. Comentarios Ruins ‘A maioria dos comentarios cai nesta categoria. Geralmente eles s4o suportes ou desculpas para um cédigo de baixa qualidade ou justificativas para a falta de decisdes, amontoados como se 0 programador estivesse falando com si mesmo, Murmirio - Usar um comentario s6 porque vocé sente que deve ou porque o proceso o requer ¢ besteira. Se optar criar um comentirio, ento gaste o tempo necessario para fazé-lo bem. Por exemplo, a seguir esti um caso que encontrei no FitNesse, no qual um comentirio poderia ter sido titil. Entretanto, o autor estava com pressa ou nao prestava muita atengao. Seu murmurio foi deixado para tras como um enigma: public void loadProperties() { try 60 = Capitulo 4: Comentarios String propertiesPath = propertiesLocation + */* + PROPERTIES_FILE; FileInputstream propertiesStream = new FileInputstream(propertiesPath); loadedPropert ies.load(propertiesStream); } catch(ToRxception e) { // Nenhum arquivo de propriedades significa que todos os padrées est&o carregados } } O que esse comentario no bloco catch significa? Claramente fazia sentido para o autor, mas o significado nao foi muito bem transmitido. Aparentemente, se capturarmos (catch) uma IOException, significaria que nao hé arquivo de propriedades; e, neste caso, todos os padroes esto carregados. Mas quem carrega os padres? Eles foram carregados antes da chamada a0 loadPropert ies.load? Ou este capturou a excecao, carregou os padrées e, entdo, passou a excegaio para que ignoréssemos? Ou loadProperties. load carregou todos os padrdes antes de tentar carregar 0 arquivo? Serd que o autor estava limpando sua consciéncia por ter deixado 0 bloco do catch vazio? Ou — e essa possibilidade é assustadora — ele estava tentando dizer a si mesmo para voltar depois ¢ escrever 0 cédigo que carregaria os padroes? Nosso nico recurso ¢ examinar o cédigo em outras partes do sistema para descobrir 0 que estd acontecendo. Qualquer comentario que Ihe obrigue a analisar outro médulo em busca de um significado falhou em transmitir sua mensagem c nao vale os bits que consume. Comentarios Redundantes A Listagem 4.1 uma fungdo simples com um comentario no eabegatho que é completamente redundante. Provavelmente leva-se mais tempo para Ié-lo do que 0 cédigo em si. Listagem 4-1 waitForClose // Utility method that returns when thie.closed is true. Throws an exception (/ if the timeout is reached. public synchronized void waitPorClose(final long timeoutMillis| throws Exception if({closed) { wait [timeoutMillis}; if{tclosed) throw new Exception("MockResnonseSender could not be closed") ; Qual © propésito desse comentério? Certamente nao é mais informativo do que 0 eédigo. Nem mesmo justifica o cédigo ou oferece uma intengao ou raciocinio. E mais facil ler 0 eédigo apenas. De fato, ele é menos preciso do que o c6digo ¢ induz.o leitor a accitar tal falta de preciso Comentarios Ruins 61 em vez da interpretacao verdadeira. E mais como um vendedor interesseiro de carros usados Ihe garantindo que nio é preciso olhar sob 0 capé. ‘Agora considere o grande mimero de javadocs intiteis ¢ redundantes na Listagem 4.2 retirada do Tomcat. Esses comentarios s6 servem pata amontoar e encobrir 0 cédigo. Eles no passam informaco alguma. Para piorar, s6 Ihe mostrei os primeiros, mas hi muito mais neste médulo. Listagem 4-2 ContainerBase.java (Tomcat) public abstract class Containergase implements Container, Lifecycle, Pipeline, MBeanRegistration, Serializable ( + The processor delay for this comgonent protected int backoroundProcessorbelay = ~ 8 event support for this compone: protected Lifecyclesupport lifecycle = new LifecycleSupport (this); * The container event listeners for this protected Array! ntainer. t listeners = new ArrayList (); * The Loader implem * associated. ation with which chis Container is protected Loader loader = null; * The Logger implementation with which this Container is * associared protected Log logger = null; * associated logger nane. protected String logName = null * The Manager implementation with which this Container is * associated protected Manager manager null; 62 Capitulo 4: Comentarios Listagem 4-2 (continuagao): Container! java (Tomcat) * the cluster with which 7) pr 28 Container is associated, cted Cluster cluster = null; * The human-readable name of this Container. protected String name = null; * ‘The parent Container to which this Container is a chil d Container parent = null; * the parent class ioader to be configured when we install a * Loader. protected Classhoader parentCla joader = mull; * The Pipeline object with which thie Container is * associated. protected Pipeline pipeline - new standard?ipeline(this) ; * the Realm with which this Container is associated. protected Realm realm = null: * The resources DirContext object wit + is associated. which this Container protected DirContext resources = null Comentarios Ruins 6B Comentarios Enganadores As vezes, com todas as melhores das intencdes, um programador faz. uma afirmacao nfo muito clara em seus comentarios. Lembre-se também do redundante ¢ enganador comentario que vimos na Listagem 4.1 Como vocé descobrit que 0 comentario era enganador? O métodoniio retornava quando this closed Virava true (verdadeiro), mas 86 se this.closed ja fosse true (verdadeiro); caso contrario, ele esperava por um tempo limite e, entdo, langava uma excegao s¢ this.closed ainda nao fosse true (verdadeiro). ssa pequena desinformagdo, expressada em um comentario mais dificil de ler do que 0 codigo em si, poderia fazer com que outro programador despreocupadamente chamasse essa fun¢ao esperando-a que retornasse assim que this .closed se tomasse true (verdadero). Esse pobre programador logo se veria efetuando uma depuragio tentando descobrir o porqué da lentidio do e4digo. Comentarios Imperativos E basicamente tolo ter uma regra dizendo que toda fungo deva ter um Javadoc, ou toda variavel um comentario. Estes podem se amontoar no cédigo, disseminar mentiras € gerar confusao © desorganizacao. Por exemplo, os javadocs exigidos para cada fungdo levariam a abominagdes, como as da Listagem 4.3. Essa zona nao acrescenta nada e s6 serve para ofuscar 0 cédigo ¢ abrir 0 caminho para mentiras ¢ desinformagées. Listagem 4-3 @paran author The author of the CD @param tracks The number of tracks on the CD ationimMinutes The duration of the CD in minutes * @paran title The title of the @param d public void addep(string t: int tras String author, int durationimMinutes) { cp cd = new CD) cd.title = title; ist.add(cd) Comentarios Longos As vezes, as pessoas, toda vez que editam um médulo, sempre adicionam um comentario no inicio, Apés varias alteragdes, a quantidade de comentarios acumulada parece mais uma redagao ou um diario. Ja vi médulos com dezenas de paginas assim. 64 Capitulo 4: Comentarios & Re-organised the class and moved it to new package . com.jrefinery date (D3); gon ED ea getDescription() method, and eliminated NotableDate * class (Dh; * 12-Nov-2001 : IBD requires setDescription() method, now that NotableDate * class is gone (DG); Changed getPreviousDayOfweek |), * getFollowingbayOfwWeek!) and getNearestbay0fweek(} to correct . bugs (D6); * 05-Dec-2001 : Fixed bug in Spreadsheetvate class (DG): * y-2002 : Moved the month constants into a separate interface * [MonthCenstants) (DGi7 * g7-aug-2002 : Fixed bug in adéMonths() method, thanks to N???Llevka Per (0G); * t-2002 : Fixed errors reported by Checkstyle (DG) * L3-war-2 mplemented Serializable (D¢); * 29-May-2003 : Fixed bug in addMonthe method (DG); * 04-Sep-2003 : Implemented Comparable. Updated the isInRange javadocs (D6); +* 05-Jan-2005 : Fixed bug in addYears(| method (1096282) 10a); HA muito tempo, havia um bom motivo para criar ¢ preservar essas informagées no inicio de cada médulo, pois nao existiam ainda os sistemas de controle de cédigo fonte para fazer isso por nds. Hoje em dia, entretanto, esses comentarios extensos so apenas entulhos que confundem o cédigo, devendo assim ser completamente removidos. Comentarios Ruidosos As vezes vocé vé comentarios que nada sao além de “chiados”. Eles dizem 0 dbvio € nao fornecem novas informagéies od * Construter padrao. 7 protected AnnualDateRule() [ } Ah, sério? Ou este: s#* Dia do mes. #/ private int dayofMonth; E ha também o seguinte tipo de redundancia: yee * Retorna do dia do més * @return o dia do més * ‘i public int getDayofMonth() { return dayOfMonth; 3 Esses comentarios sfo to irrelevantes que aprendemos a ignori-los. Ao lermos 0 cédigo, nossos olhos passam direto por eles. No final, os comentarios passam a “mentit” conforme o cédigo muda. Comentarios Ruins 65 O primeiro comentério na Listagem 4.4 parece adequado*. Ele explica por que o block catch € ignorado. Contudo, o segundo nao passa de um chiado. Aparentemente, 0 programador estava to frustrado por criar blocos =xy/catch na fungdo que ele precisou desabafar. Listagem 4-4 startSending private void startSendina() ception €) // normal. someone stopped the request. catch (Exception e) try i response.add (Errorkesponder makeExceptionstring(e) ); response.cloaeall') 7 } catch(Exception el) J/Give me a break! } Em vez de desabafar em comentarios sem sentido e tuidosos, ele poderia ter pegado tal frustrago e usado-a para melhorar a estrutura do eédigo. Ele deveria ter redirecionado sua energia para colocar o tiltimo bloco try/catch em uma fungao separada, como mostra a Listagem 4.5. Listagem 4-5 startSending (refatorado) private void startSending() uy doSending |) ; , catch (Socket Exception ¢} { if normal. someone stopped the request. ) catch|Exception e) { 2 A tendéneia atual dag IDF de veriticagio da omografis em comentirios seri um alivio para nés que lemos bastante eodiges. Capitulo 4: Comentarios ? Listagem 4-5 (continuagao) startSending (refatorado) addixcept ionAndcloseResponse ie) : ception e} add (ErrorFesponder.makeBxcept ionstring(e}); closeall (): ‘Troque a tentagao para criar ruidos pela determinacdo para limpar scu cédigo. Vocé percebera que isso the tornar4 um programador melhor e mais feliz. Ruidos assustadores Os javadocs também podem ser vistos como ruidos. Qual 0 objetive dos Javadocs (de uma biblioteca de cédigo livre bem conhecida) abaixo? ¢s* Nome. 4/ private String name; /** The version. */ private String version; /** Nome da licenca. */ private String licenceName; 7* Vers&o. */ private String info; Releia os comentdrios com mais atengao. Notou um erro de recortar-colar? Se os autores nao prestarem atengo na hora de escrever os comentarios (ou colé-los), por que os leitores deveriam esperar algo de importante deles? Evite 0 comentario se é possivel usar uma fun¢ao ou uma variavel Considere 0 pedago de cédigo abaixo: 1/7 © médulo da lista global depende do “/ subsistema do qual fazemos parte? if (smodule.getDependSubsystems().contains(subSysMod.getSubSystem())} Comentarios Ruins 67 Poderia-se evitar 0 comentario e ArrayList moduleDependees = smodule.getDependsubsystems(); String ourSubSystem = subSysMod.getSubSystem(); if (moduleDependees .contains(ourSubSystem)) O autor do cédigo original talvez tenha escrito primeiro 0 comentario (pouco provavel) e, entao, 0 c6digo de modo a satisfazer 0 comentario. Entretanto, o autor deveria ter refatorado 0 cédigo, como eu fiz, para que pudesse remover o comentario. Marcadores de Posicao Algumas vezes os programadores gostam de marcar uma posigao determinada no arquivo fonte. Por exemplo, recentemente encontrei o seguinte num programa: MW BgBes MMII, E raro, mas ha vezes que faz sentido juntar certas fungdes sob um indicador como esses. Mas, de modo geral, eles so aglomeragées ¢ devem-se exclui-los—especialmente as varias barras no final. Pense assim: um indicador é chamativo e Gbvio se vocé nao os vé muito frequentemente. Porianto, use-os esporadicamente, ¢ sé quando gerarem beneficios significativos. Se usar indicadores excessivamente, eles cairdo na categoria de ruidos € serdo ignorados. Comentarios ao lado de chaves de fechamento As vezes. os programadores colocam comentarios especiais ao lado de chaves de fechamento, como na Listagem 4.6. Embora isso possa fazer sentido em fungdes longas com estruturas muito aninhadas, s6 serve para amontoar o tipo de fungdes pequenas e encapsuladas que preferimos. Portanto, se perceber uma vontade de comentar ao lado de chaves de fechamento, tente primeiro reduzir suas fungGes. Listagem 4-6 we.java ass we { static void mai ring[] args) { Bufferedkeader in String line; int lineCount i axCount = ‘dCount. = while {(line = in.readlane(}) {= null) ( ineCount ++; ine. length) : String wo line. split (\\W"); wordCount += words. length; ) s/while System.out print In(*wordCount wordCount) + system.cut .printIn(*lineCount LineCount } ; Systen.cut .printIn(*charCount = + charCcunti; 1 try 68 Capitulo 4: Comentarios ” Listagem 4-6 (continuagao) we. java cateh (IOException e} { Systen.err.println("Error:" + ¢.getMessage()}; ) /Icatch 3 #fmain Créditos e autoria /* Adicionado por Rick */ Os sistemas de controle de cédigo fonte so muito bons para lembrar que adicionou 0 qué e quando. Nao ha necessidade de poluir 0 cédigo com comentarios de autoria. Talvez vocé ache que tais comentarios sejam titeis para ajudar outras pessoas a saberem 0 que falar sobre 0 cddigo. Mas a verdade é que eles permanecem por anos, ficando cada vez menos precisos e relevantes. Novamente, 0 sistema de controle de cédigo fonte é€ um local melhor para este tipo de informagao. Explicagao do cédigo em comentarios Poucas priticas so to condendveis quanto explicar 0 cédigo nos comentarios. Nao faca isso! InputStreamResponse response = new InputStreamResponse(}; response.setBody(formatter.getResultStream(), formatter. getByteCount()); // Inputstream resultsStream = formatter.getResultStream(); // StreamReader reader = new StreamReader(resultsStream); // cesponse.setContent (reader.read(formatter.getByteCount())); Outros que vissem esse cédigo nao teriam coragem de excluir os comentérios. Eles achariam que esto ld por um motivo ¢ so importantes demais para serem apagados, Portanto, explicagaio de cédigos em comentirios se acumula como sujeira no fundo de uma garrafa de vinho ruim. Observe 0 eédigo do Commons do Apache: this.bytePos = writeBytes(pngIdBytes, 0); //naxPos = bytePos; writeHeader(); writeResolution(}; HdataPos = bytePos; if (writeTmageData()) { writeEnd(); this.pngBytes = resizeByteArray(this.pngBytes, this.maxPos); } else { this.pngBytes = null; ) return this.pngBytes; Por que aquelas duas linhas de e6digo esto comentadas? Elas sao importantes? Foram deixados como lembretes para alguma alteragdo iminente? Ou sdo apenas aglomerados que alguém comentara anos atras ¢ simplesmente nao se preocupou em limpar?

You might also like