agile Lexandro on 18 Nov 2010
Pár gondolat a collective code ownershipről
… avagy a collective code ownership tapasztalatok agile projekteken.
Bevezetés
A collective code ownership (továbbiakban CCO, mert nincs kedvem mindig beírni) az agile metodológiák egyikének az extreme programmingnek (XP) részét képező alapelv vagy szabály, ami szerint a kód egészéért maga a csapat felelős nem pedig az egyes fejlesztők, akik írják az adott kódrészletet. Azaz aki belenyúl valahol a kódba felelős azért, hogy a meglévő unit teszteket ne rontsa el, az új funkcionalitás coverage-e is az elvárt szinten mozogjon és a termék integritását se sértse meg. Általam hallott vagy olvasott szinonímák: code stewardship, shared responsibility, team responsibility.
Én bugom, te bugod, ő bugja = mi bugunk!
Képzeljük el azt a helyzetet, amikor valaki besubmittál egy olyan kódot, amitől elszáll a build vagy valamelyik unit teszt és borul a CI szerver (már ha van) vagy csak egyszerűen többek munkáját akadályozza a beküldött bug. Mi történik hagyományos esetben? Elkezdjük keresni a logokban, hogy ki küldte be, megkeressük az illetőt és szólunk, hogy javítsa ki, majd várunk, amíg megcsinálja. Lehet most idézni az okos módszertani könyvekből, de én a hétköznapi életről beszélek, ahogy a dolgok valójában történnek.
Elképzelhetjük azt az esetet is, amikor t. kollégánk unit teszt nélkül rak be új funkciót, amit akkor veszünk észre, amikor már 2 napja szabin van és még 5 napig nem fog előkerülni, de a coverage ott árulkodik róla, hogy valaki bizony slendrián volt.
Azt hiszem ismerjük azt az esetet is, amikor egy meglévő osztályt nézünk meg valami okból (bele akarunk hívni, vagy ő hív belénk, stb.) és azt vesszük észre, hogy a kód nem valami szép ésvagy hatékony. Mivel sürget az idő legyintünk a dologra és gyorsan megcsináljuk a melónkat, hogy mehessünk már kávézni.
Mi a közös ezekben az esetekben? Az, hogy amikor találkozunk egy olyan problémával, amiért nem vagyunk felelősek azt egyszerűen kikerüljük és a legjobb esetben is megpróbáljuk rátolni arra, aki felelős érte vagy egyszerűen csak legyintünk és hagyjuk, hogy a projekten egyre erősebben jelen legyen a törött ablak szindróma és a kód minősége egyre gyengébb legyen.
Látható, hogy a single person code ownership mennyire veszélyes és költséges helyzetet teremtHET. A feltételes mód azért szükséges, mert létezhet olyan csapat, ahol a tagok törekednek a jó minőségű munkára és megfelelő riadólánc alkalmazásával az adott bugot okozó személy mindig időben javítja, amit okoz vagy optimalizálja a gyengébb minőségű kódját, de ez a valóságban igen ritka. A probléma – csökkenő kódminőség – enyhítésére született a CCO, ami kimondja, hogy az adott termék forráskódját az egész csapat birtokolja, azaz az egész csapat felelős a munka minőségéért és azt nem lehet egy emberen leverni.
Hogyan értessük meg a csapattal a CCO-t?
Eljutottunk oda, hogy a csapat felismerte a kód minőségével kapcsolatos problémákat és megoldásra van szükségük. Itt jön a képbe a CCO-t ismerő és alkalmaző szakember, hogy megtanítsa nekik azt a pár apró, de hasznos fogást, ami ehhez kell. Nem egy ördöngősség a CCO. Tényleg nem. A CCO lényege két dolgon nyugszik: 1. ha hibát találsz bárki kódjában, akkor javítsd meg, 2. könyörtelen refaktorálás (merciless refactoring)
Fix-it, improve it
Az írás elején említett példák közül az első és második esetben mit tesz egy CCO-t alkalmazó csapattag ha hibát talál? Anélkül, hogy más munkáját félbeszakítaná ő maga nekiáll és megfixálja a kódot. Miért? Mert nem csak az felelős érte aki írta, hanem ő is, aki épp a hibát találta. Valószínűleg úgyis az ő munkájával kapcsolatos, különben nem ő nézegetné (kevés kivétel azért akad) így simán belefér a feladatába, hogy azt a hibát is kijavítsa, amit eredetileg nem is várt, hogy felbukkan. Ugyanez igaz akkor is ha új funkciót kell hozzáírni egy olyan osztályhoz, amit nem ő fejlesztett. A régi megoldás az, hogy szólsz a fejlesztőnek és megkéred, hogy írja meg te pedig vársz rá és telik az értékes idő, de CCO-t alkalmazva nyugodtan nekiállhatsz átírni más kódját, mert az a ti kódotok, így mindenki nyer vele ha te is hozzáteszed a saját képességeidet. Ez a CCO első pillére.
Merciless refactoring
Idézzük fel a harmadik példát a gyengélkedő kóddal. A kolléga műve tűrhetően működik, de nem hozza az elvárt minőséget és teljesítményt. A CCO szerint nem mehetünk el szó nélkül egy ilyen probléma mellett, de nem az a megoldás ha készítőt zaklatjuk a javításért, hanem feltűrjük az ingujjunkat és mi magunk refaktoráljuk a kódot, amíg nem lesz olyan, amilyennek lennie kell. Bármikor ha találunk a kódban refaktorálható részt, bátran tegyük meg, mert ezzel javul a kód minősége és hosszú távon sok fejlesztési időt tudunk megspórolni, ami a határidők közeledtével igen értékessé válik a csapat számára.
Mi szükséges a CCO bevezetéséhez és alkalmazásához?
A legfontosabb, hogy a csapat magáénak érezze a célt a munka minőségének javítására és belássák, hogy a “jól bevált” – azaz legacy – módszerek nem elégségesek ehhez és változtatni kell. Ellenséges környezetben nem lehet ilyen változásokat erőszakkal bevezetni, meg kell győzni a csapatot a CCO szükségességéről. Ha már megvan az elhatározás, akkor aránylag fájdalommentesen alkalmazhatóvá válik az alapelv. A legfontosabb, hogy bevezessünk – ha eddig nem tettük – egy olyan coding standardet, amit a csapat összes tagjának kötelezően alkalmaznia kell a munkája során. Ez egyrészt megkönnyíti a tagok közti kommunikációt, másrészt kódot magát is olvashatóbbá teszi az összes csapattag számára.
A következő fontos lépés, hogy amit automatizálhatunk azt ne bízzuk az emberre, mert abban ott a hibázás lehetősége. Alkalmazzunk verziókezelőt a kódbázis karbantartásához (bár ezt szerintem már mondanom sem kell, mert mindenütt van egy cvs, svn, git, mercurial vagy más scm tool). Ezen felül írjunk unit teszteket a kódhoz, hogy a már elkészült munkánk folyamatos ellenőrzés alatt álljon és ne tudjanak mások akaratlanul is valami rejtett bugot hozzáírni a kódhoz.
A megírt teszteket érdemes minden kódváltozáskor újra és újra lefuttatni, de ez kézzel sok időt vinne el, ezért mindig írjunk olyan build scriptet, ami az IDE nélkül is képes a kódot lefordítani és a unit teszteket a kódon lefuttatni. Ezt automatizálhatjuk egy continuous integration szerverrel, hogy elvégezze helyettünk a piszkos munkát és visszajelzést adjon a munkánk minőségéről.
Fontos a kód elemző toolok (PMD, Checkstyle, FindBugz) használata is, hogy amit emberi közreműködés nélkül meg tudnak találni, arra ne kelljen dev munkaidőt pazarolni, elvégre a mi szakmánkban az idő kőkemény pénz nekünk és az ügyfélnek is. Ne pazaroljuk! Megkönnyíti az alkalmazásukat az az örvendetes tény, hogy a főbb build rendszerekhez (ant, maven) mindegyiknek van olyan kiegészítése, ami könnyen beilleszthetővé teszi őket a meglévő build folyamatba.
A automatizált tesztek újabb időnyerők számunkra. A tesztek lehetnek a már megírt unit tesztek vagy integration tesztek, end-to-end tesztek vagy a ui-t végigkattintgató scriptek is. Fontos, hogy a lehető legtöbb dolgot teszteljük le automatikusan, mert onnantól kezdve, hogy az adott teszt elkészül már nem kerül semmibe újra és újra futtatni.
Utoljára hagytam a pairinget, mert nem mindenhol alkalmazzák. Ha ismeretlen kóddal találkozunk, amin még nem dolgoztunk és nem vagyunk teljesen tisztában a funkciójával, akkor mindig kérjük meg az ügyfél valamelyik devjét, hogy pairingeljen velünk, mert az ő helyismerete a kódban kulcsfontosságú ahhoz, hogy ne törjünk el valami meglévő funkcionalitást és javíthassuk a kód minőségét. Elvégre nem érthetünk mindenhez és nem ismerhetjük az ügyfél rendszerének minden szegletét.
- coding standards
- scm
- automated builds, continuous integration
- automated code analysis
- automated tests
CCO félreértések, félreértelmezések
A CCO-nál az általam tapasztalt leggyakoribb félreértés abból eredt, hogy a shared responsibility sokak számára azt jelentette, hogy bárkire csak őrá nem vonatkozik, hanem majd valaki más megoldja a problémát. A hanyagság a legsúlyosabb tévedés és igen káros is a csapat moráljára nézve! A shared responsibility azt jelenti, hogy a kód bármelyik hibája a te hibád is, mert a csapat tagja vagy, tehát törekedned kell rá, hogy minél hamarabb elkészüljön a javítás és minél jobb minőségben történjen meg. Ha ehhez a pillanatnyilag fejlesztett kódot ott kell hagynod, akkor se hezitálj, mert a lehető legtöbb időt kell a kódnak olyan állapotban töltenie, amikor lefordítható, minden teszt lefut rá és nincs benne ismert hiba!
Másik probléma a prioritások rossz kezelése. Hányszor hallottuk/mondtuk már az “Én most nem érek rá megjavítani, mert máson kell dolgoznom!” mantrát ha valami bugfix került szóba és próbáltuk áttolni másra (kevés dev szeret órákat debuggolni ugye…) vagy a készítőre, hogy ő bajlódjon vele. CCO esetén a legkevésbé terhelt dev simán felvállalhatja, hogy ő nekiül a fixálásnak, hiszen a feladatot a magáénak is érzi és ezzel a csapat többi részének tesz szívességet. A jó csapatjáték, pedig nélkülözhetetlen eleme egy sikeres projektnek.
Konklúzió
Ezzel az írással szerettem volna röviden bemutatni a CCO szakmai és gazdasági előnyeit és azt, hogy mennyire könnyű lehet a bevezetése egy már futó projekten is. A CCO-val áttételesen olyan problémák is elkerülhetőek, mint a csapattagok közti feszültség kialakulása (pl. a felmerülő bugok vagy a prioritások rossz kezelése miatt) illetve sokat javul általa a kód lefordítható, futtatható, tesztelt állapotban töltött ideje azaz a minősége. A legnehezebb dolog a változást a fejekben elkezdeni, de ha a devek levetkőzik a kezdeti idegenkedést és a PM elfogadja, hogy egy adott munkával azért késett a dev, mert a CCO miatt egy gyors bugfix vagy refaktorálás elvitt pár órát, akkor hamar jelentkezik a javulás kódminőségben is.