- 4 történelmi és 4 új fejlesztési módszertant
- A 2 fő kód-kezelési policy-t
- Kitérő: a verziókezelés alapfogalmai
- Continuous Integration
- DevOps, mert az mindenhonnan kilóg :D
A fejlesztés problémái - [7:00] - 0:00 .. 7:00
Megvan,
hogy mit kell csinálni, milyen eszköztárral; megvan a csapat,
akkor hát hol a probléma? Merthogy az évtizedes tanulságok
szerint igen ritka az, ami időre készül el...
- Nem mindig jól ill. eléggé értjük a feladatot
- Nem a tényleges feladatra *tervezzük* a rendszert, hanem arra, amit értettünk belőle
- Nem a teljes feladatra *tervezzük* a rendszert, hanem csak annyira, amennyi le is volt írva.
- Más nekünk a 'nyilvánvaló' és a 'magától értetődő', mint ami a megrendelőnek az.
- Valamely előfeltevés menet közben hamisnak bizonyul
- A fejlesztőeszközök hibásak ill. nem a vártak szerint működnek
- A 3rd party komponensek hibásak vagy a teljesítményük gyengébb
- Valamely külső komponens nem készül el időben, vagy kivezetődik a piacról
- stb.
- Benézünk valamit a tervezésnél, elsiklunk valami fölött, elírunk valamit a megvalósításban, stb.
- Menet közben megváltozik az elvárás
- Mert menet közben lehetséges új feature-ök derülnek ki, és az lesz a döntés, hogy kérik ezeket is
- Mert megjelenik egy konkurrens termék, aminél többet kell tudnunk, vagy különben ki se hozzuk a piacra a miénket
- Mert csak - az ügyfélnek változik a hangulata
- Mert a láncban előttünk állókra is igaz az összes fenti probléma
Emiatt
aztán:
- A leggondosabb előkészítésnél is lesznek váratlan, előre nem látott problémák
- Nem lehet előre olyan tervet csinálni, amit változtatás nélkül időre végig is lehet vinni
- Tehát olyan módszert/processzt kell kialakítanunk, ami *tolerálja* a hibákat:
- Kis hiba - kis csúszás, nagy hiba - nagy csúszás, de katasztrófa semmiképp
- A hibák ne blokkolják a folyamat többi részét: a 'tökéletes' késsen, de az 'elég jó' lehetőleg ne
- A hibák lehetőleg hamar derüljenek ki, hogy minél kevesebb dolog épülhessen a hibás részekre
- Minél gyakrabban tudjunk feedbacket adni a megrendelőnek
- Hogy megnyugodjon a lelke, mert látja a haladást (és nem akar kétségbeesetten mikro-menedzselni)
- Hogy a feladat-értési problémák hamar kibukjanak
- Hogy ő is tudjon tesztelni
- Nem biztos, hogy mi vagyunk az utolsók a láncban, és a mögöttünk jövőknek ez aranyat ér
- Mindezt *a lehető legkevesebb overhead árán*
Az évek
során sok ilyen módszer/processz lett kitalálva, de *egyik sem
silver bullet*, bár vannak jók és vannak még jobbak. Általában
érdemes a konkrét esethez testre szabni valamelyiket,
szégyentelenül átvéve bárhonnan bármit, ami hasznos.
Minden
előny ugyanis valamilyen árért jön, pl. a jó
skálázhatóság a többlet adminisztráció árán, és az mindig
esetfüggő, hogy melyik előny mennyit ér, ill. melyik ár mennyire
fájdalmas.
Egy
háromfős csapatnál nem feltétlenül érdemes a kódban
'fennhatósági területeket' felosztani, de ha tizenöt ember
koordináció nélkül módosítgat bármit összevissza, abból
káosz lesz. Fog-e bővülni a csapat, és ha igen, akkor fogunk-e
tudni ezzel kezdeni valamit?
Megjegyzés:
Érdemes az elején pesszimistának lenni, és amikor valaki az
'...úgysem...' ill. az '...úgyis...' szavakat
kimondja, akkor már eleve készülni a pillanatra, amikor a
'...mégis...' ill. a '...mégsem...' beüt :D.
Ad-hoc, vagy Cowboy coding - [1:45] - 7:00 .. 8:45
"Megvan
az ötlet, a formaság a plebsnek való, mi viszont zsenik vagyunk,
úgyhogy ide a billentyűzetet, és rajta, jövő keddre kész is
lesz!"
Ennek az
eredménye mindig kaotikus, karbantarthatatlan gányhalmaz
lesz, ami leginkább akkor szomorú, ha megéli az első
release-t, mert onnantól már sohasem lesz
idő/kedv/akarat/pénz kivágni és újrakezdeni, de ha netán
mégis, akkor is az új verzióknak már kompatibilitást kell
tartaniuk az itt muszájból bevezetett megalkuvásokkal.
Tehát
ez a hozzáállás még magát a feladatot is képes korrumpálni!
Egyszer
használatos feladatokhoz persze lehet jó megközelítés, mert
úgysem kell majd bővíteni ('...úgysem...', ugyebár).
Tehát
az így készített kódot *fertőzőként* kell kezelni, az
értéke *nulla*, azaz a feladat terén semmilyen megalkuvást
nem szabad vállalni érte, illetve miután a feladatot elérte,
később hozzányúlni *tilos*.
Waterfall modell - [1:45] - 8:45 .. 10:30
Az 50-es
évek klasszikus, termék-ipari folyamatainak a software-re való
alkalmazása (ill. ennek kísérlete)
- Elvárások összeírása: az eredmény a specifikáció, annak az ellenőrzése a spekulatív review
- Tervezés: az eredmény a formális rendszerterv, annak ellenőrzése a spekulatív review
- Implementáció: az eredmény a kész kódbázis
- Ellenőrzés: az eredmény az átvételi nyilatkozat
- Maintenance: az eredmény a folyamatos működés, és a meg-megújított maintenance szerződés
Teljesen
rugalmatlan, mert a menet közbeni változásokkal szó
szerint semmit sem tud kezdeni; a tervezési hibák végig
megmaradnak, ha pedig zsákutcába kerül, hát tolatni akkor sem
tud, úgyhogy akkor törölni kell az egész projektet.
Tulajdonképpen
a későbbi, összetettebb módszerek elemi lépései pont ilyenek,
tehát ez lesz nagyjából az építőkocka a későbbiekben.
Inkrementális v. iteratív modell - [4:05] - 10:30 .. 14:35
Ez a
Waterfall logikus kiterjeszése:
- Először definiálunk egy minimális koncepciót, amit már futtatni lehet
- Azt megvalósítjuk a Waterfall szerint
- Aztán definiáljuk a következő, már többet tudó verziót
- Azt is megvalósítjuk, stb.
- Ha valamelyiknél elbuktunk, akkor azt a lépést töröljük és elkezdjük megint, az utolsó stabilról kiindulva
Mindig
az a legfontosabb feladat, ami
- Hoz valami működést a usernek
- Más rész-feladatot feltartana
- Stabilra lehet tesztelni, hogy többé ne kelljen bele se nézni
Minden
iterációs lépés előtt:
- Felmérjük, hogy *a megrendelő szemszögéből* mik a feltétlenül elérendő dolgok, mik jelentenének pluszt, és mi az, ami közvetlenül semleges
- Felmérjük, hogy ezeket milyen módon, milyen megközelítéssel érhetnénk el
- Felmérjük, hogy ezekhez milyen előfeltételeket látunk szükségesnek
- Felmérjük, hogy ezek melyikével mennyi kockázatot látunk
- Azt vesszük előre, ami a legkisebb kockázattal a legnagyobb előrelépést hozza
- Az összes szükséges közreműködő bevonását előre lekötjük, az összes szükséges előfeltételt előre biztosítjuk
Működni
működik, szóval ez már jelentős előrelépés, és van, ahol
konkrétan használható is:
- Ahol a köztes verziók már élet- és piac-képesek, így az egyes lépések nem pass-or-die jellegűek
- Ahol az egyes lépések elég kicsik ahhoz, hogy a Waterfall jó eséllyel meglépje őket
Persze
ennek is ára van:
- Ha egy későbbi koncepció kivált egy korábbit, akkor annak a korábbinak a fejlesztési költsége megy a lecsóba.
- A szakadékokon nem lehet sok apró lépéssel átkelni; vagy egy nagy ugrással, vagy sehogy.
Rapid Application Development (RAD) - [2:20] - 14:35 .. 16:55
Ez a
módszertan szintén az iteratív modellről indul, csak a
specifikálási, a tervezési és a tesztelési lépésekbe bevonja
a megrendelőt is,
*azonnali* visszajelzést érve el ezzel, illetve a megrendelő is
jobban át fogja látni a rendszer viselkedését.
Tipikus
példa erre, amikor egy esetleg bonyolult viselkedésű program
esetén először csak statikus példa-adatokat használva a userrel
együtt megtervezzük a részegységek bemenetét, user interface-ét,
és kimenetét, megelőzve ezzel rengeteg *félreértést*.
Ez
viszont sajnos eseti feladatokra eseti megoldásokat fog
szállítani, ami gyengén tervezett, azaz későbbiekben nehezen
bővíthető, nehezen módosítható rendszert eredményez.
Tipikus
példái ezeknek a 2000-es évek vége tájéki Delphi-ben írt
könyvelő vagy készlet-nyilvántartó programok, amiket akkor
pár nap alatt 'fejlesztettek' ki, viszont 3-4 évvel később
már nem lehetett a közben megváltozott igényekhez alakítani, és
még az addigra bennük felgyűjtött adatokat is nehéz volt
elmigrálni.
Kisebb,
tool-jellegű programokhoz ill. ötletek prototípus-tesztjéhez jó,
de ahol fennáll a komoly rendszerré fejlődés esélye, ott nem
ajánlatos.
Agile - [3:30] - 16:55 .. 20:25
Buzzword,
amivel még a Szaharában homokot is el lehet adni manapság :D. Na
jó, talán mégsem annyire csak ez.
Ezen
szóval azon fejlesztési módszertanokat szokás összefoglalni
(innentől ezek jönnek majd), amelyek:
- Tudják kezelni a valóságot, az elkerülhetetlen változásokat kezelni tudják
- Működő, használható terméket állítanak elő, még ha a megrendelő nem is tudta ezt pontosan megfogalmazni
- A fejlesztőket is egyénként kezelik, ennek minden előnyével és hátrányával, és nem csak fogaskerékként próbálnak rájuk építeni.
Ehhez
pedig az alábbi alapelvek vezetnek el:
- Gyakran vagy folyamatosan generálni kipróbálható eredményt
- Motivált és célirányossá tett résztvevők minden területen, a ballaszt semmire sem jó
- Gyakori és lehetőleg személyes kommunikáció, ez a legpontosabb és leggyorsabb információ-átadás
- Egyszerűségre törekvés
- Gyors körülfordulási ciklusok jól definiálható célokkal és jól mérhető eredményekkel
Ezzel a
hozzáállással el lehet érni, hogy a folyamat ne lassuljon be és
ne akadjon el az előre nem látott akadályoknál, viszont
természetesen ennek ára is van:
Előre
nem lehet *egyszerre* megmondani azt, hogy *mi* lesz kész és
azt, hogy *mikorra* (a'la Heisenberg)
Az Agile
módszertanok erre azzal válaszolnak, hogy
- Minden lépésben kész lesz *valami*
- Mindig tudjuk, hogy meddig látunk előre, és
- Ekkorra mit fogunk majd kapni
Mission-critical
rendszerekhez ez természetesen alkalmatlan, és egy mosógép
mikrokontrolleres vezérléséhez sem érdemes ezzel hozzáállni, de
a valós élet feladataira egész jól alkalmazhatóak, túlnyomórészt
mert az akadályoknál tudnak alternatív megoldások felé mozdulni.
Extreme Programming (XP) - [2:40] - 20:25 .. 23:05
Itt az
'extreme' arra utal, hogy ami hasznos
dolog, azt az extremitás határáig pörgeti,
azaz mindaddig, amíg az hasznot hoz.
Az
alapfeltevés itt az, hogy 'az egyszerű szép', azaz a
feladatot a lehető legegyszerűbben kell megoldani:
- erős code review / pair programming
- homogén csapat, nincs code ownership, egymás észrevételeit is ügyfél-észrevételként kezeljük.
- gyakori teszt mindenre: unit test, integration test, acceptance test, TDD
- YAGNI / KISS
- 'always stable' -> commit előtt is unit test, CI
- bármi eldobható, ha a feladat túlnőtt rajta
- egyezményes coding & naming style, 'legyen magától értetődő'
Ez
rengeteg adminisztrációs overheadet megszüntet, és jól kezeli a
*kezdetben* nem teljesen tisztázott feladatokat, de mint mindennek,
ennek is ára van:
- csak motivált *és* tapasztalt emberekkel működik
- scope creep lehetősége (mindkét irányba)
- a sok teszt időköltséges
- a sok újratervezés szintén
Inkább
'házon belüli' ill. K+F projektekhez alkalmas, és teljes csőd a
nem kooperatív vagy részint másban érdekelt ügyféllel.
Scrum - [13:20] - 23:05 .. 36:25
Ez már
kicsit komplexebb lesz, mert már nem csak egyszerűen megoldást
keres a problémára, hanem igyekeznek *optimális-közeli*
megoldást találni, és
ehhez már nem csak általános törekvéseket fogalmaz meg, hanem
konkrét szereposztást és koreográfiát, folyamat-lépéseket is.
Az alap
elgondolás az, hogy
- Ne akarjunk messzebbre tervezni, mint ameddig ellátunk, de addig viszont igen, hogy fölöslegesen ne aprózzuk el
- Ne áltassuk magunkat olyasmi bevállalásával, amiről már az elején tudjuk, hogy úgy és akkorra lehetetlen megcsinálni
- A fontosabb dolgokkal foglalkozzunk először
- A processz mindig egyértelmű lépést mutasson, ne legyen nem definiált helyzet
- Jól definiált hatáskörök, hogy ne legyen se káosz, de túl-adminisztrálás se
Háromféle
szereplővel dolgozunk:
- Product Owner / customer representative. Ő
- Képviseli az ügyfelet a csapat felé és a csapatot az ügyfél felé
- Vezeti a projekt státuszát
- Tervezi és szervezi a release-eket
- Developer
- Részt vesz a tervezésben
- Fejleszt, tesztel, integrál, dokumentál, stb.
- A Dev csapat létszáma általában 3..7 között üzemképes.
- Az eredeti séma szerint a csapat homogén, mindenki mindenhez ugyanannyira ért, de ez persze ritkán teljesül
- Scrum Master / játékmester
- Ügyel, hogy a folyamatok a medrükben maradjanak
- Kezeli a váratlan helyzeteket
A
sikerhez szükséges előfeltételek (feature, bugfix, stb.) egy
'Product Backlog' nevű listán vannak nyilvántartva, erre
menet közben is kerülnek fel elemek (pl. bugfixek).
Minden
ilyen elem kap két *pontszámot*:
egyet a PO-tól, hogy ez mennyire értékes az ügyfél számára, és
egyet a Dev csapattól, hogy ez mennyi erőfeszítést igényel.
Ez
alapján lehet majd eldönteni, hogy melyik elem mennyire fontos,
mire mikor kerüljön sor.
Ide
kívánkozik egy fogalom, a 'User Story': ez valójában
valamilyen ügyfél-elvárás naív megfogalmazását takarja, pl.
"Mint
felhasználó, szeretném látni a futó megrendeléseim listáját",
"Mint ügyfélszolgálatos, tudnom kell a felhasználók
emailcímét módosítani",
"Mint
admin, tudnom kell a bejelentkező képernyőre aktuális
értesítéseket kiírni, hogy a karbantartásokat jelezni lehessen"
Ezek
általában a "Mint ..., tudnom kell .... [, hogy ...]"
formájúak, emberi nyelven és ügyfél-szemszögből vannak
megfogalmazva, és a *mit*-re koncentrálnak, nem a *hogyan*-ra.
Az ilyen
'User Story'-k felhasználói értékességét jelző pontszám
mértékét hívják Story Point-oknak, azaz pl. 'Ez a User
Story 3 Story Point-ot ér, az 8-at'.
A
pontszámokat -tapasztalat szerint- célszerű a Fibonacci-számokból
kiosztani, így könnyebb lesz kisakkozni, hogy mi fér bele egy
lépésbe :). A fejlesztési csapat pontszámai jók, ha konkrét
időegységekre is válthatóak (óra/fél nap/nap), az értékességre
ilyen megkötés nincsen.
Maga a
fejlesztési folyamat két finomságú lépésközzel halad: vannak
1..6 hetes 'sprintek', illetve azon belül a napok.
A sprint
egy tervezéssel kezdődik:
- A hossza a sprint hosszának 1/20-a (2 hét esetén 1/2 nap, 1 hét esetén 2 óra, 1 hónap esetén 1 nap, stb)
- Az első felében a Dev csapat kiválogatja azokat, amik szerintük megoldhatóak a sprint alatt (ez lesz a Sprint Backlog). Itt értelemszerűen törekedni kell az 'értékesebb' elemek priorizálására.
- A második felében ezeket az elemeket atomi lépésekre bontják, valamint meghatározzák, hogy mikor számít az adott elem 'kész'-nek (Definition of Done – DoD)
- Ha ilyenkor kiderül, hogy valami mégsem fér be, akkor azt lehet osztani vagy átpriorizálni
- Eközben alakul ki az is, hogy melyik atomi lépést ki fogja csinálni
- Ügyelni lehet arra, hogy senki se vállalja túl magát.
Fontos
koncepció: *nem szabad homályos tételt hagyni*!
Tehát
nincs olyan, hogy 'megjavítani az X hibát', mert amíg azt sem
tudjuk, hogy mi a baj, addig nem tudjuk becsülni az időigényét
sem.
Ez két
lépés lesz: (1) kivizsgálni a lehetséges hipotéziseket, (2) majd
az 1. után meglátjuk!
Minden
elemi lépés definit és véges legyen, jól meghatározott
eredménnyel (deliverable), amit a végén fel lehet mutatni.
Ez nem
feltétlenül kód vagy teszteset vagy dokumentáció, hanem lehet
pl. egy elemzés eredményének a szóbeli(!) összefoglalása, pl.
'az 5 eredeti hipotézisből a 4. a valós'.
A napi
időlépés egy szigorúan 15 perces rövid státusz-egyeztetést
jelent, amin:
- Bárki részt vehet, nem csak a Dev csapat
- Senkire sem várunk, pont a megadott időben zajlik
- Elvárás, hogy mindenki felkészülve érkezzen, elvégre nem nagybeszámolót kell tartani
- Mindenki 3 dolgot mond el:
- Mit végzett tegnap óta
- Mit tervez mára
- Lát-e valamit, ami akadályozza a sprint teljesítését
- Semmi egyéb nem hangzik el, tehát nincs részletezés, vagy visszakérdezés
- A PO adminisztrál, eredetileg neki szól ez, csak így a többiek is hallják
- Ha van valami előre nem látott akadály, akkor azt a SM intézi, *a terven kívül* (Emlékszünk: menet közben kiderülő dolog nem lehet, mert olyat nem tettünk a backlogra tovább bontás nélkül)
A sprint
végén megint tart egy *max.* 1/20-os szeánszot a csapat,
aminek szintén két fele van:
- Review: Mi lett készen? Ezt be is lehet mutatni, ha van rá igény.
- Retrospective: A Dev csapat beszéli meg, hogy mi ment jól/rosszul, mivel lehetne/kéne javítani a köv. sprintben.
Ezen
hozzáállással *elvileg* a sprint elején lehet tudni, hogy mi lesz
a végén; a hátralévő elvárások száma monoton módon csökken,
és a haladás jól definiált mérőszámokon követhető:
- Sprint Burndown: a napok előrehaladtával a lezárt ill. hátralévő
- Taskok száma
- Időigény
- Érték (Story Point-ok száma)
- Product Burndown: az elért ill. kész termékig hátralévő Story Point-ok száma
- MVP = Minimal Viable Product, ill. az ehhez szükséges pontszám
- Ezek alapján valamelyes 'tól-ig' becslést is lehet adni a várható haladás ütemére, de ez persze csak becslésként értendő!
Korlátok
viszont:
- Szoros csapaton belüli kommunikációt igényel
- Általános hozzáértésre épít, a speciális képességeket rosszul kezeli
- Továbbra sem tud abszolut határidőket jósolni/betartani
- Az elkészülési sorrendet sem tudja előre jósolni, mert az a menet közbeni változások mentén alakul
Kanban - [3:35] - 36:25 .. 40:00
Ez a
módszertan konkrét gyártási ütemezésből lett átvéve, és ez
valamelyest meg is látszik rajta :).
Sokkal
egyszerűbb és rugalmasabb a Scrumnál, ugyanakkor viszont
(sajnos) még kevésbé pontos, és főképp DevOps jellegű
fejlesztéseknél van nagy szerepe.
A
központi eleme a Kanban-tábla, ami kb. egy faliújság-szerű
tábla, oszlopokkal az egyes állapotoknak, és ezen cetlik
képviselik az egyes teendőket.
'Teendő'
bármilyen igény lehet, de itt is igaz az, hogy indefinit feladattal
nem foglalkozunk, tehát ha valami nem látható át végig, akkor
azt darabolni kell, új cetliket adva a rendszerbe.
Minden
teendő az alábbi 'állapotok' között mozog:
- Vár: aktuálisan még épp nem foglalkozunk vele, mert pl. egy másik elem logikailag előbb jön
- Folyamatban: dolgozunk rajta, foglalkozunk vele
- Tesztelés alatt: reméljük, hogy kész, de ezt még igazolni kell
- Kész: ellenőrizve, készen van
Mivel a
túl gyakori kontextus-váltás nem jó dolog, érdemes
maximalizálni, hogy egy embernek legfeljebb hány task-ja
lehet az egyes kategóriákban egyszerre.
A csapat
lehet ön-koordináló, de lehet csop.vez. általi kiosztás is, a
lényeg az, hogy mindenki valamelyik oszlopból dolgozik valamely
másikba, pl.:
- Az 'új' oszlopba bárki vehet fel jegyet
- A QA az 'új' oszlopból húz jegyeket, ellenőrzi őket (minden szükséges info meg van-e adva, ellenőrizhető-e, fennáll-e még, stb.), és teszi át vagy a 'kész (semmis)' oszlopba, vagy az 'ellenőrizve' oszlopba
- A fejlesztők az 'ellenőrizve' kupacból húznak cetlit, menet közben a 'folyamatban'-ba teszik, végül a 'befejezve' rovatba rakják (vagy darabolják, és akkor a maradék, nem becsülhető rész megy vissza az 'ellenőrizve' fázisba).
- A QA a 'befejezve' állapotú jegyeket ellenőrzi, és teszi vagy vissza az 'ellenőrizve', vagy a 'kész' rovatba
- stb.
Ha menet
közben célszerűnek látszik, akkor lehet
az igényekhez igazítani a
workflow-t
(fázis-átmenetek, tevékenységi körök, stb.)
ScrumBan - [1:45] - 40:00 .. 41:45
A Scrum
és a Kanban ötvözete, mi más :D.
Kevésbé
'viráglelkű' idealista, mint a nyers Scrum, de jobban
darabolódik, mint a Kanban, így konstruktív fejlesztésekhez is
használhatóbb:
- Csapatokkal dolgozik, és nem egyénekkel
- De ezek a csapatok struktúráltak, van vezetőjük, stb.
- Engedi a specializációt
- Konkrét workflow policy-ket írhatunk elő
- A priorizáció nem csak a Dev csapaton múlik
- Időegységekben/lépésekben halad, nem szabad folyamatossággal
- A visszacsatolásnak határozott helye van: a Scrum szeánszai
- On-demand planning: ha a Product Backlog-ból adott mennyiséget feldolgoztunk, ideje újraértékelni a maradékot
- Feature freeze: ha közeledik valamely határidő, akkor addig a már folyamatban lévőket kell lezárni, új dolgot megkezdeni nem szabad
Egyéb - [0:55] - 41:45 .. 42:40
Agile
filozófia: Ami beválik, az beválik
és át kell venni; ami
nem, azt el kell hagyni; ami meg nem biztos, azt ki kell próbálni,
mert esete (cége, projektje, ügyfele, stb-je) válogatja, hogy mi
lesz a nyerő stratégia. Viszont érdemes először utánakeresni,
hogy más próbálkozott-e már ilyesmivel, és milyen
tapasztalatokra jutott.
Nincs
silver bullet, semmiből nem lesz valami, tehát továbbra sem
fogjuk tudni előre pontosan megmondani egy komplex feladat
időigényét, lefutását, de a folyamatos és fokozatos fejlődést,
valamint a problémák korai észlelését elérhetjük.
Kódbázis-kezelési policy-k - [0:45] - 42:40 .. 43:25
Az
említett módszertanok a konkrét fejlesztői tevékenységekről
csak annyit mondak, hogy 'fejlesztés' ill. 'tesztelés', de ennek a
részletein nagyvonalúan túlléptek.
Ehhez
hasonlóan arra sem válaszoltak, hogy mi történik, ha valami
hiba csúszik a folyamatba, és valami balul sül el.
Az ember
olykor hibázik, de a felelősség *mindig* a processzen van,
mert annak kell tudnia észlelnie és kontrolláltan lereagálnia az
ilyen hibákat is!
A 'Baseline mindig stabil' policy - [14:35] - 43:25 .. 58:00
Főképp
*kritikus termékeknél*
elvárás, hogy a kiadott termékbe csak (ismert) 100%-ra tesztelt
kód kerülhessen, és mivel az ilyen rendszerek fejlesztése
általában erősen költséges, az ügyfél a határidők
pontos betartását is el szokta várni a pénzéért.
Ez
lehetséges is, csak mint mindennek, ennek is ára van, mégpedig a
szigorú minőségbiztosítási folyamat, ami összetettséggel,
erős policy-kkel, fajlagosan nagy adminisztratív és tesztelési
időigénnyel jár.
Amikor
egy ilyen rendszerben egy fejlesztési igény megjelenik, akkor
- Jó esetben (ha új feature-ről vagy reprodukálható hibáról van szó), vagy a fejlesztő, vagy a QA ír egy teszt-esetet, ami el tudja dönteni majd a fejlesztői munka sikerét (TDD - Test Driven Development).
Kevésbé jó esetben (nem reprodukálható hiba) megfogalmazzuk a 'Definition of Done'-t, azaz azt a követelményt, amit elvárunk majd - A fejlesztő a saját munkakörnyezetében addig reszeli a kódot, amíg a fenti teszt sikerrel le nem fut, ill. úgy nem véli, hogy a követelményt elérte.
Amíg ezt el nem éri, addig próbálkozik, vagy ha elakad, akkor eszkalálja a problémát és lép a következőre. Ez a 'fejlesztői teszt'. - Ezután ezt másvalakinek (QA) is ellenőriznie kell, mert a fejlesztő óhatatlanul is arra koncentrál, amivel ő nehézségekbe ütközött, és a technikailag egyszerű dolgokat hajlamos átlépni.
Pl. Egy felolvasandó file struktúrális hibáit valószínűbb, hogy jól kezeli, mint az olyan corner case-eket, hogy az adott néven nem file van, hanem könyvtár. "A fene se gondolta, hogy..."
Ez a 'feature teszt' vagy 'bugfix teszt'. - Ezután azt is ellenőrizni kell, hogy ez az új változtatás kompatibilis-e a többi változtatással, azaz nem ront-e el valami mást.
Pl. Valaki átszervez egy hívási interface-t, ezt minden használt ponton át is vezeti, de közben másvalaki meg egy új ponton használná a régi séma szerint. Önmagában mindkettő helyes, együtt viszont ütik egymást. Ez az 'integrációs teszt'. - Ezután a megfelelésen túl a teljesítmény-vonatkozásokat is ellenőrizni kell, úgyhogy ez a 'teljesítmény teszt'.
- (Opcionálisan) Ezután kikerülhet a termék adott állapota béta-tesztre.
- Végül kikerülhet éles release-be.
Mivel
több fejlesztő dolgozik egyszerre, biztosítani kell azt is, hogy
ne húzkodják egymás lába alatt a szőnyeget, azaz az egyik
fejlesztői tévedés ne akadályozza a többiek munkáját.
Ehhez
hasonlóan szintén elvárás, hogy az egyik task (feature/bugfix)
hibája ne akadályozza a többi task előrehaladását.
Mindemellett
a rendszernek magának skálázhatónak, párhuzamosíthatónak
kell lennie, hogy lehetőleg ne legyen szűk keresztmetszet a
folyamatban.
A
gyakorlat ezen elvárásokra általában hasonló
rendszer-kialakításokat eredményezett, több-kevesebb eltéréssel,
helyenként az esetileg szükségtelen részek kihagyásával:
- A forráskód és minden, a termékhez szükséges információ/adat verziókezelve van. Ez azt takarja, hogy ugyanazon dolognak a múltbeli állapotai is elérhetőek, valamint lehetséges párhuzamos fejlődési vonalakat is elágaztatni, illetve az ezeken véghezvitt változtatásokat egymástól (többé-kevésbé) függetlenül másik ágra *olcsón* átvinni. (Erről kicsit bővebben külön szakaszban később.)
- Stage
Ezen az ágon a következő kiadásra szánt javításokat/fejlesztéseket gyűjtjük itt. Ide csak ellenőrzött, stabil kód kerülhet, ami *nem rosszabb*, mint az utolsó release volt. - Integration
Ez majdnem olyan, mint a Stage, csak egy lépéssel előtte jár: ide kerül(nek) először azon, külön-külön már ellenőrzött javítások, amiknek az összes többire gyakorolt hatását még nem ellenőriztük.
Ha ezen az integrációs teszten (és a performance teszten) átmegy, akkor ez a változás-csomag kerül át a Stage-re, ha viszont nem, akkor a változás-csomagot (innen) eldobjuk, ezt az ágat visszaállítjuk a Stage-dzsel megegyező állapotra, és az érintett fejlesztőket összetrombitáljuk, hogy ugyan beszélnék meg a dolgot közösen :D. - Development
Ez is a Stage-ről van elágaztatva, a fejlesztők ezen dolgoznak, és a feature/bugfix tesztek is ezen vannak végrehajtva.
Amikor egy feature önmagában megáll a lábán, akkor innen kerül át az Integration-re.
Célszerű párhuzamos fejlesztésenként egy-egy ilyen ágat létrehozni, így a félkész állapotú, vagy tévedésből elrontott kód nem destabilizálja a többiek munkáját. - Release
Amikor a Stage-en összeáll a soron következő kiadás anyaga, akkor arról archiválási céllal készítünk egy-egy Release ágat, és az ügyfélnek kiadandó binárist már erről buildeltetjük. Később viszont ezen ágakhoz már *nem* nyúlunk, lévén archív adat. - Időről időre a Development ágakat szinkronizáljuk a Stage-ről, hogy amit közben a többiek elkészítettek, az a Developmenten is ott legyen. Ha itt kód-ütközés van, mert pl. ugyanazt a részt mindketten módosítanánk, de másképpen, akkor a Stage-ről jövő kódnak van prioritása (mert az már tesztelve van), és a Development ágat kell ahhoz igazítani.
- Ha a fejlesztő úgy érzi, hogy készen van, akkor a Development ág tesztelését átadja a QA-nak.
- A QA a Development ágról generáltat egy termék-binárist (Continuous Integration-nél részletezzük), és elvégzi az adott hibajegy ellenőrzését.
Ha a QA hibát talált, akkor a labda visszapattan a fejlesztőhöz, ha nem, akkor pedig a változtatást át lehet vinni a Developmentről az Integration-re. - Az integráláskor általában az erre kész összes javítását egyszerre visszük az Integration-re.
Ezután az Integration-ből lehet buildeltetni egyet, és azt funkcionálisan ellenőrizni, hogy nem rontottunk-e el valami korábban már működő dolgot.
Ha kudarcra fut a teszt, pl. az átemelt 20 hibajegyből *valamelyik* elrontott valamit, akkor lehet felezgetni, hogy mely(i|e)k volt(ak) a bűnös(ek).
Worst case: ha az N átemelt hibajegyből egyik sem jó, akkor ennek kiderítése N*log2(N) Integrációs teszt-futtatást igényel.
Fontos, hogy az eddigi *összes* build ún. debug-build volt, azaz a kód nem teljesítményre, hanem nyomozhatóságra volt optimalizálva, azaz pl. voltak benne részletes progress-jellegű log-üzenetek, belső integritás-constraint-ellenőrzések, stb., amik a végső, kiadási buildekbe már nem fordulnak bele. - Ha az integrációs teszt sikeres volt, akkor az Integration ágról lehet egy production-buildet forgattatni, ebben már nincsenek részletes debug log-üzenetek, sebességre van optimalizálva, nincsenek benne debug szimbólumok (emiatt kvázi nyomozhatatlan), viszont már van értelme a teljesítmény-tesztet is lefuttatni rajta.
- Ha a teljesítmény-teszt is elfogadható lett, akkor az Integrációs ágról az ott lévő változásokat át lehet emelni a Stage-re.
- Amikor a Stage-en összejött a megcélzott javítás-halmaz (vagy elértük a határidőt :D), akkor arról készül egy Release snapshot-ág és az erről forgattatott bináris megy ki az ügyfél felé.
Mint
mindenhol, itt is tele vagyunk kellemetlen tradeoff-döntéssel, pl.
- Minden hibajegyhez csináljunk-e külön Development ágat?Ha igen, akkor az esetleg elrontott javítások nem destabilizálják a többi javítást, még akkor sem, ha valamiről menet közben derül ki, hogy elhúzódik. Viszont ez plusz adminisztrációval jár, bár ezt lehet automatizálni.Ha nem, hanem pl. fejlesztőnként/feature-önként/csapatonként van egy-egy ág, akkor az relatíve 'olcsó' lesz, viszont egyrészt egy elrontott commit kihat mások munkájára is, másrészt pedig nyilván kell tartani, hogy *melyik ág épp milyen fázisban van, és ki foglalkozik vele*.
Ha Scrum-jellegű rendszert használunk, akkor már a sprint elején láthatjuk, hogy hány párhuzamos láncolaton fogunk dolgozni, tehát akár külön Dev-ágakat is rendelhetünk hozzájuk, és mivel a sprint végére minden folyamat véget ér, ezért nem marad elvarratlan szál sem. - Tehát ha kevés, és egymástól jól elkülönülő hibajegy-láncolatunk (pl. független feature-ök megvalósításai) van, akkor célszerű Feature-brancheket tartani, de ha minden mindenre kihatással lehet, és sok a meglepetés (akkor elrontottunk valamit a tervezésnél...), akkor extrém esetben "one bug - one branch".
Mindenesetre az infrastruktúrát célszerű már eleve úgy kialakítani, hogy olcsó, de legalábbis lehetséges legyen a Development-ágak létrehozása ill. az azokkal való fejlesztés. - Ha túl sok az integrációs hiba, akkor jegyek gyakrabban érik el az integrációra kész állapotot, mint amennyi idő alatt egy Integrációs teszt lefut, és így ez utóbbi sosem éri utól magát. Ezzel viszont *nem lehet* mit kezdeni, az ilyesmi azt jelzi, hogy a kód koncepciója túl gyakran változik, azaz *nem fejlődik, hanem burjánzik*, és valami nagyon el van rontva már a feladat-felfogás szintjén.
A
'Baseline mindig stabil' séma tehát garantálja, hogy minden
pillanatban van egy kiadható, ellenőrzött változatunk, ez azonban
erős szervezést és intenzív tesztelést igényelt.
A 'Baseline mindig friss' policy - [5:10] - 58:00 .. 1:03:10
Sok
esetben, pláne a projektek elején a fenti adminisztrációt
túlzásnak tartják, mert 'még nincs mit tesztelni', 'tudjuk, hogy
még nem stabil', ezért inkább a 'Baseline mindig friss' elvet
követik, miszerint:
- Minden változtatás *azonnal* a közös Baseline-ra történik, esetleg minimális helyi fejlesztői tesztelés után, de ez is opcionális
- Amikor valaki 'eltöri' a kódbázist, akkor akár ő, akár aki először észrevette, az javítja és commitolja is
- Amikor közeledik egy release, akkor *leágaztatnak a Baseline-ról egy Stage ágat*, és elkezdik azt stabilizálni
- A fejlesztés a Baseline-on halad tovább (!)
- Minden megtalált hibát a Baseline-on javítanak, és onnan cherry-pickelik át a Stage ágra
- Amikor a tesztek szerint a Stage ág stabil, akkor archiválási céllal elágaztatnak róla egy Release ágat
- Ezt a Stage-et letörlik (majd a köv. release-kor ágaztatnak újat)
Mondani
sem kell, hogy kezdetben ez roppant gyors és fordulékony
hozzáállás, és mint láthatjuk, a fejlesztési fázisban szinte
semmi adminisztrációt nem igényel, tehát *egész amíg nincs
valami release-elni való*, addig igencsak kecsegtető.
A
problémák ott kezdenek szaporodni, amikor eljön a release ideje:
- Minél több a kiteszteletlen, félkész, potenciálisan bugos kód a Baseline-on, annál bizonytalanabb, hosszabb és nehezebb a Release ág stabilizálása
- Ha többen dolgoznak a Baseline továbbfejlesztésén, mint a Release stabilizálásán, akkor ott a teszteletlen kód szaporodni fog
- Amikor a stabilizálás már éppen csak sikerül határidőre, akkor a következő Release-t már nem a Baseline-ról fogják elágaztatni, hanem kényszerből az előző Release-ről
- Onnantól a két ág között a szinkron megszűnik, és egy idő után a Baseline-ról egyáltalán nem lehet javításokat átvinni az aktuális Release-re, tehát a kért feature-öket/javításokat már direkt a Release ágon kell megcsinálni
- Tesztelés híján a Baseline annyira instabil/esetleges/ismeretlen állapotúvá válik, hogy önmagában használhatatlan lesz, értelmetlen leágaztatni is róla, így az összes fejlesztés szépen átköltözik a Release ágra
- Tehát innentől az aktuális Release ág veszi át a Baseline szerepét, és ebből fognak új stabilizációs ágakat indítani, és az egész folyamat kezdődik előről egy szinttel lejjebb a fában :(
Egy-egy
ilyen elkuszálódási lépés 1..2 év alatt következik be, és a
kód minden szinttel egyre merevebbé, eseti patkolásokkal telibbé,
és így karbantarthatatlanabbá, módosíthatatlanabbá válik.
A 6.-7.
szinttől a lehetőségek teljesen bezáródnak, csak az eseti
bugjavítgatás marad, a helyzet dollár-árverés jellege miatt sem
a teljes újraírást, sem az ennél amúgy nehezebb letisztázást
nem fizeti ki senki, és a projekt holtpontra ér.
A
'Baseline mindig friss' módszer tehát egyszerű és működőképes,
de:
- Gondoskodni kell róla, hogy Baseline folyamatosan tesztelve legyen (lásd Continuous Integration)
- A hibajavításnak a további fejlesztésekkel szemben abszolút prioritást kell adni
- A Stage stabilizálásával mindig több ember foglalkozzon, mint a Baseline továbbfejlesztésével
Version Control alapfogalma - [9:25] - 1:03:10 .. 1:12:35
A dolog
legelső vonatkozása az, hogy a file-jainknak nem csak az aktuális
állapotát szeretnénk ismerni, hanem az összes múltbelit
is, és ezen állapotokhoz
meta-információt
(dátum, módosító ember, hibajegy-szám, stb.) is szeretnénk
csatolni. Pl. amikor egy hibás/gyanús kódrészt találunk,
szeretnénk tudni, hogy az mikor, milyen módosítás-halmaz
keretében keletkezett, mert lehet, hogy az ezzel egyszerre végigvitt
többi között is lesz hiba. A javításhoz jó tudni, hogy ki
csinálta, és milyen céllal, stb.
A
második igény onnan ered, hogy ha többen szeretnének ugyanazon
file-okon egyszerre dolgozni, akkor a sima file-szintű
nyilvántartásnál aki utoljára menti el a változtatását, az
felülírja azokat a változtatásokat, amik az ő munkája
közben keletkeztek.
Ezen
lehetne segíteni a file zárolásával, de mint mondtuk,
*egyszerre* szeretnének többen dolgozni, és nem pedig *egymás
után*...
Az erre
adott megoldások alapgondolata az, hogy a felhasználók nem magukat
a (teljes) file-okat 'mentik el', hanem azokat a *differenciális
változtatásokat*, amiket azokon véghezvittek, azaz nagyjából
pl. 'az X és Y sorok közé szúrd be a Z-t', 'az A és a C közül
töröld ki a B-t', ill. 'a D sorban az "alma"-t cseréld
le "körte"-re'.
Így
aztán ha valaki a fenti példánál maradva beszúrja a Z-t, közben
másvalaki meg kitörli a B-t, akkor teljesen mindegy, hogy melyikük
*változtatása* hajtódik végre először, az eredmény ugyanaz
lesz: bekerül a Z és eltűnik a B.
Gond
akkor van, ha többen konkrétan ugyanazt a részt
változtatják, pl. mindketten az X és az Y sorok közé szúrnának
be valamit, csak az egyik Z-t, a másik meg W-t. Erre már nincsen
automatikus megoldás, ilyenkor az első 'beküldő' változtatása
sikerül, a másiké másik 'beküldése' viszont meghiúsul, hiszen
(már) nincs X és Y közvetlenül egymás után.
Ezt
hívják 'conflict'-nak, és ilyenkor a második versenyző
feladata, hogy megnézze, hogy mi változott a közös kódbázisban
az ő munkálkodása közben, ill. ő mit változtatna azon, és a
két változást összefésülje, majd ennek az eredményét küldje
be. Ezt hívják a 'conflict feloldásának', ill. magát a
beküldést 'commit'-olásnak.
Minden
ilyen commit során az elkövetési dátum és az elkövető
azonossága is feljegyzésre kerül, továbbá szokás csatolni egy
leírást is, amiben megmondjuk, hogy mit miért csináltunk.
Hagyományosan ennek az első sora egy rövid összefoglalás, hogy
amikor egy-egy file élettörténetét vizsgáljuk, akkor csak az
első sorokat listázva szép tömör áttekintést kapjunk.
A 'közös
kód' elérhetőségi helyét nevezzük 'repository'-nak, az
onnan helyi munkapéldány kihozatalát 'checkout'-nak,
illetve a helyi munkapéldánynak a repo-ból való frissítését
'update'-elésnek.
Mármint
többnyire, mert ez már az épp használt verziókezelő rendszer
nevezéktanától és működési logikájától függ, mert lehetnek
(vannak...) a folyamatban részletesebb lépések és egyéb szintek
is, de az alap gondolat nagyjából ez.
Ha a
file-oknak az élettörténetét lánc-szerűen nyilván tudjuk
tartani, akkor nem nagy ugrás innen az, hogy ezeket a láncokat el
is tudjuk ágaztatni. Például egy hosszabb, több napon/héten
átívelő fejlesztés esetén elkülöníthetünk egy 'másolatot' a
közös kódbázisról, aminek az elágazás pillanatától saját
élettörténete van.
Ha a
file-oknak bármelyik múltbeli állapotához hozzá tudunk férni,
akkor az sem okoz gondot, hogy bármely két állapot közötti
különbséget előállítsuk: csak össze kell fűznünk a két
állapot közötti változtatásokat.
Ez pedig
akkor lesz nagyon hasznos, ha pl. az egy elágazást 'vissza
szeretnénk futtatni' a főágra: az elágazási pont óta ott
elkövetett változtatásokat szépen rájátsszuk a főágra, mintha
egy fejlesztés eredménye volna. Persze itt is lehet conflict, amit
fel kell oldani, és érdemes eladminisztrálni azt is, hogy mit és
honnan hoztunk át, de a működés ugyanaz.
Ha már
korábban egyszer így átszinkronizáltuk az egyik ág változásait
a másikra, de azután azon tovább dolgoztunk, és most megint
szeretnénk ezt megtenni, akkor értelemszerűen nem az elágazási
ponttól vett változásokra lesz szükségünk, hanem az utolsó
szinkronizálási ponttól, de a működés megintcsak ugyanaz.
Amikor
így valamit átveszünk egy másik ágról, azt hívjuk
'merge'-elésnek, amikor pedig egyesével (tehát nem valamely
pontig mindent mindent), azt 'cherry picking'-nek, de ez
utóbbi rizikós művelet, a hiányzó előfeltételek miatt nem
feltétlenül sikerül.
A mai
verziókezelő rendszereknél az elágazás amúgy 'olcsó'
művelet, tehát ténylegesen csak a változtatások (és minimális
adminisztratív adat) kerül eltárolásra, függetlenül az
elágaztatott kódbázis méretétől.
Érdemes
még megemlíteni a verziókezelők kapcsán egy koncepcionális
különbséget:
- A 'centralizált' rendszerek valami dedikált szerveren tartják a repository-t.
Ennek előnye, hogy az embernek csak az őt érdeklő részeket kell kihoznia, hátránya viszont, hogy a kód eléréséhez a szervert el kell tudni érni. - Az 'elosztott' rendszereknél mindenkinél megvan a repository másolata, és alkalmi jelleggel ezeket a repository-kat szinkronizálják egymáshoz.
Ennek előnye, hogy pl. repülőn is dolgozhat az ember, és ha valamelyik repo alatti gép megsemmisül, bármelyik másolata teljes értékű replika, hátránya viszont, hogy némi önfegyelmet igényel, hogy az ember gyakran szinkronizáljon, különben ha egy heti conflict szakad egyszerre a nyakába, akkor abból nehezen ássa ki magát :D.
Continuous Integration (CI) - [4:35] - 1:12:35 .. 1:17:10
Beszéltünk
arról, hogy 'valaki ilyen/olyan ágról fordíttat egyet'. Az
emögötti koncepció és infrastuktúra a következő:
- A fejlesztők helyileg fordított kódjai megbízhatatlanok, mert tele vannak helyi, commitolatlan kiegészítésekkel, ki tudja milyen beállításokkal lettek fordítva, és semmi garancia, hogy utólag reprodukáhatóak lennének.
- Tehát kellenek dedikált *build szerverek*, amelyek *valamely ág valamely állapotát* checkout-olva, *valamely beállítás-halmaz szerint* lefordítják, csomagolják, stb., előállítva belőle a kész termék-csomagot.
- Ehhez az előállítási folyamatot emberi beavatkozástól mentesre kell kialakítani: fordítás-vezérlő rendszereket (make, ant, gradle, stb.) kell használni, de legalábbis le kell scriptelni mindent.
- Az eredményt, az összes bemenő paraméterrel és a folyamat során keletkező logokkal együtt egy azonosítható helyen tárolni kell, szükség esetben rotálva ritkítani, stb.
Erősen
ajánlott az ilyen 'build szervereket' *opcionálisan* az
automatizált teszteléssel is összekötni, hogy
- Minden keletkező buildre egyben azonnal ráfussanak az eddigi tesztesetek is
Ahol a
'Baseline mindig friss' policy-t használják, ott ezen felül:
- Minden lehetséges alkalommal, tehát *folyamatos* jelleggel a Baseline buildelődjön le
- Fussanak rá az automatizált tesztek
- Az összes talált hiba prioritást kapjon, még a határidős feature fejleszés fölött is
- Worst case a hibás commitokat el kell revertálni, és ez annál könnyebb, minél kevesebb minden épül rájuk azóta
- Ha épp van Stage, akkor az is folyamatosan buildelődjön, tesztelődjön
- És annak a hibái abszolut prioritást kapjanak, még a Baseline hibái fölött is
- A Stage build eredménye automatikusan kerüljön ki a Teszt környezetbe
Hát,
innen ered a 'Continuous Integration' neve, és ebből láthatjuk a
'Baseline mindig friss' elterjedtségét is...
A
Continuous Integration maga tehát elég jól skálázódik,
az ilyen rendszerek tipikusan egy központi orchestrator
rendszerből és nagy halom build/teszt agentből állnak,
hiszen
- Egyszerre több ágat is kellhet buildelni
- Több támogatott platformra
- Többféle opcióval
- Többféle teszteset-készletet is kellhet lefuttatni rajtuk
A DevOps fejlesztési helyzet - [7:15] - 1:17:10 .. 1:24:25
A
klasszikus 'dobozos' termék fejlesztésétől némiképp eltér az
*online termékek*
fejlesztése, hiszen itt
- Olcsó és ezért gyakori release-ek vannak, akár olyan gyakran, ahogy egy-egy feature elkészül vagy egy-egy bug (tesztelve) kijavul
- Tehát általában egyetlen, de maximum egy pár fejlesztési vonulat zajlik párhuzamosan
- Azaz a specialitása mellett mindenki ért mindenhez, mert különben az épp nem fejlesztett terület 'gazdái' kihasználatlanul állnának
- A fejlesztés és a stabilizálás szinte semennyire sem fedi át egymást, kvázi egymás utáni szakaszokként jelentkeznek
- A stabilizálás és a tesztelés egyszerre zajlik, és mivel kvázi egyetlen feature-ről van szó, ezért a QA-ra és a Dev-re csak váltakozva van szükség, és nincs olyan, hogy 'Amíg a QA teszteli az X feature-t, azalatt a Dev stabilizálja az Y-t és/vagy fejleszti a Z-t'
- A bugjavításért sincs külön release-re szükség, a következő feature lépéssel egyben kerül kiadásra
A fenti
ismérvek szinte kiáltanak a Scrum/Kanban után, valamint
magukkal vonják, hogy nincs értelme külön Dev, QA és
üzemeltetési csapatot szervezni, mert ezekre egymással váltva van
szükség, egyszerre szinte soha! Tehát a DevOps csapat egyszerre
fejlesztő, QA-s és üzemeltető is egyben.
Ami
persze maga után von egy pár, eddig evidens követelményt:
- Aki egy hibajegyhez tesztesetet, egy feature-höz specifikációt ír, annak nem szabad azt implementálnia, mert akkor óhatatlanul is lesznek le nem írt, 'magától értetődő', 1 db fejben megtartott információk.
- Aki valamit implementál vagy javít, annak nem szabad azt tesztelnie, mert akkor óhatatlanul az általa nehéznek talált részekre fog fókuszálni, és elsiklik a corner case-ek fölött.
Hogy is
néz ki ilyen esetben a ScrumBan?
- Egy csapat van, *A* csapat, ha ennél ennél komplexebb a rendszer, akkor azt rendszer-szinten kell független egységekre darabolni
- A csapat kvázi homogén
- A backlog az élő hibajegyekből és a felvetett feature-ökből áll
- A sprint teljesen definit, mindennek látszik a vége (Ami csak valameddig látható előre, az a tervezésnél ott el lett vágva)
- A sprintbe bevállalt elemek közül szabad vadászat van
- Minden elemről mindig tudni lehet, hogy hogyan áll, ki mit csinált vele
- A sprint végén release
Mi újság
az ág-kezeléssel? Friss-e a Baseline, vagy stabil? Van,
amikor egyik sem, és van, amikor mindkettő :D !
- A sprint eleje táján a Baseline mindig friss, mindenki commitolja, amit épp csinál
- A Continuous Integration keretében a Baseline mindig fordítódik és tesztelődik
- A fogott hibák javításának abszolút prioritása miatt a kód fokozatosan stabilizálódik
- Ahogy a sprint feladatai fogynak, a végére csak stabilizáció marad
- Mivel a sprint feladatai véges sokan vannak, és *amíg ez nincs kész, addig újakba nem kezdünk bele*, ezért
- A sprint végére a Baseline megint *biztosan* stabil
- Release ágat igazából csak archiválási céllal kell csinálni, mintegy felcímkézendő a Baseline adott állapotát
Tehát
háromféle *környezetről* vagy *állapotról* beszélhetünk:
- A *fejlesztési környezet* a fejlesztők helyi munkapéldányát jelenti
- A *teszt környezet* a Baseline utolsó (lefordult) buildje
- A *production környezet* az utolsó Release
Ez a
módszer sem silver bullet persze, mert korlátozott az érvényességi
tartománya:
- Online, olcsó és gyakori release kell hozzá
- A rendszeren csak kis (max 3..9 fős) csapatok által rövid idő (max. 6 hét) alatt megvalósítható lépéseket lehet fejleszteni
- A konkrét megvalósulási időket (mi mikorra lesz kész) nem lehet előre megmondani
Idő- és költség-becslés
Tehát akkor egy projekt indításakor hogyan tudunk időt/költséget becsülni? Sajnos sehogyan, a jövőbe továbbra sem látunk, valamint ezek a módszerek egy másik problémát céloztak.
Ha a befejezés után visszatekintve megnézzük egy projekt történetét, akkor már látjuk, hogy
- összesen mennyi fejlesztési + tesztelési idő ment bele
- ebből mennyi volt az előre nem látott kitérő
- amiből mennyi volt a szükségszerű, ami a menet közbeni változások miatt kellett
- és mennyi volt az, ami fölösleges volt, amit, ha előre látunk mindent, akkor megspórolhattuk volna
minimálisra.
Menet közben ehhez tesznek ugyan rövid távú becsléseket, de ez nem segít a hosszú távú becslés problémáján.
A 'mindset' viszont lehet, hogy használható ide is, és bár az egzakt megoldás lehetetlen, de az 'elég jó' segíthet, szóval
- A kezdeti tervezésnél bugjavítás még nincs, csak a feature-öknek kell megbecsülnünk az időigényét
- Az előzetes specifikációt mindenképpen meg kell csinálnunk. Ez kb. a Product Backlog összerakását jelenti, illetve egyes elemeket addig osztani/finomítani, amíg csak teljesen egyértelmű és teljesen bizonytalan részek (amiből már nem lehet egyértelmű részt kiemelni) lesznek benne.
- Az egyértelmű részekhez becsülhetünk időt, és ezekkel mindenképpen számolnunk, már mehetnek is a végösszeghez.
- A bizonytalan részek közül pár fajtát szintén tudunk kezelni:
- Ami a hatáskörünkön kívüli dolog (pl. a projekt másik résztvevőjétől jövő input), az külső függőség, így nem csak hogy nem lehet, de nem is szabad belevonni a mi költségbecslésünkbe, ezt külön kell amellett feltüntetni.
- Ami valami viszonylag olcsó ellenőrzéstől, vagy könnyen beszerezhető információtól függ, azt esetleg érdemes a költségbecslés előtt egy feasibility study keretében eldönteni.
- Amihez hasonló már korábbi projektek során fordult elő, ott az akkori tapasztalatok alapján lehet tippelni, de ez már ingoványos terület
- Ami ezután marad, az az, amiről már konkrétan fogalmunk sincsen!
Ha ez megvan, akkor már 'csak' az előre nem látható, de szükségszerű tételeket kellene valahogy belevonni. Ezeknek a leggyakoribb okai a következőek, de emellett a korábbi projekteknél előfordult hasonlóakat is célszerű figyelembe venni:
- Új feature merül fel/válik lehetségessé, ill. az ügyfél új igénnyel áll elő
Ez a fajta már egy Change Request keretében új megállapodás tárgyát kell, hogy képezze, ami kitér a dolog plusz időigényére is. - Valamely tool/3rd-party lib hibája, megszűnése
Az előzetes tervben használt ilyesmik megbízhatóságának érdemes előre utánanézni. - Mi néztünk el valamit
Hát ennek az esélyét legfeljebb csak módszeres hozzáállással lehet csökkenteni, pl. az előzetes specifikáció és terv elkészítését is egy külön projektként kezelni.
Ennek viszont már több köze van a tőzsdei becslésekhez és a csillagjósláshoz, mint bárminemű módszertanhoz :D.
No comments:
Post a Comment