You are on page 1of 366
RERATORACAO APERFEICOANDO 0 PROJETO DE CODIGO EXISTENTE MARTIN FOWLER femmes Kent Beck, John Bra Os autores Martin Fowler é consultor independente ¢ trabalha com a aplicagao de objetos em problemas empresariais ha mais de uma década. E consultor de sistemas em campos como satide, negécios e financas corporativas. Entre seus clientes estao a Chrysler, Citibank, UK National Health Service, Andersen Consulting e Netscape Communi- cations. Além disso, Fowler faz palestras sobre objets, UML (Unified Modeling Lan- guage) e padrdes de projeto. Ele é 0 autor de Analysis Patterns e do premiado UML Distilled. Kent Beck é um conceituado programador, testador, refatorador, autor e tocador de banjo. John Brant e Don Roberts sao os autores do Refactoring Browser for Smalltalk, que pode ser encontrado em http://st-www.cs.uiuc.edu /~brant /RefactoringBrowser. Eles também sdo consultores e estudiosos dos aspectos praticos e tebricos da refato- ragao ha seis anos. A pesquisa de doutorado de William Opdyke sobre frameworks orientados a ob- jetos para a refatoracao (na University of Illinois) levou a primeira publicacao impor- tante sobre este t6pico. Ele é atualmente um DMTS (Distinguished Member of Technical Staff) na Lucent Technologies /Bell Laboratories F787r Fowler, Martin Refatoragao [recurso eletronico] : aperfeigoando o projeto de cédigo existente / Martin Fowler ; tradugao Acauan Fernandes, — Dados eletronicos. ~ Porto Alegre : Bookman, 2008. Editado também como livro impresso em 2004. ISBN 978-85-7780-415-3 1. Computagao ~ Linguagem de programagao — Refatoragao. 1 Titulo. CDU 681.3/.08 Catalogagao na publicagdo: Renata de Souza Borges — CRB-10/Prov-021/08 MARTIN FOWLER Com contribuigées de KENT BECK, JOHN BRANT, WILLIAM OPDYKE e DON ROBERTS ReraToracio APERFEICOANDO 0 PROJETO DE CODIGO EXISTENTE Tradugao: Acauan Fernandes Mestre em Ciéncia da Computacdo pela UFRGS Professor da Universidade da Regido da Campanha (Urcamp) Consultoria, supervisao e revisao técnica desta edigao: Jonas Knopman DSC. COPPE/UFR] Analista, pesquisador e professor do NCE/UFR] Versio impressa desta obra: 2004 oO 2008 Obra originalmente publicada sob o titulo Refactoring — Improving the Design of Existing Code ©2000, Addison-Wesley ISBN 0-201-48567-2 Tradugdo autorizada a partir do original em lingua inglesa publicado por Pearson Education, Inc., sob o selo Addison-Wesley Professional Capa: Mario Réhnelt Leitura Final: Marcos Rubenich Supervisio editorial: Arysinha Jacques Affonso Editoragao eletronica: Laser House Reservados todos os direitos de publicagao, em lingua portuguesa, & ARTMED’ EDITORA S.A. Ay. Jeronimo de Ornelas, 670 - Santana 90040-340 Porto Alegre RS Fone (51) 3027-7000 Fax (51) 3027-7070 E proibida a duplicacao ou reprodugao deste volume, no todo ou em parte, sob quaisquer formas ou por quaisquer meios (eletrénico, mecanico, gravacao, fotocépia, distribuigao na Web e outros), sem permissdo expressa da Editora. SAO PAULO Av. Angélica, 1091 - Higiendpolis 0127-100 Sao Paulo SP Fone (11) 3665-1100 Fax (11) 3667-1333 SAC 0800 703-3444 IMPRESSO NO BRASIL PRINTED IN BRAZIL Para Cindy Apresentacao “refatoragao” foi inicialmente concebida nos circulos Smalltalk, mas nao de- morou muito a encontrar seu caminho em outras linguagens de programa- cdo. Devido ao fato da refatoracao ser essencial ao desenvolvimento de frame- works, 0 termo vem a tona rapidamente quando desenvolvedores de frameworks fa- lam sobre seu trabalho. Ele surge quando eles refinam suas hierarquias de classes e quando se empolgam com 0 ntimero de linhas de cédigo que conseguiram apagar. Desenvolvedores de frameworks sabem que um framework nao estara pronto na pri- meira tentativa — ele deve evoluir 4 medida em que eles ganham experiéncia. Eles também sabem que 0 cédigo seré lido e modificado mais freqiientemente do que se- 14 escrito. A chave para manter o cédigo legivel e modificdvel é refatorar — para fra- meworks, em particular, ou para qualquer outro software, de maneira geral. Entdo, qual é 0 problema? Simplesmente este: refatorar tem seus riscos. O pro- cesso requer alteragdes no cdigo em funcionamento que podem introduzir falhas sutis. A refatoracao, se nao for feita apropriadamente, pode lhe atrasar dias, ou até mesmo semanas. E a refatoragao se torna mais ainda mais arriscada quando prati- cada informalmente e sem seguir nenhuma metodologia aceita. Vocé comega a alte- rar 0 cédigo. Logo descobre novas oportunidades de mudancas, e altera ainda mais 0 cédigo. Quanto mais vocé trabalha, mais coisas aparecem e mais alteragdes sao fei- tas. No final, vocé se enterra em um buraco do qual nao consegue mais sair. Para evi- tar cavar seu préprio ttimulo, a refatoragao deve ser feita sistematicamente. Quando meus co-autores e ett escrevemos Design Patterns, mencionamos que os padrdes de projeto fornecem alvos para refatoracées. Entretanto, identificar 0 alvo éapenas uma parte do problema; transformar seu cédigo de modo que vocé obtenha os resultados esperados é outro desafio. Martin Fowler e os autores colaboradores fazem uma contribuicao inestimavel ao desenvolvimento de software orientado a objetos clareando processo de refatora- do. Este livro explica os principios e as praticas ideais da refatoracdo, e mostra quan- do e onde vocé deve comecar a mexer no seu cédigo para melhord-lo. Na sua essén- vii APAESENTAGAO cia, o livro apresenta um catélogo abrangente de refatoracdes. Cada refatoragao apre- sentada descreve a motivagao e o mecanismo de uma transformagao de cédigo com- provada. Algumas delas, como 0 Método Extrair ou Mover Campo, podem parecer Sbvias. Mas nao se deixe enganar. Compreender 0 mecanismo de tais refatoragdes & achave para aplicar a refatoracao de uma maneira disciplinada. As refatoragoes des- te livro Ihe ajudarao a alterar seu cédigo, um pequeno passo de cada vez, reduzindo assim 0s riscos da evolucao do seu projeto. Rapidamente, vocé acrescentard estas re- fatorages e seus nomes ao seu vocabulario de desenvolvimento. Minha primeira experiéncia com refatoracao disciplinada, “um passo de cada vez”, foi quando estava programando em parceria com Kent Beck, a 10.000 m de al- tura. Ele assegurou-se de que aplicévamos passo a passo as refatoracdes descritas neste livro. Fiquei impressionado como quao bem esta pratica funcionava. Nao ape- nas aumentou minha confianga no cédigo resultante, como também me senti menos estressado. Eu recomendo enfaticamente que vocé experimente estas refatoracdes: vocé e seu cédigo irao se sentir muito melhor com isso. Erich Gamma Object Technology International, Inc. Prefacio 4 muito tempo, um consultor fez uma visita a um projeto de desenvolvimen- to. Ele olhou uma parte do cédigo que havia sido escrito; havia uma hierar- quia de classes no centro do sistema. Enquanto vagava por essa hierarquia, viu que ela era bastante confusa. As classes de nivel mais alto faziam certas suposi- Ges a respeito de como as classes de nivel mais baixo deveriam funcionar, suposi- Ges essas que estavam embutidas no cédigo herdado. Além disso, o cédigo presen te nas superclasses nao servia para todas as subclasses, e era bastante modificado por estas. Se a superclasse tivesse sido um pouco modificada, muito menos cédigo teria de ser reescrito. Em outros lugares, uma parte dos objetivos da superclasse nao havia sido entendida apropriadamente, e 0 comportamento presente na superclasse era duplicado nas subclasses. Em outros lugares, diversas subclasses implementavam 0 mesmo cédigo, o qual, claramente, poderia ser movido para niveis mais altos da hie- rarquia. O consultor recomendou a geréncia do projeto que 0 cédigo fosse examinado e colocado em ordem, mas esta ndo pareceu muito entusiasmada. O cédigo parecia funcionar e havia consideravel pressao quanto ao cronograma. Os gerentes disseram que iriam retornar ao c6digo mais tarde. O consultor também havia mostrado aos programadores que tinham trabalhado na hierarquia o que estava acontecendo. Os programadores estavam interessados e vi- ram 0s problemas. Eles sabiam que nao era realmente culpa deles; is vezes pessoas de fora sao necessérias para perceber um problema. Assim, eles passaram um dia ou dois colocando em ordem a hierarquia de classes. Quando terminaram, haviam removido metade do c6digo da hierarquia sem diminuir sua funcionalidade. Eles ficaram satis- feitos com o resultado e descobriram que se tornou mais r4pido e facil tanto acrescen- tar novas classes a hierarquia quanto usar as classes no resto do sistema. Por outro lado, a geréncia do projeto nao ficou satisfeita. Os cronogramas esta- vam apertadose havia muito trabalho a fazer. Estes dois programadores haviam gas- to dois dias executando um trabalho que nao havia acrescentado nada as muitas fun- x PaEFACIO cionalidades que o sistema tinha que apresentar dali ha alguns meses. O c6digo an- tigo funcionava bem. O projeto estava um pouco mais “puro” e um pouco mais “or- ganizado”. O projeto tinha que gerar cédigo que funcionasse, nao cédigo que agra dasse a um académico. O consultor sugeriu que esta reorganizacao fosse feita em ou- tras partes vitais do sistema. Tal atividade poderia parar o projeto por uma semana ou duas. Toda esta atividade era voltada a fazer o cddigo mais organizado, nao a fa- zé-lo executar algo que ainda nao executava. Como vocé se sente em relagao a essa histéria? Vocé acha que 0 consultor esta- va certo em sugerir tais modificagdes? Ou voce segue aquele velho adagio da enge- nharia “se funciona, nao mexa”? Devo admitir uma certa parcialidade aqui. Eu era aquele consultor. Seis meses mais tarde o projeto falhou, em grande parte porque o cdigo era complexo demais para depurar ou ajustar a um desempenho aceitdvel. O consultor Kent Beck foi trazido para recomecar o projeto, um exercicio que levou a reescrita de quase todo o sistema, do zero. Ele fez diversas coisas de modo diferente, mas uma das mais importantes foi insistir no continuo aperfeigoamento do cédigo usando refatoracao. O sucesso desse projeto e o papel que a refatoracao de- sempenhou nele, foi o que me inspirou a escrever este livro, de modo que eu pudes- se passar adiante o conhecimento que Kent e outros obtiveram no uso da refatoracao para melhorar a qualidade do software. O que é Refatoracao? Refatoracao é 0 processo de alteragao de um sistema de software de modo que 0 com- portamento externo do cédigo nao mude, mas que sua estrutura interna seja melho- rada. £ uma maneira disciplinada de aperfeicoar 0 cédigo que minimiza a chance de introdugao de falhas. Em esséncia, quando vocé usa refatoracao, vocé est melhoran- do 0 projeto do cédigo apés este ter sido escrito. “Melhorar o projeto apés ele ter sido escrito.” Esta é uma frase esquisita. Na nos- sa compreensio atual de desenvolvimento de software, acreditamos que projetamos e depois codificamos. Um bom projeto vem antes, ¢ a codificagéo vem em seguida. O problema é que, com o passar do tempo, 0 c6digo seré modificado ea integridade do sistema, sua estrutura em relacdo ao projeto original, aos poucos enfraquece. O pro- cesso de construcao de cédigo, lentamente passa da engenharia a experimentacdo. Refatorar é o oposto desta pratica. Com a refatoracao, vocé pode pegar um pro- jeto ruim, até mesmo caético, e transforma-lo em um cédigo bem projetado. Cada passo é simples, até mesmo simplista. Vocé move um campo de uma classe para ou- tra, tira um pouco de cédigo de um método para transformé-lo em outro método e desce ou sobe uma parte do cédigo pela hierarquia de classes. O efeito cumulativo dessas pequenas alteragées pode melhorar radicalmente 0 projeto. E 0 exato oposto da nogao comum de decadéncia de software. Com a refatoragao, vocé descobre que o ponto de equilibrio do trabalho muda. Descobre que © projeto, em vez de acontecer todo no inicio, ocorre continuamente durante o desenvolvimento. Aprende, com a construgao do sistema, a como melho- rar 0 projeto. A interacio resultante leva a um programa que permanece bom & me- dida em que o desenvolvimento continua. Prericio xi O Que Este Livro Contém? Este livro é um guia para a refatoragao; foi escrito para um programador profissio- nal. Meu objetivo é Ihe mostrar como executar refatoraco de uma maneira contro- ada e eficiente. Vocé aprender a refatorar de um modo que nao introduza erros no cédigo, ao contrario, melhore metodicamente a estrutura. tradicional comecar livros com uma introdugao. Embora eu concorde com esse principio, nao acho fécil introduzir a refatoracao com uma discussao generalizada ou com definicdes. Ent4o, comeco com um exemplo. O Capitulo 1 pega um pequeno programa com alguns problemas comuns de projeto e o refatora em um programa orientado a objetos mais aceitavel. Durante esse percurso, vemos tanto 0 proceso de refatoracao quanto a aplicacao de diversas refatoragdes titeis. Este é 0 capitulo chave a ser lido se vocé quiser entender do que a refatoracao trata. No Capitulo 2 sao vistos mais alguns principios gerais da refatoracao, algumas definigdes e os motivos para refatorar. Descrevo ainda alguns dos problemas com a refatorag4o. No Capitulo3, Kent Beck me ajuda a descrever como encontrar “maus cheiros” no cédigo e como limpé-los com refatoracées. Testes desempenham um pa- pel muito importante na refatoragao, entao o Capitulo 4 descreve como inserir testes no cédigo com um framework simples de testes de cédigo aberto Java. O coragao deste livro, o catélogo de refatoragies, se estende do Capitulo 5 ao 12. Este nao é, de forma alguma, um catélogo definitivo. E 0 comeco de tal catdlogo. Ele inclui apenas as refatoracdes que tive de fazer até hoje no meu trabalho neste campo. Quando quero fazer algo, como Substituir Comando Condicional por Polimorfismo (218), © catélogo me lembra, passo a passo, como fazé-lo com seguranga. Espero que esta seja a segao do livro a qual vocé voltaré com freqiiéncia. Neste livro descrevo o resultado da pesquisa de muitas outras pessoas. Os tilt mos capitulos foram escritos, a convite, por algumas dessas pessoas. O Capitulo 13 é de Bill Opdyke, que descreve as questdes com as quais se deparou na adogao da re- fatoragao no desenvolvimento comercial. O Capitulo 14 é de Don Roberts e John Brant, que descrevem o verdadeiro futuro das ferramentas de refatoragao automati- zadas. Deixei a palavra final, o Capitulo 15, para o mestre da arte, Kent Beck. Refatorando em Java Por todo este livro uso exemplos em Java. A refatoragio pode, é claro, ser feita com outras linguagens, e espero que este livro seja titil Aqueles trabalhando com outras linguagens. Entretanto, achei que seria melhor focar este livro em Java porque éa lin- guagem que conheco melhor. Acrescentei notas ocasionais sobre refatoragao em outras linguagens, mas espero que outras pessoas construam sobre esta fundacao com livros voltados para linguagens especificas. Para ajudar a comunicar melhor as idéias, nao usei 4reas especialmente comple- xas de Java. Assim, evitei usar classes internas, reflexao, threads e muitas outras ca- racteristicas poderosas de Java. Isto porque quero focar nas refatoracdes basicas, tio claramente quanto puder. Devo enfatizar que estas refatoracdes nao s4o feitas tendo em mente programa- do concorrente ou distribuida. Esses tpicos introduzem questdes adicionais que es- tao fora do escopo deste livro. xi PaEFAcio, Quem Deve Ler Este Livro? Este livro visa um programador profissional, alguém que escreve software para viver. Os exemplos e a discussao incluem muito c6digo para ser lido e compreendido. Os exemplos sao todos em Java. Escolhi Java porque é uma linguagem cada vez mais co nhecida e que pode ser compreendida por qualquer um com formagao em C. Tam- bém é uma linguagem orientada a objetos, e mecanismos orientados a objetos sio de grande ajuda na refatoragao. Embora esteja focada no c6digo, a refatoracao tem um grande impacto no proje- to do sistema. E vital para projetistas e arquitetos sénior compreenderem os princi- pios da refatoracao e usé-los nos seus projetos. O processo tem melhores resultados se introduzido por um desenvolvedor respeitado e experiente. Tal desenvolvedor pode entender melhor os principios por tras da refatoracao e adapté-los ao seu am- biente de trabalho especifico. Isto é especialmente valido para uma linguagem que no seja Java, porque vocé tem que adaptar os exemplos que dei a outras linguagens. Aqui estd como obter o maximo deste livro sem té-lo de ler todo: m Se vocé quiser entender o que é refatoragao, leia o Capitulo 1;0 exemplo de- ve tornar 0 processo claro. Se vocé quiser entender por que deve refatorar, leia os primeiros dois capitu- los. Eles Ihe dirao 0 que é a refatoracao e por que vocé deve fazé-la. ™ Se vocé quiser descobrir onde deve refatorar, leia 0 Capitulo 3. Ele lhe conta os sinais que sugerem a necessidade de refatoracao. m Se vocé quiser realmente executar refatoracao, leia os primeiros quatro capi- tulos completamente. Apés, leia 0 catélogo. Leia o suficiente do catélogo para saber em linhas gerais o que ha I. Vocé nao tem que compreender todos os de- talhes. Quando vocé realmente precisar executar uma refatoracao, leia essa re- fatoragao em detalhe e use-a para Ihe ajudar. O catélogo é uma segao de refe- réncia, de modo que provavelmente vocé nao ira querer Ié-Io todo, de uma vez 86. Vocé também deve ler os capitulos dos colaboradores, especialmente o Ca- pitulo 15. Construindo Sobre Fundacées Assentadas por Outros Preciso dizer agora, no comeco, que tenho uma grande divida com este livro, uma di- vida com aqueles cujo trabalho, durante a iiltima década, desenvolveu 0 campo da refatoracao. Idealmente, um deles deveria ter escrito este livro, mas eu acabei sendo a pessoa com o tempo ea energia para fazé-lo. Dois dos principais proponentes da refatoracao sao Ward Cunningham e Kent Beck. Eles a usaram, desde o inicio, como parte central de seu proceso de desenvol- vimento e desde entao tém adaptado estes processos para tirar proveito dela. Em es- pecial, foi minha parceria com Kent Beck que realmente me mostrou a importancia da refatoracao, uma inspiracao que levou diretamente a este livro. Ralph Johnson lidera um grupo na University of Illinois em Urbana-Champaign que é notavel por suas contribuigdes praticas a tecnologia de objetos. Ralph tem sido PaerAcio um defensor da refatoragao h4 muito tempo, e muitos de seus alunos tém trabalha- do nesse t6pico. Bill Opdyke desenvolveu o primeiro trabalho detalhado escrito so- brea refatoracao na sua tese de doutorado. John Brant e Don Roberts foram além de escrever, fazendo uma ferramenta, 0 Refactoring Browser, para refatorar programas em Smalltalk. Agradecimentos Mesmo com todas essas pesquisas para consultar, ainda precisei de muita ajuda pa- ra escrever este livro. Primeiro e principalmente, Kent Beck foi de grande ajuda. As primeiras sementes foram plantadas em um bar em Detroit quando Kent me falou a respeito de um trabalho que ele estava escrevendo para o Smalltalk Report [Beck, ha- noi]. Nao s6 pude roubar muitas idéias deste artigo para escrever o Capitulo 1 como também ele me iniciou na tomada de notas sobre refatoracdes. Kent me ajudou em outras partes também. Ele trouxe a idéia dos “maus cheiros” no cédigo, me encora- jou em varios pontos confusos e geralmente trabalhou comigo para fazer este livro funcionar. Nao posso deixar de pensar que ele proprio poderia ter escrito este livro muito melhor, mas eu tinha o tempo e apenas posso esperar que tenha feito justiga ao assunto. Como fui eu que o escrevi, queria dividir muito deste conhecimento diretamen- te com vocé, de modo que estou muito grato que muitas dessas pessoas tenham gas- to seu tempo acrescentando material a este livro. Kent Beck, John Brant, William Opdyke e Don Roberts escreveram ou co-escreveram capitulos. Além disso, Rich Garzaniti e Ron Jeffries acrescentaram notas titeis. Qualquer autor the diré que revisores técnicos fazem muito para ajudar em um livro como este. Como sempre, Carter Shanklin e sua equipe na Addison-Wesley jun- taram uma grande seco de revisores. Estes foram Ken Auer, Rolemodel Software, Inc. ® Joshua Bloch, Sun Microsystems, Java Software John Brant, University of Illinois em Urbana-Champaign Scott Corley, High Voltage Software, Inc. Ward Cunningham, Cunningham & Cunningham, Inc. Stéphane Ducasse Erich Gamma, Object Technology International, Inc. Ron Jeffries Ralph Johnson, University of Illinois Joshua Kerievsky, Industrial Logic, Inc. Doug Lea, SUNY Oswego @ Sander Tichelaar Todos eles acrescentaram muito a legibilidade e precisao deste livro, e remove- ram pelo menos alguns dos erros que podem surgir em qualquer manuscrito. Gos- xiv PaerAcio taria de destacar algumas das sugest6es que fizeram diferenca visivel na aparéncia do livro. Ward e Ron me convenceram a fazer 0 Capitulo 1 no estilo lado-a -lado. Jos- hua Kerievsky sugeriu a idéia dos esbogos de cddigo no catélogo. Além da segao oficial de revisdo, houve muitos revisores nao oficiais. Estas pes- soas olharam o manuscrito ou 0 trabalho em progresso nas minhas paginas Web e fi- zeram comentarios titeis. Elas incluem Leif Bennett, Michael Feathers, Michael Fin- ney, Neil Galarneau, Hisham Ghazouli, Tony Gould, John Isner, Brian Marick, Ralf Reissing, John Salt, Mark Swanson, Dave Thomas e Don Wells. Tenho certeza de que hA outros que esqueci; peco desculpas e ofereco meu agradecimento. Um grupo de revisao especialmente interessante € 0 grupo de leitura na Univer- sity of Illinois em Urbana-Champaign. Devido a este livro refletir tanto de seu traba- Iho, estou especialmente grato a seus esforcos capturados em audio em tempo real. Este grupo inclui Fredrico “Fred” Balaguer, John Brant, lan Chai, Brian Foote, Alejan- dra Garrido, Zhijiangn “John” Han, Peter Hatch, Ralph Johnson, Songyu “Ray- mond” Lu, Dragos-Anton Manolescu, Hiroaki Nakamura, James Overturf, Don Ro- berts, Chieki Shirai, Les Tyrrel e Joe Yoder. Qualquer idéia boa precisa ser testada em um sistema de producao sério. Eu via refatoragdo ter um grande efeito sobre o sistema Chrysler Comprehensive Compen- sation (C3). Quero agradecer todos os membros daquela equipe: Ann Anderson, Ed Anderi, Ralph Beattie, Kent Beck, David Bryant, Bob Coe, Marie DeArment, Marga- ret Fronczak, Rich Garzaniti, Dennis Gore, Brian Hacker, Chet Hendrickson, Ron Jef- fries, Doug Joppie, David Kim, Paul Kowalsky, Debbie Mueller, Tom Murasky, Ri- chard Nutter, Adrian Pantea, Matt Saigeon, Don Thomas e Don Wells. Trabalhar com eles solidificou em mim, de maneira original, os principios e beneficios da refatora- cdo. Ver seu progresso 4 medida em que usam refatoracdo me ajuda muito a ver 0 que ela pode fazer quando aplicada por muitos anos a um projeto grande. Mais uma vez tive a ajuda de J. Carter Shanklin na Addison-Wesley e sua equipe: Krysia Bebick, Susan Cestone, Chuck Dutton, Kristin Erickson, John Fuller, Christo- pher Guzikowski, Simone Payment e Genevieve Rajewski. Trabalhar com um bom editor é um prazer; eles fornecem muito apoio e ajuda. Falando em apoio, quem mais sofre com um livro so sempre as pessoas mais proximas do autor, neste caso minha (agora) esposa Cindy. Obrigado por me amar mesmo quando estava oculto na sala de estudos. Durante todo o tempo em que tra balhei neste livro nunca deixei de pensar em voce. Martin Fowler Melrose, Massachusetts ‘fowler@acm.org http:/fewww.martinfowler.com Attp://www.refactoring.com Sumario Capfruto 1: Refatoragéo, um Primeiro Exemplo O Ponto de Partida .. . O Primeiro Passo na Refatoracéo Decompondo e Redistribuindo 0 Método Conta . : Substituindo a Légica Condicional no Cédigo do Prego com Polimorfismo ... 41 Consideragées Finais CariruLo 2: Prinefpios da Refatoracao Definindo Refatoracao . Por que Vocé Deve Refatorar? Quando Vocé Deve Refatorar? O que Digo ao Meu Gerente? Problemas com a Refatoragao Refatoragao e Projeto ... Refatoragio e Desempenho .. De Onde Veio a Refatoragao?. SRPSBRERB CariTuLo 3: “Maus cheiros” no Cédigo (por Kent Beck e Martin Fowler) Cédigo Duplicado. . Método Longo . Classes Grandes. . Lista de Parametros Longa. Alteracao Divergente . Cirurgia com Rifle Inveja dos Dados. BRaagssea 16 SumAnio Grupos de Dado: Obsessao Primitiva . Comandos Switch . Hierarquias Paralelas de Heranga Classe Ociosa . Generalidade Especulativa . Campo Temporario. Cadeias de Mensagens Intermediario Intimidade Inadequada . Classes Alternativas com Interfaces Diferentes Biblioteca de Classes Incompleta Classe de Dados. . 79 Heranga Recusada -80 Comentérios. -80 CapfTuLo 4: Construindo Testes . O Valor do Cédigo de Autoteste . O Framework de Teste JUnit . .. Acrescentando Mais Testes Cariruto 5: Rumo a um Catélogo de Refatoragdes . Formato das Refatorages Encontrando Referéncias Qual o Grau de Maturidade Destas Refatoragdes? CariTuLo 6: Compondo Métodos Extrair Método... Internalizar Método Internalizar Varivel Tempordria Substituir Variavel Tempordria por Consulta . Introduzir Variavel Explicativa Dividir Variével Tempordria : Remover Atribuigdes a Parametros . Substituir Método por Objeto Método. Substituir o Algoritmo i 14 7 CapiTULo 7: Movendo Recursos Entre Objetos .. Mover Método . Mover Campo .... Extrair Classe . . Internalizar Classe. Ocultar Delegagao Remover Intermediério .. Introduzir Método Externo . Introduzir Extensio Local . +6125 129 132 142 144 SumAnio 17 +149 150 153 156 159 161 164 171 174 177 178 179 187 187 192 195 200 +204 205 206 208 210 214 218 222 CarituLo 8: Organizando Dados Auto-Encapsular Campo . Substituir Atributo por Objeto Mudar de Valor para Referéncia. Mudar de Referéncia para Valor. Substituir Vetor por Objeto . Duplicar Dados Observados Transformar Associacao Unidirecional em Bidirecional . ‘Transformar Associagao Bidirecional em Unidirecional . Substituir Ntimeros Mgicos por Constantes Simbélicas Encapsular Campo . Encapsular Colecao. Substituir Registro por Classe de Dados . Substituir Enumeracao por Classe . Substituir Enumeragdo por Subclasses Substituir Enumeracao pelo Padrao State/Strategy Substituir Subclasse por Campos Cariruto 9: Simplificando Expresses Condicionais... Decompor Condicional .. Consolidar Expressao Condicional. Consolidar Fragmentos Condicionais Duplicados Remover Flag de Controle Substituir Condigao Aninhada por Cldusulas Guarda Substituir Comando Condicional por Polimorfismo Introduzir Objeto Nulo. Introduzir Assergao. +6232 233 235 236 237 241 243, 246 249 CapiTULO 10: Tornando as Chamadas de Métodos Mais Simples. .. . Renomear Método. . Acrescentar Parametro Remover Parametro Separar a Pesquisa do Modificador . Parametrizar Método .......... Substituir Parémetro por Métodos Explicitos. Preservar 0 Objeto Inteiro .... Substituir Parametro por Método Introduzir Objeto Parametro . . Remover Método de Gravacio Ocultar Método . Substituir Construtor por um Método Fabrica Encapsular Downcast. . Substituir Cédigo de Erro por Excecao Substituir Excegao por Teste 259 259 269 18 SumAnio Carituto 11: Lidando com Generalizagio. .. Subir Campo na Hierarquia Subir Método na Hierarquia Subir 0 Corpo do Construtor na Hierarquia Descer Método na Hierarquia . Descer Campo na Hierarquia . +273 274 275 277 279 280 Extrair Subclasse 281 Extrair Superclasse . 286 Extrair Interface . . 290, Condensar Hierarquia Criar um Método Padrao . Substituir Heranga por Delegacao . Substituir Delegacao por Heranca . 292 293 300 302 +308 307 312 314 317 CariTuLo 13: Refatoragio, Retiso e Realidade (por William Opdyke) 322 Um Teste de Realidade 323 Por que os Desenvolvedores Estao Relutantes em Refatorar Seus Programas? 324 Um Teste de Realidade (Revisitado). Recursos e Referéncias para Refatoracao. Implicagdes Quanto ao Retiso de Software e Transferéncia de Tecnologia Uma Nota Final .... CariruLo 12: Refatoragdes Grandes (por Kent Beck e Martin Fowler) .. Desembaragar Heranca Converter Projeto Procedural em Objetos Separar o Dominio da Apresentacao .. Extrair Hierarquia .. 335 336 337 CapituLo 14: Ferramentas de Refatoragao (por Don Roberts e John Brant). 340 Refatorando com uma Ferramenta. Critérios Técnicos para uma Ferramenta de Refatoracao 2342 Critérios Praticos para uma Ferramenta de Refatoracao. 344 Conclusao 345 346 CapftuLo 15: Juntando Tudo (por Kent Beck) . Referéncias ... - 351 Lista de Idéias Basicas. .. +355 - 387 CaPiTULO 1 Refatoracao, um Primeiro Exemplo omo comegar a escrever sobre refatorac4o? O modo tradicional de comegar a falar sobre algo é resumir a hist6ria, princfpios gerais e assim por diante. Quando alguém faz isso em uma conferéncia, costumo ficar um pouco sono- lento. Minha mente comega a divagar em um processo em segundo plano de baixa prioridade que fica sondando o orador até que ele ou ela dé um exemplo. Os exem- plos me acordam porque é com exemplos que posso ver 0 que esté acontecendo. Com principios ¢ facil fazer generalizagses, dificil é descobrir como aplicar as coisas. Um exemplo ajuda a tornar as coisas mais claras. Entao, comecarei este livro com um exemplo de refatoragao. Durante o processo, falarei bastante a respeito do modo pelo qual a refatoracao funciona e Ihe darei uma idéia sobre o processo de refatoracao. Depois disso, posso entdo fazer a introducao comum baseada em princfpios. Com um exemplo introdut6rio, entretanto, me deparo com um grave problema. Se escolher um programa grande, sua descrigéo e 0 modo como ele é refatorado é complicado demais para qualquer leitor acompanhar. (Experimentei e até mesmo um programa ligeiramente complicado ocupa mais do que uma centena de paginas). Por outro lado, se eu escolher um programa que seja pequeno o suficiente para ser compreensivel, a refatoragao nao parece valer a pena. Assim, estou na dificil e classica situagao de alguém que quer descrever técnicas que sejam titeis para programas do mundo real. Sinceramente, nao vale a pena 0 es- forgo para aplicar a refatoracdo em um programa pequeno como o que usarei. Porém. se 0 cédigo que estou Ihe mostrando for parte de um sistema maior, entdo a refatora- cdo logo se torna importante. Entao tenho que lhe pedir para olhar o exemplo e ima- gind-lo no contexto de um sistema muito maior. 20 Reraronacho O Ponto de Partida O programa exemplo é muito simples. E um programa para calcular e imprimir 0 va- lor devido por um cliente em uma video locadora. O programa recebe como entrada quais filmes o cliente alugou e por quanto tempo. Ele entao calcula o valor devido, que depende de quanto tempo o filme foi alugado, e identifica o tipo do filme. Ha trés tipos de filmes: normais, infantis e lancamentos. Além de calcular os custos, 0 programa também calcula os pontos do locador freqiiente, que variam se o filme é um lancamento. Diversas classes representam os elementos da locadora. A seguir é mostrado um diagrama de classe para representé-los (Figura 1.1). Filme Locagio Cliente j i ccigoPrege:nt dasAlugaos: nt * 1 conta) Figura 1.1 Diagrama de classes das classes inciis. Apenas as caracteristicas mais importantes estéo mostradas. A notagéo 6 UML [Fowler, UML] Mostrarei o cédigo para cada uma destas classes, uma de cada vez. Filme Filme é apenas uma classe simples de dados. public class Filme { public static final int INFANTIL = 2; public static final int NORMAL = 0; public static final int LANGAMENTO_Novo = 1 private String titulo; private int _codigoPreco; public Filme (String Eitulo, int codigoPreco) ( _titule + eftulo; TeodigePreco = codigoPreso; } public int lerCédigoPrego() ( return _codigoPrego; } public void gravarcedigoPrego(int ara) { LeodigoPrego = arg; } ReraTonagio, uM Paimeino Exemeto 21 public String lerTitulo() { return _titulo; i Locagao Aclasse Locagao representa um cliente alugando um filme. class Locagao { private Filme _filme; private int _diasAlugadoa; public Locagdo (Filme filme, int diasAlugados) { filme = filme; _diasalugados {.asAlugados: ) public int lerDiasAlugados () { return _diasAlugados; ) public Filme lerFilme () { return filme: } Cliente A classe Cliente representa 0 cliente da locadora. Como as outras classes, possui da- dose métodos de acesso: class Cliente { private String _nome; private Vector _locagées = new Vector(); public Cliente (string nome) ( Me public void adicionarLocagao(Locagao arg) { _locagdes.add#lement (arg) ; } public String lerNome (){ return _nome; ye Cliente também tem 0 método conta, que produz uma relagao de despesas. A figura 1.2 mostra as interagGes deste método. O corpo do método esté a seguir. 22 Reraroracho unGenie umatocagio unFime T T conta | | | lerFime | lercedgoPrego woecdugatos | | = | | | “(para todo os augue) Figura 1.2 Interagdes do método conta. public String conta() { double quantiaTotal = 0; int pontosLocadorFreqiiente = 0; Enumeration locagdes = _locagdes.elenenta(); String resultado = "Registro de locagao de "+ lerNiome() + *\n"; while (locagées.hasMoreBlenenta()) ( double estaguantia = 0; Locagao cada = (Liocagao) locacdes-nextBlement () //determinar quantias para cada linha switch (cada. lerFilme() .lerCédigoPrego()) { case Filme. NORMAL: estaQuantia += 2; if (cada. lerDiasAlugados() > 2) estagquantia += (cada.lerDiasAlugados() - 2) * 1.5; break; case Filme. LANGAMENTO: estaQuantia += cada.lerDiasAlugados() * 3; break; case Filme. INFANTILE: estaguantia += 1.5; if (cada.lerDiasAlugados() > 3) estaguantia += (cada-lerDiasAlugados() - 3) * 1.5; break; } /Jadicionar os pontos do lecador freqiente pontosLocadorFregiiente ++; //adicionar bénus para uma locagao de langamentos por dois dias if ((cada.lerFilme().lerCédigoPrego() == Filme LANCAMENTO) && cada.lerDiasAlugados() > 1) pontoshocadorFreqiente ++; ReraTonagao, um Paimeino Exeurio 23 JJnostrar valores para esta locagao resultado += "\t" + cada.lerFilme().lerTitulo() + "\t" + String-valueOf (estaQuantia) + "\n"; quantiaTotal estaQuantia; } //adicionar linhas de rodapé resultado += "0 valor devido 6 "+ String.valueof (quantiaTotal) + "\n"; resultado += "Vocé ganhou " + String.valueOf (pontosLocadorFregiiente) + " pontes de locador fregtiente"; return reaultado; Comentarios Sobre o Programa Inicial Quais sao as suas impressbes a respeito do projeto desse programa? Eu o descreveria como mal projetado e, certamente, nao orientado a objetos. Para um programa sim- ples como esse, isto realmente nao importa. Nao ha nada errado com um programa simples feito de forma rpida e imperfeita. Mas caso esse seja um fragmento represen tativo de um sistema mais complexo, entéo nao o acho conveniente. Aquele longo método conta na classe Cliente faz coisas demais. Muito do que ele faz. deveria, na verdade, ser feito pelas outras classes Mesmo assim o programa funciona. Este nao é apenas um julgamento estético, uma aversao a um cddigo pouco elegante? Sim, até que queiramos alterar o sistema. Ocompilador nao se importa se o cédigo é elegante ou nao. Mas, quando alteramos o sistema, hé um humano envolvido, e humanos se importam. Um sistema mal pro- jetado é dificil de ser alterado. Dificil porque nao ¢ facil descobrir onde as alteraces sio necessédrias. Se for dificil descobrir o que alterar, ha uma grande chance de que 0 programador cometa um erro e introduza falhas. No caso do exemplo, imagine que os usuarios gostariam de fazer uma alteragao no software. Em primeiro lugar, eles querem a conta impressa em HTML, de modo que esta possa ser apresentada na Web, aderindo assim, completamente, ao jargao mais recente da rea. Considere o impacto que esta alteracao teria. Quando vocé olha 0 cédigo, pode ver que é impossivel reutilizar qualquer parte do método con- ta atual em uma versio HTML do método. Sua tinica alternativa é escrever por in teiro um novo método que duplique muito do comportamento do antigo método. E claro que isto nao é muito dispendioso. Vocé pode simplesmente copiar o antigo mé- todo conta e fazer nele quaisquer alteragdes que precisar. Mas 0 que acontece quando as regras de cobranca mudam? Vocé tem que conser- tar tanto o método conta quanto sua versao HTML, contaxtml e se assegurar de que as alteracées ficardo consistentes. O problema com copiar e colar cédigo aparece quando vocé tem que alterar este cédigo mais tarde. Se vocé estiver escrevendo um. programa que nao espera alterar, entdo recortar e colar nao trard problemas. Se o pro- grama tiver vida longa e for provavel que sofra alteracdes, entao recortar e colar é uma ameaca. Isso me conduz a uma segunda alteragao. Os usuérios querem fazer alteragdes no modo pelo qual classificam os filmes, mas ainda nao decidiram sobre as mudan- cas que irdo fazer. Eles tém varias mudangas em mente. Essas afetarao tanto o modo como 0s locadores serao cobrados pelos filmes quanto 0 modo pelo qual os pontos dos locadores freqiientes serao calculados. Como desenvolvedor experiente vocé tem. 24 EEATORAGAO. certeza de que, qualquer que seja o esquema pelo qual os usuarios se decidam, a tini- ca garantia que vocé teré é que, em seis meses, eles 0 mudarao novamente. O método conta é onde as alteragSes devem ser feitas para lidar com as mudan- as nas regras de classificacao e cobranga. Se, entretanto, copiarmos a conta para uma conta HTML, precisamos nos assegurar de que quaisquer mudangas serao completa- mente consistentes. Além disso, 4 medida que as regras se tornam mais complexas, seré mais dificil descobrir onde fazer as alterages e fazé-las sem cometer erros. Vocé pode ser tentado a fazer o menor ntimero possivel de alteracdes no progra- ‘ma; afinal, ele funciona bem. Lembre-se do velho ditado de engenharia: “se nao esta estragado, nao conserte.” O programa pode nao estar estragado, mas tem problemas. Esta dificultando sua vida, porque vocé acha dificil fazer as mudangas que seus usudrios querem. E af que a refatoragao entra. ty. Quando voce descobre que tem que acrescentar uma caracteristica a um programa e 0 c6- CPI digo desse programa nao esta estruturado de uma forma conveniente para tal, primeiro refatore o programa para facilitar o acréscimo da caracteristica e s6 depois faca a adigio. O Primeiro Passo na Refatoragao Sempre que executo alguma refatoracao, o primeiro passo é sempre o mesmo. Preci- so criar um s6lido conjunto de testes para aquele trecho de cédigo. Os testes sao es- senciais porque, embora eu siga refatoracdes estruturadas para evitar a maioria das chances de introdugao de falhas, ainda sou humano e ainda cometo erros. Assim, preciso de testes sdlidos. Devido ao fato do método conta produzir uma string, eu crio alguns clientes, atri- buo a cada um deles algumas locagdes de varios tipos de filmes e gero 0s relatérios. Entao fago uma comparagao entre as strings geradas e algumas strings de referéncia que tenha checado & mao. Monto todos estes testes de forma a poder executé-los a partir de um comando Java na linha de comando. Os testes demoram apenas alguns segundos para serem executados e, como voce verd, eu 0s executo freqiientemente. Uma parte importante dos testes é 0 modo através do qual eles geram seus resul- tados. Eles podem dizer “OK”, significando que todas as strings sao idénticas as strings de referéncia, ou imprimir uma lista de falhas: linhas que sairam diferentes das strings de referéncia. Desta forma, os testes testam a si proprios. E vital criar tes- tes deste tipo. Caso contrério, vocé acaba gastando tempo checando a mao os resul- tados dos testes contra as referéncias, o que termina por atrasar seu trabalho. Quando aplicamos a refatoracao, temos de nos apoiar nos testes. Eu confiarei nos testes para me dizer se introduzi alguma falha. E essencial para a refatoracao que vo- cé tenha bons testes. Vale a pena gastar o tempo que for necessario para a criagao dos testes, porque eles Ihe dao a seguranca que vocé precisa para alterar o programa mais tarde. Essa é uma parte t4o importante da refatoracao que irei detalha-la melhor no capitulo 4. IF Antes de vocé comecar a refatorar, verifique se tem um conjunto sdlido de testes. Esses testes devem testar a si proprios. ReraTonagao, um Paimeino Exeurto 25 Decompondo e Redistribuindo o Método Conta O primeiro alvo ébvio da minha atencao é 0 excessivamente longo método conta. Quando vejo um método como esse, procuro decompé-lo em partes menores. Partes menores de cédigo tendem a tornar as coisas mais gerencidveis. Elas s40 mais faceis de trabalhar e mover. A primeira etapa das refatoragdes neste capitulo mostra como divido 0 método longo e movo os pedagos para classes mais apropriadas. Meu objetivo é tornar mais facil escrever o método conta em HTML, com muito menos duplicacao de cédigo. Meu primeiro passo é encontrar um agrupamento ldgico de cédigo e aplicar ne- le 0 Extrair Método (100). Um candidato ébvio aqui é o comando switch. Ele parece constituir um bom trecho de cédigo para ser extraido do método conta e dar origem a.um novo método. Quando extraio um método, como em qualquer outra refatoracao, preciso saber © que pode dar errado. Se eu fizer a a extracdo mal feita, poderei introduzir falhas no programa. Entao, antes de fazer a refatoracao, preciso descobrir como fazé-la de mo- do seguro. Jé fiz esta refatoracao algumas vezes antes, entao escrevi o caminho segu- ro no catdlogo. Primeiro preciso procurar no fragmento por quaisquer variaveis que sejam de esco- po local no método que estamos examinando, as varidveis locais e parametros. Este seg- mento de cédigo usa duas: cada e estaQuantia. Dessas, cada nao é modificada pelo cédi- go alvo, porém estaQuantia o &, Posso passar qualquer variavel nao modificada como um parametro. Varidveis modificadas pelo cédigo precisam de mais atengao. Se houver apenas uma, posso usé-la como valor de retorno do método. A variavel temporaria es- taQuantia é inicializada com 0a cada passagem pelo laco e 86 é alterada pelo comando switch, Posso entao usé-la como valor de retorno do novo método a ser criado. As proximas paginas mostram o cédigo antes e depois da refatoragéo. O ebdigo antes da refatoracao é apresentado antes do cédigo resultante. O cédigo que estou ex- traindo do cédigo original e quaisquer alteragdes no novo cédigo que nao julgo serem muito dbvias estdo em negrito. No restante deste capitulo, manterei essa convencao public String conta() { double quantiaTotal = 0; int pontostocadorFregiente = 0; Enumeration locagdes = _locagées.elements(); String resultado = "Registro de locagao de " + lerNome() + "\n"; while (locagSes.hasMoreBlements()) { double estaQuantia = 0 Locagéo cada = (Locagao) locagées.nextBlement (); //determinar quantias para cada linha switch (cada. lerFilme() .lercédigoPrego()) { Filme .NORMAL: estaQuantia += 2; if (cada.lerDiasAlugados() > 2) estaguantia += (cada-lerDiasAlugados() - 2) * 1.5; brea) Filme. LANGAMENTO: estaQuantia += cada.lerDiasAlugados() * 3; 26 Reraroracho break; case Filme. INFANTIL: estaQuantia += 1.5; if (cada.lerDiasAlugados() > 3) estaguantia += (cada-lerDiasAlugados() - 3) * 1. /Jadicionar os pontos do lecador freqiente pontosLocadorFregiiente ++; /Jadicionar bénus para uma locagie de langamentos por dois dias if ((cada-lerFilme()lexcédigoPrego() == Filme-LANCAMENTO) && cada. lerDiasAlugados() > 1) pontosLocadorFreqiente ++; /Jnostrar valores para esta locagao resultado += "\t" + cada.lerFilme().lerTitulo() + "\t" + String.valueOf (estaQuantia) + "\n"; quantiaTotal += estaQuantia; } j/adicionar linhas de rodapé resultado += "0 valor devido é "+ String.valueOf (quantiaTotal) + "\n’ resultado += "Vocé ganhou " + String. valueOf (pontosLocadorFreqiente) +" pontos de locador fregiente"; return resultado; public String conta() { double quantiaTotal = 0; int pontosLocadorFregiiente = 0; Enumeration locagées = _locagées.elements(); String reaultado = "Registro de locagio de " + lerNome() + "\n"; while (LecagSes.hasMorezlements()) { double estaQuantia = 0; Locagio cada = (Locagdo) locagées.nextEle estaQuantia quantiaDe (cada); /Jadicionar os pontos do lecador freqiente pontosLocadorFregiiente ++; /Jadicionar bénus para uma locagdo de langamentos por dois dias if ((cada-lerFilme() -lerCédigoPrego() «= Filme LANCAMENTO) && cada.lerDiasAlugados() > 1) pontoshocadorFreqiente ++; JJnostrar valores para esta locagao resultado += "\t" + cada.lerFilme().lerTitulo() + "\t" + String.valueof (estaQuantia) + "\n"; quantiaTotal += estaQuantia; } //adicionar linhas de rodapé resultado += "0 valor devido é "+ String.valueof (quantiaTotal) + a ReraTonagao, um Paimeino Exeuco 27 resultado += "Voc€ ganhou " + String.valueOf (pontosLocadorFregiente) + " pontos de locador fregtiente"; return resultado; ) private int quantiaDe(Locagao cada) ( int estaguantia = 07 awitch (cada. lerFilne () -lercédigoPrego()) { case Filme NORMAL: estaguantia += 2; if (cada.lerDiasAlugados() > 2) eataguantia += (cada.lerDiasAlugados() ~ 2) * 1.5; break; case Filme .LANGAMENTO: estaQuantia += cada.lerDiasAlugados() * 3; break; case Filme. INFANTIL estaguantia += 1 if (cada.lerDiasAlugados() > 3) estaQuantia += (cada lerDiasAlugados() - 3) + 1.5: break: d return estaQuantia; , Sempre que realizo uma alteracao como esta, compilo e testo novamente o pro grama. No entanto, nao tive um comeco muito bom — os testes deram errado. Alguns valores dos testes me deram uma resposta errada. Fiquei confuso durante alguns se- gundose entao percebi o que havia feito. Tolamente, eu tinha tornado o tipo de retor- no de quantiaDe como int em vez de double: private double quantiaDe(Locac&o cada) ( double estaQuantia = 0; switch (cada.lerFilne() .lercédigoPrego()) { case Filme.NORMAL eotaguantia += 2; if (cada.lerDiasAlugados() > 2) estaQuantia += (cada.lerDiasAlugados() - 2) * 1.5; break; case Filme. LANCAMENTO: estaQuantia += cada.lerDiasAlugados() * 37 break; case Filme. INFANTIL: estaQuantia +2 1.5; if (cada-lerDiasAlugados() > 3) estaQuantia += (cada.lerDiasAlugados() - 3) * 1.5; break; ) return estaguantia; 28 Reraronacho Eo tipo de erro bobo que eu freqiientemente cometo, e que pode ser um tormen- to para rastrear. Neste caso especifico, Java converte doubles para ints sem reclamar, arredondando o niimero real [Java Spec]. Felizmente o erro foi fécil de encontrar nes- te caso, porque a alteracao foi muito pequena e eu tinha um bom conjunto de testes. Aqui esta a esséncia do proceso de refatoracao, ilustrada acidentalmente. Devido ao fato de cada alteracao ser tao pequena, todos os erros podem ser encontrados facil- mente. Vocé nao tem de gastar muito tempo depurando o cédigo, ainda que voce se- ja tao descuidado quanto eu. LK A refatoragao altera os programas em pequenos passos. Se vocé comete um erro, & y encontrar a falha. Por eu estar trabalhando com Java, preciso analisar o c6digo para descobrir o que fazer com as varidveis locais. Uma ferramenta, entretanto, pode tornar esta tarefa realmente simples. Tal ferramenta existe em Smalltalk, o Refactoring Browser. Com esta ferramenta, refatorar é muito simples. Simplesmente realco 0 cédigo, escolho “Extract Method...” no menu, digito um nome de método e est pronto. Além disso, a ferramenta nao comete erros bobos como o meu. Estou aguardando uma versio pa- ra Java!* Agora que dividi o método original em pedacos, posso trabalhar neles separada- mente. Nao gosto de alguns dos nomes de varidveis em quantiaDe, e este é um bom lugar para alteré-los. Aqui esté o cddigo original: private double quantiaDe(Locago cada) ( double estaguantia = 07 switch (cada.lerFilne() -lercédigoPreso()) { case Filme NORMAL: estaguantia += 2; if (cada. lerDiasAlugados() > 2) estaQuantia += (cada.lerDiasAlugados() - 2) + 1.5; break: case Filme. LANGAMENTO estaQuantia e= cada.lerDiasAlugados() * 37 break; case Filme. TNFANTIL estaguantia += 1.5; if (cada.lerDiasAlugados() > 3) estaQuantia (cada. lerDiasAlugados() - 3) * 1.5; break; } return estaQuantia; * N.deR. T: Por ocasiio da traducio deste livro para o portugués, tal ferramenta existe integrada a plataforma Eclipse® pa- ra desenvolvimento Java ou na forma de plugins para os ambientes NetBeans, Sun ONE Studio, JBuilder e Oracle9i JDeve- oper. ReraTonagao, um Paimeino Exe 29 E aquio cédigo modificado: private double quantiaDe(Locago umaLocagéo) { double resultado = 0; auitch (umalocagio.lerFilme() .lexcédigoPrego()) ( cage Filme NORMAL: resultado += 2; if (umaLocagio.lerDiasAlugados() > 2) resultado += (umabocagdo.lerDiasAlugados() - 2) * 1.5; break; case Filme. LANCAMENTO: resultado += umaLocagio.lerDiasAlugados() * 3; break; cage Filme, INFANTIL: resultado += 1.5; if (umaLocagio.lerDiasAlugades() > 3) resultado += (umabocag&o.lerDiasAlugados() - 3) * 1.5; break; } return resultado; d Assim que tiver terminado a renomeagao, compilo e testo para garantir que néo estraguei nada. Vale a pena renomear varidveis? Claro! Um bom cédigo deve transmitir com cla- reza 0 que ele est fazendo, e os nomes adeqiiados das varidveis sio importantissi- mos para um cédigo claro. Nunca tenha receio de alterar os nomes de coisas para melhorar a clareza. Com boas ferramentas de busca e substituicao, este trabalho nor- malmente nao é complicado. Tipagem forte e testes irao mostrar qualquer coisa que vocé nao perceber. Lembre-se DAK Qualquer tolo consegue escrever cédigo que um computador entenda, Bons programa- y dores escrevem eédigo que humanos possam entender. Um cédigo que comunica seu propésito é muito importante. Freqiientemente re- fatoro no momento em que estou lendo algum cédigo. Desta maneira, 4 medida que ganho conhecimento sobre o programa, insiro essa compreensao no cédigo para mais tarde, de modo que nao esquega o que aprendi. Movendo o Calculo do Total Quando olho o método quant iaDe, posso ver que ele usa informagao sobre a loca cao, mas nao sobre o cliente. class Cliente private double quantiaDe(Liocagao unabocagéo) { double resultado = 0; awitch (umatocagao. lerFilme() .lexcédigoPreco()) { case Filme .NORMAL: 30__Reraronacho resultado += 2; if (umaLocagao.lerDiasAlugados() > 2) resultado += (umaLocagdo.lerDiasAlugados() - 2) * 1.5; break; case Filme.LANGAMENTO: resultado break; case Filme. INFANTIL: umaLocagdo.lerDiasAlugades() * 3; resultado += 1.5; if (umaLocagdo.lerDiaeAlugados() > 3) resultado += (umaLocagdo. lerDiasAlugados() - 3) * 1.5; break; } return reaultado; d Isso imediatamente levanta minha suspeita de que o método est no objeto erra- do. Na maior parte dos casos, um método deve estar no objeto cujos dados ele usa. Assim, 0 método deve ser movido para a classe Locacao. Para fazer isso, uso Mover Método (142). Com isso, vocé primeiro copia o cédigo para Locacao, ajusta-o a nova localizacao e o compila, como se segui class Locagao « double lerPrego() ( double resultado = 0; switch (LerPilme() .lercédigoPrego()) { case Filme NORMAL: resultado += 2; if (lerDiasAlugados() > 2) resultado += (lerDiasAlugados() - 2) * 1.5 break; case Filme.LANCAMENTO: resultado += lerDiasAlugados() + 3; break: case Filme. INFANTIL: resultado += 1.5 if (lerDiasAlugados() > 3) resultado += (lerDiasAlugados() - 3) * 1.5; break; } return resultado; d Neste caso, ajustar 0 método a sua nova localizagao significa remover o parame- tro. Também renomeei o método quando realizei a movimentacao. Posso agora testar para ver se este método funciona. Para fazer isso, substituo a implementacao de Cliente.quantiaDe de modo a delegar a chamada para este novo método. clase Cliente private double quantiaDe(Locagao umaLocagao) { return umaLocagao.lerPrego() ; } ReraTonagio, uM Paimeino Exemeto 31 Agora posso compilar e testar para ver se estraguei alguma coisa. O proximo passo é encontrar cada referéncia ao método antigo e ajust4-la para usar 0 novo método, como se segue: class Cliente public String conta() { double quantiatotal = 0; int pontesLocadorFreqiente = 0; Enuneration locagdea = _locagSea.elementa (); String resultado = "Registro de locagao de " + lexNome() + "\a"s while (locages.hasHoreBlementa()) ( double estaguantia = 0; Locagao cada = (Liocagao) locagdea.nextBlement () estaQuantia = quantiaDe(cada); /Jadicionar os pontes do lecador freqiente pontosLocadorFregiente ++; /J/adicionar bénus para uma locagao de lancamentos por dois dias if ((cada.lerPilme(),lerCédigoPrego() == Filme.LANGAMENTO) && cada. lerDiasAlugados() > 1)pontosLocadorFreqiente ++; /Jnostrar valores para esta locagao resultado += "\t" + cada.lerFilme().lerTitulo() + "\t" + String.valueOf (estaQuantia) + "\n"; quantiaTotal += estaQuantia; } //adicionar linhas de rodapé resultado += "0 valor devido é "+ String.valueOf (quantiaTotal) + "\n"; resultado "Voc8 ganhou " + String.valueOf (pontosLocadorFregiiente) + "pontos de locador fre snte" ; return resultado; } Neste caso, este passo é facil porque acabamos de criar 0 método e ele esté em apenas um local. De modo geral, entretanto, vocé precisa realizar uma busca por to- dass classes que poderiam estar usando esse método: class Cliente.. public String conta() { double quantiaTotal - 0; int pontosLocadorFregiente = 0; Enumeration locagées = _locagées.elenenta() ; String reaultado = "Registro de locagao de " + lerNone() + *\n"; while (locagées.hasMorezlenents()) ( double estaguantia = 0; Lecagéo cada = (Locacdo) locag3es.nextzlement () ; estaguantia = cada-lerPrego(); /Jadicionar os pontos do locador freqiente pontoshocadorFregiente ++; 32 EEATORAGAO. } /Jadicionar bénus para uma locagao de lancamentos por dois dias if ((cada.lerFilme().lexCédigoPrego() == Filme.LANGAMENTO) && cada.lerDiasAlugados() > 1)pontosLocadorFreqiente ++; /Jmostzar valores para esta locagao "\t" + cada-lerFilme().lerTitulo() + "\t" + String-valueOf (estaQuantia) + "\n"; resultado quantiaTotal estaQuantia; } //adicionar linhas de rodapé resultado += "0 valor devido & "+ String.valueOf (quantiaTotal) + *\n"; resultado += "Vocé ganhou " + String.valueOf (pontosLocadorFregiente) + " pontos de locador fregiiente"; return resultado; Apés realizar a alteracao (Figura 1.3), a proxima coisa a se fazer é remover o mé- todo antigo. O compilador deve me dizer se esqueci alguma coisa. Testo ento para ver se estraguei alguma coisa. Locagio Cliente Filme 1 ee Ea azAlugadosint cbioPrego:nt were) conta) Figura 1.3 Estado das classes apds a movimentago do método de cobranga As vezes deixo 0 método antigo e este delega a chamada para 0 novo método. Is- s0 6 titil se o método antigo for um método piiblico e eu nao quero alterar a interface da outra classe. HA certamente algo mais que eu gostaria de fazer com Locagao.lerPrego mas, por enquanto, o deixarei assim e retornarei ao método Cliente .conta. public String conta() { double quantiaTotal = 0; int pontosLocadorFreqiente = 0; _locages. elements () ; Enumeration locacées String resultado = "Registro de locagao de " + lerNome() + "\n"; while (locagSes.hasMoreBlements()) { double estaQuantia = 0; Locagao cada = (Locagao) locagdes.nextBlement () ; estaguantia = cada.lerPreco(); /Jadicionar os ponte do locador freqiente pontosLocadorFregiiente ++; /Jadicionar bénus para uma locagdo de langamentos por dois dias if ((cada.lerFilme().lercédigoPrego() == Filme-LANCAMENTO) && cada.lerDiasAlugados() > 1) pontoshocadorFregilente ++; ReraTonagao, um Paimeino Exeurio 33 , Jimostrar valores para esta locagao resultado += "\t" + cada.lerFilme().lerTitulo() + "\t" + String-valueOf (estaQuantia) + "\n"; quantiaTotal estaQuantia; } J/adicionar linhas de rodapé resultado "0 valor devide 6 "+ String.valueof(quantiaTotal) + "\n"; resultado += "Vocé ganhou " + String.valueOf (pontosLocadorFreqiente) + " pontos de locador fregilente"; return resultado; A proxima coisa que me aflige é que estaQuantia é agora redundante. Ela recebe © resultado da chamada de cada.lerPreco e, depois disso, ndo é mais alterada. Assim, posso eliminar estaQuantia usando Substituir Varidvel Tempordria por Consulta (108): public String conta() { d double quantiaTotal = 0; int pontosLocadorFreqiente = 0; Enumeration locagdee = _locagdes.elements (); String reaultado = "Registro de locagao de " + lezNome() + "\n" while (locagées.hasoreflements()) { Locagao cada = (Locagao) locagdes.nextBlement () ; /Jadicionar os pontos do locador freqiente pontosLocadorFregiiente ++; //adicionar bénus para uma locagdo de langamentos por dois dias if ((cada.lerPilme(),lerCédigoPrego() == Filme.LANGAMENTO) && cada. lerDiasAlugados() > 1)pontosLocadorFreqiente ++; Jimostrar valores para esta locagao resultado += "\t" + cada.lerFilme().lerTitulo() + "\t" + String.valueot (cada.1erPrego()) + "\n"; quantiaTotal += cada.lerPrego(); } /fadicionar linhas de rodapé resultado += "0 valor devido é "+ String.valueOf(quantiaTotal) + "\n"; "Voc8 ganhou " + String.valueOf (pontosLocadorFreqiiente) +" pontos de locador freqiente"; return resultado; resultado Assim que tiver feito essa alteracao, compilo e testo para me certificar de que nao estraguei nada. Tanto quanto possivel, gosto de me livrar de varidveis temporérias como essa. Varidveis temporarias sio muitas vezes um problema pelo fato de fazerem com que muitos parametros tenham de ser passados, quando nao precisariam ser. Vocé pode facilmente perder o registro do motivo pelo qual elas estao la. Variéveis temporarias 34 EEATORAGAO. sdo particularmente traicoeiras em métodos longos. E claro que ha um preco a ser pa- go em termos de desempenho. O preco da locago tem agora de ser calculado duas vezes. Mas ¢ facil otimizar a classe Locacao, e vocé pode otimizar muito mais efeti vamente quando 0 cédigo esta fatorado de modo apropriado. Falarei mais sobre es- ta questao posteriormente, em “Refatoracao e Desempenho”. Extraindo os Pontos dos Locadores Freqiientes O proximo passo é fazer algo semelhante para os pontos dos locadores freqiientes. As regras variam com o filme, embora ocorra menos variag4o do que com a cobran- a. Primeiro precisamos usar Extrair Método (100) sobre a parte do cdigo dos pontos dos locadores freqiientes (em negrito): public String conta() { double quantiaTotal = 0; int pontosLocadorFreiente = 0; Enuneration locacdes = _locacdes.elementa (); String resultado = "Registro de locagéo de " + lerNome() + *\n"; while (locagdes-hastiorezienenta()) { Locagae cada = (Locagao) locagdes.nextBlement () /Jadicionar 08 pontos do locador freqiente pontosLocadorFreqiente ++7 //adicionar bénus para uma locagio de langamentos por dois dias Af ((cada.lerFilme().lerCédigoPrego() == Filme LANGAMENTO) && cada. lerDiasAlugados() > 1) pontoslocadorFreqiente ++; /Imostrar valores para esta locagao resultado += "\t" + cada.lerFilme().lerTitulo() + "\r" + String.valueOf (cada.lerPrego()) + "\n"; quantiaTotal += cada.lerPrego(); } J/adicionar linhas de rodapé resultado += "0 valor devido é "+ String.valueof(quantiaTotal) + "\n"; resultado "Vocé ganhou " + String.valueOf (pontosLocadorFreqiente) +" pontos de locador freqiente"; return resultado; d Mais uma vez, olhamos 0 uso das variveis de escopo local. Mais uma vez, a va- ridvel cada é usada e pode ser passada como um pardmetro. A outra variavel tem- poraria é pontosLocadorFreqiente. Neste caso, pontosLocadorFreqiiente tem realmente um valor anterior. Entretanto, o corpo do método extraido nao Ié 0 va- lor, de modo que nao precisamos pass4-lo como um parametro desde que usemos uma atribuicao adicional. ReraTonagao, um Paimeino Exeurio 35 Executei a extracdo, compilei, testei e entao movi, compilei e testei novamente. Coma refatoragao, pequenos passos sao os melhores. Dessa forma, menos coisas ten- dem a dar errado. class Cliente public String conta() { double quantiaTotal = 0; int pontostocadorPreqiente = 0; Enumeration locagdes = _locagdes.elenenta(); String resultado = "Registro de locagdo de " + lerNome() + "\n" while (locagées.hasMorezlements()) { Locaco cada = (Locag&o) locagdes.nextBlement () ; pontosLocadorFreqiente += cada.lerPontosLocadorFreqiente() ; //nostrar valores para esta locagao resultado += "\t" + cada.lerFilme().lerTitulo() + "\t" + String-valueof (cada.lerPrego()) + "\n"; quantiaTotal += cada.lerPrego(); } /Jadicionar linhas de rodapé resultado += "0 valor devido € "+ String.valueOf (quantiaTotal) + "\n"; resultado += "Vocé ganhou " + String.valueof (pontosLocadorFreqiente) +" pontos de locador fregiente"; return resultado; class Locagao. int lerPontosLocadorFreqtente() { if ((lerFilme() .lercédigoPrego() Filme.LANGANENTO) && lerDiasAlugados() > 1) return 2; else return 1; d Resumirei as alteragdes que acabei de fazer com alguns diagramas UML antes e depois das alteragGes (Figuras 1.4 a 1.7). Novamente, os diagramas anteriores & mu- danga vém primeiro. ay Fine 1 = x Le otc ctr ca) vePat) Figura 1.4 Diagrama de classe de antes da extrago e movimentagao do célculo dos pontos dos locadores freqientes. 36 Reraronacho uments umatocagio unFine T T conta — \ | “partodas soaps i leer | vcd veoistumds | | aaa | | | Figura 1.5 Diagramas de sequéncia antes da extragdo e movimentago do célculo dos pontos dos locadores. freqientes. Locagio nto Fim 1 angst * a legal) ) aa lrPonosLocadorreqente) Lael Figura 1.6 Diagrama de classe apés a extragio e movimentagGo do céleulo dos pontos dos locadores freqlientes. utente umalocagio unFline T T conta | | *Ipra todas as locagées] lercodgoPrego lero onireeie \ 1 cadre it Figura 1.7 Diagramas de seqiéncia apés a extragio e movimentagéo do céleulo dos pontos dos locadores freqlientes. ReraTonagio, um Paimeino Exeurio 37 Removendo Variaveis Temporarias Como sugeri antes, varidveis tempordrias podem ser um problema. Elas sao titeis apenas dentro de suas préprias rotinas, e desta forma encorajam rotinas longas e complexas. Nesse caso temos duas varidveis tempordrias, ambas sendo usadas pa- ra obter um total das locagdes associadas ao cliente. Tanto a versdo ASCII quanto a HTML requerem esses totais. Gosto de usar Substituir Varidvel Temporéria por Con- sulta (108) para substituir quantiaTotal e pontosLocadorFregiiente por métodos de pes- quisa. Pesquisas si acessiveis por qualquer método da classe e dessa forma enco- rajam um projeto mais limpo, sem métodos longos e complexos. Clase Cliente.. public String conta() { } double quantiaTotal = 0; int pontosLocadorFreqiente = 0; Enumeration locagées = _locagdes.elements (); String resultado = "Registro de locagao de " + lerNome() + "\n"; while (locagSes.hasMoreBlements()) { Locagao cada = (Locagao) locagdes.nextBlement (); pontosLocadorFregiiente += cada. lerPontosLocadorFreqiente () ; /Jnostrar valores para esta locagao "\t" + cada.lerFilme().lerTitulo() + "\e" + String-value0f (cada.lerPrego()) + "\n"; quantiaTotal += cada.lerPrego(); resultado //adicionar linhas de rodapé resultado += "0 valor devido 6 "+ String.valueof (quantiaTotal) + "\n"; resultado += "Vocé ganhou " + String.valuedf (pontestocadorFregiiente) +" pontos de locador fregtiente"; return resultado; Comecei substituindo quant iaTotal por um método prego na classe Cliente: clase Cliente.. public String conta() { int pontosLocadorFreqiente = Enumeration locagdee = _locagdes.elements (); String reaultado = "Registro de locagao de " + lerNone() + *\n"; while (locagées hasMorezlenents()) ( Lecagdo cada = (Locagdo) locagdes.nextzlement () ; pontoshocadorFreqiente += cada. lerPontosLocadorFregiente () ; JJnostrar valores para esta locagao resultado += "\t" + cada.lerFilme().lerTitulo() + "\t" + String.valueof (cada.lerPrego()) + "\n"; } //adicionar linhas de rodapé resultado += "0 valor devido é "+ String.valueOf (lerPregoTotal ()) +\n"s 38__Reraronacho resultado += "Voc8 ganhou " + String.valueOf (pontosLocadorFregiente) + " pontos de locador freqiente"; return resultado; private double lerprecorotal () { double reaultado = 0; Enumeration locagdes = _locagdes.elements () while (locagées hasMorezienents()) ( Lecagéo cada = (Locacdo) locag3es.nextzlement () ; resultado += cada.lerPrego() ; } return resultado; } Esse no 6 0 caso mais simples de Substituir Varidvel Temporéria por Consulta (108), quantiaTotal foi atribuida dentro do lago, entao tenho que copiar o lago para 0 método de pesquisa. Apés compilar e testar essa refatoragao, fiz a mesma coisa para pontosLoca- dorFreqiente: class Cliente. public String conta() { int pontosLocadorFregliente = 0; Enumeration locagSes = _locagSee.elements(); String reaultado = "Registro de locagao de " + lerNone() + *\n"; while (lecagdes.hasMoreBlements()) { Locagae cada = (Locagao) locagdea.nextBlement (); pontoshocadorFreqi ente ++ cada. lerPontosLocadorFreqiente |) ; /Jnostrar valores para esta locagao resultado += "\t" + cada.lerFilme().lerTitulo() + "\t" + String.valueof (cada.lerPrego()) + "\n"; } //adicionar linhas de rodapé resultado += "0 valor devido € "+ String.valueOf (lerPregoTotal ()) + \n"; resultado += "Voc8 ganhou " + String.valueOf (pontosLocadorFregiente) + " pontos de locador fregiente"; return resultado; clase Cliente.. public String conta() { Enumeration locagdes = _locagdes.elementa(); String resultado = "Registro de locagao de * + lerNome() + "\a"s while (locages.hasHorezlements()) ( Locagio cada = (Locagéo) locagées.nextElement (); //nostrar valores para esta locagao resultado += "\t" + cada.lerFilme().lerTitulo() + "\t" + String-valueof (cada.lerPrego()) + "\n"; ReraTonagao, um Paimeino Exerto 39 /fadicionar linhas de rodapé resultado + \a" resultado "0 valor devido € "+ String.valueOf (1erPregoTotal ()) "Vos ganhou " + String.valueof (lerTotalpontostocadorFregiente()) + " pontos de locador fr return resultado; private int lerTotalPontosLocadorFreqiente() { int reaultado = 0; Enumeration locages = _locagéee.elements (); while (lecages.hasMorezlements()) { Locagio cada = (Locagdo) locagées.nextBlement () ; resultado += cada.lerPontosLocadorFrequente () ; } return resultado; } As Figuras 1.8 a 1.11 mostram as alteragdes causadas por essas refatoragdes nos diagramas de classe e interacao para o método conta. Locagio lente Fime 1 asAtvgadosint * | ctrdgnPrgo: it lxProgo() conta) a lePonnsLocadorequete) Figura 1.8 Diagrama de classes antes da extragdo dos totais umclnte umaLocacao unFine T conta | * [para todas as cages] lerPrego leCédigor reco lePontost scaorFeqiente lerCbdiorego ——s Figura 1.9 Diagrama de seqiiéncia antes da extragdo dos totais. 40__Reraronacho Locagio Cliente Fime 1 ashgatosint * conta) cecigoPreo: in lePrgo() irPregaT. ) lento. ccasorreqene) iret. ocadorreqera,) Figura 1.10 Diagrama de classes apés a extragdo dos totais. umctene umaLocarao unFine conta — leregoToal | | (pra odas as locagées] Prego lerTotaPotosocadrFroqiente | <—_ | | | para todas as cages} lerPortosL ocadorrequente —— secitpreo —_| Figura 1.11. Diagrama de seqiiéncia apés a extragdo dos totais. Vale a pena parar para pensar um pouco sobre a tiltima refatoragao. A maioria das refatoragdes reduz a quantidade de cédigo, mas essa aumenta. Isso ocorre por- que Java 1.1 requer muitos comandos para implementar um lago de acumulagao. Mesmo um simples lago desse tipo, com uma tinica linha de cédigo por elemento, precisa de seis linhas de suporte. E um cédigo dbvio para qualquer programador, mas s4o muitas linhas do mesmo modo. Aoutra preocupagao com esta refatoragao recai sobre o desempenho. O cédigo antigo executava o lago “while” uma vez, enquanto que o cédigo novo o executa trés vezes. Um laco “while” muito demorado poderia prejudicar 0 desempenho. Muitos programadores nao executariam essa refatoracdo simplesmente por esse motivo. Perceba, contudo, as palavras se e poderia. Até que eu trace o perfil da aplicacao, nao posso dizer quanto tempo é necessério para o lago processar ou se o lago é chamado com freqiiéncia suficiente para afetar o desempenho geral do sistema. Nao se preo- cupe com isso ao refatorar. Quando vocé for otimizar tera que se preocupar com is- so, mas vocé entao estaré em uma posicéo muito melhor para fazer algo a respeito, e tera mais opcées para otimizar efetivamente (veja a discussdo mais adiante). Essas consultas esto agora disponiveis para qualquer cédigo escrito na classe Cliente. Elas podem ser facilmente adicionadas a interface da classe, se outras partes ReraTonagio, uM Paimeino Exemeio 41 do sistema precisarem dessa informagao. Sem consultas como essas, outros métodos tém que lidar com 0 conhecimento a respeito das locacdes e com a criagao de lagos. Em um sistema complexo, isto levaria a muito mais cédigo para escrever e manter. Vocé pode ver a diferenca imediatamente com a contaHtmi. Estou agora no pon- to onde tiro meu chapéu de refatoracao e coloco meu chapéu de adicao de funcdes. Posso escrever contaitm! como se segue e adicionar testes apropriados: public String contaHitml() { Enumeration locagdes = _locagées.elements () String resultado = "bocagées de " + lerNome() + "

\n"; while (locag3es.hasMoreBlements()) ( Locagao cada = (Locacao) locagdes.nextBlement () ; /Jnostrar valores para cada locagéo resultado += cada.lerFilme().lerTitulo() +": "+ string.valueof(cada.lerPrego()) + "
\n"; } /Jadicionar linhas de rodapé resultado += "

\n"; resultado += "Nesta locagdo vocé ganhou " + String -valueOf (lerTotalPontosLocadorFregiiente()) + " pontos de locador freqiente

"; return resultado; d Apésextrair os célculos, posso agora criar 0 método contalHim! e reutilizar todo 0 c6- digo de célculo que estava no método original do método conta. Nao copiei e colei, de modo que seas regras de célculo mudarem s6 tenho um local no cédigo aonde ir. Qual- quer outro tipo de conta seré realmente rapido e facil de preparar. A refatoracao nao de- morou muito. Gastei a maior parte do tempo descobrindo 0 que 0 cédigo fazia e eu te- ria que fazer isso de qualquer maneira. Algum cédigo é copiado da versto ASCII, devido principalmente ao estabelecimen- to do lago. Alguma refatoragao adicional poderia limpar isso. Extrair métodos para ca- becalho, rodapé e linhas de detalhe é um caminho que eu poderia tomar. Vocé pode ver como fazer isto no exemplo de Criar um Método Padrito (293). Mas agora os usuarios es- tao clamando de novo. Eles estao se aprontando para alterar a classificacao dos filmes na loja. Ainda nao esté claro que mudanas eles querem fazer, mas parece que novas classificagGes serao introduzidas, e as existentes poderiam ser alteradas. As designacdes. dos custos e pontos de locadores freqiientes dessas classificagdes ainda estao por ser de- terminadas. No momento, fazer esse tipo de alteragao é pouco pratico. Tenho que entrar nos métodos de custos e pontos de locadores freqiientes e alterar 0 cédigo condicional para fazer as alteraces nas classificacdes dos filmes. De volta ao chapéu de refatoragao. Substituindo a Légica Condicional no Cédigo do Prego com Polimorfismo A primeira parte deste problema é aquele comando switch. £ uma ma idéia fazer um switch baseado em um atributo de outro objeto. Se vocé tiver que usar um comando switch, ele deve ser usado sobre seus préprios dados, nao nos de outros. EEATORAGAO. class Locagao. double lerPrego() { double resultado = 0; switch (lerFilme() .lercédigoPreco()) { case Filme NORMAL: 2; if (lerDiasalugados() > 2) resultado += (lerDiasAlugados() - 2) * 1.5 break; case Filme. LANGAMENTO: resultado += lerDiasAlugados() * 3; break; case Filme. INEANTIL: resultado resultado += 1.5; if (erDiasAlugados() > 3) resultado += (lerDiasAlugados() - 3) * 1.5, break; } return resultado; } Isto significa que ler Prego deve ser movido para a classe Filme: class Filme. double lerPrego(int diasAlugados) { double resultado = 0; switch (lexCédigoPrego()) { case Filme NORMAL: resultado += 2; if (diasAlugados > 2) resultado += (diasAlugados - 2) * 1.5; breal case Filme. LANGAMENTO: resultado += diasAlugados * 3; break; case Filme. INFANTIL: resultado += 1.5; if (diasAlugados > 3) resultado += (diasAlugados - 3) * 1.5; break; } return reaultado; d Para que isso funcione, tive que passar a duracao da locagao, 0 que, é claro, é um dado da classe Locacao. O método efetivamente usa dois dados: a duragao da loca- 0 e 0 tipo do filme. Por que eu prefiro passar a duragao da locacao para a classe Fil- me em vez do tipo do filme para a classe Locagao? Porque as alteragdes propostas si0 todas relacionadas a adi¢ao de novos tipos. Informagoes sobre tipos geralmente ten- dem a ser mais volateis. Se eu alterar o tipo do filme, nao quero com isso afetar as ou- tras classes, entao prefiro calcular 0 custo dentro da classe Filme. ReraTonagao, um Paimeino Exenrio 43 Compilei o método na classe Filme e entao alterei LerPrego na classe Locacao para usar 0 novo método (Figuras 1.12 e 1.13): = Cente diasAlugados: int a am leet) eons) InPontosocadrragiens) leat) lent oadeqere i Filme g9Prepe:nt Figura 1.12 Diagrama de classes antes de mover os métodos para a classe Filme 7 Cente * AlasAtugados nt an lePreco) contain) lePontost ocadereqbete) lePregootal) leoaPontoaocaderreqdente) 1 Fine igoP rego: lerPrego (as: lerPoiosocador regent (as: Figura 1.13 Diagrama de classes apés a mover os métodos para a classe Filme. class Locagao. double lerPrego() { return _filme,lerPreco(_diasAlugados) ; } Assim que tiver movido o método lerPreco, farei o mesmo com 0 célculo de pon- tos de locadores freqiientes. Isto mantém ambos os métodos que variam com 0 tipo de fita, junto a classe que possui o tip. class Locagao .. int lerPontosLocadorFregiente () { 44 Reraronacho if ((lerFilme ().lerCédigoPrego () == Filme.LANGAMENTO) && LerDiasAlugados () > 1) return 2; else return 1; } class Locagao. int lerPontosLocadorFreqiiente() { return _filme. lerPontosLocadorFreqiente(_diasAlugados) ; } class Filme int lerPontosLocadorFregiiente(int diasAlugados) { if ((lercédigoPrego() == Filme.LANCAMENTO) && diasAlugados > 1) return 2; else return 1; } E finalmente... Heranga Temos diversos tipos de filmes que tém diferentes maneiras de responder & mesma solicitagao. Isso parece um trabalho para subclasses. Podemos ter trés subclasses de Filme, cada uma das quais podendo ter sua prdpria versao de custos (Figura 1.14). Filme lerPrego Filme Normal Filme infant Flime Langamento Praga lerPrego lerProgo Figura 1.14 Usando heranga na classe Filme. Isto me permite substituir o comando switch usando polimorfismo. Infelizmente, isso apresenta uma pequena falha ~ nao funciona. Um filme pode mudar sua classi- ficago durante sua existéncia. Um objeto nao pode alterar sua classe durante sua existéncia. Todavia, hé uma solugao: o padrao State [Gangue dos Quatro]. Com o pa- drao State as classes se parecem coma figura 1.15. ReraTonagao, um Paimeino Exeurio 45 Filme Prego vere 9 1 | ere ‘etumpreglerPrego Prego Normal Prego Langamento lePrego lerPrego lerPrago Figura 1.18 Usando o padrao State em uma classe Filme. Acrescentando a referéncia a classe Preco, podemos criar as subclasses a partir dessa e alterar 0 preco sempre que precisarmos. Se vocé estiver familiarizado com os padrdes da Gangue dos Quatro, pode fi- car imaginando, “Isto é um State ou uma Strategy?” A classe Prego representa um algoritmo para o calculo do preco (caso em que eu prefiro chamé-la formadorPre- 0 ou estratégiaPreco) ou um estado do filme (Star Trek X é um langamento). Nesse estagio, a escolha do padrao (e do seu nome) reflete como vocé quer pensar a res- peito da estrutura. No momento, estou pensando nela como o estado de um filme. Se mais tarde decidir que o padrao Strategy comunica melhor minha intencao, irei refatorar mudando os nomes. Para introduzir o padrao State, usarei trés refatoracdes. Primeiro, moverei o com- portamento de enumeracao para o padrao State com Substituir Enumeragao pelo Pa- drao State/Strategy (195). A seguir, posso usar Mover Método (125) para mover 0 co- mando switch para a classe prego. Finalmente, usarei Substituir Condigdo por Polimor- ‘fismo (218) para eliminar 0 comando switch, Comego com Substituir Enumeragio pelo Padrao State/Strategy (195). O primeiro passo é usar Auto-Encapsular Campo (150) na enumeragao para garantir que todas as referéncias a ela passem por métodos de leitura e de gravacao (métodos get e set). De- vido ao fato da maior parte do cédigo vir de outras classes, a maioria dos métodos ja usa os métodos ler. Entretanto, os construtores acessam 0 cédigo do prego: class Filme. public Filme(String titulo, int codigoPreco) { titulo = titulo; LcodigoPrego = codigoPreso; } Posso usar 0 método gravar em vez disso: class Filme public Filme(String titulo, int codigoPreco) { titulo = titulo; gravarCédi goPrego(codigoPrego) ; 46 __Reraronacho ‘Compilo e testo para me assegurar de que nao estraguei nada. Agora adiciono as novas classes. Fornego 0 comportamento enumerado no objeto prego. Fago isso com um método abstrato na classe do prego e métodos concretos nas subclasses: abstract clase Prego { abstract int lercédigoPreco() ; } class PregoInfantil extends Prego { int lerCédigoPrego() { return Filme. INFANTIL; ) } class Pregobangamento extends Prego ( int lercédigoPreco() { return Filme. LANCAMENTO; } } class PregoNormal extends Prego { int lercédigoPrego() { return Filme.NORMAL; ) } Neste momento, posso compilar as novas classes. Agora preciso alterar os métodos de acesso ao cédigo do preco da classe Filme para que usem a nova classe: public int lerCédigoPrego () { return _codigoPrego; } public void gravarC6digoPrego (int arg) { _codigoPreco = arg; d private int _codigoPrego; Isto significa substituir 0 campo de c6digo do prego por um campo de prego e al- terar os métodos de acesso: clase Plime. public int lercodigopreco() ( return _prege.lercedigoPrego() ; ) public void gravarcedigoPrego(int ara) { switch (arg) { case NORMAL: “prego = new Pregotlormal (); break; case INPANTIL: _prego = new PregoInfantil(); break; ReraTonagao, um Paimeino Exeuo 47 case LANCAMENTO: _prego = new PregoLangamento(); break; default: throw new IllegalArgumentException("Cédigo de Prego Incorreto"); d private Prego prego; Posso agora compilar e testar, e 0s métodos mais complexos nao percebem que 0 mundo mudou. Agora aplico 0 Mover Método (125) em lerPrego: class Filme double lerPrego(int diasAlugados) { double resultado = 0; switch (lerCédigoPrego()) { case Filme.NORMAL: resultado if (diasAlugados > 2) resultado += (diasAlugados - 2) * 1.5; break; case Filme. LANGAMENTO: resultado += diasAlugados ¥ 3; break; case Filme. INFANTIL: resultado += 1.5; if (diasAlugados > 3) resultado += (diasAlugados - 3) * 1.5; break; } return resultado; ) E simples mover: clase Filme. double lerPrecolint diasAlugados) — { return _preco.lerPreco (diasAlugados) ; d clase Prego. double lerPrego(int diasAlugados) double resultado = 0; switch (lercédigoPreco()) { ‘case Filme.NORMAL: resultado if (diaoAlugados > 2) resultado += (diasAlugados - 2) * 1. 48 __Reraronacho break; case Filme. LANCAMENTO: resultado += diasAlugados * 3; break; case Filme. INFANTIL: resultado += 1.5; if (diasAlugados > 3) resultado += (diasAlugados - 3) * 1.5; break; } return reaultado; d Assim que esteja movido, posso comegar a usar Substituir Comando Condicional por Polimorfismo (218): class Prego double lerPrego(int diasAlugados) { double resultado = 0; switch (lerCédigoPrego()) { case Filme.NORMAL: resultado if (diasAlugados > 2) resultado += (diasAlugados - 2) * 1.5; break; case Filme. LANCAMENTO resultado += diasAlugados ¥ 3; break; case Filme. INFANTIL: reaultado += 1.5 if (diasAlugados > 3) resultado += (diasAlugados - 3) * 1.5; break; } return resultado; } Faco isso tomando uma das alternativas do comando case por vez e criando no seu lugar um método sobrescrito (override). Comeco com PregoNormal: class PregoNormal double lerPrego (int diasAlugados) { double resultado = 2; if (iasalugados > 2) resultado += (diasAlugados - 2) * 1.5; return resultado; } Isso anula o case correspondente na superclasse, a qual deixo como est. Compi- lo e testo essa alteracao e entao vou para o proximo case. Compilo e testo novamen- te. (Para assegurar que estou executando 0 codigo da subclasse, gosto de deliberada- mente colocar uma falha e executé-lo para garantir que o teste falhe. Nao que eu se- ja paranéico ou algo parecido). ReraTonagao, um Primeino Exeuo 49 class PregoInfantil double lerPrego (int diasAlugados) { double resultado = 1.5; if (diasAlugados > 3) (diasAlugados - 3) * 1.5; return resultado; resultado clase Pregotancamento . double lerPreco (int diasAlugados) { return diasAlugados * 3; d Quando tiver terminado todos os pasos, declaro 0 método Preco.lerPreco como abstrato: class Prego abstract double lerPrego (int diasAlugados) ; Agora posso executar 0 mesmo procedimento com lerPontosLocadorFre- qtiente: class Filme int lerPontosLocadorFreqiente(int diasAlugados) ( if ((lercédigoPreco() == Filme.LANGAMENTO) && diasAlugados > 1) return 2; else return 1; ) Primeiro, movo 0 método para a classe Prego: Clase Filme . int lerPontostocadorFregiiente (int diasAlugados) ( return _prego. lerPontosLocadorfreqiente (diasAlugados) ; } Clase Prego . int lerPontostocadorFregiente (int diasAlugados) ( if ({ lerc6digoPrego () == Filme.LANGAMENTO) && (diasAlugados > 1) return 2; else return 1; } Neste caso, entretanto, nao torno o método da superclasse abstrato. Em vez dis- so, crio um método de sobrescrita somente para os langamentos e deixo um método definido (como default) na superclasse: Class PregoLangamento int lerPontosLocadorFreqiente (int diasAlugados) { return (diasAlugados > 1)? 2:1; 50 RleraTonagho Class Prego int lerPontosLocadorFreqiente (int diasAlugados) { return 1; } Aplicar o padrao State foi um esforgo e tanto. Valeu a pena? O ganho é que, se eu alterar qualquer comportamento do preco, acrescentar novos precos ou acrescentar comportamento adicional dependente do prego, essa mudanga ser4 muito mais facil de ser feita. O resto da aplicacao nao fica sabendo a respeito do uso do padrao State. Para a pequena quantidade de comportamento, fungao do prego, que tenho no mo- mento, isso nao é grande coisa. Em um sistema mais complexo, com uma diizia ou mais de métodos dependentes do prego, isso faria uma grande diferenga. Todas es- sas alteracdes foram pequenos passos. Parece lento escrever dessa forma, mas nao ti- ve que abrir o depurador nenhuma vez, de modo que o proceso realmente fluiu ra- pidamente. Levou muito mais tempo para eu escrever esta secao do livro do que pa~ ra alterar 0 cédigo. Completei agora a segunda refatoragao importante. Vai ser muito mais fécil alte- rar a estrutura de classificagao de filmes e mudar as regras de cobranga e o sistema de pontuagao de locadores freqiientes. As Figuras 1.16 e 1.17 mostram como 0 pa- drao State trabalha com a informagao de preco. vumiente umaloccagio unFilme umPrego ; 1 T cova ; \ ' ‘erro 1 nt ; \ \ para tads soaps Prego ! ! \ \ lePrepo(das) lerego(dias) 1 a I Ipara todas as lcagées]lorPontosLocadoFrequente > reece ———7 lerPonos.ocadorFreqiente(is) Figura 1.16 InteragSes usando o padrio State. Reraronagao, uM Primeino ExemeLo 51 Filme tuo: sting 1 lerPrego(as: int) lerrego(is: int) Ip cobsleneteteneltertt lerPortosLocadorFrequenteiasint 1 Cd Pregolnantit PregoNormal lesPregoasint) lePregoiiasint) PregoLangamento lePregoias: int leona ocadorFrequento(as: ty = ‘lente asus * rome: Seng lero) cental) lePonoa. ocadrFeqiert) certain () lePrgoTota() lerotaPontoa ccadorreqiene() Figura 1.17 Diagrama de classes apés a adigéo do padido State Consideracées Finais Este é um exemplo simples, mas espero que Ihe dé uma idéia do que é refatoragao. Usei diversas refatoragdes, incluindo Extrair Método (100), Mover Método (125) e Subs- tituir Comando Condicional por Polimorfismo (218). Todas essas levam a responsabilida- des melhor distribuidas e c6digo em que é mais facil realizar manutencdes. Realmen- te parece diferente do estilo de cédigo procedural, e demora um pouco para se acos- tumar, porém, uma vez que vocé tenha se acostumado a ele, é dificil voltar aos pro- gramas procedurais. Alico mais importante deste exemplo é 0 ritmo da refatoracdo: teste, pequena alteragao, teste, pequena alteracdo, teste, pequena alteragao. E esse ritmo que permi- te a refatoracao andar rapidamente e com seguranca. Se vocé chegou até aqui, deve entender agora do que trata a refatoragao. Pode- mos agora avancar para alguns conceitos basicos, principios e teoria (embora nao de- CAPITULO 2 Principios da Refatoracao Ja refatoracao. Agora é hora de voltar e ver os principios chave da refatoragao Ore: anterior deve ter Ihe dado uma boa idéia a respeito do que se trata ealgumas das questdes que vocé precisa considerar ao usar refatoragao Definindo Refatoracao Fico sempre um pouco desconfiado de definigdes porque todos tém as suas, mas quando vocé escreve um livro acaba escolhendo suas prdprias definigdes. Neste ca- so, estou baseando minhas definigGes no trabalho feito pelo grupo de Ralph Johnson e diversos associados. Aprimeira coisa a dizer é que a palavra Refatoragio tem dois significados, depen- dendo do contexto. Vocé pode achar isto irritante (eu certamente acho), mas serve co- mo exemplo da realidade de trabalhar com linguagem natural. Aprimeira definigao é a da forma substantiva 1, Refatoragao (substantivo): uma alteragao feita na estrutura interna do software para J= tornd-lo mais facil de ser entendido e menos custoso de ser modificado sem alterar seu comportamento observtvel. Vocé pode encontrar exemplos de refatoragies no catélogo, tais como Extrair Mé- todo (100) e Subir Campo na Hierarquia (274). A refatoracao propriamente dita é nor- malmente uma pequena alteracao no software, ainda que uma refatoragao possa en- volver outras. Por exemplo, Extrair Classe (132) normalmente envolve Mover Método (125) e Mover Campo (129). Paincipios oa Reraroracho 53 O outro uso de refatoragio é na forma verbal. YL Refatorar (verbo): reestruturar software aplicando uma série de refatoragdes sem alte- rar seu comportamento obserodvel. Vocé poderia entao gastar algumas horas refatorando, durante as quais poderia aplicar algumas dtizias de refatoragGes individuais. Jéme perguntaram “A refatoracao é apenas limpeza de cdigo?” De certo modo, a resposta é sim, mas acho que refatoragao vai mais longe que isso, porque fornece uma técnica para limpar cédigo de uma maneira mais eficiente e controlada. Desde que comecei a usar refatoracao, percebo que limpo cédigo muito mais eficazmente que antes. Isto acontece porque sei quais refatoracdes usar e como usé-las de um mo- do que minimize as falhas, e eu testo a cada oportunidade possivel. Devo explicar com mais detalhes alguns dos pontos de minhas definig6es. Pri- meiro, o propésito da refatoracao é tornar o software mais facil de entender e mod: car. Vocé pode fazer muitas mudangas no software que alterem pouca coisa ou nada no comportamento observavel. Somente as mudangas feitas para tornar o software mais facil de entender sao consideradas refatoracdes. Um bom contraste é a otimiza- do de desempenho. Assim como a refatoracio, a otimizacao de desempenho geral- mente nao altera 0 comportamento de um componente (além da sua velocidade), ela altera apenas a estrutura interna. Entretanto, o propdsito é diferente. A otimizagao de desempenho muitas vezes torna o cédigo mais dificil de entender, mas vocé precisa fazé-la para obter o desempenho de que necesita. A segunda coisa que quero destacar é que a refatoragao nao altera 0 comporta- mento observavel do software. Esse ainda executa a mesma fungao de antes. Qual- quer usuario, seja ele um usuério final ou outro programador, nao é capaz de dizer que algo mudou. Os Dois Chapéus Esse segundo ponto leva metfora de Kent Beck dos dois chapéus. Quando usa re- fatoragao para desenvolver software, vocé divide seu tempo entre duas atividades dis- tintas: adicionar funcionalidades e refatorar. Quando adiciona funcionalidades, vocé nao deve alterar cédigo preexistente. Vocé est apenas adicionando novas capacida- des. Vocé pode medir seu progresso adicionando testes e os executando. Quando vo- cé refatora, faz questo de nao acrescentar novas funcionalidades; apenas reestrutura © cédigo. Vocé nao acrescenta novos testes (a ndo ser que encontre um caso que no havia percebido antes); vocé apenas muda os testes quando isso for absolutamente necessirio para lidar com uma alteragao em uma interface. A medida que vocé desenvolve software, provavelmente se descobre trocando chapéus com freqiiéncia. Vocé comeca tentando adicionar uma nova fungao e perce- be que seria muito mais facil se o cédigo estivesse estruturado de forma diferente. Entao vocé troca de chapéu e refatora durante um certo perfodo. Assim que 0 cédigo estiver mais bem estruturado, vocé troca de chapéu e acrescenta a nova fungao. As- sim que vocé tenha a nova funcao ativa, percebe que a codificou de uma maneira di- ficil de entender e entao troca de chapéu novamente e refatora. Tudo isso pode levar apenas dez minutos, mas durante este tempo vocé deve estar ciente de qual chapéu esté usando. 54 RlerAToRagho Por Que Vocé Deve Refatorar? Nao quero apregoar a refatoracao como a cura de todos os problemas do software. Ela nao é uma panacéia para todos os problemas. Ainda assim, é uma ferramenta valio- sa, um alicate de prata que Ihe ajuda a manter seu c6digo seguro. Refatoragao é uma ferramenta que pode, e deve, ser usada para diversos propésitos. Refatorar Melhora o Projeto do Software Sem refatoragdo, o projeto do programa termina por se deteriorar. A medida que as pessoas alteram o cédigo ~ alteracdes para executar objetivos de curto prazo ou en- tao alteragdes feitas sem uma compreensio total do projeto do cédigo — 0 cédigo se desestrutura. Torna-se mais dificil visualizar 0 projeto ao ler 0 cédigo. Refatoracao é como arrumar o cédigo. As partes do cédigo que nao estejam no lugar apropriado so removidas. A perda de estrutura do cédigo tem um efeito cumulativo. Quanto mais dificil & visualizar o projeto a partir do cédigo, mais dificil sera preserva-lo e mais rapidamente ele se desestruturara. A refatoracao sistematica ajuda 0 cédigo a conservar sua forma. Um sistema mal projetado normalmente precisa de mais cédigo para fazer as mesmas coisas, muitas vezes porque o mesmo cédigo é replicado em diversos lugares diferentes. Assim, um aspecto importante na melhoria do projeto é a eliminacao de cédigo duplicado. A importancia disto recai sobre futuras modificacdes no cédigo. Re- duzir a quantidade de cédigo nao faré o sistema rodar mais rapidamente, porque 0 efeito no desempenho dos programas raramente é significativo. Reduzir a quantida- de de cédigo faz, todavia, uma grande diferenca sobre a manutencao desse cédigo. Quanto mais cédigo houver, mais dificil seré modificé-lo corretamente. Ha mais cédi- go para ser entendido. Vocé altera um trecho de cédigo aqui, e o sistema nao faz 0 es- perado porque vocé nao alterou o cédigo em outro lugar que faz a mesma coisa em um contexto levemente diferente. Eliminando as c6pias, vocé se assegura de que 0 c6- digo diz tudo uma e apenas uma vez, o que é a esséncia do bom projeto. Refatorar Torna 0 Software Mais Facil de Entender Programar é de certa forma conversar com 0 computador. Vocé escreve cédigo que diz a esse 0 que fazer, e ele responde fazendo exatamente o que vocé Ihe diz. Com o passar do tempo, vocé diminui a distancia entre o que quer que o computador faga e ‘© que vocé Ihe manda fazer. Programar dessa forma é dizer ao computador exata- mente o que vocé quer. Ha todavia outro usudrio do seu cédigo fonte. Alguém tenta- ré ler seu cédigo dentro de alguns meses para fazer algumas alteraqdes. Esquecemos facilmente desse usuario adicional do cédigo, embora seja na verdade o mais impor- tante. Quem se importa se o seu computador gastar alguns ciclos a mais para compi- lar algo? O que faz diferenca é se um programador tiver de gastar uma semana para fazer uma alteragao que teria levado apenas uma hora se ele tivesse entendido seu cédigo. O problema é que, quando esta tentando fazer seu programa funcionar, vocé nao estd pensando no futuro desenvolvedor. E necessaria uma alteracao de ritmo para fa- zet modificagSes que tornem o cdigo mais facil de ser entendido. A refatoracao aju- daa tornar seu cdigo mais legivel. Ao refatorar, vocé tem cédigo que funciona mas que nao esté estruturado da forma ideal. Um pouco de tempo gasto refatorando po- Principios oa Reraroracho 55 de fazer com que o c6digo comunique melhor seu propésito. Programar dessa forma & explicar ao computador precisamente o que vocé quer dizer. Nao estou sendo necessariamente altrufsta a respeito deste tema. Muitas vezes, este futuro desenvolvedor sou eu mesmo. Aqui, refatorar é particularmente impor- tante. Sou um programador muito preguigoso. Uma de minhas formas de preguica é que nunca me lembro de coisas sobre 0 cédigo que escrevo. De fato, tento delibera- damente nao me lembrar de algo que eu possa procurar, porque tenho medo de que meu cérebro fique entupido. Tento colocar tudo que devo recordar no cédigo, de mo- do que nao tenha que me lembrar disso. Desta forma, fico menos preocupado com a Old Peculier* [Jackson] matando meus neurénios. Essa compreensibilidade também funciona de outra forma. Uso refatoragao para me ajudar a entender cédigo com 0 qual nao esteja familiarizado. Quando vejo tal ti- po de c6digo, tenho que tentar entender o que ele faz. Olho algumas linhas e digo pa- ra mim mesmo, ah, é isso que este trecho de cédigo esta fazendo. Usando refatora- do, no me limito ao entendimento mental. Eu realmente altero o cédigo para que reflita melhor minha compreensdo e entao testo esta compreensdo executando nova- mente 0 c6digo para ver se ele ainda funciona. Desde 0 inicio, fago refatoragdes como essa em detalhes. A medida que o cédigo vai ficando mais claro, descubro que posso ver coisas a respeito do projeto que nao conseguia ver antes. Se eu nao tivesse alterado o eddigo, provavelmente nunca teria visto essas coisas, porque ndo sou suficientemente esperto para visualizar tudo isso na minha cabeca. Ralph Johnson descreve estas refatoracdes iniciais como limpar a sujeira da janela para que vocé possa ver além. Quando estou estudando cédigo, des- cubro que a refatoracao me leva a niveis mais altos de compreensao que de outra for- ma eu ndo atingiria. Refatorar Ajuda a Encontrar Falhas Amelhora no entendimento do cédigo também me ajuda a localizar falhas. Admito que nao sou muito bom em encontrar falhas. Algumas pessoas conseguem ler um bloco de cédigo e achar falhas, eu nao. Entretanto, descubro que, se refatoro cédigo, trabalho pesado na compreensao do que ele faz, e aplico esse novo conhecimento de volta no cédigo. Clareando a estrutura do programa, clareio certas suposiges que havia feito, até o ponto em que nem mesmo eu consigo evitar de achar as falhas. Isso me lembra de uma frase que Kent Beck sempre diz a respeito de si préprio, “Nao sou um grande programador; sou apenas um bom programador com étimos habitos”. Refatorar me ajuda a ser muito mais efetivo na escrita de cédigo robusto. Refatorar Ajuda a Programar mais Rapidamente No final, todos os pontos anteriores levam a este: Refatorar ajuda vocé a desenvolver cédigo mais rapidamente. Isto nao parece intuitivo. Quando falo sobre refatoragao, as pessoas podem ver facilmente que ela melhora a qualidade. Melhorar o projeto, melhorar a legibilidade, reduzir as falhas, tudo isto melhora a qualidade. Mas isto tudo nao reduza velocida- de de desenvolvimento? * Node RT: Marea de cerveja 56 RlerAToRagho Eu realmente acredito que um bom projeto é essencial para desenvolvimento rapido de software. De fato, a grande motivagao para se ter um bom projeto é permi- tir o desenvolvimento rapido. Sem um bom projeto, vocé pode progredir rapidamen- te durante um certo tempo, mas logo o projeto ruim comega a atrasar seu trabalho. ‘Vocé perde tempo procurando e consertando falhas em vez de adicionar novas fun- cionalidades. Mudangas demoram mais 4 medida que vocé tenta compreender o sis- tema e encontrar cédigo duplicado. Introduzir novas caracteristicas demanda mais c6digo, quando é necessério remendar um remendo que remenda outro remendo no cédigo original. Um bom projeto é essencial na manutencao da velocidade de desenvolvimento de software. Refatorar ajuda vocé a desenvolver software mais rapidamente, porque evita que o projeto do sistema se deteriore. A refatoracdo pode até mesmo melhorar um projeto. Quando Vocé Deve Refatorar? Quando falo sobre refatorac4o, muitas vezes me perguntam sobre como ela deve ser programada. Devemos alocar duas semanas a cada dois meses para refatorar? Na maioria dos casos, sou contra separar tempo para refatorar. Na minha visio, a refatoracao nao é uma atividade para a qual vocé separa tempo. Refatoragao é algo que voce faz todo o tempo em pequenas rajadas. Vocé nao decide refatorar, voce re- fatora porque quer fazer alguma outra coisa qualquer e refatorar ajuda a fazé-lo. A Regra de Trés Aqui esta uma diretriz que Don Roberts me deu: na primeira vez em que faz algo, vocé apenas faz. Na segunda vez em que faz algo parecido, vocé estremece diante da duplicagao, mas a faz de qualquer forma. Na terceira vez em que faz algo parecido, vocé refatora. Trés vezes ¢ voc’ refatora. Refatore Quando Acrescentar Fungdes Ahora mais comum para refatorar é quando quero adicionar uma nova caracteristi- ca.aalgum software. Muitas vezes a primeira razao para refatorar aqui é me ajudar a compreender algum cédigo que preciso modificar. Este cédigo pode ter sido escrito por outra pessoa ou por mim. Toda vez que tenho que pensar para entender o que o cédigo faz, me pergunto se posso refatorar o cédigo para tornar esse entendimento mais rpido. Entao eu o refatoro. Em parte, isso é para a préxima vez que eu passar por aqui, mas principalmente porque posso entender mais coisas se clarear 0 cédigo A medida que vou adiante. O outro motivo que conduz a refatoracaio aqui é um projeto que nado me ajuda a acrescentar uma nova funcionalidade facilmente. Olho o projeto e digo para mim Paincipios oa Reraronacho 57 mesmo “Se eu tivesse projetado o cédigo desta forma, acrescentar esta caracterfstica seria facil”. Nesse caso, ndo lamento meus erros passados — eu os conserto refatoran- do. Fago isso em parte para tornar melhorias futuras mais féceis, mas principalmen- te porque descobri que é 0 meio mais rapido. Refatorar é um processo rapido e tran- qiiilo. Uma vez que vocé tenha refatorado, adicionar uma caracteristica pode ser muito mais rapido e traniiilo. Refatore Quando Precisar Consertar uma Falha No conserto de falhas, muito da utilidade da refatoracao vem do fato de tornar 0 c6- digo mais compreensivel. Quando olho o cédigo tentando compreendé-lo, refatoro para ajudar a melhorar minha compreensao. Muitas vezes descubro que este pro- cesso ativo de trabalho com cédigo ajuda a encontrar a falha. Um modo de encarar isso é que, se vocé recebe uma notificacao de falha, é um sinal de que precisa refato- rar, porque 0 cédigo nao estava claro o suficiente para que percebesse que havia uma falha. Refatore Enquanto Revisa 0 Cédigo Algumas organizacoes fazem revisdes de c6digo regulares. Aquelas que nao o fazem ficariam melhor se fizessem. Revisdes de cdigo ajudam a difundir conhecimento através de uma equipe de desenvolvimento. As revisdes facilitam a transmiss4o do conhecimento dos desenvolvedores mais experimentados para os menos experien- tes. Elas ajudam mais pessoas a entender mais aspectos de um sistema grande de software. Elas também s4o muito importantes na escrita de cédigo claro. Meu cédigo pode parecer claro para mim, mas nao para minha equipe. Isto é inevitavel - 6 mui- to dificil para as pessoas se colocarem no lugar de alguém que nao esteja familiariza- do com as coisas nas quais estao trabalhando. Revisdes também dao a oportunidade de mais pessoas sugerirem idéias titeis. Eu precisaria de uma semana para pensar em tantas boas idéias. Fazer outras pessoas contribuirem torna minha vida mais facil, en- tao busco sempre por novas revises. Descobri que refatorar me ajuda a revisar 0 cédigo de outras pessoas. Antes de eu comesar a refatorar, podia ler o cédigo, obter algum grau de compreensao do mes- mo e fazer algumas sugestées. Agora quando tenho uma idéia, considero se ela po- de ser facil e imediatamente implementada com refatoragao. Em caso positivo, refa- toro. Depois de fazer isso algumas vezes, posso ver mais claramente como 0 cédigo se parece com as sugestdes ja implementadas. Nao tenho que imaginar como seria, posso ver como &. Como resultado disso, posso vir com um segundo nivel de idéias que nunca teria percebido caso nao tivesse refatorado. Refatorar também ajuda a revisao do cédigo a gerar resultados mais concretos. Nao s6 as sugestdes aparecem, como também muitas delas s4o imediatamente im- plementadas. Vocé sai do exercicio com uma sensacao de realizagao muito maior. Para fazer este processo funcionar, vocé precisa ter pequenos grupos de revisao. Minha experiéncia sugere ter um revisor e o autor trabalhando no cédigo juntos. O revisor sugere alteragdes e ambos decidem se elas podem ser facilmente refatoradas. Em caso afirmativo, eles executam essas alteracdes. Se 0 objetivo é uma revisdo de projeto, freqiientemente é melhor obter diversas opinides em um grupo maior. Mostrar cédigo muitas vezes nao é a melhor maneira

You might also like