Skip to content

Hónap: 2016 December

Continuous Integration

Miért?
A szoftvergyártás automatizálása és centralizálása produktívabbá tesz és csökkenti a kiszállításkori hibák veszélyét.

Gyakran a szoftverkomponensek integrációját időben hátra tolják és fáradságosan, hibára hajlamosan „kézzel” hajtják végre. De tulajdonképpen a szoftvernek minden időpontban teljesen futásképesnek kell lennie. A Continuous Integration-nel egy olyan folyamatot jelölnek, amely gondoskodik arról, hogy változtatások bevitele után a teljes kód leforduljon és tesztelődjön.A Continuous Integration folyamat főképpen team-eknek fontos, mert gondoskodik arról, hogy változtatások megtétele utána a teljes kód lefordul és tesztelődik, nem csak az a rész, amelyen a fejlesztő éppen dolgozott. Az automatizált teszteket mindegyik fejlesztőnek végre kell hajtania, mielőtt felvinné a változtatásait a központi verziókezelőbe. Ezen a Continuous Integration nem változtat semmit. Ahhoz hogy biztosítva legyen, hogy a tesztek mindenképpen lefussanak és a hibákat idejekorán észlelni lehessen, a Continuous Integration szerveren mindenképpen le kell futniuk. Ez nem szabadítja fel a fejlesztőt azalól, hogy a teszteket minden commit előtt végrehajtsa, hiszen a verziókezelőbe bevitt hibás kód a teljes team-et hátráltatja, sőt előfordulhat, hogy további team-eket is. Így a Continuous Integration folyamat arról gondoskodik, hogy team-eken átívelően a hibákat a lehető legkorábban felismerjük.

A Continuous Integration folyamathoz számos szoftvereszköz áll rendelkezésre. A folyamatos buildelésen és tesztelésen kívül, ami azonnal megtörténik, amint változtatások kerülnek a verziókövető rendszerbe, a Continuous Integration hosszabban futó folyamatokat, mint pl. adatbázistesztet is, automatizálhatóvá tesz. Ezeket pl. csak éjszakánként hajtja végre. A zöld fokozaton csak a buildelési és teszt folyamatokat kell figyelembe venni. A szoftver folyamatos setup-ja és kiszállítása csak később, a kék fokozaton történik.

Martin Fowler egy nagyon jó cikket írt erről a témáról: http://www.martinfowler.com/articles/continuousIntegration.html

Lásd az eszközök alatt.

Statikus kódanalízis (metrikák)

Miért?
A bizalom jó, de az ellenőrzés jobb – és minél jobban automatizálva van, annál könnyebb.

Hogyan határozható meg egy kódrészlet minősége, pl. egy osztályé vagy egy komponensé? Elegendő az, ha a megrendelői követelményeknek funkcionálisan eleget tesz? Elegendő az, hogy elég gyors és eléggé skálázható? Az automatikus tesztek és végül a megrendelő tesztjei fognak erről felvilágosítást nyújtani. Az ilyen követelménynek való megfelelések nélkül a szoftvernek természetesen nincsen releváns minősége. Ha nem használ a megrendelőnek, minden további kérdés feleslegessé válik.A másik oldalon viszont nem elegendő, minden széleskörben elterjedt feltételezéssel ellentétben, a követelményeknek való megfelelés. A jó minőség nem csupán a funkcionalitásból és pl. a performanciából áll. Mert a funkcionális és nem funkcionális követelmények mellett van egy általában kimondatlan, rejtett követelmény: A megrendelők általában azt akarják, hogy a szoftver ne csak ma feleljen meg a követelményeknek, hanem holnap és holnapután is. A megrendelők befektetésvédelmet szeretnének továbbfejleszthetőség által.

A megrendelők számára ez a követelmény általában implicit. Azt hiszik, hogy ez magától értetődő, hogy egy immateriális termék, mint egy szoftver kvázi a végtelenségig fejleszhető és gombnyomásra az új követelményekhez igazítható. Gyakran azok a vezetők is ezt hiszik, akik nem a szoftverfejlesztésből kerülnek ki. Sőt még maguk a szoftverfejlesztők is!

Nem is lehetne nagyobb a félreértés a szoftverek körül. A továbbfejleszthetőség sem a szoftverfejlesztők által mindenképpen követett célok értelmében magától értetődő, sem pedig nem adódik valamiből kvázi magától. A továbbfejleszthetőség sokkal inkább kemény munka eredménye, melyet folyamatosan egyéb értékekkel szemben kell mérlegelni.

Amikor egyéb követelménynek való megfelelést csak (automatizált) tesztekkel lehet megállapítani, hogyan állunk akkor a továbbfejleszthetőséggel? Lehet a kód minőségét a túlélőképessége tekintetében automatikusan is mérni? Részben. Nem minden aspektusát lehet annak automatikusan ellenőrizni, ami a szoftvert továbbfejleszhetővé teszi. Például, hogy a szoftver nyitott-e a bővítésre az Add-In koncepció szerint, azt nem lehet automatikusan felismerni.

Mégis vannak metrikák, melyek értéke egy szoftver számára „kiszámítható”. Eszközök segítenek ebben. Ezeket az eszközöket tehát minden szoftverprojektben be kellene vetni.

  • Ezek az eszközök képesek a régebbi kódot státusz quo-nak használni, és ez alapján egy alapvonalat meghatározni, amivel a kód további fejlesztését (javítását) össze lehet hasonlítani.
  • Az új kódnál, amit a továbbfejleszthetőség szempontjából terveztek, a statikus kódanalízis azt mutatja meg, hogy a tervezés ideális állapotát elérte-e.

A Clean Code fejlesztő nem elégszik meg azzal, hogy automatizáltan tesztelje a kódot. Az egyik szemünk mindig a továbbfejleszthetőségen van, mert tudjuk, hogy a megrendelő ebben ugyanannyira érdekelt – mindegy, hogy explicit mondta-e vagy sem.

Lásd az eszközök alatt.

Inversion of Control Container

Miért?
Csak azt lehet könnyen konfigurálni, ami nincsen szorosan bedrótozva.

Már a sárga fokozaton megismerkedett a Clean Code fejlesztő a Dependency Inversion Principle-lel. Akkor még a függőséget „kézzel” oldottuk föl. A következő logikus lépés abból áll, hogy a függőségek feloldását automatizáljuk. Ehhez két eljárás áll rendelkezésre:

  • Locator
  • Container

Mindkettő egy úgynevezett Inversion of Control Container-t (IoC konténer) használ. A konténer használata előtt a használt osztályokat el kell helyezni a konténerben. Ezek után a konténer az elhelyezett osztályokból példányokat tud adni. A Locatornál ez explicit történik. Ennek az az előnye, hogy a függőségeket nem kell mind az osztály konstruktorában felsorolni. A keresztmetszeti feladatoknál, mint pl. a loggolás, ez egy általánosan elfogadott eljárás. Azonban a függőségeket rendszerint a konstruktor paraméterében sorolják fel. Ennek az az előnye, hogy minden függőség láthatóvá válik. Így a konténer képes arra, hogy a függőségeket implicit feloldja azáltal, hogy minden szükséges objektumot rekurzív példányosít.

Az IoC konténerek akkor válnak különösen fontossá, amikor az osztályok száma nő. Ha megszívleljük a Separation of Concernst, akkor sok kis osztály keletkezik átlátható feladatokkal. Ezeknek az osztálypéldányoknak összeállítása ennek megfelelően válik költségessé. Éppen itt lép akcióba az IoC konténer, segít a példányosításban és összeköti a sok kis objektumot.

Az IoC konténernek egy további előnye az a tény, hogy meg lehet határozni a konfigurációban egy objektum életciklusát. Amennyiben a futásidőben egy objektumnak csak egyetlen egy példánya létezhet (Singleton), akkor a konténert utasítani lehet, hogy mindig ugyanazt a példány adja vissza. Más életciklusokat is támogat, mint pl. egy példány session-önként.

Ahhoz, hogy a Locator használatakor ne egy bizonyos IoC konténer függőségbe csöppenjünk, lehet a Microsoft Common Service Locator-t (lásd eszközök) használni. Ez egy egységesített interfészt kínál a használatos IoC konténerekhez.

Egy ilyen IoC konténer mechanizmusának megértéséhez hasznos lehet az, hogy egyszer ezt a funkcionalitást magunk implementáljuk. Nem kell a teljes konténert implementálni, elég az alapfunkcióját.

Lásd az eszközök alatt.

A tapasztalatok továbbadása

Miért?
Aki továbbadja a tudását, az nem csak másoknak segít, hanem magának is.

A professzionális munkához természetesen aktuális tudás tartozik. Ez természetesen nem azt jelenti, hogy valakinek mindent kell tudnia a szoftverfejlesztésről vagy csak a .NET platformról. Az aktuális tudás az ember speciális területére vonatkozik – bármi légyen is az. Ezért a többi fokozat praktikáinak része a rendszeres információfelvétel a különböző médiumokból.

Több okból azonban egy ilyenfajta információgyűjtés a „tanulás”-éremnek csak az egyik oldala. A másik az információ továbbadása, a tudás megosztása. Az igazi professzionalitáshoz szerintünk nem csak a „kutatás”, hanem az „oktatás” is hozzá tartozik. Hiszen csak az „oktatás”-sal történik meg a tárgy valódi reflektálása és átlátása.

Az, hogy használjuk azt, amit hallottunk/olvastunk, az csak az egyik oldal. Természetesen felmerülnek megértési hiányosságok. Egy tárgy tanulmányozása azonban az erőfeszítés oka miatt természetesen korlátozott. Aki csak annyit kutat, amennyire egy technogiához/koncepcióhoz éppen szüksége van, az nem merül le túl mélyre.

Egészen másképpen van ez, ha a tanulás a továbbadás jegyében történik. Aki nem mindig csak magának, hanem mindig másoknak is tanul, az mélyebben sajátítja el a dolgokat. Ez akkor válik világossá, amikor az ember megpróbál (állítólag) megtanult dolgokat másoknak átadni. Ha erre nem vagyunk tekintettel a tanulás során, akkor gyorsan olyan kérdések merülnek fel, amelyeket soha sem tettünk fel magunknak. Másoknak mindig egészen más perspektívájuk van.

Ezért gondoljuk úgy, hogy csak az tanul valóban alaposan, aki újra és újra kiteszi magát a továbbadásnak és a tudás megosztásának. Csak aki a megtanultakat nem csupán használja, hanem saját szavaival megfogalmazza egy publikum számára, veszi észre ebben a folyamatban, hogy milyen mély is valójában az ő saját tudása. Mert, ha a „tanulók”-nál gyűlnek a kérdőjelek, akkor valami még nem egészen kerek.

Erre természetesen egy valódi publikum a legalkalmasabb. Minden Clean Code fejlesztőnek rendszeresen kellene keresni a lehetőséget, hogy a tudását szóban továbbadja (pl. rendezvényeken, kollégák körében vagy fórumokon). A közvetlen visszajelzésben biztos lehet. Ennek alternatívájaként vagy kiegészítéseként az írásos kompetencia-megnyilvánulások is megfelelők. Egy blogot 5 perc alatt össze lehet rakni és a szakmai folyóiratok folyamatosan keresik a szerzőket. Az ilyen helyeken ugyan nem annyira közvetlen a visszajelzés, de az írásos megfogalmazása az ismereteinknek nagyon jó gyakorlat.

A Clean Code fejlesztők a zöld fokozattól tehát már nem csak „passzívan” tanulnak, hanem „aktívan” is a tudásuk továbbadásával prezentációkban vagy írásos szövegekben. Ez lehet, hogy szokatlan – de talán a Continuous Integration is szokatlan. Mindenesetre az aktív tudás átadása jó gyakorlat a saját kompetenciáink továbbmélyítésére. „Tégy jót és beszélj róla” 😉

Magától értetődő, hogy a tanítás használ a hallgatóknak/olvasóknak is. Mások előnye nem annyira motiváló, mint a saját előnyünk. Ezért hangsúlyozzuk itt a tudásátadás hasznát a Clean Code fejlesztő számára.

A hibák mérése

Miért?
Csak az tudja úgy megváltoztatni az eljárását, hogy csökkenjen a hibarátája, aki tudja, hogy mennyi hiba lép fel.

A szoftverfejlesztés alatt hibák lépnek fel. Ezek minden fázisban előfordulnak: rosszul értett vagy nem elég világosan megfogalmazott követelmények ugyanúgy hibához vezetnek, mint a hibás implementálás. A végén minden olyasmi hiba, ami ahhoz vezet, hogy a megrendelő olyan szoftvert kap, ami nem felel meg az ő követelményeinek. Az iteratív eljárás és a reflektálás két elem a folyamat javításához vezető úton. Egy olyan mérési értékre van szükségünk, amiből a jobbrafordulás lemérhető, ahhoz, hogy felismerjük, valóban állt-e be javulás.A hibák mérése megszámlálással vagy időszakítással történhet. Amíg a mérési módszer összehasonlítható adatokkal szolgál, addig nem a precizitás lesz előtérben. A több iteráción átívelő fejlődési tendenciának leolvashatónak kell lennie. Továbbá nem az a lényeg, hogy egy adott hibának a felelősét megtaláljuk. Végülis mindegy, hogy ki okozta a hibát, amíg a team tanul belőle és javít a folyamatán.

Mely hibákat kell mérni? Nem azokat a hibákat, amelyek a fejlesztés alatt lépnek fel. Ezeket nem lehet elkerülni, és remélhetőleg oda vezetnek, hogy az iteráció végén egy hibamentes termék kerül kiszállításra. Sokkal inkább azokról a hibákról van itt szó, melyeket az iteráció után a megrendelő ill. a helyettese (pl. product owner vagy a terméktámogatás) jelez. Ezek azok a hibák, amelyek az új követelmények megvalósítását akadályozzák. A mérendő hibák tehát azok, amelyek akkor lépnek fel, amikor az ember azt hiszi, hogy nem is volna szabad létezniük. 😉 Team-től függően kell meghatározni, hogy a folyamatban a team mikor éri el ezt a pontot és kezd szitkozódni, mert már megint egy hiba gátolja az egyéb munkák elvégzését.

A fehér fokozattal zárul be a kör. Egyesíti a színes fokozatok összes elvét és praktikáját. Ennek a horizontja az összes építőelem együtt. Aki eléri a fehér fokozatot, az állandóan az értékrendszer összes elemével dolgozik. Mivel az ilyen folyamatos figyelmességet nehéz előállítani, ezért azt várjuk, hogy a Clean Code fejlesztő egy idő után újra kezdje a munkát a fokozatrendszeren elölről.

Azáltal, hogy 21 nap múlva ismét a piros fokozatot kezdi, a napi gyakorlatban egy kicsit jobban tud majd az értékrendszer egy szeletére koncentrálni. Ez arra szolgál, hogy az egyes fokozatok aspektusainak felhasználását finomítsa. Példa: A verziókövető praktika nem bináris. Aki a piros fokozat óta használja, az nem biztos, hogy kihoz belőle mindent. Amikor a fehér fokozatról visszamegyünk a piros fokozatra, akkor igyekszünk magunknak esélyt adni arra, hogy az ismétlés közben jobban belemélyedjünk a verziókövető rendszer titkaiba. Nincs olyan elv, nincs olyan praktika, amely ne profitálna abból, hogy a fokozatrendszer újbóli átfutásakor újra neki szenteljük magunkat.

A visszatérés a fehérről a piros fokozatra számunkra annak a megértésnek a kifejeződése, hogy az iterációk nem csak a szoftverprojektek praktikái. Az iterációk sokkal inkább a tanulás alaprendszerét határozzák meg. A tanulás ciklusokban történik és szüksége van az ismétlésre.

Ezen felül a fehér karkötő lecserélését a piros javára a szerénység és alázat jelének tartjuk. Ezzel nem kívánunk a CCD-értékrendszerhez spirituális dimenziót adni, hanem csak nyilvánvalóvá tenni, hogy a szoftverfejlesztés a tanulás egy örökké forgó kereke. Aki azt hiszi, hogy a végén megérkezett valahová, hogy egyáltalán megérkezhet valahová, az illúziókba ringatja magát. Aki azonban engedi, hogy a fehéret a piros kövesse, az tudatában van a tanulási körforgásnak.

Amint más helyen is említettük már, a fokozatok nem jelentenek értékelést. Aki a kék fokozaton dolgozik, az sem jobb annál, mint aki a narancs fokozaton dolgozik. A fokozatok az egész értékrendszert csak falatokra bontják, és olyan sorrendbe helyezik, amelynek követését mi egyszerűnek ítéljük. Ily módon egy olyan fejlesztő, aki sikeresen dolgozott a fehér fokozaton semmit sem ad föl, ha újra elkezdi a pirosat.

Akinek ez még mindig nem ízlik, az tetszés szerinti sorrendben ismételheti a „színes fokozatokat”. Úgy dönthet, hogy egy bizonyos időre a figyelmét egy bizonyos fokozat aspektusainak szenteli. Az, hogy ismét a piros fokozaton kezdjük csak azt biztosítja, hogy a sorrendben az összes aspektus mélyülni fog.

Tovább a piros fokozatra.

Interface Segregation Principle (ISP)

Miért?
Az olyan teljesítmény-leírások, melyek a konkrét megvalósítástól függetlenek, függetlenné tesznek.

Az Interface Segregation Principle (ISP) egy további SOLID elv. A Segregation azt jelenti, hogy leválasztás. Ez az elv azt mondja, hogy egy kliens ne függjön egy szerviz részleteitől, amelyekre neki nincs is szüksége. Minél kevesebb dolog található az interfészben, annál lazább a csatolás (coupling) a két komponens között.Gondoljunk csak bele, ha egy olyan dugaszt kellene terveznünk, amelyikkel egy monitort egy számítógépre lehet csatlakoztatni. Úgy döntünk, hogy minden jelet, amely egy számítógépben felléphet, egy dugaszon keresztül rendelkezésre bocsájtunk. Ennek ugyan lesz pár száz lába, de maximálisan rugalmas lesz. Sajnálatos módon ezzel a csatolás (coupling) is maximálissá válik.

A dugasz példáján nyilvánvaló, hogy egy monitor-összeköttetésnek csak azokat a jeleket kell tartalmaznia, amelyek egy kép ábrázolásához szükségesek. Ugyanez van a szoftver interfészeknél is. Ezeknek is a lehető legkisebbnek kellene lenniük, hogy elkerüljük a felesleges csatolást (coupling). És pont mint a monitordugasznál az interfésznek erős összetartásúnak (cohesion) kell lennie. Csak olyan dolgokat kellene tartalmaznia, amelyek szorosan összefüggnek.

Az Interface Segregation Principle alkalmazásához a két refaktorálás Extract interface és az Extract superclass áll rendelkezésre.

Dependency Inversion Principle

Miért?
A pontszerű tesztelésnek az osztályok elszigeteltsége a feltétele. Az elszigeteltség akkor lép fel, amikor az osztályoknak már nincsenek függőségeik implementációktól – sem futásidőben, sem fordításidőben. A konkrét függőségeket tehát a lehető legkésőbb kellene eldönteni. Lehetőleg futásidőben.

A Dependency Inversion Principle (DIP) is egy SOLID elv. A következőket mondja:
  • A high level osztályoknak nem szabad függniük a low level osztályoktól, hanem mindkettő interfészektől függjön.
  • Az interfészeknek nem szabad részletektől függniük, hanem a részleteknek kell az interfészektől.

Amennyiben egy high level osztály közvetlenül használ fel egy low level osztályt, akkor kettejük közt egy erős csatolás (coupling) keletkezik. Legkésőbb akkor ütközünk nehézségekbe, amikor megpróbáljuk tesztelni a high level osztályt. Ebből az okból a high level osztálynak egy interfésztől kell függnie, amit aztán a low level osztály implementál. Így a unit tesztnél a low level osztályt egy mockup helyetesítheti.

Három lehetőség mutatkozik arra, hogy az invertált absztrakt függőséget egy konkért objektummal a futásidőben feloldjuk:

  • konstruktor paraméter segítségével „kézzel”
  • Egy Inversion of Control Container (IoC Container) használatával, mint amilyen a Castle Windsor
  • Dependency Lookup

A sárga fokozaton egyelőre a függőséget a konstruktor paraméterében „fecskendezzük be”. Az elején ez a legegyszerűbb megoldás és egy csomó osztálynál egészen jól működik. Később a zöld fokozaton egy IoC konténert és dependency lookup-ot használunk majd.

Liskov Substitution Principle

Miért?
Akinek örökösökkel van dolga, nem akar meglepetéseket, ha ismeri az öröklőt.

A Liskov Substitution Principle (LSP) is egy SOLID elv. Azt írja elő, hogy az altípusoknak úgy kell viselkedniük, mint a alaptípusnak. Ez először banálisan hangzik. A kivételek (exception) példáján érthetővé válik, milyen problémák lépnek fel, ha ezt az elvet megsértik. Amennyiben az alaptípus egy eljárásának végrehajtásakor nem vált ki kivételt (exception), akkor az összes altípusnak is tartania kell magát ehhez a szabályhoz. Amennyiben az egyik altípus eljárása mégis kivételt (exception) vált ki, akkor ez gondot okoz olyan helyeken ahol egy alaptípusú objektumot használunk, mert ott nem vagyunk felkészülve erre. Ha az alaptípus ezen a helyen nem vált ki kivételt, akkor a használó nincsen felkészülve arra, hogy kivételt kell kezelnie.Általánosabban úgy is ki lehetne fejezni ezt az elvet, hogy az altípusnak csak kibővítenie szabad az alaptípus funkcionalitását, de korlátoznia nem. Amennyiben egy eljárás az alaposztályban egy értéktartományban van meghatározva, akkor az altípusnak ezt az értéktartományt szabad átvennie vagy bővítenie, de semmiképpen sem szabad korlátoznia.

A Liskov Substitution Principle-ből továbbá az az ajánlás következik, hogy alaposan gondoljuk át az öröklődést. A lehető legtöbb esetben a kompozíciót a öröklődéssel szemben előnyben kell részesíteni (Favor Composition over Inheritance). A öröklődésnél mindenképpen el kell gondolkodni a viselkedésről is, nem csak a struktúráról. Ahelyett, hogy a öröklődést mint egy is-a relációt tekintjük, és eközben csak az adatstruktúrára gondolunk, inkább egy behaves-as relációból kellene kiindulni és az osztály viselkedését figyelembe venni.

 

Principle of Least Astonishment

Miért?
Amikor egy komponens meglepő módon másképpen viselkedik, mint ahogyan várnánk, akkor a felhasználása feleslegesen komplikált és nagy a valószínűsége a hibának.

A szoftverfejlesztés nagy mértékben kreatív folyamat. Ebben a folyamatban fontos az, hogy a belemerüljünk az áramlatba (flow). Amikor elértük ezt az állapotot, akkor a kód már csak úgy dőlni fog. Az áramlat (flow) minden nemű zavara csak megszakításokhoz és végeredményben ahhoz vezet, hogy a rendelkezésre álló időben csak kevés kód jön létre, illetve a kód minősége nem lesz optimális. Mert a fejlesztőnek minden megszakítás után fel kell vennie a fonalat, és újra bekerülnie az áramlatba (flow). A meglepetések zavarok. Megszakításokhoz és hibákhoz vezetnek. Erre egy példa: Amennyiben a fejlesztői környezet úgy van beállítva, hogy a szokásos Ctrl-C billentyűkombináció teljesen más jelentéssel bír, akkor ez akadályozza a fejlesztőt. A fejlesztő minden esetre bosszankodni fog, hogy a „rossz” billentyűkombinációt nyomta meg. Ez akadályozza a kreatív munkát.A szoftvereket a lehető legkevesebb meglepetéssel kellene implementálni. Amikor egy GetValue() nevű lekérdező eljárás nem csak egy értéket ad vissza, hanem egyben a rendszer állapotát is megváltoztatja, akkor a fejlesztő ezt az eljárást a legjobb esetben is elkerüli, mivel furcsa meglepetésekkel számol. Rossz esetben viszont nem tűnik fel neki a furcsa viselkedés időben. (Az olyan lekérdező eljárások, melyek megváltoztatják az állapotot megszegik a Command Query Separation elvet). A tesztvezérelt fejlesztés elősegíti a meglepetésekben szegény interfészek készítését, mivel az interfészt a felhasználásának szemszögéből tervezik és implementálják.