objektum-orinetált mérések a gyakorlatban

20
Objektumorientált mérések a gyakorlatban Orcsik Antal Arkon Zrt. 1 Orcsik Antal vagyok, lassan 8 éve dolgozom az Arkonnál, mint PHP fejlesztő. 2000 óta foglalkozom weboldalak fejlesztésével. 5 éve vagyok a köpönyeg.hu fejlesztője. 2011. július óta futtatunk méréseket a köpönyeg kódján, rögtön elkezdett érdekelni, hogy pontosan mi is ez, és miért jó.

Upload: antal-orcsik

Post on 03-Jul-2015

246 views

Category:

Technology


1 download

DESCRIPTION

Milyen eszközökkel vizsgálhatjuk objektum-orientált PHP kódunk állapotát

TRANSCRIPT

Page 1: Objektum-orinetált mérések a gyakorlatban

Objektumorientáltmérések a gyakorlatban

Orcsik AntalArkon Zrt.

1

Orcsik Antal vagyok, lassan 8 éve dolgozom az Arkonnál, mint PHP fejlesztő.2000 óta foglalkozom weboldalak fejlesztésével.5 éve vagyok a köpönyeg.hu fejlesztője.

2011. július óta futtatunk méréseket a köpönyeg kódján, rögtön elkezdett érdekelni, hogy pontosan mi is ez, és miért jó.

Page 2: Objektum-orinetált mérések a gyakorlatban

• hatékonyan működjön• legyen átlátható• könnyen újra lehessen hasznosítani• gyorsan lehessen bele fejleszteni• (minél inkább dokumentálva legyen)

Milyen a jó szoftver (kód)?

2

Alapvetően a piac követeli meg, hogy a szoftvert alkotó kód:

• hatékonyan működjön

Persze attól még, hogy jól működik a szoftver nem biztos, hogy jó a kód is!

• legyen átlátható• könnyen újra lehessen hasznosítani• gyorsan lehessen bele fejleszteni• (minél inkább dokumentálva legyen)

Ezeknek a szempontoknak a fontossága pedig sokszorosára növekszik, ha a webről beszélünk, ahol a folyamatos karbantartás és fejlesztés a mindennapi munka része. Az oldalak aktív, nagy létszámú közönséget szolgálnak ki és óhatatlanul előfordulnak hibák, amiket villámgyorsan kell javítani. Ha lehet, már kezdetektől fogva figyelni kell erre, egy megörökölt rendszer esetében pedig talán még fontosabb.

Page 3: Objektum-orinetált mérések a gyakorlatban

• Tesszük a dolgunkat és ha valami nagyon nagy szívás, ott gond van

• Nekieshetünk átnézni az egészet, antipatternekre vadászva

• Mérjük meg…

Honnan tudhatjuk, hogy gond van a kódunkkal?

3

Vegyük azt az esetet, hogy már van egy rendszerünk, mivel konkrét tapasztalaim ezena téren vannak.

Feltételezhetjük, hogy az egész kódunk azért nem egy rakás szemét, mert az már messziről látszik. Szeretnénk tehát kideríteni, van-e olyan része amin érmes lenne a korábban említett szempontok miatt javítani.

1. Tesszük a dolgunkat és ha valahol nagyon nagy szívás van, ott gond is van

remekül fog kinézni, mikor egy gyorsjavítás kapcsán közöljük, hogy itt lenne pár nap extra munka, mert csúnya a kód, nem is beszélve a lehetséges függőségekről, meg arról, hogy hány dolgot fogunk közben eltörni. Jobb lenne talán ezt megelőzni...

2. Nekieshetünk átnézni az egészet, antipatternekre vadászva

ebből már születhetnek jó ötletek, átgondolt refaktorálási storyk, de meglehetősen időigényes dolog, és kisebb dolgok, vagy nagyobb összefüggések elkerülhetik a figyelmünket. Biztos van valami jobb megoldás...

3. Mérjük meg…

Page 4: Objektum-orinetált mérések a gyakorlatban

• Chidamber & Kemerer (1994)A metrics Suite for Object Oriented Design

• Li & Henry (1993)Maintenance Metrics for the Object Oriented Paradigm

• Thomas J. McCabe (1976)A Complexity Measure

Mit, hogyan, mivel?

4

Na persze, de mégis mit, és főleg hogyan?

Nem kell nekünk feltalálni a spanyol viaszt, az objektumorientált rendszerek mérhetőségével kapcsolatban íródott már néhány remek publikáció a '90-es években (amikre egyébként minden későbbi hivatkozik).

• [Chid94] Chidamber & Kemerer: A metrics Suite for Object Oriented Design• [LiHe93] Li & Henry: Maintenance Metrics for the Object Oriented Paradigm

Amik elsőként fogalmazták meg mit lehet és kell is mérni, illetve, hogy az eredményeket hogyan értékeljük. Meg kell viszont említenünk még egy nagyon fontos művet

• [McCa76] Thomas J. McCabe: A Complexity Measure

Thomas J. McCabe '76-ban megalkotta a Ciklomatikus Komplexitás fogalmát, azóta is ez az alapja mindennek. Erre még később részetesebben is kitérek.

Page 5: Objektum-orinetált mérések a gyakorlatban

• Manuel Pichler (@manuelp)http://www.manuel-pichler.de

• phpmd (PHP Mess Detector)http://phpmd.org

• pdepend (PHP Depend)http://pdepend.org

Mit, hogyan, mivel?

5

Ha már tudjuk mit kell mérni, akkor már csak eszközök kellenek. Ezeket sem kell nekünk megírni, ezt megtette már helyettünk

Manuel Pichler (@manuelp) - http://www.manuel-pichler.de

Maguk az eszközök pedig:

• phpmd (PHP Mess Detector) - 2009• pdepend (PHP Depend) - 2011

A pdepend Java és C programozók számára ismerős lehet, ezekhez a nyelvekhez is létezik ez az eszköz.

Először a Mess Detectorról lesz szó.

Page 6: Objektum-orinetált mérések a gyakorlatban

• Unused Code Rules• Unused Formal Parameter• Unused Private Method• Unused Private Field• Unused Local Variable

PHP Mess Detector Rules 1.

function example($a, $b) { return $a * 2;}

/** * @SuppressWarnings(PHPMD.UnusedFormalParameter) */

6

A phpmd arra való, hogy feltérképezze a kódunkat és szóljon, ha valami szerinte nincs rendben. A több tucat csomagokba rendezett szabály van, melyeket a kódunkra alkalmazhatunk. A teljes lista elérhető a pmd online dokumentációjában (http://phpmd.org/rules/index.html), lássunk a fontosabb csoportokat és néhány szabályt, amit én is használok:

• Unused Code Rules, nem használt kódrészletek◦ Unused Formal Parameter◦ Unused Private Method◦ Unused Private Field◦ Unused Local Variable

Ezek ugyan nem tűnnek komoly dolgoknak, de sokszor segítettek egy-egy hiba felfedezésében. Volt egy eset, mikor elírtam egy változó nevét egy metódusban, a pmd pedig szólt, hogy nem használom a metódus egyik paraméterét. Ezek sárga színnel jelennek meg a listában, és csak figyelmeztetések, de kijavításuk általában egyszerű így ezt érdemes minél hamarabb megtenni!

Vannak szükségtelennek tűnő figyelmeztetések is, pl. mikor egy interface megkövetel egy paramétert a metódusban, de mi azt nem használjuk. Itt trükközhetünk is, de pont az ilyen esetekre létezik a metódus vagy osztály szintű szabály elnyomás, amit a fejléc commentbe kell tenni.

Page 7: Objektum-orinetált mérések a gyakorlatban

• Naming Rules• Controversial Rules • Design Rules• Code Size Rules

• Exessive Method Length

• Cyclomatic Complexity

PHP Mess Detector Rules 2.

7

• Naming Rules• Controversial Rules

Ezek a szabályok a metódusok és változók elnevezéseivel és használatával kapcsolatos következetességre figyelnek, túl rövid vagy hoszzú változónevek, CamelCase, getX(), isX().

• Design Rules

Ezek arra figyelnek, hogy ne legyen a kódban exit, eval vagy goto, illetve bizonyos öröklődéssel kapcsolatos jellemzőket, amikről majd később még lesz szó.

• Code Size Rules, pedig a kód méretével kapcsolatos szabályokat tartalmazza, pl.:◦ Exessive Method Length, a különösen hosszú metódusokat nézi◦ Cyclomatic Complexity, ami a metódusok Ciklomatikus Komplexitását figyeli, térjünk is

ki egy kicsit erre

Page 8: Objektum-orinetált mérések a gyakorlatban

• E: élek (5)• N: pontok (5)• P: kilépési pontok (1)

Cyclomatic Complexity 1.

CYCLO = E - N + 2P = 2

8

Korábban már említettem, hogy bizonyos Thomas McCabe nevéhez fűződik ez az érték. Ezzel lehet a legjobban jellemezni egy kódrészlet, metódus vagy osztály bonyolultságát. Nem nehéz kiszámolni sem, képzeljünk el a folyamat ábrát. Ez ugye egy gráf, élekkel és pontokkal. Ebből a Ciklomatikus Komplexitást úgy kapjuk meg, ha az élek számából kivonjuk a pontok számát és hozzáadjuk a kilépési pontok számának kétszeresét.

• E: élek• N: pontok• P: kilépési pontok

CYCLO = E - N + 2P

Page 9: Objektum-orinetált mérések a gyakorlatban

Cyclomatic Complexity 2.function example($a) { if ($a) { for ($i=1;$i<$a;$i++) { if ($i%2 && $a>10) { echo $i; } } }}

• minden metódus alaból 1• minden elágazás és kör +1

9

Na pesze senki ne ijedjen meg, lehet ezt egyszerűbben is:

• minden metódus komplexitása alapból 1 • amihez annyiszor adunk még egyet, ahány elágazás és kör van a kódban

Egy metódus komplexitása annak bonyolultságát határozza meg. Egy túlságosan komplex metódus valószínűleg többet csinál, mint amit kéne neki, érdemes lehet szétszedni több részre. Na de, mi számít túlságosan komplexnek? Mondjuk a 10.

Mikor 2011-ben bevezettük a phpmd-t, én is elkezdtem figyelni erre a dologra, és ma már úgy kódolok, hogy fejben számolom a komplexitást. Ha egy metódus eléri a 10-et, akkor újra átgondolom amit csinálok, és sok esetben sikerül egy nagyobb részletet kiszervezni úgy, hogy azt máshol is fel tudom használni. Ezen felül leszoktat a terjengős elágazás erdőkről, és megtanít rá, hogy kétszer is meggondoljuk mit és mikor vizsgálunk.

Page 10: Objektum-orinetált mérések a gyakorlatban

Cyclomatic Complexity 3.

if ($cond) { $result = 1;} else { $result = 0;}

$result = 0;if ($cond) { $result = 1;}

switch ($cond) { case “a”: $x = 1; break; case “b”: $x = 2; break; default: $x = 3;}

$switch = array( “a” => 1, “b” => 2,);$x = 3;if (isset($switch[$cond])) { $x = $switch[$cond];}

10

Mutatok még két nagyon egyszerű példát, komplexitás csökkentésre.

Page 11: Objektum-orinetált mérések a gyakorlatban

Tapasztalat

11

A szabályok finomhangolása után a köpönyeg nagyjából 400 pmd hibát tartalmazott, amit az elmúlt egy évben refaktorálással körülbelül 100-ra csökkentettem, és a cél természetesen, hogy végül egy se maradjon, bár vannak tipikusan kihívást jelentő komplexitás és metódus hossz hibák.

Egyik-másik parser vagy ábra rajzoló a 20-30 komplexitást is eléri, amit csak igen kemény munkával lehet rendbetenni.

Page 12: Objektum-orinetált mérések a gyakorlatban

PHP Depend

Áttekintő piramis

AbsztrakcióInstabilitásgrafikon

12

Térjünk át akkor a következő eszközre.

A korábban említett publikációk számos értéket határoznak meg, a PHP Depend, a dokumentéciója szerint (http://pdepend.org/documentation/software-metrics/index.html), közel 40 olyan metrika kiszámítására képes, amikből a kódunk minőségére következtethetünk, viszont most csak néhányat emelnék ki.

A program két összefoglaló ábrát készít a kódunkról

• az Áttekintő piramist és • az Absztrakció Instabilitás grafikont

Kezdjük az előzővel.

Page 13: Objektum-orinetált mérések a gyakorlatban

Piramis - Code Size

• CYCLO: Cyclomatic Complexity

• LOC: Lines of Code

• NOM: Number of Methods

• NOC: Number of Classes

• NOP: Number of Packages (Namespaces)

13

A piramis három sarka három mérési kategóriát jelöl, bennük pedig a mért adatok és az azok hányadosaiból számolt értékes metrikák találhatóak:

• Code Size (a kód méretei) A komplexitás mellet nagyon fontos még a kód mérete, amit PHP esetén négy értékkel határozunk meg:◦ CYCLO: Cyclomatic Complexity, ismét itt◦ LOC: Lines of Code, azaz a sorok száma◦ NOM: Number of Methods, azaz a metódusok száma◦ NOC: Number of Classes, azaz az osztályok száma◦ NOP: Number of Packages (Namespaces), azaz a csomagok, vagy 5.3 óta a

névterek száma

Ezeknek viszont a hányadosai hordozzák a fontos információt.

A CYCLO/LOC egy sor átlagos komplexitása a LOC/NOM pedig egy metódus átlagos hossza. Az előző 0.2 alatt van, az utóbbi pedig 13 alatt, akkor vagyunk a zöldben, de ez azt is jelenti, hogy átlagosan 2,6 komplexitása lehet egy metódusnak, ha a zöldben szeretnénk maradni. Ez jóval kevesebb, mint a 10, amit a phpmd-nél mondtam, de látszik, hogy arra kell törekedni, hogy minél egyszerűbb és érthetőbb legyen egy metódus.

Nekem a LOC/NOM okozta a legtöbb gondot, mert a köpönyeg elég sok procedurális kódot tartalmazott az MVC átírás előtt. Konkrétan 26-ról kellett szépen lassan ezt a számot lefelé terelgetni.

Ököl szabály, hogy a kisebb jobb. Szóval a legjobb a kódunk akkor lesz, ha minél több névteret hozunk létre, bennük lehetőleg kevés osztályt, néhány egyszerű és rövid metódussal. Ezzel így valami nem stimmel, de majd később visszatérünk erre.

Page 14: Objektum-orinetált mérések a gyakorlatban

Piramis - Coupling

• CALLS: metódus hívások

• FANOUT: típus kényszer,a rendszer más részéből

14

• Coupling (kapcsolódás) a program egyes részei közötti kapcsolatot is mérhetjük◦ CALLS: ez különálló metódushívások száma◦ FANOUT: ez pedig a metódusok paraméterlistájában lévő típus kényszereket számolja,

ha azok az alkalmazás egy másik ágához kapcsolódnak

A kapcsolódás már keményebb dió, itt azt kell megértenünk, hogy ha a CALLS/NOM, azaz a kapcsolódás intenzitása, nagy az azt jelenti, hogy az egész szoftverünk durván néhány metódusból áll, amik folyton egymást hívogatják. Ez arra utalhat, hogy nagyon kusza a szoftverünk részegységei közötti kapcsolat, ami nem csak a hibák felderítésében okozhat gondokat, de egy apró baki is képes lehet rendszer szintű gondokat okozni.

Page 15: Objektum-orinetált mérések a gyakorlatban

Piramis - Inheritance

• ANDC: Average Number of Derived Classes (szélesség, intenzitás)

• AHH: Average Hierarchy Height (mélység)

15

Itt nincsenek hányadosok, ezt a két átlagot önmagában kell vizsgálnunk. Itt is érvényes az ökölszabály, hogy a zöld a jobb, de árnyaltabb a kép.

• Inheritance (öröklődés) az öröklődést is leírhatjuk két értékkel◦ ANDC: Average Number of Derived Classes, azaz a származtatott osztályok átlagos

száma. Ez az osztályok számának súlyozott átlaga, ahol minden osztály súlya a közvetlen leszármazottainak száma.

Ez a szám az örökési rendszerünk szélességét mutatja meg, hogy mennyire vesszük igénybe az öröklést, és annál kisebb, minél több a gyermektelen osztály.

◦ AHH: Average Hierarchy Height, azaz az öröklési hierachia átlagos magassága. Ez a gyökér osztályok számának súlyozott átlaga, ahol minden osztály súlya a belőle kiinduló öröklési fa legnagyobb mélysége.

Ez a szám pedig a arról tájékoztat, milyen mennyire mélyek az öröklések, és annál kisebb, minél kevesebb a mély öröklési fa.

Az ANDC esetében pl. csúnyán a narancsba kerülünk, ha egy db absztrakt objektumból örököltetünk mindent. De hát, miért ne tennénk, láttunk már ilyet, hogy minden egy Base object leszármazottja, és ennek megvannak a jó oldalai is. Ennek ellenére ez a mérési rendszer azt javasolja, az osztályaink inkább legyenek különállóak, mintsem egy terebélyes hierachia részei, a pmd még figyelmeztetni is tud, ha ilyesmire utaló jeleket talál!

Page 16: Objektum-orinetált mérések a gyakorlatban

PHP Depend - Low, Avg, High!

16

Ez is most nagyon furcsa, hiszen van nagyon jó és szép rendszer, ami intenzíven alkalmazza az öröklést, akkor ez mégis miért rossz? Nem az.

Nézzük meg a színkódot: szürke: alacsony zöld: átlagos narancs: magas

A piramis öröklés sarkára különsen igaz, de a többire is, hogy a narancs nem “rossz”, hanem “magas”. Ez az ábra pedig nem azt mutatja meg, hogy a kódunk milyen rossz vagy jó, hanem azt, hogy “milyen”. Áttekintést ad arról, hogy a kódunkban milyen intenzitással használunk öröklést, óriási osztályink, vagy csak kicsik, hosszú rövidek-e a metódusaink vagy hosszúak és bonyolultak?

Nagyon jó, ha a piramisunk zöld, de nem cél! Ne felejtsük el, hogy az ideák kergetésében nagyon könnyű szemelől téveszteni a célt.

Page 17: Objektum-orinetált mérések a gyakorlatban

Absztrakció és Instabilitás 1.• ac: absztrakt osztályok• cc: konkrét osztályok

A = ac / (ac + cc)• Ce: efferens kapcsolatok• Ca: afferens kapcsolatok

I = Ce / (Ce + Ca)

17

Ezen a látványos ábrán az egyes csomagokat (névtereket) láthatjuk az absztrakciójuk, instabilitásuk és méretük függvényében.

Az absztrakció egyszerű, a csomagban található absztakt osztályok aránya az összeshez. Minél több van belőlük, annál inkább jobbra helyezkedik el a kis golyó az ábrán.

A = ac / (ac + cc)Az instabilitás már bonyolultabb. Vannak az Afferens kapcsolatok, azok a csomagok, amik valahogy függenek a vizsgált csomag osztályaitól, illetve az Efferens kapcsolatok, azok a csomagok, amiktől valahogy függenek a vizsgált csomag osztályai.

• Ca: Afferent Couplings, amik tőlem függenek• Ce: Efferent Couplings, amiktől én függők

Az instabilitást úgy számolhatjuk ki, hogy az osztály saját függőségeinek számát elosztjuk az összes függőséggel, vagyis egy csomag instabil, ha több indetől függ, mint amennyien tőle függenek.

I = Ce / (Ce + Ca)

Page 18: Objektum-orinetált mérések a gyakorlatban

Absztrakció és Instabilitás 2.

?

18

Egy csomag akkor van az ideális zónában, ha az instabilitás és az absztrakció összege 1. Teht egy olyam csomag, ami főleg másoktól függ, tipikusan ilyenek a kontrollerek, azokban ne legyen túlsúlyban az absztrakt osztályok száma a konkrétakkal szemben. A másik oldalon viszont, ha egy csomag főként absztrakt csomagokból áll, akkor inkább tőle függjenek más csomagok, azaz legyen minél inkább stabil.

Jellemző, hogy olyan absztrakt csomag, amitől semmi nem függ nem vagyon van, hisz ki gyártana ilyen csomagot?

Az már gyakrabban fordul elő, hogy egy konkrét csomag nem függ semmitől, sőt talán még tőle függenek. Ezeket célszerű megvizsgálni és valahogy átszervezni.

Page 19: Objektum-orinetált mérések a gyakorlatban

Összefoglalás

• Előnyök• sokkal gyorsabb, mint bármi más

• aprólékos (pmd)

• átfogó kép (pdepend)

• Hátrányok• néha szigorú és ellentmondásos

19

A bemutatott két eszköz kiválóan alkalmas arra, hogy viszonylag gyorsan adjon információt a kód állapotával kapcsolatban. Nálunk minden buildnek része, hogy ezek a mérések lefutnak, hogy legalább élesítés előtt mindenképp lássuk, mit is csináltunk. Ha figyeljük a számokat könnyen észrevehetjük, ha rossz irányba haladunk.

Előnyök

Hátrányok

Mindenképp javaslom, hogy futtassátok le ezeket a saját rendszereiteken is, ha még nem tettétek és fontoljátok meg, hogy a talált problémákat kijavítsátok.

A személyes tapasztalatom, hogy az elmúlt évben úgy fejlesztettem, hogy ezeket szem előtt tartottam és a köpönyeg ma sokkal jobb állapotban van, mint előtte, és fejleszteni is könnyebb.

Page 20: Objektum-orinetált mérések a gyakorlatban

Kérdések?

Orcsik Antalhttp://blog.intiweb.hu/ [email protected]@aorcsik

20