Strokovne razprave Refactoring - Preoblikovanje programske kode Uroš Grajfoner. Peter Repinc OdaTeam d.o,o. Meljsha 36, SI-2000 Maribor e-pošta: uras@odateam.com, pero@odateam.com URL http:/Avww.odateam.com Izvleček Spreminjanje obstoječe programske kode zaradi dodajanja nove funkcionalnosti se lahko izvaja z natančno izbranimi in definiranimi koraki. Takemu procesu pravimo preoblikovanje programske kode. Izvaja se združeno z drugimi razvijatski-mi aktivnostmi, pri ekstremnem programiranju pa je bistveni del razvojnega procesa. Z njim programska struktura postane razumijivejša, jasnejša, pravilnejša in fleksibilnejša za dodajanje nove funkcionalnosti. Proces je podprt z avtomatiziranim testiranjem. V najboljšem primeru se proces izvaja avtomatsko z orodji za preoblikovanje. Preoblikovanje zbija ceno spremembe obstoječega sistema in povečuje njegovo preglednost. Abstract Refactoring is a process of adding new functionality by changing the existing program code. It can be performed by exactly chosen and defined steps. It is practiced together with other design activities, while in extreme programming it is an essentia/ part of the development process. With refactoring, the program structure becomes more understandable, clearer, more correct and flexible for adding new functionalities. Automatic testing by refactoring too/s support trie process. Refactoring reduces trie cost of changing the existing system and improves its transparency. Ill L UVOD Ko se začne zapletati... V življenjskem ciklu informacijskega sistema naletimo na dele informacijskega sistema, ki več ne odsevajo dejanskega stanja v realnosti. Dokler taki deli sistema delujejo pravilno in ni razlogov, da bi na njih i/vajali spremembe, je na videz vse lepo in prav. Ko se v realnosti pojavijo spremembe, se morajo te spremembe odražati tudi na programski kodi. Zaradi spreminjanja sistema skozi čas se zgradba in namembnost sistema zameglita, K temu še največ doprinesejo kratkoročni in hitri posegi v sistem, ki so posledica zahtev uporabnikov, časovne stiske, ipd. Zaradi tega se dogaja, da določeni deli sistema vsebujejo veliko začasnih rešitev, naknadnih dograditev in jih je posledično vedno težje vzdrževati, so vedno bolj nepregledni, vedno pogosteje se dogaja, da se nove funkcionalnosti ne da enostavno dodati. Zaradi tega pridemo do logičnega zaključka, da jt> sistem treba preoblikovati, da bi lahko ob dodajanju nove funkcionalnosti še vedno ustrezno deloval, ali pa da bi ga po določenem časovnem obdobju sploh še lahko razumeli. Dodajanja nove funkcionalnosti se lahko lotimo na različne načine. En način je, da določen podsistem zgradimo znova. Tak pristop pa je lahko zelo drag, dolgotrajen in zelo tvegan. Druga možnost je kopiranje in prirejanje delov Sistema in s tem razširjanje sistemskih zmogljivosti. Vendar so te zmogljivosti le na videz velike, saj sistem s takimi posegi postane prehitro prevelik, napake se hitreje množijo, implementacija sistema več ne ustreza načrtu, stroški inkremen-talnih popravil pa se pomnožijo. Najbolj sprejemljiva rešitev je srednja pot: preoblikovanje sistema v majhnih, obvladljivih korakih. Na tak način je vpogled v problem boljši, bolj osredotočen, arhitektura sistema se s takimi popravili izboljšuje, s tem pa je olajšano tudi dodajanje novosti. 2. Lastnosti preoblikovanja Izhod Učne informacije 2.1 Definicija preoblikovanja Preoblikovanje je proces spreminjanja programske kode tako, da se obnašanje sistema navzven ne spremeni, spremeni in izboljša(l) pa se notranja struktura sistema. Je sistematičen način »prečišče vanja- kode in zmanjševanja možnosti napak. Namen preoblikovanja je spreminjanje sistema tako, da ga je lažje razumeti in dopolnjevati. Preoblikovanje 2000-številka4-letnik Vlit 17* wl N FOR M ATI KA Uros Grajfoner, Peler Repine: Refació ring - Preoblikovanje programske kode Spreminja način gradnje informacijskih sistemov iz ustaljenega zaporedja »načrtovanje, gradnja, vzdrževanje« v delovni proces, kjer načrtovanje, gradnja in vzdrževanje niso več ločeni procesi, ampak se prepletajo in ponavljajo v celotnem življenjskem ciklu informacijskega sistema. S pomočjo preoblikovanja lahko sistem načrtujemo tudi, ko je že implementiran. 2.2. Kdaj preoblikovati Idealno bi bilo imeti programski sistem z brezhibno arhitekturo, s čudovito strukturirano in jasno programsko kodo. Število podjetij, ki si lahko privoščijo tak sistem, ki hkrati deluje brez časovnih omejitev, limitira proti nič. Na žalost. Čas in denar sta vedno omejeni dobrini. Zaradi tega preoblikovanje ni proces, ki bi se nenehno odvijal skozi celotno življenjsko dobo nekega informacijskega sistema. Pomembno je prepoznati trenutke, ko jc preoblikovanje kode najbolj smiselno. 2.2.1. Dodajanje nove funkcionalnosti Najpogostejši vzrok za preoblikovanje obstoječe kode je dodajanje nove funkcionalnosti. Zahteve uporabnikov praviloma niso popolne in dokončne. Okolje delovanja programskega sistema se vedno spreminja. Znanje razvijalcev in načrtovalcev je različno. Vsi ti vzroki botrujejo rojevanju potrebe po novi fukcional-nosti, ki jo mora sistem vsebovati. Pri dodajanju nove funkcionalnosti vedno naletimo na programsko kodo, ki jo je treba na neki način spremeniti. Verjetnost, da to kodo popolnoma poznamo, je majhna. Da bi kodo lahko bolje razumeli, jo lahko preoblikujemo. S tem izboljšamo njeno izraznost, kar vsekakor pride prav, ko naslednjič naletimo na isto kodo. Drugi dober razlog za preoblikovanje je struktura kode, ki ne omogoča preprostega dodajanja nove funkcionalnosti. Seveda lahko vedno dogradimo obstoječo kodo in / določenimi posegi in izjemami dosežemo, da koda deluje tudi z novo funkcionalnostjo, vendar na ta način še povečamo nerazumljivost kode, naše življenje bo pa precej manj lepo, ko bomo spet naleteli na njo. Svet si lahko naredimo prijaznejši, Če v takem primeru kodo najprej preoblikujemo tako, da je novo fukcionalnost enostavno dodati. In šele nato dodamo novo funkcionalnost. 2.2.2. Popravljanje napak Dober razlog za preoblikovanje kode je popravljanje napak. Kodo najprej preoblikujemo, da bolje razumemo kontekst. Ko je sistem razumljivejši, je napako mnogo lažje najti in jo zatem popraviti. Povedano drugače, napaka, ki jo popravljamo, je verjetno posledica nejasnosti kode. Preoblikovanje je torej tudi način, s katerim si zaradi boljše preglednosti zagotavljamo boljše razumevanje kode in s tem zmanjšujemo verjetnost napak. 2.2.3. »V tretje gre rado» To smernico je dal Don Roberts Martinu Fovvlerju [1], Prvič napišemo kodo in upamo na najbolje. Ko drugič ustvarimo nekaj podobnega, se očitnega podvajanja zavedamo, morda celo ustrašimo, a večinoma zaradi različnih pritiskov kodo vseeno podvojimo. Ko ustvarimo podobno kodo že tretjič, je čas za preoblikovanje. 2.2.4. Preoblikovanje ob pregledih kode Pregledi kode omogočajo prepoznavanje namer programerjev. Prepoznava se slabo načrtovanje, dobre ideje, odkrivajo se napake. Pri pregledih kode razvijalci z manj izkušnjami pridobivajo novo znanje. Pri tem se velikokrat zbirajo ideje in predlogi kako kodo spremeniti, da bi bolje služila svojemu namenu. S preoblikovanjem lahko take predloge udejanji mo. Rezultat je drugačna struktura programa, ki jo lahko za vržemo, če se izkaže kot slabša alternativa, ali pa jo uporabimo kol izhodišče za naslednjo izboljšavo. Le-to bi si seveda težko predstavljali, če ne bi naredili prve spremembe. Poleg tega pri pregledu kode ostane samo pri predlogih, pri preoblikovanju pa lahko rezultate novih idej vidimo pred sabo zelo kmalu. Če je nov načrt dober, ga lahko obdržimo in sistem bo boljši. Če ne bo, se lahko vrnemo na prejšnje stanje in bogatejši bomo za novo izkušnjo. Pri ekstremnem programiranju je tak način preoblikovanja potenciran, saj se programira v parih, kjer je preoblikovanje konstanten del razvojnega procesa. Razvijanje v parih zato deluje kot nenehen pregled kode s preoblikovanjem. Seveda pa preoblikovanje ni univerzalen odgovor na vsako težavo. Prav tako ga je na nekaterih področjih težavno uporabiti, so tudi primeri, ko sploh ni priporočljivo. Problematično je lahko recimo preoblikovanje baze podatkov (oz. objektnega modela), kjer se moramo v večini primerov soočiti s konvertiranji v nova stanja podatkov. Prav tako lahko nastopijo težave, ko spremenimo vmesnik komponente, ki se pogosto uporablja. V nekaterih primerih pa preoblikovanje enostavno ne pomaga in je najbolje kak del sistema odstraniti in implementirati znova. Po našem mnenju so to sistemi / resnimi napakami v samem načrtu ali sistemi, ki su preveč nestabilni za produkcijsko uporabo. Novo gradnjo kakega sistema si, če je to mogoče, lahko zamislimo tudi kol dolgotrajno globalno preoblikovanje. 2.3. Ko »zavohamo« priložnost... V prejšnjem poglavju so opisane različne situacije, pri katerih je preoblikovanje potrebno ali priporočljivo. ¡tjumihi ml NFOfi M ATI KA 2000 Stevlikai-lemik VIII Uros Grajfoner, Peler Repine: Refació ring - Preoblikovanje programske kode Ni pa konkretnih navodil, na katerih mestih naj se lotimo dela. Prav tako nam pri samem začetku, ko se lotevamo preoblikovanja prvič, ni popolnoma razvidno, kje naj rešujemo težave najprej. Cez čas odkrijemo, da smo dobili »nos« za določene konstrukte kode, kjer imamo precej dobro zamisel, kako bi ta koda lahko delovala bolje in kako bi lahko bila jasnejša. V naslednjih nekaj vrsticah so opisana nekatera mesta v kodi, kjer je (zelo) očitno, da je potrebno preoblikovanje. Veliko primerov je gotovo prepoznavnih iz vsakdanjega obdelovanja kode, ■ Podvojena programska koda - najpogostejši razlog za preoblikovanje. Če se pojavi pri istem razredu, je rešitev ponavadi izsek podvojene kode in definiranje nove metode. Pri razredih v hierarhiji se skupno uporabljana koda premakne na ustrezen abstraktni razred. Če povezav med razredi ni, lahko naredimo celo nov razred, ki opravlja naloge podvojene kode. ■ Predolga metodu - Merila za dolžino metod v objektnih programih so različna. V večini primerov pa se predolgih metod lahko rešimo z. izsekom dela kode in definiranjem nove metode. V drugih primerih lahko veliko množico parametrov zamenjamo z objektom. Metodo lahko predstavimo tudi kot nov objekt ali hierarhijo objektov. ■ Prevelik razred - Razred združuje preveč funkcionalnosti in informacij, ima »kompleks švicarskega noža«. Rešitev je dekompozicija na več manjših razredov, odgovornih za posamezne naloge. ■ Po Ig nabor parametrov -, ki jih potrebuje neka metoda, lahko nadomestimo s povpraŠevalnimi stavki, predajanjem objekta kot parametra itd. ■ Raznolike spremembe -, ki jih opravljamo pri vedno istem razredu, sugerirajo kreiranje več različnih razredov z jasnimi odgovornostmi. ■ Poseg s Šibrovko - Pri določenih spremembah je potrebno spreminjati kodo na vedno enakih mestih v različnih delili sistema. Rešitev je v definiciji centralnega razreda ali metode, kjer se izvaja vsakokratna sprememba. ■ Zavidanje lastnosti - se pojavlja pri razredih, ki opravljajo svoje delo na drugih objektih in jim »zavidajo« njihove lastnosti. Najpogostejša rešitev je premik kode ali dela kode k pravemu lastniku. ■ Kepe podatkov - podatki, ki večinoma nastopajo skupaj, se morajo pravzaprav združiti v skupen objekt, ki kasneje pridobi še nekatere odgovornosti in operacije. m .pre-memb ne bomo mogli izpeljati do konca. Kljub temu opravljenega dela ni potrebno zavreči, Vsak korak je natančno definiran in preverjen s testnim orodjem, zato sistem še vedno deluje pravilno in je v vsakem primeru boljši, kot je bil pred začetkom preoblikovanja. Po vsakem koraku preoblikovanja lahko torej zaključimo z delom in nadaljujemo naslednjič. 4. Orodja za preoblikovanje Olajšanje življenja Natančno definirani koraki preoblikovanja programske kode [1] nudijo razvijalcem gotovost, da bodo koraki izvedeni pravilno in popolno. S tem se do določene mere lahko znebimo negotovosti, ki lahko spremlja razvijalce pri preoblikovanju, Proti taki negotovosti imamo še eno orožje: avtomatizirano testiranje. Čeprav je preoblikovanje podprto s sistematiko in testiranjem, pa se ga razvijalci vseeno pogosto izogibajo. Razlog je preprost. Preoblikovanje zahteva svoj čas. Razvijalci se ga izognejo, ker je na prvi pogled predrago. Na tem mestu ni odveč poudariti, da je preoblikovanje proces, ki razred A metoda MA metoda Ma2 ** A S / ~~--- 2000 - številka 4 - letnik VIII iifjitmbiuANFORM ATIKA 235 rurH A nn.rlLui.i M melotfa M Uros Grajfoner, Peler Repine: Refació ring - Preoblikovanje programske kode dolgoročno poceni dodajanje funkcionalnosti. Z njim odkrivamo napake in izboljšujemo programsko kodo. Brez preoblikovanja bi vsako naknadno dodajanje funkcionalnosti bilo vedno težje izvedljivo in s tem vedno dražje. Z uporabo preoblikovanja je razvoj pro-gramja na začetku navidezno upočasnjen, vendar se s časom praksa ustali, dodajanje nove funkcionalnosti ima Še vedno relativno nizko ceno, napredek je zmernejši, a konstantnejši in hitrejši. Orodja za preoblikovanje nudijo avtomatsko izvajanje korakov preoblikovanja. S tem je vklop preoblikovanja v vsakdanji razvojni proces močno olajšan. Vsak korak preoblikovanja, ki se mu razvijalec lahko izogne zaradi pomanjkanja časa, je zdaj lahko opravljen hitro in avtomatsko, z označevanjem kode in izbiro ustreznih ukazov. S tem odpadejo tudi preverjanja pravilnosti predajanja novih parametrov, osve-ževanja klicateljev preimenovanih metod in drugo. Proces izvedbe posameznega koraka preoblikovanja traja nekaj sekund, medtem ko bi manualno izvajanje enakega postopka lahko trajalo kar nekaj minut. Poleg tega postane vsakokratno testiranje nepotrebno, saj se vse potrebno delo izvede avtomatsko. Kar pa še ne pomeni, tla s preoblikovanjem postane testiranje odvečno. Preprosto ga ne potrebujemo tako pogosto. Z orodji se cena preoblikovanja zniža, posredno s tem pade tudi cena razvojnih napak. Zaradi tega se lahko izognemo pogosto zapletenim, vnaprej pripravljenim razvojnim načrtom, ki nastajajo zaradi pomanjkanja zahtev. Takšni razvojni načrti vsebujejo fleksibilnosti, ki se s kasnejšo uporabo izkažejo kot nepotrebne. Tako se povečuje kompleksnost program j a. Brez poznavanja preoblikovanja pa bi bilo nefleksibil-ne sisteme zelo drago spreminjati. Z avtomatiziranim preoblikovanjem si lahko privoščimo enostavnejše načrtovanje, saj je spremembe lažje izvajati, razširjanje načrtov in dodajanje funkcionalnosti ni več tako cenovno potratno. Na področju preoblikovalnih orodij na žalost vlada zaenkrat velika praznina. V integriranih razvojnih okoljih kot so recimo okolja za Smalltalk, je zaenkrat razvito orodje poimenovano Refactoring Browser {Preoblikovalni brskalnik), ki pa se je pričel znatneje uporabljati šele, ko je bila njegova funkcionalnost vključena v vsakdanji brskalnik knjižnic razredov. Za okolja kot je npr. Java, kjer se programska koda vpisuje tako rekoč v preprost urejevalnik besedila, se medsebojno prepletene reference na objekte in metode ne shranjujejo, zato je izdelava orodja za preoblikovanje Še posebej otežena. Nekatera naprednejša okolja, kot je npr. IliM-ov VisualAge for Java, posnemajo smalltalkovsko dinamično osveževanje programskega repozitorija. Orodje za preoblikovanje naj bi torej na neki način obvladovalo programske reference med razredi, moralo bi delovati natančno, dovolj hitro za Vsakdanjo uporabo, omogočati preklice posameznih korakov preoblikovanja (»korakanje nazaj«), še najlepše pa bi bilo, ko bi bilo tako orodje integrirano v razvojno okolje samo. 5. Zaključek Končno Programska koda skrbi za dve vrsti komunikacije. Prva in neizpodbitna vrsta je komunikacija med programsko kodo in računalnikom. Računalnik nedvoumno razume in dosledno izvaja programsko kodo. Druga vrsta komunikacije, ki na prvi pogled ni opazna, je komunikacija med programsko kodo in programerjem. Le-ta pa ni nujno nedvoumna in lahko funkcionira zelo slabo. Z preoblikovanjem izboljšujemo predvsem komunikacijo med programsko kodo in programerjem. Hkrati pa skrbimo, da je naš informacijski sistem jasna in nedvoumna slika realnosti. LITERATURA 1. FOWLER, Martin, "Refactoring". Addison-We s ley, Reading, 1999 2. BECK, Kent, "Extreme programming explained", Addison Wesley, Reading, 1999 3. FOWLER. Martin, KENDALL, Scott, "LIML Distilled", Addison-Wesley. Reading, 1997 4. ROBERTS Don et al., "Why Every Smalftalker Should Use the Refactoring Browser", The Smalltalk Report, lelnik 6, številka 10, september 1997 5. ROSTAHER, Matevž, KLINE. Andrej "Proces skupinskega razvoja programske opreme (Extreme programming)", Zbornik srečanja Objektna tehnologija v Sloveniji 99, junij 1999 6. httpV/www.c2.com/cgi/wiki?ExtremeProgramming, Extreme Programming Discussion 7. extremeprogramming@Bgroijp5.coni, Extreme Programming Mailing List * Uroš Grajfoner je diplomira! na Fakulteti za elektrotehniko, računalništvo m informatiko v Mariboru m je študent podiplomskega študija informatike na tej fakulteti. Zaposlen je v podjetju FJA Oda Team d.o,o. kot razvijalec informacijskih sistemov. V zadnjih petih letih je sodeloval pri številnih projektih v Smalltalku, Javi in pri uvajanju prvin ekstremnega programiranja v proces razvoja. V oktobru 2000 je sodeloval pri delavnici "From Moderate programming fo eXtreme Programming" na konferenci OOPSLA. Minneapolis, ZDA ♦ Peter Repinc je študent računalništva in informatike na Fakulteti za elektrotehniko, računalništvo in informatiko v Mariboru Od leta 7 998 je zunanji sodelavec podjetja OdaTeam d.o.o. Sodeloval je pri projektih v Smalltalku. Javi in XP i(;mmïiij(jlNFORMATIKA 2000-številka 4-letnik VIII