Refaktorování Code refactoring Lukáš Hájek Objektově orientované programování ČVUT v Praze - Fakulta jaderná a fyzikálně inženýrská 8. října 2013 1 / 31
Struktura prezentace 1 Co je refaktorování 2 Historie 3 Proč refaktorovat 4 Kdy refaktorovat 5 Jak refaktorovat 6 Code obfuscation 2 / 31
Co je refaktorování? Systematický proces provádění změn v kódu bez ovlivnění funkčnosti Pouze drobné změny Vylepšení / zpřehlednění kódu 3 / 31
Historie Na začátku 80. let mezi programátory jazyka Forth pojem factoring Přelom 80. a 90. let používání refaktorovacích technik programátory ve smalltalku Počátek 90. let první akademické práce o refaktorování (funckionální i procedurální) 1999 Fowler Martin, Refactoring: Improving the Design of Existing Code. 4 / 31
Proč refaktorovat? Zvýšení přehlednosti kódu Při psaní programu je jednodušší myslet pouze na funkčnost Zefektivnění kódu Odstranění repetetivity Zbavení se zbytečných proměnných Zlepšení vlastní reprezentace jakožto programátora 5 / 31
Vyplatí se refaktorování? 6 / 31
Kdy refaktorovat? 1/2 Již při vývoji kódu (průběžně) nedílná součást vývoje Pokud po nás bude kód číst někdo jiný Pokud se chci ke kódu po nějaké době vrátit Chceme si ujasnit cizí kód Kód je ve špatném stavu, málo flexibilní, chybný Nelze nalézt chybu v kódu 7 / 31
The first time you do something, you just do it. The second time you do something similar, you wince at the duplication, but you do the duplicate thing anyway. The third time you do something similar, you refactor. Don Roberts 8 / 31
Kdy refaktorovat? 2/2 Příliš mnoho public Mnoho komentářů ( nejasný kód) Přílišné řetězení Dlouhé metody Velké třídy Špatná dědičnost 9 / 31
Refaktorujte brzo, refaktorujte často 10 / 31
Jak refaktorovat? Opatrnost, nepřeceňování svých zkušeností Pro ladění rychlosti kódu profiler Podrobný katalog na adrese http://www.refactoring.com/catalog/ 11 / 31
Pozor! Refaktorování je riskantní! Připravovat sady testů Testovat po co nejmenších krocích 12 / 31
13 / 31
Martin Fowler 22 pachů kódu Pro každý pach jiná technika by Kent Beck and Martin Fowler If it stinks, change it. Grandma Beck, discussing child-rearing philosophy 14 / 31
Duplicitní volání u podmínek if (isspecialdeal()) { total = price * 0.95; send();} else { total = price * 0.98; send();} Nahradit za: if (isspecialdeal()) total = price * 0.95; else total = price * 0.98; send(); 15 / 31
Duplicitní kód Rodičovská třída 1 0.9 0.8 Drink 0.7 0.6 0.5 0.4 0.3 0.2 0.1 getname() Milk getname() Beer 0 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 16 / 31
Duplicitní kód Rodičovská třída správný postup 1 0.9 0.8 0.7 getname() Drink 0.6 0.5 0.4 0.3 0.2 0.1 Milk Beer 0 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 17 / 31
Vícenásobné podmínky Původně: double disabilityamount() { if (_seniority < 2) return 0; if (_monthsdisabled > 12) return 0; if (_isparttime) return 0; // compute the disability amount Nahradit za: double disabilityamount() { if (isnoteligablefordisability()) return 0; // compute the disability amount 18 / 31
Komplikované if-then-else Původně: if (date.before (SUMMER_START) date.after(summer_end)) charge = quantity * _winterrate + _winterservicecharge; else charge = quantity * _summerrate; Nahradit za: if (notsummer(date)) charge = wintercharge(quantity); else charge = summercharge (quantity); 19 / 31
Veřejné soukromé Původně: public String _name Nahradit za: private String _name; public String getname() {return _name;} public void setname(string arg) {_name = arg;} 20 / 31
21 / 31
Příliš dlouhá metoda nebo struktura Duplicitní kód Dříve snaha o co nejmenší počet volání Dnes přehlednost 22 / 31
Vyjmutí metody Původně: void printowing() { printbanner(); //print details System.out.println ("name: " + _name); System.out.println ("amount " + getoutstanding()); } 23 / 31
Vyjmutí metody Oprava Nahradit za: void printowing() { printbanner(); printdetails(getoutstanding()); } void printdetails (double outstanding) { System.out.println ("name: " + _name); System.out.println ("amount " + outstanding); } 24 / 31
Příliš dlouhá metoda Odstranění nepotřebných proměnných Původně: double baseprice = anorder.baseprice(); return (baseprice > 1000) Nahradit za: return (anorder.baseprice() > 1000) 25 / 31
Dlouhý seznam parametrů Předávání celého objektu Původně: int min = dailytemperature.getmin(); int max = dailytemperature.getmax(); mystat = stat.range(min, max); Nahradit za: mystat = stat.range(&dailytemperature); 26 / 31
Komentáře Špatně pojmenovaná funkce? Nejasný kód? Komentáře uvnitř metod lepší vyjmout na samostatné místo Co, jak a proč metoda dělá 27 / 31
Přiřazení Původně: int x; x = 7; Nahradit za: int x = 7; Hodnota vždy nastavená Zpomalení (C++) 28 / 31
Code obfuscation Inverzní postup k refaktorování char*f="char*f=%c%s%c;main(){printf(f,34,f,34,10); }%c"; main(){printf(f,34,f,34,10);} 29 / 31
Shrnutí Refaktorování - co to je Kdy a proč refaktorovat Techniky refaktorování 30 / 31
Děkuji za pozornost! Celá prezentace je dostupná na http://kfe.fjfi.cvut.cz/~hajeklu2/files/oop/ 31 / 31