Você está na página 1de 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 so um complemento perfeito para nosso clima timido e, geralmente, frio. Parte do charme do Ga-lol, para nés dinamarqueses, sao 0s dizeres sébios impressos em cada caixa. Comprei dois pacotes dessa iguaria essa manha e nela veio este antigo ditado dinamarqués: ZErlighed i smé ting er ikke nogen lille ting. “Honestidade em pequenas coisas no é€ uma coisa pequena”. Era um bom pressagio para com o que eu ja desejava dizer aqui. Pequenas coisas sao importantes. Este é um livro sobre preocupagdes modestas cujos valores esto longe de ser pequenos. Deus esta nos detalhes, disse o arquiteto Ludwig Mics van der Rohe. Essa citagdo retoma, argumentos com contemporancos sobre 0 papel da arquitetura no desenvolvimento de software, especialmente no mundo Agile. Bob e eu, as vezes, acabavamos engajados entusiasmadamente debatendo sobre este assunto. E sim, Mies van der Rohe atentava para os utilitarios e as formas imemoriais de construgdo que fundamentam uma étima arquitetura. Por outro lado, ele também selecionava pessoalmente cada maganeta para cada casa que ele projetava, Por qué? Por que pequenas coisas so 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 difereneas sao relativamente irrelevantes contudo, pois podemos admitir que profissionais responsdveis dedicam algum tempo para pensar e planejar o inicio de um projeto. As nogdes de desenvolvimento dirigido apenas por testes e por cédigos do final da década de 1990 jAndo existem mais. Mesmo assim, a atengdo 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 dircito ou o azulejo levemente torto do cho, 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 metdfora para o desenvolvimento de software, especialmente para a parte que entrega 0 produto inicial no mesmo sentido que um arquiteto entrega uma construgdo imaculada. Nessa época do Scrum e do Agile, 0 foco esta em colocar 0 produto rapidamente no mercado. Desejamos que a indistria funcione em velocidade maxima na producdo de software. Essas faibricas humanas: programadores que pensam e sentem que trabalham a partir das pendéncias de um produto ou do user story para criar o produto. A metéfoora da fabricago esta mais forte do que nunca no pensamento. Os aspectos da producao da manufatura japonesa de automéveis, de um mundo voltado para a linha de montagem, inspiraram grande parte do Scrum, Ainda assim, mesmo na indiistria automobilistica, a maior parte do trabalho nao esta na fabricagao, mas na manutengdo — ou na prevengdo. Em software, 80% ou mais do que fazemos & chamado de “manutengao”: 0 ato de reparar, Em vez de abracar o upico foco ocidental sobre a produg&o de bons softwares, deverfamos pensar mais como um pedreiro que conserta casas na industria de construg&o, ou um mecdnico de automdveis 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 cra na manutencdo em vez da produ¢ao. 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 jargio no cenario ocidental, e cada vez mais conhecida no mundo dos softwares. Esses principios nao so uma opedio. Assim como Uncle Bob diz em suas preliminares, a pratica de um bom software requer tal disciplina: foco, presenga de espirito ¢ 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 préximos capitulos. Seiton, ou arrumacao (pense em “sistematizar”). Ha um antigo ditado americano que diz: “Um lugar para tudo, ¢ tudo em seu lugar”. Um pedago de cédigo deve estar onde vocé espera encontré-lo — caso nao esteja, refatore e o coloque 1a. Seiso, ou limpeza (pensem em “polir”); manter 0 local de trabalho livre de fios pendurados, gordura, migalhas e 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 padronizacao: a equipe concorda em manter o local de trabalho limpo. Vocé acha que este livro fala algo sobre ter um estilo de programacaio consistente e uma série de priticas dentro da equipe? De onde vém tais padrées? Continue a leitura. Shutsuke, ou disciplina (autodisciplina). Isso significa ter disciplina para seguir as priticas refletir frequentememt isso no trabalho e estar disposto a mudar. Se aceitar o desafio — isso, 0 desafio — de ler e aplicar o que ¢ aconselhado neste livro, yocé entendera e apreciara o ultimo item. Aqui estamos finalmente indo em dire¢do as raizes do profissionalismo responsavel numa profissio que deve se preocupar com o ciclo de vida de um produto. Conforme facamos a manutengao de automéveis ¢ outras maquinas na TPM, a manutencao 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 dleo para testar o desgaste. No cédigo, a refatoracdo é impiedosa. Vocé ainda pode melhorar um nivel a mais com 0 advento do movimento da TPM ha 50 anos; construa maquinas que sejam passiveis de manutengao. Tornar seu cédigo legivel ¢ tio importante quanto tornd-lo executavel. A ultima pratica, adicionada a TPM em tomo de 1960, ¢ focar na incluso de maquinas inteiramente novas ou substituir as antigas. Como nos adverte Fred Brooks, provavelmente 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 visao ocidental de mundo sobre a vida; a sabedoria de ingleses ¢ americanos também est cheia dessas adverténcias. A citagdo de Seiton mais acima veio da ponta da caneta de um ministro cm Ohio que visualizou literalmente a organizag3o “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 questées? Quem ¢ fiel no pouco também é no muito. E que tal ficar ansioso para refatorar na hora certa, fortalecendo sua posi¢ao para as “grandes” decisdes subsequentes, em vez de descarta-las? Um homem prevenido vale por dois. Deus ajuda a quem cedo madruga. Nao deixe para amanha 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 o local de esforgos pequenos e individuais num grande todo? De griio em grao a galinha enche o papo. Ou que tal integrar um trabalho de prevengdo no dia a dia? Antes prevenir do que remediar. O cédigo limpo honra as profundas raizes do conhecimento sob nossa cultura mais ampla, ou como ela fora um dia, ou deve ser, € poderd vir a ser com a atengao correta aos detalhes. Mesmo na grande literatura na area de arquitetura encontramos visdes que remetem a esses supostos detalhes. Pense nas maganetas de Mies van der Rohe. Aquilo é sciri. E ficar atento a cada nome de variavel. 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 ¢ constante refinamento jamais acaba. arquiteto Christopher Alexander — pai dos padrées ¢ das linguagens de padrdes ~ enxerga cada o proprio design como um conserto pequeno ¢ local. E ele enxerga a habilidade de uma boa estrutura como 0 tinico objetivo do arquiteto; pode-se deixar as formas maiores para os padrées e seus aplicativos para os moradores. O design é constante no sé ao adicionarmos um novo cémodo a uma casa, mas ao nos atentarmos a repintura, a substituigdo de carpetes gastos ou a melhoria da pia da cozinha. A maioria das artes refiete relagdes 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 uabalhar nele seria abandoni-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 vocé ser desafiado a retomar a disciplina que vocé ha muito largou para a apatia ou um desejo pela espontaneidade e apenas “respondia as mudangas”. Infelizmente, nao costumamos enxergar essas questées como pecas fundamentais da arte de programar. Abandonamos nosso cédigo antecipadamente, nao 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 aten¢o nos custa: Dinheiro ruim sempre reaparece. Pesquisas, nem no mercado e nem nas universidades, so humildes o bastante para se rebaixar € manter 0 cédigo limpo. Na época em que trabalhei na empresa Bell Labs Software Production Research (producio, de fato!), ao ficarmos mexendo aqui e ali, nos deparamos com descobertas que sugeriam que 0 estilo consistente de endentacao 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 programaco ou outra nogao de alto nivel; conforme as pessoas cujo suposto profissionalismo se dé 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 aplicagao consistente em um estilo de endentagao. Para citar meu proprio livro de 17 anos atras, tal estilo faz a distingao entre exceléncia e mera competéncia. A visio de mundo japonesa entende 0 valor crucial do trabalhador diario e, além do mais, dos sistemas de desenvolvimento voltados para as ages simples ¢ didrias desses trabalhadores. A qualidade é o resultado de um milhdo de atos altruistas de importar-se — nao apenas um grande método qualquer que desga dos céus. Nao ¢ porque esses atos sao simples que eles sejam simplistas, e muito menos que sejam faceis. Eles siio, ndo obstante, a fabrica de magnitude e, também, de beleza em qualquer esforgo humano. Ignori-los é no ser ainda completamente humano. E claro que ainda defendo 0 conceito de um escopo mais amplo, ¢, especialmente, 0 do -valor de abordagens arquiteténicas arraigadas profundamente no conhecimento do dominio ¢ de usabilidade do software. Este livro ndo é sobre isso — ou, pelo menos, nao de modo direto. Mas ele passa uma mensagem mais sutil cuja esséncia nao deve ser subestimada. Ele se encaixa 4 méxima atual das pessoas que realmente se preocupam com o cédigo, como Peter Sommerlad, Kevlin Henney ¢ Giovanni. “O codigo € 0 projeto” e “Cédigo simples” sao seus mantras. Enquanto devamos tentar nos lembrar de que a interface é 0 programa, ¢ que suas estruturas dizem bastante sobre a estrutura de nosso programa, é crucial adotar a humilde postura de que 0 projeto vive no cédigo. E enquanto o retrabalho na metifora da manufatura leva ao custo, o no projeto leva ao valor. Devemos ver nosso cédigo como a bela articulacao dos nobres esforgos do projeto — projeto como um proceso, ¢ nao uma meta estatica. F no cédigo que ocorrem as medidas estruturais de acoplamento ¢ coesao. Se vocé vir a descrigao de Larry Constantine sobre esses dois fatores, ele os conccitua em termos de codigo — e nao em conceitos de alto nivel como se pode encontrar em UML. Richard Gabriel nos informa em seu artigo Abstraction Descant que a abstrago é maligna. O cédigo é antimaligno, e 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 no sO prestar atengo a pequenas coisas, mas também a ser honesto em pequenas coisas. Isso significa ser honesto com 0 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 o encontramos"”? Refatoramos nosso cédigo antes de verifica- lo? Essas nao sao preocupagées externas, mas preocupagOes que esto no centro dos valores do Agile. Que a refatoragdo seja parte do conceito de “Pronto”, é uma pritica recomendada no Scrum. Nem a arquitetura e nem o cédigo limpo exigem perfeigao, apenas honestidade ¢ que fagamos o melhor de nés. Errar é humano; perdoar € diyino. No Scrum, tornamos as coisas visiveis. Arejamos nossa roupa suja. Somos honestos sobre 0 estado de nosso cédigo porque © cédigo nunca € perfeito. Tornamo-nos mais completamente humanos, mais merecedores do divino e mais préximos da magnitude dos detalhes. Em nossa profissao, precisamos desesperadamente de toda ajuda que conseguirmos. Se 0 piso de uma loja reduz os acidentes ¢ suas ferramentas bem organizadas aumentam a produtividade, entdo sou totalmente a favor. F relagdo a este livro, ele é a melhor aplicag4o pragmatica dos principios de Lean ao software que ja vi. Eu ndo esperava nada mais deste pequeno grupo pratico de individuos que se esforcaram juntos por anos ndo s6 para se aperfeigoarem, mas também para presentear com seus conhecimentos 0 mercado com obras como esta em suas mAos agora. Isso deixa o mundo um pouco melhor do que quando o encontrei antes de Uncle Bob me enviar © manuscrito. Apds ter finalizado estes exercicios com conhecimentos to sublimes, agora vou limpar minha mesa. James O. Coplien Mordrup, Dinamarca Introducao ‘The OMLy VALI meAGugenenn— oF Code Quaciry: WTFs/ninure wrF Good code. Reproduzido com a gentil autorizago de Thom Holwerda. http://www.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 revisdo normal de cédigo ou encontramos uma série de problemas terriveis logo apés iniciarmos a apresentaga0? Estamos depurando em panico, lendo meticulosamente um cédigo que pens4vamos que funcionava? Os clientes estio indo embora aos bandos e estamos com os gerentes em nossos pescogos? Como podemos garantir que cheguemos atrés da porta certa quando 0 caminho fica dificil? A resposta ¢: habilidade profissional Ha duas vertentes para se obter habilidade profissional: conhecimento ¢ trabalho. Vocé deve adquirir o conhecimento dos principios, padrdes, priticas ¢ heuristicas que um profissional habilidoso sabe, ¢ também esmiugar esse conhecimento com seus dedos, olhos e corpo por meio do trabalho arduo e da pratica, Posso Ihe ensinar a mecanica para se andar de bicicleta. Na verdade, a matematica classica é relativamente direta. Gravidade, atrito, momento angular, centro de massa, e assim por diante, podem ser demonstrados com menos de uma pagina cheia de equagdes. Dada essas formulas, eu poderia provar para vocé que é pritico andar de bicicleta ¢ Ihe dar todo 0 conhecimento necessdrio para que yocé consiga. E mesmo assim vocé caira na primeira vez que tentar. Programar nao é diferente. Poderiamos por no papel todos os principios necessirios para um cédigo limpo e, entao, confiar que vocé faré as tarefas (isto é. deixar vocé cair quando subir na bicicleta), mas que tipo de professores ¢ de estudantes isso faria de nds? ‘Nao. Essa nao é a forma que este livro seguira, Aprender a criar cédigos limpos é uma tarefa ardua e requer mais do que o simples conhecimento dos prineipios ¢ padrées. Vocé deve suar a camisa; praticar sozinho e ver que cometeu eros; assistir a outros praticarem ¢ errar: ‘-los tropecar e refazer seus passos; Vé- los agonizar para tomar decisdes e 0 prego que pagarao por as terem tomado da mancira errada. Esteja preparado para trabalhar duro enquanto ler este livro. Esse nao é um livro facil ¢ simples que vocé pode ler num aviao ¢ terminar antes de aterrissar. Este livro Ihe faré trabalhar, e trabalhar duro. Que tipo de trabalho vocé faré? Vové lera cédigos aqui, muitos eddigos. E vocé devera descobrir 0 que esté correto e errado nos cédigos. Vocé terd de seguir 0 raciocinio conforme dividirmos médulos e os unirmos novamente. Isso levara tempo ¢ esforgo, mas achamos que valera a pena. Dividimos este livro em trés partes. Na primeira ha diversos capitulos que descrevem os principios, padrdes e praticas para criar um cédigo limpo. H4 um tanto de cédigos nessa parte, ¢ sera desafiador lé-los. Eles Ihe prepararao para a seco seguinte. Se vocé 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, Voeé terd de ir e voltar por entre as folhas de textos ¢ cédigos, e analisar e entender 0 cédigo com o qual estamos trabalhando e captar nosso raciocinio para cada alteragdo que fizermos. Reserve um tempo para essa parte, pois deverd levar dias. A terceira parte é a compensagao. E um tnico capitulo com uma lista de heuristicas e “odores” reunidos durante a criag3o dos estudos de caso. Conforme progredirmos ¢ limparmos os cédigos nos estudos de caso, documentaremos cada motivo para nossas agdes como uma heuristica ou um “odor”. Tentaremos entender nossas préprias reagdes em relagdio ao cédigo quando estivermos lendo ou alterando-o, ¢ trabalharemos duro para captar por que nos sentimos de tal forma e por que fizemos isso ou aquilo. O resultado seré um conhecimento base que descreve a forma como pensamos quando criamos, lemos ¢ limpamos um cédigo. Este conhecimento base possui um valor limitado se vocé nao ler com atengao ao longo dos casos de estudo na segunda parte deste livro. Neles, anotamos cuidadosamente cada alteracao que fizemos com referéncias posteriores as heuristicas. Tais referéncias aparecem em colchetes, assim: [H22]. Isso lhe permite ver 0 contexto no qual sao aplicadas ¢ escritas aquelas heuristicas! Essas, em si, no so tao valiosas, mas, sim, a relacdo entre elas e as diferentes decisdes que tomamos ao limpar 0 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 usé-la com um guia rapido de consulta para saber onde uma determinada heuristica foi aplicada. Mesmo se vocé ler a primeira ¢ a terccira segdes e pular para os casos de estudo, ainda assim tera lido um livro que satisfaz sobre a criacdo de um bom software. Mas se nao tiver pressa ¢ explorar os casos de estudo, seguindo cada pequeno passo e cada minuto de decisio, se colocando em nosso lugar e se forcando a seguir a mesma linha de raciocinio que usamos, entéo vocé adquiriu um entendimento muito mais rico de todos aqueles principios, padrées, praticas @ heuristicas, Todo esse conhecimento ficara em cada fibra de seu corpo. Ele se tornara parte de voce da mesma forma que ao aprender a andar de bicicleta, ela se torna uma parte de sua vontade de pedali-la. Agradecimentos Tlustragées Meus agradecimentos a minhas duas artistas, Jeniffer Kohnke ¢ Angela Brooks, Jennifer ¢ a responsdvel 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 esto 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 Galéxia Sombrero -, que fica na constelagao de Virgem e esta a pouco menos de 30 milhdes de anos-luz de nés. Em seu centro ha um buraco negro supermassivo cujo peso equivale um bilhio de vezes a massa do sol A imagem lhe faz lembrar da exploso da lua Praxis, de Klingon? Eu me recordo vividamente acena de Jornada nas Estrelas VI que mostrava um anel equatorial de destro¢os voando devido a explosio. Desde essa cena, 0 anel equatorial se tomiou um componente comum as explosdes em filmes de fiego cientifica. Ele até foi adicionado a explosao de Alderaan nas (iltimas versdes do filme Jornada nas Estrelas. O que causou a formagao desse anel em torno de M104? Por que cle possui um bojo to amplo ¢ um niicleo to minusculo e brilhoso? Parece-me como se o buraco negro central perdgu sua graga ¢ langou um buraco de 30.000 anos-luz no meio da galaxia, devastando quaisquer civilizacdes que estivessem no caminho daquele distirbio césmico. Buracos negros supermassivos engolem estrelas inteiras no_almogo, convertendo_uma consideravel fragao de sua massa cm energia. 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 dic: ‘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 galaxia. Na luz visivel, vemos apenas a extremidade frontal do anel como uma silhueta. O bojo central ofusca o resto do ancl. Mas no infravermelho, as particulas “quentes” — isto 6, altamente radioativas ~ no anel brilham através do bojo central, A combinag&o de ambas as imagens nos mostra uma visdo que ndo haviamos visto antes e indica que, ha muito tempo atrés, 14 havia um inferno enfurecido de atividades. over image: © Spitzer Space Telescope Cédigo Limpo Ha duas razdes pelas quais voce esta Iendo este livro: voeé € programador e deseja se tornar um ainda melhor. Otimo. Precisamos de programadores melhores. : Capitulo 1: Cédigo Limpo Este livro fala sobre programagao e esta repleto de cédigos que examinaremos a partir de diferentes perspectivas: de baixo para cima, de cima para baixo de dentro para fora. Ao terminarmos, teremos um amplo conhecimento sobre cédigos ¢ seremos capazes de distinguir entre um cédigo bom e um cédigo ruim. Saberemos como escrever um bom cédigo e como tomar um ruim em um bom. O Cédigo Podem dizer que um livro sobre cédigos ¢, de certa forma, algo ultrapassado, que a programacdo deixou de ser uma preocupagao € que devemos nos preocupar com modelos € requisitos. Outros até mesmo alegam que o fim do cédigo, ou seja, da programagao, esta prdximo; que logo todo cédigo serd gerado, ¢ nao mais escrito. E que nao precisarao mais de programadores, pois as pessoas criario programas a partir de especificagdes. Bobagens! Nunca nos livraremos dos eédigos, pois eles representam os detalhes dos requisitos. Em certo nivel, nfo ha como ignorar ou abstrair esses detalhes; eles precisam ser especificados. F especificar requisitos detalhadamente de modo que uma maquina possa executi-los é programar ~ ¢ tal especificagdo 6 0 cédigo. Espero que o nivel de de nossas linguagens continue a aumentar ¢ que o mimero de linguagens especificas a um dominio continue crescendo. Isso sera bom, mas nio acabara com a programaciio. De fato, todas as especificagdes escritas nessas linguagens de niveis mais altos € especificas a um dominio serdo cédigos! Eles precisar‘io ser minuciosos, exatos e bastante formais ¢ detalhados para que uma maquina possa entendé-los ¢ executa-los. As pessoas que pensam que o c6digo um dia desaparecera sto como mateméticos que esperam algum dia descobrir uma matematica que nao precise ser formal. Elas esperam que um dia descubramos uma forma de criar méquinas 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. Isso jamais acontecera. Nem mesmo os seres humanos, com toda sua intui¢Ao ¢ criatividade, 1@m sido capazes de criar sistemas bem-sucedidos a partir das caréncias confusas de seus clientes. Na verdade, se a matéria sobre especificagao de requisitos nZo nos ensinou nada, € porque os requisitos bem especificados so tao formais quanto os cédigos e podem agir como testes executaveis de tais cédigos! Lembre-se de que 0 cédigo é a linguagem na qual expressamos nossos requisitos. Podemos criar linguagens que sejam mais préximas a cles. Podemos criar ferramentas que nos ajudem a analisar a sintaxe e unir tais requisitos em estruturas formais. Mas jamais eliminaremos a preciso necessaria — portanto, sempre havera um cédigo. Cédigo Ruim 2 Codigo 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 frdgi?? Nao concordo! Acho que essa premissa é uma das mais robustas, apoiadas € plenas do que todas as outras em nossa area (e 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 c usaram. Mas, entdo, o intervalo entre os langamentos das novas~ distribuigdes comegou a aumentar, Os bugs ndo eram consertados na distribuigéo seguinte. E o tempo de carregamento do aplicativo ¢ 0 niimero de travamentos aumentaram, Lembro-me do dia em que, frustrado, fechei 0 programa e 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 0 perguntei o que havia acontecido, e 0 que eu temia fora confirmado. Eles tiveram de apressar o langamento do produto e, devido a isso, 0 cddigo ficou uma zona. Entao, conforme foram adicionando mais e mais recursos, o cédigo piorava cada vez mais até que simplesmente nao era mais possivel gerencid-lo. Foi 0 cédigo ruim que acabou com a empresa. ‘Alguma vez um cédigo ruim jé lhe atrasou consideravelmente? Se vocé for um programador, independemte de sua experiencia, ento ja se deparou varias vezes com esse obsticulo. Alias, é como se caminhdssemos penosamente por um lamagal de arbustos emaranhados com armadilhas ocultas.Isso ¢ 0 que fazemos num cédigo ruim. Pelejamos para encontrar nosso caminho. esperando avistar alguma dica, alguma indicagao do que esti acontecendo; mas tudo 0 que vemos ¢ um cédigo cada vez mais sem sentido. E claro que um cédigo ruim ja Ihe atrasou. Mas, entiio, por que vocé o escreveu dessa forma” Estava tentando ser rapido? Estava com pressa? Provavelmente. Talyez 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 c6digo. Talvez vocé estava apenas cansado de trabalhar neste programa e queria termind-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 0 proximo. Todos ja fizemos isso, j4 vimos a bagunca que fizemos e, entao, 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 nés ja dissemos que revisariamos e limpariamos 0 cédigo depois. E claro que naquela época nao conheciamos a lei de LeBlanc: Nunca é tarde 1 [Beck07} 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 significativo. 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 alterac4o feita no cédigo causa uma falha em outras duas ou trés partes do mesmo eédigo, Mudanca alguma é trivial. Cada adigo ou modificagdo ao sistema exige que restauragOes, amarragdes e remendos sejam “entendidas” de modo que outras possam ser incluidas. Com o tempo, a bagunga se torna to grande ¢ profunda que nao da para arrumé-la. ‘Nao hé absolutamente solug&o alguma. Conforme a confusio aumenta, a produtividade da equipe diminui, assintoticamente aproximando-se de zero. Com a redugo da produtividade, a geréncia faz a tinica coisa que cla pode; adiciona mais membros ao projeto na esperanga de aumentar a produtividade. Mas esses novos membros nao conhecem o projeto do sistema, nao sabem a diferenca entre uma mudanga que altera o propésito do projeto e aquela que o atrapalha. Ademais, eles, e todo o resto da equipe, esto sobre tremenda presstio para aumentar a produtividade. Com isso todos criam mais € mais confusdes, levando a produtividade mais perto ainda de zero (veja a Figura 1.1). o8 8888 Time Figura 1.1 Produtividade v, tempo 0 Custo de Ter um Cédigo Confuso 5 O Grande Replanejamento No final, a equipe se rebela. Todos informam 4 geréncia que nao conseguem mais trabalhar neste irritante cédigo-fonte e exigem um replanejamento do projeto. Apesar de a geréncia ndo querer gastar recursos em uma nova remodelago, ela nfo pode negar que a produtividade esta péssima. No final das contas, ela acaba cedendo as exigéncias dos desenvolvedores e autoriza o grande replanejamento desejado. E, entio, formada uma nova equipe especializada. Por ser um projeto inteiramente novo, todos querem fazer parte dessa equipe. Eles desejam comegar do zero e criar algo belo de verdade. Mas apenas os melhores ¢ mais brilhantes sio selecionados e os outros deverao continuar na manutengao do sistema atual. Agora ambos os times esto numa corrida. A nova equipe precisa construir um novo sistema que faga 0 mesmo que o antigo, além de ter de se manter atualizada em relagao as mudangas feitas constantemente no sistema antigo. Este, a geréncia nado substituira até que o novo possa fazer tudo também. Essa corrida pode durar um bom tempo. J4 vi umas levarem 10 anos. E, quando ela termina, os membros originais da nova equipe ja foram embora ha muito tempo, ¢ 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 cdigo nao é apenas eficaz em termos de custo, mas uma questiio de sobrevivéncia profissional. Atitude Vocé ja teve de trabalhar penosamente por uma confusdo to grave que levou semanas © que deveria ter levado horas? Vocé ja presenciou 0 que deveria ser uma alteraco tinica e direta, mas que em vez disso foi feita em diversos médulos distintos? Todos esses sintomas sao bastante comuns. Por que isso ocorre em um cédigo? Por que um cédigo bom se decompée tio rapido em um ruim? Temos diversas explicagdes para isso. Reclamamos que os requisitos mudaram de tal forma que estragaram 0 projeto original. Criticamos os prazos por serem curtos demais para fazermos as coisas certas. Resmungamos sobre gerentes tolos ¢ clientes intolerantes ¢ tipos de marketing intiteis ¢ técnicos de telefone, Mas 0 padrio, querido Dilbert, nao esté em nossas estrelas, mas sim em n6és mesmos. Somos profissionais. Isso pode ser algo dificil de engolir. Mas como poderia essa zona ser nossa culpa? E os requisitos? E o prazo? E os tolos gerentes ¢ tipos de marketing intiteis? Eles nfo carregam alguma parcela da culpa? Nao. Os gerentes ¢ marketciros buscam em nés as informagdes que precisam para fazer promessas ¢ firmarem compromissos; € mesmo quando nao nos procuram, nao devemas dar uma de timidos ao dizer-Ihes nossa opinio. 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 relagao a um codigo ruim. 6 Capitulo 1: Cédigo Limpo “Mas, espere!™, vocé diz. “E se eu ndo fizer 0 que meu gerente quer, serei demitido”. E provavel que nao. A maioria dos gerentes quer a verdade, mesmo que demonstrem 0 contrario. A maioria deles quer um cédigo bom, mesmo estourando 0 prazo. Eles podem proteger com paixao 0 prazo ¢ 03 requisitos, mas essa é a fungdio deles. A sua é proteger 0 cédigo com essa mesma paixio. Para finalizar essa questo, ¢ se vocé fosse médico ¢ 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 o chefe neste caso € 0 paciente; mas, mesmo assim, o médico devera totalmente se recusar obedecé-lo. Por qué? Porque 0 médico sabe mais do que o paciente sobre os riscos de doengas e infecgdes. Nao scria profissional (sem mencionar criminoso) que o médico obedecesse ao paciente neste cenario. Da mesma forma que nao é profissional que programadores cedam 4 vontade dos gerentes que nao entendem os riscos de se gerar cédigos confusos. 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 0 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 esta errada, Vocé no cumpriré 0 prazo se fizer bagunga no cédigo. De fato, tal desorganizagao reduzira instantaneamente sua velocidade de trabalho, e vocé perder o prazo. A uinica maneira de isso no acontecer — a tinica maneira de ir mais répido— & sempre mamter 0 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 voce aceite 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 vocé nfo souber o que isso significa. ‘As més noticias so que escrever um cédigo limpo é como pintar um quadro. A maioria de nds sabe quando a figura foi bem ou mal pintada. Mas ser capaz de distinguir uma boa arte de uma Tui nio significa que vocé saiba pintar. Assim como saber distinguir um eddigo limpo de um ruim nao quer dizer que saibamos escrever um cédigo limpo. Escrever um cédigo limpo exige 0 uso disciplinado de uma miriade de pequenas técnicas aplicadas por meio de uma sensibilidade meticulosamente adquirida sobre “limpeza”. A “sensibilidade ao cédigo” é 0 segredo. Alguns de nés jé nascemos com cla. Outros precisam se esforgar para adquiri-la. Ela nfo sé nos permite perceber se 0 cddigo é bom ou ruim, como também nos mostra a estratégia ¢ disciplina de como transformar um cédigo ruim em um limpo. Um programador sem “sensibilidade ao cédigo” pode visualizar um médulo confuse reconhecer a bagunga, mas nao sabera o que fazer a respeito dela. J4 um com essa sensibilidade olharé um médulo confuso e verd alternativas. A “sensibilidade ao cédigo” ajudara a esse ‘a Rew 1807. memes Serer Bemrmmedbwose we:neien vole peinolen ‘enc airbag llc, sel Go vejebtadh, Chaicanidnvie is ich de apie wa nidices imma weupades: O Custo de Ter um Codigo Confuso 7 programador a escolher a melhor alternativa e 0 orientara na criago de uma sequéncia de comportamentos para proteger as alteragdes 8 aqui e ali, Em suma, um programador que escreve um cddigo limpo € um artista que pode pegar uma tela em branco e submeté-la a uma séric 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 cxperiéncia o que achavam. Bjarne Stroustrup, criador do C++ e autor do livro A linguagem de programagao C++ Gosto do meri cédigo elegante e eficiente A légica deve ser direta para difieultar o encobrimento de bugs. cas dependéncias minimas pars facilitar a manuten¢ao. © tratamento de erro completo de acordo com uma estratégia clara € 0 desempenho préximo do mais efielente de modo a nao incitar as pessoas a tornarem 0 cddigo confuso com otimizacdes sorratetras. O cédigo impo faz bem apenas uma coisa. Bjarne usa a palavra “elegante” — uma palavra e tanto! O diciondrio possui as seguintes definigoes: que se caracteriza pela naturalidade de harmonia, leveza, simplicidade; naturalidade no modo se dispor; requintado, fino, estiloso Observe a énfase dada & palavra “naturalidade”. Aparentemente, Bjarne acha que um cédigo limpo proporciona uma leitura natural; ¢ lé-lo deve ser belo como ouvir uma misica num ridio ou visualizar um carro de design magnifico. Bjame 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 Bjarne usa a palavra “‘ineitar” para descrever a consequéncia de tal deseleganeia, 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 pioré-lo. Pragmaticos. Dave Thomas e Andy Hunt expressam isso de outra forma, Eles usam a metafora das janelas quebradas.’ Uma construgdo 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 ¢ deixam acumular lixo. Uma Gnica janela inicia 0 processo de degradagio, ‘9 Shite haa ath XE ah 8 Capitulo 1: Cédigo Limpo Bjarne também menciona que o tratamento de erro deva ser completo. Isso significa prestar atengilo nos detalhes. Um tratamento de erro reduzido apenas uma das maneiras pela qual 0s programadores deixam de notar os detalhes. Perdas de meméria e condigdes de corrida so outras. Nomenclaturas inconsistentes so ainda outras. A conclusio é que um cédigo limpo requer bastante atengio aos detalhes. Bjarne conclui com a asseveragdo de que um eédigo limpo faz bem apenas uma coisa. Nao é por acaso que ha inumeros principios de desenvolvimento de software que podem ser resumidos a essa simples afirmagio. Varios escritores jé tentaram passar essa ideia. Um eédigo ruim tenta fazer coisas demais, cle esti cheio de propdsitos obscuros ¢ ambiguos. O cédigo limpo ¢ centralizado. Cada fungao, cada classe, cada médulo expée 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 eserita. Ele jamais tora confuso 0 objetivo do desenvolvedor. em vez disso, ele esta repleto de abstracoes claras ¢ linhas de controle objetivas. Grady fala de alguns dos mesmos pontos que Bjarne, yoltando-se mais para questio 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 vocé jé leu. Lembre-se de como as palavras eram substituidas por imagens! Fra como assistir a um filme, nfo era? Melhor ainda, voeé via os personagens, ouvia os sons, envolvia-se nas emogdes e no humor. Ler um cédigo limpo jamais sera 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 20 leitor aquele “Aha! Mas € claro!”, como as questdes ¢ 0s suspenses que so solucionados na revelagao de uma solugio ébvia. ‘Acho que o uso que Grady faz da frase “abstragdes claras” é um paradoxo fascinante! ‘Apesar de tudo, a palavra “clara” é praticamente um sinénimo para “explicito”. Meu diciondrio MacBook tem a seguinte definigao para “claro(a)": direto, decisivo, sem devaneios ou detalhes desnecessdrios. Apesar desta justaposi¢ao de significados, as palavras carregam uma mensagem poderosa. Nosso cédigo deve ser decisivo, sem especulagdes. Ele deve conter apenas 0 necessario 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 criador, um desenvotvedor pode ler ¢ methorar um cédigo limpo. Ele tem testes de unidade e de aceitacao, nomes significativos; ele oferece apenas uma maneira, e nto varias, de se facer uma tarefa; possi poucas dependéncias, ‘as quais so explicitamente declaradas ¢ oferecem um API minimo e claro. O cédigo deve ser imteligivel jé que dependendo da linguagem, nem toda informacdo necessaria pode expressa na 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 dbvio, mas nao se deve enfatizar muito isso, Ha, afinal de contas, uma diferenga entre um cédigo facil de ler ¢ um facil de alterar. Dave associa limpeza a testes! Dez anos atras, isso levantaria um ar de desconfianga. Mas 0 estudo do Desenvolvimento Dirigido a Testes teve grande impacto em nossa indiistria e se tornou uma de nossos campos de estudo mais essenciais. Dave esta certo. Um codigo, sem testes, nao esta limpo. Nao importa o quo elegante, legivel ou acessivel esteja que, se ele nao possuir testes, ele nao é limpo. Dave usa a palavra minima duas vezes. Aparentemente cle da preferéncia a um cédigo pequeno. De fato, esse tem sido uma citagao comum na literatura computacional. Quando menor. melhor. Dave também diz que 0 cédigo deve ser inteligivel — referéncia esta & programagdo imeligivel (do livro Literate Programming) de Donald Knuth. A conclusao é que 0 codigo deve * ser escrito de uma forma que seja 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 impo, mas hd: wma predominaee que leva a todas as outras, Um cédigo limpo sempre parece que foi excrito por alguém que se importava. Nao hi nada de dbvio no que se pode fazer para tornc-to melhor. Tudo foi pensado pete autor do cédigo, se tentar pensar em algumas melhoras, vocé voltardé ao inicio, ou seja, apreciando o cédigo deixado para voes por alguém que se importa bastante com essa tarefa. : poe One word: care. E esse o assunto deste livro. Talvez, i um subtitulo apropriado seria Como se importar HL {+ com 0 cédigo. es que foi cuidado por alguém. Alguém que calmamente 4. [Kauth®2} 10 Capitulo 1: Cédigo Limpo © manteve simples e organi que se importou. .do; alguém que prestou a atengao necesséria aos detalhes; alguém 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, e criou cédigos em quase todas as linguagens ¢ maquinas. Vale a pena considerar suas palavras: estes anos recentes, comecei, e quase finalizei, com as regras de Beck sobre cédigo simples. Em ordem de priovidade, sao. + Efete todos os testes + Sem duplicagao de cédigo: + Expressa todas as ideias do projeto que estao no sistema + Minimiza © miimero de ensidades, como classes, métodos. funges e outras do tipo. Dessas quatro, foco-me mais na de duplicagdo. Quando a mesma coisa ¢ feita repetidas vezes, é sinal de que uma idvia em sua cabega nao extd bem representada no codigo. Tento descobrir 0 que ¢ e, entio. expressar ‘aquela ideia com mais clareza Expressividade para mim sao nomes significativos e costume mudar o nome das coisas varias vezes antes de finalizar. Com ferramentas de programacdo modernas, como a Eclipse, renomear & bastante facil, e por isso ‘ndo me incomodo om fazer isso. Entretanto, a expressividade vai além de names. Também verifico se um método ‘ou objeto faz mais de uma tarefa. Se for wm objeto, provavelmente ele precisard ser dividlido em dois ou mais. Se for um méiodo, sempre uso a refatoracda do Métode de Extracao nele, resuliando em wm método que expressa mais claramente sua fungao e em outros métodos que dizem como ela & feita Duplicagdo e expressividade me levam ao que considero wn cédigo limpo, @ methorar um cddigo ruim com ‘apenas esses dois conceitos na mente pode fazer uma grande diferenca. Ha, porém, uma outra corsa da qual estou ciente quando programo, que é um pauco mais dificil de explicar. “Apis anos de rabalho, parece-me que todos os programadores pensar tudo igual. Um exemplo & “encontrar ‘coisas muma coleeao". Tenhamos uma base de dados cam registros de junciondrios ou uma tabela hash de chaves ¢ valores ou um vetor de itens de algum tipo, geralmente procuramos um item especifico naguela cole¢do. Quando percebo isso, costume implementar exsa fungao em um metodo ou classe mals abstrato — 0 (que me proporciona algumas vantagens interessante. Passo implementar a funcionalidade agora com algo mais simples, digamos uma tabela hash, mas como agora todas as referéncias aquela busca estdo na minha classe ou método abstrato, posso alterar a implementacdo sempre que desejar. Posso ainda prosseguir rapidamente enquanto preservo a copacidade de alteragio futur. ‘Além disso, a de colecdes geralmente chama minha atengdo para o que realmente esti acontecendo, e impede (que cu implemenue funcionalidades arbitrarias em colecdes quando tudo que eu preciso so simples maneiras de encontrar o que desejo. Reducdo de duplicacdo de codigo, alta expressividade e criacdo no inicio de absiragoes simples. E isso que torna para mim um cadigo limpo. Aqui, em alguns breves pardgrafos, Ron resumiu o conteiido deste livro. Sem duplica¢ao, uma tarefa, expressividade, pequenas abstragdes. Tudo foi mencionado. O Custo de Ter um Cédigo Confuso H 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. Vocé sabe que esté criando um eédigo timpo quando cada rotina que voc® leia se mostra como o que vocé esperava. Vocé pode chamar de cédigo belo quando ele também faz parecer que ay linguagem foi feita para 0 problema. 7 Declaragdes como essa sito caracteristicas de Ward. Vocé a le, coloca na sua cabega e segue para a proxima. Parece to racional, to ébvio que raramente é memorizada como algo profundo. Voeé acha que basicamente ja pensava assim. Mas observemos mais atentamente. “....0 que vocé esperava”. Qual foi a altima vez que vocé viu um médulo como voce 0 esperava que fosse? Nao é mais comum eles serem complexos, complicados, emaranhados? Interpreté-lo erroneamente nao é a regra? Vocé nao esté acostumado a se descontrolar ao tentar entender 0 raciocinio que gerou todo 0 sistema ¢ associé-lo ao médulo que estas lendo? Quando foi a dltima 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, ndo seré nem preciso muito esforgo. Vocé ird Ié-lo c sera basicamente © que vocé jd esperava. O cédigo ¢ dbvio,* simples ¢ convincente. Cada médulo prepara o terreno para o seguinte. Cada um Ihe diz como 0 préximo estara escrito. Os programas que sao to limpos ¢ claros assim foram tao bem escritos que voce nem percebera. O programador o faz parecer super simples, como o é todo projeto extraordindrio. E.anogao de beleza do Ward? Todos ja reclamamos do fato de nossas linguagens nao tiverem sido desenvolvidas para os nossos problemas. Mas a declaracao de Ward coloca novamente © peso sobre nds. Ele diz que um cédigo belo faz parecer que a linguagem foi feita para o problema! Portanto, & nossa responsabilidade 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)? O que é um cédigo limpo para mim? isso o que este livro lhe dird em detalhes, 0 que eu e meus compatriotas consideramos um cddigo limpo. Diremo-lhe 0 ‘que consideramos como nomes limpos de variaveis, fungoes limpas, classes limpas etc. Apresentaremos nossos conceitos como verdades absolutas, e no nos desculparemos por nossa austeridade. Para nés, a essa altura de nossa carreira, tais conceitos sdo absolutos. Si 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 melhor técnica dentro de uma arte marcial espeeffica. Geralmente, cles criam suas proprias escolas de pensamento ¢ recrutam alunos para serem ensinados. Dessa forma, temos 0 Jiu Jitsu dos Gracie, criado ¢ ensinado pela familia Gracie, no Brasil; 0 Jiu Jitsu de Hakkoryu, criado ¢ ensinado por Okuyama Ryuho, em Téquio; e o Jeet Kune Do, criado ¢ ensinado por Bruce Lee, nos EUA. Os estudantes se dedicam a doutrina ensinada por aquela determinada arte, e aprendem o que seus mestres ensinam, geralmente ignorando os ensinamentos de outros mestres. Depois, conforme os estudantes progridem, costuma-se mudar 0 mestre de modo que possam expandir seus conhecimentos e praticas. Alguns, no final, continuam a fim de refinar suas habilidades, descobrem novas técnicas e criam suas proprias escolas. ‘Nenhuma dessas escolas esté 100% certa. Mesmo assim dentro de uma determinada escola agimos como os ensinamentos ¢ téenicas 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 nao invalida as técnicas de outra. Considere este livre como uma descrigao da Escola de Codigo Limpo da Object Mentor. As téenicas ¢ ensinamentos sao a maneira pela qual praticamos nossa arte. Estamos dispostos a alegar que se vocé seguir esses ensinamentos, desfrutard dos beneficios que também aproveitamos e aprender a escrever codigos limpos ¢ profissionais. Mas nao pense vocé que nés estamos 100% “certos”. Provavelmente ha outras escolas e mestres que tém tanto para oferecer quanto nés. O correto seria que vocé aprendesse com elas também. De fato, muitas das recomendagdes neste livro sao contraditorias. Provayelmente vocé nao concordara com todas e podera até mesmo discordar intensivamente com algumas. Tudo bem. Nao podemos querer ter a palavra final. Por outro lado, pensamos bastante € por muito tempo sobre as recomendagdes neste livro. As aprendemos ao longo de décadas de experiéncia ¢ repetidos testes ¢ erros. Portanto, concorde vocé ou nao, seria uma pena se vocé nao conseguisse enxergar nosso ponto de vista. Somos Autores 13 Somos Autores © campo @author de um Javadoc nos diz quem somos. Nés somos autores, e todo autor tem leitores, com os quais uma boa comunicagao é de responsabilidade dos autores. Na préxima vez em que voce escrever uma linha de cédigo, lembre-se de que vocé ¢ um autor, escrevendo para leitores que julgarao seus esfor¢os. Vocé talvez se pergunte: quanto realmente se Ié de um cédigo? A maioria do trabalho nao é escrevé-lo? Vocé j4 reproduziu uma sesso de edigdo? Nas décadas de 1980 e 1990, tinhamos editores, como 0 Emacs, que mantinham um registro de cada tecla pressionada. Vocé podia trabalhar por horas ¢, endo, reproduzir toda a sua sesso de edigo como um filme passando em alta velocidade. Quando fiz isso, os resultados foram fascinantes. A grande maioria da reprodugdo era rolamento de tela ¢ navegagao para outros médulos! Bob entra no modulo, Ele descia até a funcdo que precisava ser alterada. Ele para e pondera suas opcies. Oh, ele sobe para o inicio do médulo a fim de verificar a inicializacao da varidvel. Agora ele desce novamente e comeca a digitar. Opa, ele esté apagando 0 que digitou! Ele digita novameme. Ele apaga novamente. Ele digita a metade de algo e apaga! sy Ele desce até outra funcéo que chama a que ele esté modificando para ver como ela é, chamada. Ele sobe novamente e digita 0 mesmo cédigo que acabara de digitar. Ele para. Ele apaga novamente! Ele abre uma outra janela e analisa uma subclasse. A fingdo é 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 & tamanha diferenga, desejamos que a leitura do cédigo seja facil, mesmo se sua criagdo for ardua. E claro que n&o ha como escrever um cédigo sem Ié-lo, portanto tornd-lo de facil leitura realmente facilita a escrita. Nao hé como escapar desta légica. Vocé no pode escrever um cédigo se nao quiser ler as outras partes dele. O cédigo que voce tenta escrever hoje sera de dificil ou facil leitura dependendo da facilidade de leitura da outra parte do eédigo. Se quiser ser rapido, se quiser acabar logo, se quiser que seu cédigo seja de facil eserita, tone-o de facil leitura. 14 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 preveneao da degradacao. [A Boy Scouts of America (maior organizagao de jovens eseoteiros dos EUA) tem uma regra simples que podemos aplicar 4 nossa profissao. Deixe a drea do acampamento mais limpa do que como vocé a encontrou.s Se todos deixdssemos nosso cédigo mais limpo do que quando o comecamos, ele simplesmente nao degradaria. A limpeza nao precisa ser algo grande, Troque o nome de uma varidvel por um melhor, divida uma funcZo que esteja um pouco grande demais, elimine um pouco de repeti¢ao de cédigo, reduza uma instrugao i £ aninhada, Consegue se imaginar trabalhando num projeto no qual o codigo simplesmente melhorou com o tempo? Voce 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 principios do projeto orientado a objeto ¢ muitas das priticas utilizadas por desenvolvedores profissionais. Se vocé ainda nao Icu o PPP, talvez ache que € a continuagao deste livro. Se ja o leu, entio perceberd que ele é bastante parecido a esse em relacao aos codigos Neste livro ha referéncias esporadicas a diversos principios de projeto, dentre os quais esto: Principio da Responsabilidade Unica (SRP, sigla em ingles), Principio de Aberto-Fechado (OCP, sigla em¥inglés), Principio da Inversdo da Independéncia (DIP, sigla em inglés), dentre outros, Esses prineipios sao descritos detalhadamente no PPP. Conclusao Livros sobre arte nljo prometem Ihe tornar um artista. Tudo 0 que podem fazer ¢ The oferecer algumas das ferramentas, técnicas e linhas de pensamento que outros artistas usaram. Portanto, este livro nao pode prometer Ihe tornar um bom programador. Ou Ihe dar a “sensibilidade ao codigo”, Tudo o que ele pode fazer ¢ Ihe mostrar a linha de pensamento de bons programadores © 0s truques, técnicas ¢ ferramentas que cles usam. ‘Assim como um livro sobre arte, este esta cheio de detalhes. H4 muitos cédigos. Vocé vera cédigos bons ¢ ruins; eédigo ruim sendo transformado em bom; listas de heuristicas, orientagdes e técnicas; e também exemplo apés exemplo. Depois disso, é por sua conta Lembre-se daquela piada sobre o violinista que se perdeu no caminho para a apresentagao em sihaieeretioen diblsss cake euluiale ti Bibliografia 15 um concerto? Ele aborda um senhor na esquina e the pergunta como chegar ao Camegie Hall. O senhor observa 0 violinista com seu violino debaixo dos bragos e diz “Pratique, filho. Pratique!”. Bibliografia [Beck07]: Implementation 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 Introdugao Ha nomes por todos os lados em um software, Nomeamos nossas variaveis, 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 e nomeamos. Como fazemos muito isso, ¢ melhor que o fagamos bem. A seguir esto algumas regras simples para a criagao 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 e troque-os quando encontrar melhores. Todos que lerem seu c6digo (incluindo ‘vocé mesmo) ficarao agradecidos. © nome de uma variavel, fungdo ou classe deve responder a todas as grandes questdes. Ele deve Ihe dizer porque existe, o que faz e como € usado. Se um nome requer um comentirio, entaio ele nao revela seu propésito. int d; // tempo decorrido em dias O nome d nao revela nada, Ele nfo indica a ideia de tempo decorrido, nem de dias. Devemos escolher um nome que especifique seu uso para mensuragdo ¢ a unidade usada. int elapsedTimeInDays; int daysSinceCreation; int daysSinceModification; int fileageInDays; Escolher nomes que revelem seu propésito pode facilitar bastante o entendimento ea alteragao do cédigo. Qual o propésito deste cédigo? public List getThem() { List listl = new ArrayList(); for (intl] x : theList) if (x[0] == 4) listl.addtx); return list1; } Por que € dificil dizer o que o eédigo faz? Nao ha expressdes complexas. O espacamento ¢ a endentagdo sto cabiveis. S6 ha wés variéveis e 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 cédigo, mas seu aspecto implicito, isto ¢, 0 contexto ntio estd explicito no cédigo. Devido a isso, é necessério que saibamos as repostas para questdes como: 1. Que tipos de coisas estdo em theList? 2. Qual a importincia de um item na posi¢do zero na theList? 3. Qual a importineia do valor 4? 4, Como eu usaria a lista retornada? |As respostas para tais questées nfo estilo presentes no exemplo do cédigo, mas poderiam. Digamos que estejamos trabalhando num jogo do tipo “campo minado”. Percebemos que o tabulciro é uma lista de células chamada theList. Vamos renomed-la para gameBoard. Evite Informagées Erradas 19 Cada quadrado no tabuleiro é representada por um vetor simples, Mais tarde, descobrimos que a posigao zero é armazena um valor de status ¢ que o valor 4 significa “marcado com uma bandeirinha’”, Ao dar esses nomes explicativos, podemos melhorar consideravelmente 0 codigo: public List getFlaggedCells() ( bist flaggedCells = new ArrayList(); for (int[] cell : gameBoard} if (cell[STATUS_VALUE] flaggedCells.add(cell return flaggedCells; FLAGGED) } Note que a simplicidade do codigo nao mudou. Ele ainda possui o mesmo nitmero de operadores € constantes, com o 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 ints. Ela pode ter uma fungao com um nome revele seu propésito (chamada isF lagged, ou seja “esté mareada com uma bandeirinha”) para ocultar os numeros magicos. O resultado é uma nova versio da funcao: public List getFlaggedcells() { List flaggedCells = new ArrayList(); for (Cell cell : gameBoard) if (cell.isFlagged()} flaggedcells.add(cell); return flaggedCells; Com essas simples alteragdes de nomes, nio fica dificil entender 0 que esta acontecendo. Esse € o poder de escolher bons nomes. 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, hp, aix e sco scriam nomes ruins de varidveis, pois sio nomes de plataformas Unix ou variantes. Mesmo se estiver programando uma hipotenusa e hp parecer uma boa abreviagao, 0 nome pode ser mal interpretado. Nao se refira a um grupo de contas como accountList, a menos que realmente seja uma List. A palavra /ist (lista) significa algo especifico para programadores. Se 0 que armazena as contas ndo 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édulo ¢ XYZControllerForBfficientStorageOfStrings em outro. Ambas as palavras sio muito semelhantes. 20 Capitulo 2: Nomes Significativos Usar conceitos similares para montar palavras é informagao. Usar formatos inconsistentes para palavras leva a uma md interpretacdo. Com os ambientes Java de hoje dispomos do recurso de autocompletar palavras. Digitamos alguns caracteres de um nome ¢ pressionamos uma combinagdo de teclas (se houver uma) ¢, 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 ébvias, pois é mais provavel que 0 desenvolvedor escolha um objeto pelo nome, sem consultar seus comentarios ou mesmo a lista de métodos fornecidos por aquela classe Um exemplo real de nomes que podem gerar confusfo é 0 uso da letra “I” minuscula ou da vogal “o” maitiscula como nome de variiveis. O problema é que cles se parecem com 0 um ¢ © zero, respectivamente. int a= 1 if (0 ) a= Ol; else 1 = 01; © leitor pode achar que inventamos esse exemplo, mas j4 vimos cédigos nos quais isso acontecia bastante, Uma vez, 0 autor do codigo sugeriu 0 uso de fontes distintas de modo a realgar mais as diferencas, uma solugdo que teria de ser repassada de forma oral ou escrita a todos os futuros desenvolvedores. Com uma simples troca de nome, o problema ¢ resolvido com objetividade ¢ sem precisar criar novas tarefas. Faca Distingées Significativas Os programadores criam problemas para si proprios quando criam um cédigo voltado unicamente para um compilador ou interpretador. Por exemplo, como. no é possivel usar 0 mesmo nome para referir-se 1a duas coisas diferentes num mesmo escopo, vocé pode decidir alterar o nome de maneira arbitraria, As vezes, isso € feito escrevendo um dos nomes errado, produzindo a uma situagao na qual a corre¢do de erros de ortografia impossibilita a compilagao.’ Nao basta adicionar niimeros ou palavras muito comuns, mesmo que o compilador fique satisfeito, Se os nomes precisam ser diferentes, entdo também devem ter significados distintos. Usar mimeros sequenciais em nomes (al, a2,...,aN) € @ oposto da selegao de nomes expressivos. Eles nao geram confusdo, simplesmente nao oferecem informagao alguma ou dica sobre a intengao de seu criador. Considere o seguinte: public static void copyChars(char al[], char a2{l) { for (int i = 0; i < al-length; i++) { a2[i] = allil; ? 5 Use Nomes Pronuncitiveis Fica muito mais ficil ler essa fung&o quando usam-se source ¢ destination como nomes de pardmetros. Palavras muito comuns s4o 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 nao revelam nada de diferente. Info ¢ Data sao palavras muito comuns € vagas, como “um”, “uma’” ¢ “a”. Observe que nao ha problema em usar prefixes como “um” e “a”, contanto que fagam uma distingdo significativa. Por exemplo, vocé pode usar “um” para varidveis locais ¢ “a” para todos os parimetros de fungdes.’ © problema surge quando vocé decide chamar uma variavel de aZork s6 porque jé existe outra chamada zork. Palayras muito comuns sao redundantes. O nome de uma variavel jamais deve conter a palavra “varidvel”. O nome de uma tabela jamais deve conter a palavra tabela. Entéo como ‘NameString é melhor do que Name? Um Name pode ser um numero do tipo ponto flutuante? Caso possa, estatia violando uma regra sobre passar informagées incorretas, Imagine que vocé encontre uma classe Customer ¢ outra CustomerObject. O que a diferenga nos nomes Ihe diz? Qual seria a melhor para possuir 0 histérico de pagamento de um cliente? Conhecemos um aplicative que é assim. A fim de proteger seus desenvolvedores, trocamos os nomes, mas abaixo estd exatamente 0 tipo de erro: getActiveAccount (); getActiveAccounts|); getActiveAccountInfo(); Como os programadores desse projeto poderiam saber qual das trés fungdes chamar? ‘Na auséncia de convengdes especificas, ndo h como distinguir moneyAmount de money, customerInfo de customer, accountData de accounte theMessage de message. Faga a distingao dos nomes de uma forma que o leitor compreenda as diferengas. Use Nomes Pronunciaveis Os ser humano ¢ bom com as palavras. Uma parte consideravel de seu cérebro é responsivel pelo conceito das palavras. E, por definigdo, as palavras so pronunciaveis. Seria uma lstima no tirar proveito dessa importante parte de nosso cérebro que evoluiu para lidar com a lingua falada.Sendo assim, crie nomes pronuncidveis. Se no puder pronuncié-lo, nao teré como discutir sobre tal nome sem parecer um idiota. “Bem, aqui no bé cé erre trés cé ene t@, temos um pé esse 7é qué int, viram?”. Isso importa porque a programagao é uma atividade social. Conhego uma empresa que possui uma varidvel genymdhms (generation date, year, month, day, hour, minute e second) ¢ seus funcionarios saem falando “gé dabliu eme dé agd eme esse”, Tenho um hébito irritante de pronunciar tudo como esta escrito, portanto comecci a falar “gen-yah-muddahims”. Depois desenvolvedores ¢ analistas estavam falando assim também, e ainda soava estupido. Mas estavamos 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 varidveis, e, ento, em vez de usar termos existentes na lingua, inventavam palavras bobas ao pronuncié-las. Compare 21 22 Capitulo 2: Nomes Significativos class Dtakerdi02 { private Date genymdhms; private Date modymdhms; private final String pszgint = “1027; Twa * com class Customer { private Date generationTimestamp; private Date modificationTimestamp;; private final string recordId = ~102"; eae y Agora é possivel uma conversa inteligente: “Ei, Mikey, dé uma olhada este registro! A generation timestamp (“criagao de marcagao de horario”) esta marcada para amanha! Como pode?”. Use Nomes Passiveis de Busca Nomes de uma sé letra ou ntimeros possuem um problema em particular por nao ser facil localiz’- los ao longo de um texto. Pode-se usar facilmente o grep para MAX_CLASSES_PER_STUD! mas buscar 0 nimero 7 poderia ser mais complicado. Nomes, definigdes de constantes ¢ varias outras expressdes que possuam tal mimero, usado para outros propésitos podem ser resultados da busca, Pior ainda quando uma constante € um nimero grande ¢ alguém talvez tenha trocado os digitos, criando assim um bug e ao mesmo tempo nfo sendo captada pela busca efetuada. ‘Damesma forma, onome“ =” é uma escolha ruim para qualquer varidvel a qual um programadot talvez precise fazer uma busca. E uma letra muito comum e provavelmente apareceré 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 tnica letra SO sejam usados como variaveis locais dentro de métodos pequenos. O samanho de um nome deve ser proporcional ao tamanho do escopo. [NS]. Se uma variavel ou constante pode ser vista ou usada em varios lugares dentro do cédigo. € imperativo atribui-la um nome fécil para busca. Novamente, compare for (int j=0; j<34; i+) ( s += (t[j]*4)/5; com int realDaysPerlIdealDay = 4; const int WORK_DAYS_PER_WEEK = 5; int sum = 0; for (int j=0; j < NUMBER_OF_TASKS; j++) ( int realTaskDays taskEstimatel[j] * realDaysPerIdealDay; int realTaskWeeks (realdays / WORK_DAYS_PER_WEEK); sum += realTaskileeks; Evite Codificagies 23 Note que sum nao é um nome pratico, mas pelo menos é facil de procurar. O nome usado no cédigo serve para uma fungio maior, mas pense como seria muito mais facil encontrar WORK_ DAYS PER WEEK do que buscar em todos os lugares nos quais 0 5 aparece ¢, entio, filtrar os resultados para exibir apenas as instncias que vocé des Evite Codificacées Ja temos de lidar com bastante codificagao e nao precisamos acrescentar mais. Codificar informagées do escopo ou tipos em nomes simplesmente adiciona uma tarefa extra de decifraco. Dificilmente parece légico contratar um novo funcionario para aprender outra “linguagem”™ codificadora além da atual usada no cédigo no qual se est trabalhando. £ uma sobrecarga mental desnecessaria ao tentar resolver um problema. Nomes codificados raramente sao pronuncidveis, além de ser facil escrevé-los incorretamente. A Notagio Hingara Antigamente, quando trabalhavamos com linguagens com limite de tamanho para os nomes, viokivamos essa regra quando necessario, com certo arrependimento. O Fortran forgava codificagdes ao tomar a primeira letra uma indicagao para o tipo. Versdes anteriores do BASIC so permitiam uma letra mais um digito. A Notagéo Hungara (NH) inovou essas limitagdes. Na €poca da API em C do Windows, a NH era considerada muito importante, quando tudo era um inteiro ou um 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 verificava os tipos naquele tempo, ento os programadores precisavam de ajuda para lembrar dos tipos. Em linguagens modemas, temos tipos muito melhores, ¢ 08 compiladores os reconhecem e os tomam obrigatérios. Ademais, ha uma certa tendéncia para criagao de classes e fun¢des menores+ de modo que as pessoas possam ver onde cada varidvel que esto usando foi declarada. ‘Os programadores Java no precisam definir o tipo. Os objetos ja so 0 proprio tipo, ¢ a ediglo de ambientes se tornou tao avangada que detectam quando se usa inadequadamente um tipo antes mesmo da compilagao! Portanto, hoje em dia, a NH ¢ outras formas de convengao de tipos sao basicamente obstaculos. Eles dificultam a alteragao do nome ou do tipo de uma variavel, fungao ou classe; dificultam a leitura do cédigo; e criam a possibilidade de que o sistema de codificagao induza 0 leitor ao erro. PhoneNumber phoneString; // 9 nome nao muda na alteracao do tipo! Prefixos de Variaveis Membro Vocé nao precisa mais colocar o prefix m_em variaveis membro. Mas para isso, suas classes € fungdes devem ser pequenas. E vocé deve usar um ambiente de edigio que realce ou colore as varidveis membro de modo a distingui-las. public class Part { private String m_dsc; // Descrigaéo textual void setName(String name) ( 24 Capitulo 2: Nomes Significativos m_dsc = name; } public class Part ( String description; void setbescription(String description) { this.description = description; ) } ‘Além 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 partes invisiveis e um indicativo de cédigo velho. Interfaces e Implementagées Agvvezes, hd casos especiais para codificagdes. Por exemplo, digamos que vocé esteja construindo uma ABSTRACT FACTORY para criar formas. Essa factory seré uma interface, ¢ implementada por uma classe concreta. Como devemos nomed-la? IshapeFactory e ShapeFactory? Prefiro nao enfeitar as interfaces. O “z” no inicio, tao comum no hoje em dia, é na melhor das hipéteses uma distragdo, e na pior sao informagdes excessivas. Nio quero que meus usuarios saibam que estou thes dando uma interface, e, sim, apenas uma ShapeFactory. Portanto, se eu devo codificar seja a interface ou a implementacao, escolho esta, Para codificar a interface, é preferivel chama-la de ShapeFactoryImp, ou mesmo de CShapeFactory. Evite o Mapeamento Mental Os leitores nao devem ter de traduzir mentalmente os nomes que vocé escolheu por outros que cles conhegam. Essa questéo costuma levar a deciso de n&o usar os termos do dominio do problema e nem os da solugo. Este ¢ um problema com nomes de variaveis de uma sé letra. Certamente um contador de iteragdes pode ser chamado de “i”, 3” ou “k” (mas nunca 1) ~ isso j4 se tornou uma tradig&o — 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 ha razao pior do que usar 0 nome “c” s6 porque “a” € “b” jd esto sendo usados. De maneira geral, os programadores so 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 0 “r” mindisculo é uma versao da url sem 0 host ¢ 0 contexto, entao obviamente yocé € muito esperto. ‘Uma diferenca entre um programador esperto ¢ um programador profissional ¢ que este entende que clareza é fundamental. Os profissionais usam seus poderes para o bem, ¢ escrevem cédigos que outros possam entender. ‘Nomes de Métodos 25 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 no 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, alteragdio e autenticagao segundo seus valores ¢ adicionar 08 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 estiticos com nomes que descrevam os parimetros. Por exemplo, Complex fulcrumPoint = Complex.FromRealNumber (23.0); melhor do que Complex fulcrumPoint = 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 irdo lembra-los, e sé enquanto se lembrarem da brincadeira. Eles saberio o que deve fazer a fungdo HolyHandGrenade? Claro, € engragado, mas talvez nesse caso Deletertems fique melhor. Opte por clareza no lugar de divertimento. Essas gracinhas em codigos costumam aparecer na forma de coloquialismos e girias. Por exemplo, nao use firmar () para significar terminar(). Nao use piadas de baixo calao, como cairFora para significar abortar |). Diga 0 que vocé quer expressar. Expresse 0 que vocé quer dizer. 26 Capitulo 2: Nomes Significativos Selecione uma Palavra por Conceito Escolha uma palavra por cada conceito abstrato ¢ fique com cla, 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 contrario, vocé perde muito tempo vasculhando pelos cabegalhos e exemplos de cédigos antigos. Os ambientes modernos de edigo, como o Eclipse e 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 nfo Ihe oferece 03 comentirios que vocé escreveu em tomo dos nomes de suas fungdes. Vocé tem sorte se receber o parimetro 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 cédigo-fonte. Qual a principal diferenga entre um GerenciadorDeDi spositivo eum controlador-de-prot ccolo? Por que ambos nao sao controladores ougerenciadores? Ambos so realmente drivers? © nome faz com que vocé espere dois objetos com tipos bem distintos, assim como ter classes diferentes. Um lexico consistente é uma grande vantagem aos programadores que precisem usar seu cddigo. 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”, voeé pode acabar ficando com muitas classes que possuam, por exemplo, um método ada. 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 palavra add por fins de “consisténcia” quando cla na verdade nao aplica o mesmo sentido a todas. Digamos que tenhamos muitas classes nas quais add criara um novo valor por meio da adigao e concatenagao de dois valores existentes. Agora, digamos que estejamos criando uma nova classe que possua um método que coloque seu Unico pardmetro em uma colegao. Deveriamos chamar este método de ada? Por termos tantos outros métodos add, isso pode parecer consistente. Mas, neste caso, a semantica & diferente. Portanto, deveriamos usar um nome como inserir ou adicionar. Chamar este novo método de add seria um trocadilho. Nosso objetivo, como autores, ¢ tornar a leitura de nosso codigo o mais facil possivel. Desejamos que nosso cédigo seja de rapida leitura, e no um estudo demorado, Queremos usar a linguagem de um livro popular no qual é responsabilidade do autor ser claro, nao uma linguagem académica na qual a tarefa do estudioso é entender minuciosamente o que esta escrito. Use nomes a partir do Dominio da Solucao Lembre-se de que serio programadores que lerdo seu cédigo. Portanto, pode usar termos de Informatica, nomes de algoritmos, nomes de padrdes, termos matematicos etc. Nao é prudente Adicione um Contexto Signifieativo 27 pensar num nome a partir do dominio do problema, pois nao queremos que nossos companheiros de trabalho, tenham de consultar o cliente toda hora para saber 0 significado de um nome o qual eles ja conhecem 0 conceito, 6 que por outro nome. O nome Account Visitor (“conta do visitante”) significa o bastante para um programador familiarizado com 0 padrio VISITOR. Qual programador nao saberia 0 que ¢ uma JobQueue (“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 ndo houver uma soluedo “a la programador”, use © nome do dominio do problema. Pelo menos 0 programador que fizer a manutencao do seu cé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 solugao é 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 sao significativos por si sé—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 necessirio adicionar prefixos ao nome. Imagine que vocé tenha varidveis chamadas firstName, lastName, street, houseNumber, city, state e zipcode. Vistas juntas, fica bem claro que elas formam um enderego. Mas ¢ se vocé sé 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 entenderdo que essas varidiveis sdo parte de uma estrutura maior, E claro que uma melhor solugao seria criar uma classe chamada Adaress. Entao, até o compilador sabe que as varidveis pertencem a um escopo maior. Veja o método na Listagem 2.1. As variaveis precisam de um contexto mais significative? O nome da fungao oferece apenas parte do contexto; 0 algoritmo apresenta o resto. ‘Apés ter lido a fungao, vocé vé que trés varidveis, number, verb € pluralModifier, fazem parte da mensagem de dedugao (guess statistics message). Infelizmente, 0 contexto deve ser inferido. Ao olhar pela primeira vez o metodo, o significado das varidveis ndo esté 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 pluralNodifier; if (count == 0) { number = “no*: verb = “Existem*; pluralModifier = “s"; else if (count == 1) { number = "1"; verb = “Existe’; pluralNedifier = **; } else { number = Integer.toString(count) ; verb = “Existem*; pluralNedifier = “s": 1 String guessMessage = String. format( “here ts $s tet", verb, number, candidate, pluralModifier ie print (guessMessage) ; ‘A funcdo é um pouco extensa demais também e as variaveis sao bastante usadas. A fim de dividir a fungao em partes menores, precisamos criar uma classe GuessStatisticsMessage € tomar as trés variaveis como campos desta classe. Isso oferecera um contexto mais claro para as trés variéveis. Elas sao definitivamente parte da GuessStatisticsMessage. A melhora do contexto também permite ao algoritmo ficar muito mais claro ao dividi-lo em fungées 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) { creacePluralDependentMessageParts (count) : return string. format ( “There $s 4s tsts’, verb, number, candidate, pluralModiner ); ) private void createPluralDependentMessageParts (int count) { if (count == 0) ¢ thereareNoLetters(); } else if (count == 1) { thereTsOneLetter () ; j else { Nao Adicione Contextos Desnecessarios 29 Listagem 2-2 (continuagio) Variaveis possuem contexto thereAreManyLet ters (count) ; } d private void thereAreManyLetters(int count) { number = Integer. toString(count) ; verb = “Existem” pluralModifier = *s"; ? private void thereTsOneLetter() { number = "1": verb = *Existe* pluralMedifier = *Y; y private void thereareNoLetters() { number = “no": verb = “Existem"; pluralMedifier = “s": t Nao Adicione Contextos Desnecessarios Em um aplicativo ficticio chamado “Gas Station Deluxe” (GSD), seria uma péssima ideia adicionar prefixos a toda classe com GSD. Para ser sincero, vocé estara trabalhando contra suas ferramentas, Vocé digita ¢ e pressiona a tecla de autocompletar e recebe uma lista quilomeé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 GSDAccountaddress.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 sio melhores contanto que scjam claros. Nao adicione mais contexto a um nome do que o necessario. Os nomes accountAddress € customerAddress esti bons para instancias da classe ‘Address, mas seriam ruins para nomes de classes. Address esté bom para uma classe. Se precisar diferenciar entre enderecos MAC, enderegos de portas ¢ enderegos da Web, uma ideia seria PostalAddress, MAC ¢ URT. Os nomes resultantes s&io mais precisos, motivo esse da tarefa de se atribuir nomes. Conclusdo O mais dificil sobre escolher bons nomes é a necessidade de se possuir boas habilidades de descri¢ao e um histérico cultural compartilhado. Essa é uma questio de aprender, e no técnica, gerencial ou empresarial. Como consequéncia, muitas pessoas nessa area nao aprendem essa tarefa muito bem. 30 Capitulo 2: Nomes Significativos 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 yezes, ndo memorizamos os nomes de classes e métodos. Mas usamos ferramentas modernas para lidar com detalhes de modo que possamos nos focalizar e ver se 0 cédigo € lido como pardgrafos, frases, ou pelo menos como tabelas € estruturas de dados (uma frase nem sempre é a melhor forma de se exibir dados). Provavelmente vocé acabard surpreendendo alguém quando renomear algo, assim como qualquer outra melhoria no codigo. Nao deixe que isso atrapalhe seu progress Siga alguma dessas regras e note se vocé nfo melhorou a legibilidade de seu c6digo. Se estiver fazendo a manutengao do cddigo de outra pessoa, use ferramentas de refatoragao para ajudar a resolver essas questées. Em pouco tempo valeri 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/I, usavamos programas, subprogramas ¢ fungdes. De tudo isso, apenas funcao prevaleceu. As fungdes so a primeira linha de organizacao em qualquer programa. Escrevé-las bem € 0 assunto deste capitulo. 32 ‘Capitulo 3: Fungdes Veja 0 cédigo na Listagem 3.1. E dificil encontrar uma fungao grande em FitNesse', mas procurando um pouco mais encontramos uma. Além de ser longo, seu cédigo é repetido, ha diversas strings estranhas e muitos tipos de dados e APIS esquisitos e nada dbvios. Veja o quanto vocé consegue compreender nos préximos trés minutos. Listagem 3-1 Htmlvtil.java (FitNesse 20070619) public static String testableltent! ( PageData pageData, boolean includeSuitesetup ) throws exception { Page = pageData.getWikiPaget); + buffer = new FageCrawlerInp .getInheritedPaget SuiteResponder SUITE SE7UP_NAME, wikiPage iteSetup != null) ( WikiPagePath pagePath = suitesetup.aetPageCrawler! String pagePathName = Pat} butter getFullPathisuitesetup); rser.render (pagePath) ; appendi* include -setup jagePathName) atl: ) ) WikiFage setup PageCrawlerInp: eritedPage(*Setlp", wikiPage) ; ” if (setup != mull) { WikiPagePath setupPath wikiPage. getPageCrawler() .getFullpath (setup) + serin setupPathName = FathParser.render{setupPath) ; nelude -setup .") sappend (set upPat hName) pend? \al buffer.append (pageData.getContent (|); if (pageData.hasAttribute("Test"!) { WikiPage teardown PageCrawlerImpl.getInheritedPage(*TearDown", wikiPage) ; if [teardown != null) { WikiPagerath tearDowneath wikiPage.getPageCrawler (i .getPull Path (teardown) ; ‘tring tearDownPathName = FathParser. render |tearDownPath) ; buffer.append(*\n*) -append(*!include -teardewn -append (tearDownPat -append("\n") : 2) 1.75 reels de Gewiilchk clilines Gentes orereelienerane’d Fungies 33 Listagem 3-1 (continuagio) HtmlUtil.java (FitNesse 20070619) if includesuiteSetup! ( Wikibage suiteTeardown FageCrawlerimpl.get InheritedPage( SuiteResponder. SUITE_TEARDOW_NAME, wikipage Lf (suiteTeardown kiBagePath pagePath suiteTeardown.getPageCrawler().getFullfath (suits String pagePathName = PathParser.render !pagePath}; ffer.append("!include -teardown .* .append (pagePathName) lappend(*\n"}; Teardown) ; pagedata.setContent (buffer.tostringi))+ return pagelata.getHtml (|; Conseguiu entender a fungdo depois desses trés minutos estudando-a? Provavelmente nao. Ha muita coisa acontecendo la em muitos niveis diferentes de . Ha strings estranhas e chamadas a fungdes esquisitas misturadas com dois if aninhados controlados por flags. Entretanto, com umas poucas extragdes simples de métodos, algumas renomeagdes € um pouco de reestruturagao,fui capaz de entender 0 propésito da funcaio nas nove linhas da Listagem 3.2. Veja se vocé consegue compreender também em trés minutos. Listagem 3-2 HtmlUtil.java (refatorado) public static String renderPageWithsetupsAndreardowns ( PageData pageData, boolean :sSuite ) throws Exception { boolean isTestPage = pageData.hasAttribute/"Test"); if (isTestPage) [ WikiPage testPage = pageData.getWikiPage!); StringBuffer newFageContent = new StringBuffer ()+ includeSetupPages (testPage, newPageContent, issuite); newPageContent .append (pageData.ge=Content {)); includeTeardownPages (testPage, newPageContent, iss pageData.setContent (nexPageContent .toString|)): ite) : return pageData.getHtml (1; 4 Capitulo 3: Fungoes ‘A menos que jé estivesse estudando o FitNesse, provavelmente vocé nao entendeu todos os detalhes. ‘Ainda assim vocé talvez tenha compreendido que essa fungio efetua a incluso de algumas paginas SetUp e TearDown em uma pagina de teste e, entio, exibir tal pagina em HTML. Se estiver familiarizado com o JUnit’, vocé ja deve ter percebido 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 ela esta bastante obscura na Listagem 3.1. Ento, 0 que torna uma funcdo como a da Listagem 3.2 ficil de ler e entender? Como fazer uma fungao transmitir seu propésito? Quais atributos dar as nossas fungdes que permitirao um Jeitor comum deduzir o tipo do programa ali contido? Pequenas! ‘A primeira regra para fungdes ¢ que clas devem ser pequenas. A segunda ¢ que precisam ser mais espertas do que isso. Nao tenho como justificar essa afirmag&o. Nao tenho referéncias de pesquisas que mosirem que fungées muito pequenas s4o melhores. S6 posso dizer que por cerca de quatro décadas tenho criado fungdes de tamanhos variados. Jé escrevi diversos monstros de 3,000 linhas; bastantes fungdes de 100 a 300 linhas; e fungdes 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 fimedo nao deveria ser maior do que a tela. E claro que na época usivamos 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 e grande + monitor, vocé consegue colocar 150 caracteres em uma linha — ndo 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 fungdo? Em 1999, fui visitar Kent Beck em sua casa, em Oregon, EUA. Sentamo-nos ¢ programamos um pouco juntos. Em certo ponto, cle me mostrou um simpatico programa de nome Java/Swing 0 qual ele chamava de Sparkle. Ele produzia 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 fungiio neste programa tinha apenas duas, ou trés, ou quatro linhas. Esse deve ser o tamanho das suas fungdes* © quao 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 aberto de teste de unidade para Java, www.junit.org, Faga Apenas uma Coisa 35 Blocos e Endentacaio Aqui quero dizer que blocos dentro de instrugdes if, else, while e outros devem ter apenas uma linha. Possivelmente uma chamada de fungao. Além de manter a fungo pequena, isso adiciona um valor significativo, pois a fungao chamada de dentro do bloco pode receber um nome descritivo. Isso também implica que as fungdes no devem ser grandes ¢ ter estruturas aninhadas. Portanto, o nivel de endentagdo de uma fungdo deve ser de, no maximo, um ou dois. Isso, é claro, facilita a leitura e compreensao das fungdes. Faca 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, ancxa 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 aparecide 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 declaracao é que é dificil saber 0 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 pigina em HTML. Entao, uma ou trés coisas? Note que os trés passos da fungao esto em um nivel de abaixe do nome da fungao, Podemos descrever a fungdo com um breve parigrafo TO*: 4 Alinguagem LOGO usave a pelavra “TO” PARA") da mesma forma que Raby ¢ Python usam “det” Portnto, tna fungi comeya com a palavra “TO”, 36 Capitulo 3: Fungies TO RenderPageWithSetupsAndTeardowns, verificamos se a pagina é de teste, se for; incluimos SetUps e TearDowns. Em ambos os casos, exibimos a pagina em HTML Se uma fungdo faz apenas aqueles passos em um nivel abaixo do nome da fungdo, entio ela esté fazendo uma sé coisa, Apesar de tudo, 0 motivo de criarmos fungdo é para decompor um conceito maior (em outras palavras. o nome da fungo) 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 abstracao , como comprovado pela nossa capacidade de redugdo. Mas ficaria muito dificil reduzir a Listagem 3.3 de modo significativo, Poderiamos colocar a instrug3o if numa fungao chamada includeSetupsandTeardowns! fTest 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 fungao dela a partir de seu nome que nao seja apenas uma reformulacio de sua implementagao (G34). Secées Dentro de Funcgées Veja a Listagem 4.7 na pagina 71. Note que a fungdo generatePrimes esti dividida em segdes, como declaragées, inicializacdes ¢ selecdo. Esse ¢ um indicio ébvio de estar fazendo mais de uma coisa. Nao da para, de forma significativa, dividir em segdes as fungdes que fazem apenas uma coisa. Um Nivel de Abstrac¢ao por Funcao A fim de confirmar se nossas fungdes fazem s6 “uma coisa”, Precisamos verificar se todas as instrugdes dentro da fungao estdio no mesmo nivel de abstragdo. E facil ver como a Listagem 3.1 viola essa regra. Ha outros conceitos 14 que estao em um nivel de bem alto, como 0 get Html (}: outros que esto em um nivel intermediario, como String pagePathName = PathParser render (pagePath); e outros que esto em um nivel consideravelmente baixo, como id (™\n"). jos niveis de dentro de uma fungio sempre geram confusao. 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. -ap) Estrutura Switeh Ler o Cédigo de Cima para Baixo: Regra Decrescente Queremos que o cédigo seja lido de cima para baixo, como uma narrativa*. Desejamos que cada fungao 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 fungécs. 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 o nivel atual de e fazendo referéncia aos paragrafos TO consecutivos no proximo nivel abaixo. Para incluir SetUps e TearDowns, incluimos os primeiros. depois 0 contetido da pagina de teste e, entdo, adicionamos os segundos. Para incluir Setlips, adicionamos 0 suite setup, se este for uma colecdo, incluimos 0 setup normal. Para incluir o suite setup, buscamos na hierarquia acima a pagina “SuiteSetUp” ¢ adicionamos uma instrugdo de incluséo com 0 caminho aquela pagina. Para procurar na hierarquia acima ‘Acaba sendo muito dificil para os programadores aprenderem a seguir essa regra ¢ criar fungdes que fiquem em apenas um nivel de . Mas aprender esse truque € também muito importante, pois cle ¢ 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 paragrafos TO é uma técnica eficiente para manter o nivel de consistente. ‘Vejaa listagem 3.7 no final deste capitulo. Ela mostra toda a fungo testableHtml refatorada de acordo com os principios descrito aqui, Note como cada fungao indica a seguinte ¢ 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. Tambem ¢ 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 est em uma classe de baixo nivel e nunca é repetido. Para isso, usamos 0 polimorfismo. Veja a Listagem 3.4. Ela mostra apenas uma das operagées que podem depender do tipo de funcionario (employee, em inglés). 37 38 Capitulo 3: Fungies Listagem 3-4 Payroll.java public Money calculatePay {Employee e} Invalidemployeetype teh (e.type) case CONMISSTONE! ulateConmi'ssionedPay (e) ; ceHourlyPay (¢ return calculateSalariedPay le); ult: row niew TnvalidmployeeType(e. type): Esta fungao tem varios problemas. Primeiro, ela ¢ grande, e quando se adiciona novos tipos de funcionarios ela crescera mais ainda. Segundo, obviamente ela faz mais de uma coisa. Terceiro, ala viola o Principio da Responsabilidade Unica’ (SRP, sigla em inglés) por haver mais de um motivo para altera-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 fungao € a quantidade ilimitada de outras fungdes que ter’o 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 solugao (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 usara 0 switch para criar instancias apropriadas derivadas de Employee, e as fungdes, como calculateray, isPayday ¢ deliverPay, serdo enviadas de forma poliférmica através da interface Employee. Minha regra geral para estruturas switch é que sio aceitdveis se aparecerem apenas uma vez, como para a criagio de objetos poliférmicos, ¢ estiverem escondidas atras de uma relagao de heranga de modo que 0 resto do sistema nao possa enxergd-la [G23]. E claro que cada caso é um caso e haverd vezes que nao respeitarei uma ou mais partes dessa regra. Listagem 3-5 * Employee e Factory public abstract class Employee { public abstract boolean isPayday(); public abstract Money calculatePay(); public abstract void deliverPay(Money pay); } "7 a ngpden Wikipsiinconp/Wiki’Singlé ‘reapanaibility principle ‘Use Nomes Descritivos 39 Use Nomes Descritivos Na Listagem 3.7, eu mudei 0 nome do exemplo de nossa fun¢fo testableHtml para SetupTeardownIncluder.render, que ¢ bem melhor, pois descreve 0 que a fungao faz. Também dei a cada método privado nomes igualmente descritivos, como isTestable ou includeSetupandTeardownrages. E dificil superestimar o valor de bons nomes. Lembre-se do principio de Ward: “Voce sabe que esté criando um codigo limpo quando cada rotina que vocé lé é 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 fungio, mais facil ser pensar em um nome descritivo. Nao tenha medo de criar nomes extensos, pois eles sio melhores do que um pequeno € enigmatico. Um nome longo ¢ descritivo é melhor do que um comentario extenso e descritivo. Use uma convengio de nomenclatura que possibilite uma ficil leitura de nomes de fungdes com varias palavras e, enti, use estas para dar a fungao um nome que explique o que ela faz. Nao se preocupe com o tempo ao escolher um nome. Na verdade, vocé deve tentar varios nomes e, entdo, ler o cédigo 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. Sclecionar nomes descritivos esclareceré 0 modelo do médulo em sua mente ¢ Ihe ajudara a melhora-lo. E comum que ao buscar nomes adequados resulte numa boa reestruturagao do cédigo. Seja consistente nos nomes. Use as mesmas frases, substantivos e verbos nosnomes de fungdes de seu médulo. Considere, por exemplo, os nomes includeSetup-AndTeardownvages, includeSetupPages, includeSuitesetupPage e includeSetupPage. A fraseologia nesses nomes permite uma sequéncia de facil dedugdo. Na verdade, se cu lhe mostrasse apenas a série acima, vocé se perguntaria: “O que aconteceu com includeteardownPages, includeSuiteTeardownPage e includeTeardownPage?”, como isso é “... como 0 que vocé esperava?”. ParAmetros de Fungées ‘A quantidade ideal de pardmetros para uma fungao é zero (nulo). Depois ver um (ménade), seguido de dois (diade). Sempre que possivel devem-se evitar trés pardimetros (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 entdo nossos leitores teriam de interpreta-lo sempre que o vissem. Ao ler a 40 Capitulo 3: Fungoes est6ria contada por pelo modulo, fica mais facil entender includeSetupPage() do que includeSetupPageInto (newPage-Content). O pardmetro nfo esta no nivel de que o nome fungao, forgando-lhe reconhecer de um detalhe (ou seja, 0 StringBuffer) que nao seja importante particularmente naquele momento. Os parametros so 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 parimetros funcionem adequadamente. Se nao houver parimetros, essa tarefa € simples. Se houver um, nao € tao dificil assim. Com dois, a situagdo fica um pouco mais desafiadora, Com mais de dois, pode ser desencorajador testar cada combinagao de valores apropriados. Os parémetros de saida sio ainda mais dificeis de entender do que os de entrada. Quando lemos uma fungao, estamos acostumados ideia de informagées entrando na fungao através de parametros 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 parmetro. E facil entender SetupTeardown-Includer.render (pageData). Esta ébvio que renderizemos os dados no objeto pageData. Formas Ménades Comuns ‘Ha duas razées bastante comuns para se passar um Unico pardmetro a uma fungao. 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 ¢ retornando-o. Por exemplo, InputStream fileOpen(*MyFile”) transforma a string do nome de um arquivo em um valor retornado por InputStream. Sdo esses dois usos que os leitores esperam ver em uma fungo. Vocé deve escolher nomes que tomem clara a disting’io, e sempre use duas formas em um contexto consistente. (Veja a seguir Separagdo comando-consulta). Uma forma menos comum mas ainda bastante {itil de um parametro para uma fungdo é um evento. Nesta forma, ha um pardmetro de entrada, mas nenhum de saida. O programa em si serve para interpretar a chamada da fungao como um evento, ¢ usar o parametro para alterar o estado do sistema, por exemplo, void passwordAttemptFailedNtimes(int attempts). Use esse tipo com cautela. Deve ficar claro para 0 leitor que se trata de um evento. Escolha os nomes ¢ os contextos com aten¢ao, Tente evitar funcdes mOénades que nao sigam essas formas, por exemplo, void include SetupPageInto(StringBuffer pageText). Usar um parametro de saida em vez de um valor de retorno para uma modificagiio fica confiiso. Se uma fungdo vai transformar seu parametro de entrada, a alteragao deve aparecer como o valor retornado, De fato, StringBuffer transform(StringBuffer in) ¢ melhor do que void! transform-(stringBuffer out), mesmo que a implementagdo do primeiro simplesmente retorne 0 parimetro de entrada. Pelo menos ele ainda segue 0 formato de uma modificacao. Pardmetros Légicos Esses parmetros so feios. Passar um booleano para uma fungo certamente € uma pratica horrivel, pois ele complica imediatamente a assinatura do método, mostrando explicitamente que a fungio faz mais de uma coisa. Ela faz uma coisa se 0 valor for verdadeiro, e outra se for falso! Use Parametros de Fungées 41 Na Listagem 3.7, nao tinhamos alternativa, pois os chamadores j4 estavam passando aquela flag (valor booleano) como parimetro, e¢ eu queria limitar 0 escopo da refatoragio 4 fungao 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 fungdo em duas: renderForSuite() e¢ renderForSingleTest (}. Fungées Diades Uma fungao 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)", Emborao significado de ambas esteja claro, a primeira apresenta seu propésito explicitamente quando a lemos. A segunda requer uma pequena pausa até aprenderios 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 sc esconderio os bugs. Hi casos, é claro, em que dois parametros sio necessérios 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 parémetros neste caso so componentes de um iinico valor! Enquanto que output-Stream e name nfo sio 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 parametros nao possuem uma ordem pré-determinada natural. A ordem expected, actual é uma conven¢%o que requer pratica para assimilé-la Diades no sao ruins, e vocé certamente ter de usd-las, Entretanto, deve-se estar ciente de que havera 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 o método writeField um membro de outputstream de modo que pudesse dizer outputStreamwritePield (name); tornar outputStream uma varidvel membro da classe em uso de modo que nao precisasse passé-lo por pardimetro; ou extrair uma nova classe, como Pieldwri ter, que receba o outputStream em seu construtor e possua um método write. Triades Fungdes que recebem trés parametros so consideravelmente mais dificeis de entender do que as diades. A questo de ordenagdo, 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 parametros: assertEquals(message, expected, actual). Quantas vezes vocé precisou ler o pardmetro message e deduzir o que ele carrega? Muitas vezes j4 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, entiio, a ignoro. Riad lai sic ili ns Tie ni ind Sis Weebl a edn Wl sin uc Use Pardametros de Fungdes a formato imbuimos os nomes dos parametros no nome da fungao. Por exemplo, pode ser melhor escrever assertEquals do que assertExpectedZqualsactual (expected, actual),o que resolveria o problema de ter de lembrar a ordem dos parametros, Evite Efeitos Colaterai: Efeitos colaterais so mentiras. Sua fungao promete fazer apenas uma coisa, mas ela também faz outras coisas escondida. As vezes, cla fara alteragdes inesperadas nas varidveis de sua propria classe. As vezes, ela adicionara as variaveis aos parametros passados 4 fungao ou as globais do sistema. Em ambos os casos elas si “verdades” enganosas € prejudiciais, que geralmente resultam em acoplamentos temporarios estranhos e dependéncias. Considere, por exemplo, a fungao aparentemente inofensiva na Listagem 3.6. Ela usa um algoritmo padrao para comparar um userName (nome de usuario) a um password (senha). Blaretomatrue (verdadeiro) se forem iguais,e false {falso) caso contrario. Mas ha também um efeito colateral. Consegue identificd-lo Listagem 3-6 UserValidator.java ographer cryptographer; public boolean checkPssword(String use: User user = UserGateway. find2yName (user iuser {= User.NULL) ( |. String codedPhrase = user. getPhraseEncodedByPaasword() : String phrase = cryptographer. decrypt (codedehrase, password) : i£ ("Valid Password" equals phrase) | session return ame, String password) { lame} ; Lizei); return false; © efeito colateral ¢ a chamada ao Session.initialize(), é claro. A fungio checkPassword, segundo seu nome, diz que verifica a senka. O nome nao indica que ela inicializa a sesso, Portanto, um chamador que acredita no que diz 0 nome da fungio corre o risco de apagar os dados da sesso existente quando ele decidir autenticar do usuari Esse efeito colateral cria um acoplamento temporirio. Isto é, checkPassword s6 poder ser chamado em determinadas horas (em outras palavras, quando for seguro inicializar a sessiio). Se for chamado fora de ordem, sem querer, os dados da sessiio poderdo ser perdidos. Os acoplamentos tempordrios so confusos, especialmente quando so um efeito colateral. Se for preciso esse tipo 4 Capitulo 3: Fungées de acoplamento, é preciso deixar claro no nome da fung&o. Neste caso, poderiamos renomear a fungdo para checkPasswordAndInitializeSession, embora isso certamente violaria 0 “fazer apenas uma tinica coisa”. ParAmetros de Saida Os pardmetros so comumente interpretados como entradas de uma fungao. Se j4 usa o programa hd alguns anos, estou certo de que vocé j teve de voltar ¢ ler novamente um parametro que era, nna verdade, de saida, e nao de entrada. Por exemplo: appendFooter(s); Essa fungao 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 (StringBuffer report) Isso esclarece a questo, mas a custa da verificagdo da declaragao da fungaio. Qualquer coisa que Ihe force a verificar a assinatura da fun¢ao ¢ equivalente a uma relida. Isso é uma interrupgao do raciocinio e deve ser evitado. Antes do surgimento da programagao orientada a objeto, as vezes era preciso ter parimetros de saida. Entretanto, grande parte dessa necessidade sumiu nas linguagens OO, pois seu proposito éservir como um parametro de saida. Em outras palavras, seria melhor invocar appendFooter como: report.appendFooter |); De modo geral, devem-se evitar parametros de saida. Caso sua fungao precise alterar o estado de algo, faga-a mudar 0 estado do objeto que a pertence. Separacio comando-consulta ‘As fungdes devem fazer ou responder algo, mas nilo ambos. Sua funcdo ou altera o estado de um objeto ou retorna informagdes sobre ele. Efetuar as duas tarefas costuma gerat confusio Considere, por exemplo, a funcdo abaixo: public boolean set(String attribute, String value); Esta fungao define o valor de um dado atributo ¢ retorna tru (verdadeiro) se obtiver éxito e false (£also) se tal atributo nao existir, Isso leva a instrugdes estranhas como: if (set(“username’, “unclebob"))... Imagine isso pelo ponto de vista do leitor. O que isso significa? Esté perguntando se o atributo “username” anteriormente recebeu 0 valor “unclebob”? Ou se “username” obteve éxito ao receber 0 valor “unclebob”? E dificil adivinhar baseando-se na chamada, pois nao est claro se a palavra “set” um verbo ou um adjetivo. Prefira exeegées a retorno de cédigos de erro 45 CO intuito do autor era que set fosse um verbo, mas no contexto da estrutura if, parece um adjetivo. Portanto, a instrugdo lé-se “Se o atributo username anteriormente recebeu o valor unclebob” ¢ niio “atribua o valor unclebob ao atributo username, ¢ se isso funcionar, entao...”. Paderiamos tentar resolver isso renomeando a funeo set para setandcheckifExists, mas nao ajudaria muito para a legibilidade da estrutura i. if (attributeExists(*username”)) [( setAttribute(“username", “unclebob"); Prefira excegdes a retorno de cédigos de erro Fazer fungdes retornarem cédigos de erros é uma leve violagdo da separagdo comando-consulta, pois os comandos sao usados como expressdes de comparagao em estruturas if. E_OK) if (deletePage (page) problema gerado aqui nao € a confusio verbo/adjetivo, mas sim a criagdo de estruturas aninhadas. ‘Ao retornar um cédigo de erro, vocé cria um problema para o chamador, que deverd lidar imediatamente com 0 erro. if (deletePage (page) E_OK) { if (registry.deleteReference(page.name) E_OK) { if (configkeys.deleteKey(page.name.makeKey(}) E_OK){ logger.log(*pagina excluida"); . } else { logger.log(*configkey nao foi excluida”); } } else { logger.logi"deleteReference nao fo1 excluido do registro"); } } else { logger.log("a excluséo falhou"); return B_ERROR; } Por outro lado, se vocé usar excegdes em vez de retornar cédigos de erros, entdo 0 cédigo de tratamento de erro poderd ficar separado do cédigo e ser simplificado: 4 try deletePage(page); registry.deleteReference(page.name); configkeys .deleteKey(page.name.makeKey()}; ) catch (Exception e) { logger. log(e.getMessage()); 3 46 Capitulo 3: Fungées Extraia os blocos try/catch Esses blocos niio tém 0 direito de serem feios. Eles confundem a estrutura do cédigo ¢ misturam © tratamento de erro com o processamento normal do cédigo. Portanto, é melhor colocar as estruturas try ¢ catch em suas proprias fungdes. public void delete(Page page) { try { deletePageAndal1References (page); t catch (Exception e] { logError(ej: y d private void deletePageAndAllReferences(Page page) throws Exception { delet ePage(page); registry.deleteReference (pagename); configkeys .deleteKey (page-name.makeKey()); } private void logError(Exception e) ( logger. log(e.getMessage()); } A fungao delete acima sé faz tratamento de erro. E é facil entendé-la e seguir adiante, A fungdo deletePageAndAllReferences $6 trata de processos que excluem toda uma pagina. Pode-se ignorar o tratamento de erro. Isso oferece uma boa separagao que facilita a compreensio e alteragdo do cédigo. Tratamento de erro é uma coisa s6 As fungées devem fazer uma coisa s6, Tratamento de erro é uma coisa sé. Portanto, uma fungao que trata de erros nao deve fazer mais nada. Isso implica (como no exemplo acima) que a palavra try esta dentro de uma fungdo e deve ser a primeira instrugao e nada mais deve vir apés os blocos catchy finally. Error.java, © chamariz A dependéncia Retomar cédigos de erro costuma implicar que ha classes ou enum nos quais esto definidos todos os cédigos de erro. = public enum Error ( OK, INVALID, NO_SUCH, LOCKED, QUT_OF_RESOURCES, WAITING _FOR_EVEN?; Programacao estruturada 47 Classes como esta so chamarizes @ dependéncia, muitas outras classes devem importa-las ¢ usé-las, Portanto, quando o enum da classe Exror enum, é preciso recompilar todas as outras classes ¢ redistribui-las". Isso coloca uma pressio negativa na classe Error. Os programadores nao querem adicionar novos erros porque senao eles teriam de compilar e distribuir tudo novamente. Por isso, eles reutilizam cddigos de erros antigos em vez de adicionar novos. Quando se usam excegdes em vez de cédigos de erro, as novas excegdes sdo derivadas da classe de excegdes. Podem-se adiciona-las sem ter de recompilar ou redistribuir' Evite repeti¢4o« Leia novamente com ateng4o a Listagem 3.1 ¢ notara que ha um algoritmo que se repete quatro vezes em quatro casos: SetUp, SuiteSetUp, TearDown ¢ SuiteTearDown. Nao€ facil perceber essa duplicagao, pois as quatro instancias esto misturadas com outros eddigos ¢ nao esto uniformemente repetidas. Mesmo assim, a duplicagao é um problema, pois ela amontoa 0 cédigo e serdo necessarias quatro modificagdes se 0 algoritmo mudar. Além de serem quatro oportunidades para a omissdo de um erro. ‘Sanou-se essa duplicagao através do método include na Listagem 3.7. Leiaestecédigonovamente ‘note como a legibilidade do médulo inteiro foi melhorada com a retirada de tais repetigSes. ‘A duplicagdo pode ser a raiz de todo o mal no software. Muitos prineipios e préticas t@m sido eriados com a finalidade de control-la ou elimind-la. Considere, por exemplo, que todas as regras de normalizagao de bando de dados de Ted Codd servem para eliminar duplicagao" de dados. Considere também como a programagao orientada a objeto serve para centralizar 0 cédigo em classes-base que seriam outrora redundantes. Programagao estruturada, Programagao Orientada a Aspecto e Programagao Orientada a Componentes sao todas, em parte, estratégias para climinar duplicagao de cédigo. Parece que desde a invengao da sub-rotina, inovagdes no desenvolvimento de software tém sido uma tentativa continua para eliminar a duplicagio de nossos cédigos-fonte. Programagio estruturada Alguns programadores seguem as regras programagdo estruturada de Edsger Dijkstra’, que disse que cada fungao ¢ bloco dentro de uma fungao deve fer uma entrada e uma saida. Cumprir essas regras significa que deveria haver apenas uma instrugio return na fungdo, nenhum break ou continue num loop e jamais um goto. Enquanto somos soliddrios com os objetives e disciplinas da programagao estruturada, tais regras oferecem pouca vantagem quando as fungdes so muito pequenas. Apenas em fungdes maiores tais regras proporcionam beneficios significativos. Portanto, se vocé mantiver suas fungdes pequenas, entdo as varias instrugdes return, break ou continue casuais no trardo problemas e poderao ser até mesmo mais expressivas do que 71 dlnsantaecqaue eumrmnreon ame eedasiamn oo livenr da eacissidleciis @ dis obieisibisbilih Gavia ennciatnelies, aiwndiia te cilia sircwhlleiel. 48 Capitulo 3: Fungdes a simples regra de uma entrada ¢ uma saida. Por outro lado, 0 goto s6 faz sentido em fungdes grandes, portanto ele deve-se eviti-lo. Como escrever fungées como essa? Criar um software ¢ como qualquer outro tipo de escrita, Ao escrever um artigo, vocé primeiro coloca seus pensamentos no papel e depois os organiza de modo que fiquem ficeis de ler. O primeiro rascunho pode ficar desastroso e desorganizado, entdo vocé o apare, reestrutura ¢ refina até que ele fique como vocé deseja. Quando escrevo fungdes, elas comegam longas e complexas; hé muitas endentagdes € loops aninhados; possuem longas listas de parametros; os nomes s&o arbitrdrios; e hd duplicagao de cédigo. Mas eu também tenho uma colegio de testes de unidade que analisam cada uma dessas linhas desorganizadas do cédigo Sendo assim, eu organizo e refino 0 codigo, divido fungdes, troco os nomes, elimino a duplicagao, reduzo os métodos e os reorganizo, As vezes, desmonto classes inteiras, tudo com ‘08 testes em execugio. No final, minhas fungGes seguem as regras que citei neste capitulo. Nao as aplico desde o 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 so os verbos dessa linguagem, e classes os substantivos. Isso no um tipo de retomada da antiga nogo de que substantivos ¢ verbos nos requerimentos de um documento sejam os primeiros palpites das classes ¢ funydes de um sistema, Mas sim uma verdade muito mais antiga. A arte de programar é, ¢ sempre foi, a arte do projeto de linguagem. Programadores experientes veem os sistemas como histérias a serem contadas em vez de programas a serem escritos. Eles usam os recursos da linguagem de programago que escolhem para construir uma linguagem muito mais rica e expressiva do que a usada para contar a estéria, Parte da linguagem especifica a um dominio é a hierarquia de fungdes que descreve todas as agdes que ocorrem dentro daquele sistema, Em um ato engenhoso, escrevem-se essas fungdes para usar a mesma linguagem especifica a um dominio que eles criaram para contar sua propria parte da histéria. Este capitulo falou sobre a mecénica de se escrever bem fungdes. Se seguir as regras aqui descritas, suas fangdes serao curtas, bem nomeadas ¢ bem organizadas. Mas jamais se esqueca de que scu objetivo verdadeiro € contar a historia do sistema, e que as fungdes que vocé escrever precisam estar em perfeita sincronia ¢ formar uma linguagem clara ¢ precisa para Ihe ajudar na narragao. SetupTeardownIncluder SetupTeardownIncluder Listagem 3-7 SetupTeardownIncluder. java vackage fitnesse.htnl; import fitnesse. responders. run.SuiteResponder; import fitnesse.wiki.*; public class SetupTeardownncluder { private PageData paueDate; private boolean isSuite; private Wikifage testPage: private StringBuffer newPageContent; private PageCrawler pageCrawler; public static String render(PageData pageData) throws Exception retum render(pageData, false) ; } pul lic static String throws Exception { retum new Setupfeardownincluder (pageData) .render (issuite) ; } ender (PageData pageData, boolean isSuite) private SetupTeardownIncluder(PageData pageDatei this.pageData = pageDa testPage = pageData.aetnikiPage (i; pageCrawler = testPage.getPageCrawler i); newPageContent = new StringBuffer(); vate String render (boolean issuite) throws Exception ( this.isSuite = issuite; if (isTestPage()) includeSetupandTeardownPages (} return pageData.getitml (i; y private boolean isTestPage() throws Exception { return pagefara-hasAttribute(*Test* private void includesetupandteardownPages() throws includesetupPages (3 includePageContent () ; includeTeardowaPages |); updatePageContent () ; 50 Capitulo 3: Fungdes Listagem 3-7 (continuagao SetupTeardownIncluder. java ows Exception { private void includesecuy if (issuite) ineludesuitesecuppage() ; includeSetupPage(): } Pages (| tI private void includeSuitesetupPage!) throws Exception ¢ include SuiteResponder. SUITE_SETUE NAME, *-setup"); } private void includeSetupPage(} throws Exception { include(*setUp", ‘-setup"|? } private void includePagecontent () throws Exception { newPageContent append [pageData.getContent ()); a private void includeTeardownPages() throws kxception { includeTeardownPage |) : if (isSuite) includeSuiteTeargownPage(!; vate void includeTeardownPage(} throws Exception { include("TearDewn", "-teardown") ; private void includeSuiteTeardownPage() throws Exception { include (SuiteResponder.SUITE_TEARDOWN_NAME, *-teardown"): } private void updatePageContent (} throws Exception [ pageData.setContent (newPageContent .teString(]) ; private void include(Scring pageName, String arg) throws Exception { WikiPage inheritedPage = findInheritedPage (pageNamei ; if (inheritedPage !> null) { String pagePathName = get PathNameForPage (inheritedPage) ; buildincludeDirective(pagePathName, arg); } ) 2 private WikiPage findInheritedPage|String pageNane) throws Exception [ return PageCrawlerInp] get InkeritedPage (pageName, testPage); private String getPathNameForPage(WikiPage page) throws Exception { WikiPagePath pagePath = pageCrawler.getFull Path (page) ; return PathParser. render (pagePath) ; } private void buildincludeDirectiveiString pagePathName, String arg) ( newPageContent append(*\ntinclude *} 4 Comentarios “Nao insira comentarios num eddigo ruim, reescreva-o”. —Brian W. Kernighan e’. J. Plaugher' Nada pode ser t4o util quanto um comentério 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 e informagdes incorretas, Comentirios nao so como a Lista de Schindler. Nao sao o “bom puro”. De fato, eles so, no maximo, um mal necessério. Se nossas linguagens de programagao fossem expressivas 0 suficiente ou se tivéssemos 0 talento para manipular com destreza tais linguagens de modo a expressar nossa intengo, nao precisarfamos de muitos comentarios, qui¢é nenhum. 54 Capitulo 4: Comentarios x © uso adequado de comentarios é compensar nosso fracasso em nos expressar no cédigo. Observe que usei a palavra fracasso. E € isso que eu quis dizer. Comentarios siio sempre fracassos. Devemos usi-los porque nem sempre encontramos uma forma de nos expressar sem eles, mas seu uso nao € motivo para comemoracao. Entdo, quando vocé estiver numa situago na qual precise criar um comentirio, pense bem € veja se no hé como se expressar através do cédigo em si. Toda vez que vocé fizer isso, dé em si mesmo um tapinha de aprovacdo nas costas. Toda vez que vocé escrever um comentario, faga uma careta ¢ sinta o fracasso de sua capacidade de expresso. Por que sou n&o gosto de comentirios? Porque eles mentem. Nem sempre, ¢ nao intencionalmente, mas é muito comum. Quanto mais antigo um comentirio for e quanto mais longe estiver do eddigo o qual ele descreve, mais provavel sera que esteja errado. © motivo € simples. Nao € realistico que programadores consigam manté-los atualizados. Cédigos mudame evoluem, Movem-se blocos para ld e para cd, que se bifurcam e se reproduzem ese unem novamente, formando monstros gigantescos. Infelizmente, os comentirios nem sempre os seguem nem sempre ¢ possivel. E, muito frequentemente, os comentarios ficam longe do eédigo © qual descrevem e se tornam dizeres érfios com uma exatidio cada vez menor. Por exemplo. olhe © que aconteceu com o comentario abaixo ¢ a linha que ele procurava descrever MockRequest request; private final String HTTP_DATE_REGEXP = *([SMTWF] [a-z] (2)\\.\\s [0-91{2}\5 [JFMASOND] [a-z] {2)\\s"+ (0-91 (4) \\s [0-9] {2}\\: [0-9] (2}\\: [0-9] (2)\\SGMP"s private Response response; private PitNesseContext context: private FileResponder responder; private Locale saveLocale; i] Exemplo: “Tue, 02 Apr 2003 22:18:49 GMT” Outras instdncias de variéveis que provavelmente foram adicionadas posteriormente ficaram entre a constante H'T'TP_DATE_REGEXP e seu comentario descritivo. F possivel dizer que os programadores deveriam ser disciplinados o bastante para manter 0s comentarios em um elevado estado de atualizagio, relevancia ¢ precisdo. Concordo que deveriam. Mas eu preferiria que essa energia fosse direcionada para tornar 0 cédigo tao claro ¢ descritive que de inicio nem se precisaria de comentarios. Comentarios imprecisos so muito piores do que nenhum, Eles enganam ¢ iludem; deixam expectativas que jamais scrdo cumpridas; citam regras antigas que nao precisariam mais, ou no deveriam, ser seguidas. ‘ S6 se pode encontrar a verdade em um lugar: no cédigo. $6 ele pode realmente the dizer o que ele faz. Ele é a tnica fonte de informagdes verdadeiramente precisas. Entretanto, embora as vezes comentarios sejam necessarios, gastariamos energia consideravel para minimiza-los. Comentarios Compensam um Codigo Ruim Uma das motivacdes mais comuns para criar comentarios é um cédigo ruim. Construimos um modulo ¢ sabemos que esta confuso e desorganizado, Estamos cientes da bagunga. Nos mesmos dizemos “Oh, é melhor inserir um comentdrio!”. Nao! E melhor limpa-lo. Comentarios Bons Cédigos claros e expressivos com poucos comentarios so de longe supcriores aumamontoado € complexo com muitos comentirios. Ao invés de gastar seu tempo criando comentarios para explicar a bagunga que vocé fez, use-o para limpar essa zona. Explique-se no cédigo Certamente hé vezes em que no ¢ 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? Isso: // Verifica se 0 funcionario tem direito a todos os beneficios if ((employee.flags & HOURLY_FLAG) && (employee.age > 65)) Ou isso? if (employee.isEligibleForFullsenefits()) $6 € preciso alguns segundos de pensamento para explicar a maioria de sua intengao no cédigo. Fm muitos casos, é simplesmente uma questao de criar uma fungao cujo nome diga a mesma coisa que vocé deseja colocar no comentiirio. Comentarios Bons Certos comentirios so necessirios ou benéficos. Veremos alguns que considero valerem os bits que consumem. Tenha em mente, contudo, que 0 unico comentario verdadeiramente bom & aquele em que vocé encontrou uma forma para nfo escrevé-lo. Comentarios Legais [As vezes, nossos padrées de programagao corporativa nos forgam a escrever certos comentarios por questdes Iegais. Por exemplo, frases sobre direitos autorais ¢ autoria séo informagdes necessiitias ¢ légicas para se colocar no inicio de um arquivo fonte. Por exemplo, abaixo esté 0 comentario padrao de cabecalho que colocamos no inicio de todo arquivo fonte do FitNesse. Fico feliz em dizer que nossa IDE evita a unido automética desse comentario para que nao fique aglomerado. // Direitos autorais (C) 2003,2004,2005 por Object Mentor,*Inc. Todos os direitos reservados. // Distribuido sob os termos da versdo 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 e condicdes no mesmo comentario. 56 y/ Capitulo 4: Comentarios Comentarios Informativos As vezes é pritico fornecer informages basicas em um comentério. 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 comentirio como este pode ser titi] as vezes, mas, sempre que possivel, é melhor usar 0 nome da fungao para transmitir a informacao. Por exemplo, neste caso, 0 comentario ficaria redundante se trocdssemos 0 nome da fungdo: responderBeingTested. Assim ficaria um pouco melhor: / formato igual a kk:mm:ss EEE, MMM dd, aaaa Pattern timeMatcher = Pattern.compile("\\d*:\\d*\\d* \w, \Wwe \d*, Wd"); Neste caso, 0 comentario nos permite saber que a expressdo 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 codigo tivesse sido colocado em uma classe especial para converter os formatos de datas ¢ horas, Ent&o, 0 coment provavelmente seria supérfluo. Explicacdo da intengao As vezes, um comentario vai além de ser apenas informag@es tteis sobre a implementagao e fornece a intengo por trés de uma decistio. No caso a seguir, vemos uma decisio interessante documentada através de um comentitio. Ao comparar dois objetos, 0 autor decidiu que queria classificar como superiores os objetos de sua classe em relacao aos de outras. public int compareTo{Object o) { if(o instanceof WikiPagePath) c WikiPagePath p = (WikiPagePath) o; String compressedName = StringUtiljoin(names, °"); String compressedArgumentName = StringUtil.join(p.names, ™"); return compressedName.compareTo(compressedArgumentName}; } “ return 1; // somos superiores porque scmos tipo certo. Abaixo esta um exemplo melhor ainda. Talvez vocé discorde da solugao do programador, mas pelo menos vocé sabe 0 que cle estava tentando fazer. public void testConcurrentAddWidgets() throws Exception { WidgetBuilder widgetBuilder = new WidgetBuilder(new Class{]{BoldWidget.class}); String text = "bold text!’"*; Comentarios Bons ¢ 57 ParentWidget parent = new BoldWidget(new MockilidgetRoot(), *’’"bold text’’’); AtomicBoolean failFlag = new AtomicBoolean(); failPlag.set(false); /7essa e a nossa melhor tentativa para conseguir uma condicao de corrida. /feaxa isso criamos um grande numero de threads. for (int i = 0; i < 25000; i++) { WidgetBuilderThread widgetBuilderThread = new WidgetBuilderThread(widgetBuilder, text, parent, failFlag); ‘Thread thread = new Thread(widgetBuilderthread); thread.start(); ? assertEquals(false, failFlag.get()); , Esclarecimento As vezes € bom traduzir o significado de alguns parametros 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 padraio, ou de um cédigo que nao se possa alterar, ent&io 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: “a assertTrue(a.compareto(b) != 0); // a assert True(ab.compareTo(ab} 0); 7 ab == assert True(a.compareTo(b) “Ii ach assertTrue(aa.compareTo(ab) -1); // aa < ab assertTrue(ba.compareTo(bb) -1); # ba < bb assertTrue(b.compareTo(a) == 1); //) b> a assertTruelab.compareTo(aa) == 1); // ab > aa assert True(bb.compareTo(ba) 1); // bb > ba } “ Ha um risco considerdvel, é claro, de que um comentario esclarecedor possa estar incorreto, Leia © exemplo anterior ¢ veja como ¢ dificil verificar se estilo corretos. Isso explica tanto 0 porqué da necessidade do esclarecimento como seu risco. Portanto, antes de eriar comentarios como esses, certifique-se de que ndo ha outra saida melhor e, ento, certifique-se ainda mais se esto precisos. 58 Capitulo 4: Comentarios Alerta Sobre Consequéncias As vezes 6 til alertar outros programadores sobre certas consequéncias. Por exemplo, 0 comentario abaixo explica porque um caso de teste cm particular esta desabilitado: 11 M&ONKo execute a menos que vocé W/ tenha tempo disponivel. public void _testWithReallyBigFile() { writeLinesToFile(10000000); response.setBody(testFile); response.readyToSend(this); String responseString = output. toString(); assertSubString("Content-Length: 1000000000", responseString); assertTrue(bytesSent > 1000000000); 3 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 convengdo comum era colocar um traco 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 é uma thread segura, Wé preciso criar cada instancia independentemente. SimpleDateFormat df = new SimpleDateFormat(*EEE, dd MMM yyyy HH:mm:ss 2"); a£.setTimeZone(TimeZone.getTimeZone(*GMT*)); return df; } Talvez vocé reclame por haver melhores maneiras de resolver esse problema. Talvez eu concorde com vocé, mas © comentario como foi feito € perfeitamente I6gico. Ele evitara que um programador afoito use um inicializador estatico em prol da eficiéncia. Comentario TODO 2 As vezes ¢ cabivel deixar notas “To Do” (‘Fazer’) em comentarios no formato // ToDo. No caso a seguir, 0 comentario TODO explica por que a fung3o tem uma implementagao degradante e o que se deveria fazer com aquela fungao. HTODO-MGM essas néo séo necessérias W/ Bsperamos que isso nfo esteja mais aqui quando verificarmos o modelo protected Versioninfo makeVersion() throws Exception { return null; }

Você também pode gostar