Hiába dolgozik egy szoftverfejlesztői csapat valamely agilis keretrendszer (leggyakrabban scrum) mentén, sok esetben nincs tényleges élesbe telepítés a sprint végén. A csapatok „bezsebelik” a sprint végén a sztoripontot (done = dev complete), de amikor eljön az igazság pillanata és a kód az élesítéshez közeledik, lázasan beindul a tesztelés, az aggodalmaskodás, a release-adás közben vagy után pedig jönnek a hibák…
Van egy másik gyakori eset is, amikor a csapat gyakran release-el ugyan (például hetente), azonban a release-adás az orosz rulettet idézi: vajon működni fog a rendszer a telepítés után is? A válasz gyakran inkább nem, és a keletkező hibák miatt a fejlesztői csapat hetekig (ha nem hónapokig) újabb feladatokat kap az éles rendszerből tűzoltás jelleggel.
Mindkét esetre igaz, hogy az élesbe telepítés stresszes folyamat, amelyet sok félelem kísér. Nemzetközi kutatások szerint ez a stressz egy idő után kiégéshez vezethet, vagy egyszerűen nem bírják a fejlesztők, és felmondanak.
Pedig ennek nem kellene így lennie. A release-adás lehet fenntartható (értsd: zökkenőmentes, tervezhető, normál munkaidőben elvégezhető, üzletileg megtérülő), ezáltal pedig stresszmentes, és közben nem fog lassulni a szállítás. Ennek kulcsa a minél gyakoribb release-adás, ami a Continuous Delivery (CD) alkalmazásával valósítható meg, amihez elengedhetetlen a szervezet egészében a műszaki kiválóságra való törekvés. Ehhez pedig a fejlesztés és az üzleti oldal partneri együttműködése szükséges, és az, hogy az utóbbi is értsen valamennyire a fejlesztéshez (hogy mennyire, azt ld. majd egy későbbi cikkben).
Minél nagyobb a szervezet, annál nagyobb kihívás a változás, ami véleményem szerint fokozatosan, hosszú távú folyamatként az aktuálisan rendelkezésre álló büdzsével megvalósítható.
Megjegyzés: A cikk szerveroldali alkalmazások fókusszal íródott, de az elvek felhasználhatóak más alkalmazások esetében is (pl. mobil, beágyazott rendszerek, desktop alkalmazások), szervezetileg pedig ugyanazok a szempontok továbbra is érvényesek.
A scrum és az üzleti agilitás nem elég, a műszaki kiválóság is ugyanolyan fontos
Az agilis transzformációs törekvések során nagy hangsúlyt fektetnek a menedzsment részekre (product management, value streamek mentén történő business process reengineering), de a csapatokban a műszaki kiválóság elérésén általában már nincs elég hangsúly.
Gyakori például a scrum keretrendszer bevezetése, aminek egyik alappillére a megfelelően lebontott product backlog, ami alapján a csapat sprintről sprintre a user storykat implementálhatja. A scrum arról viszont nem mond semmit (nem is tisztje), hogy hogyan lesz valójában képes a csapat arra, hogy gyakran és stabilan szállítson éles környezetbe.
Attól, hogy „leszállított” valamit a csapat a review-ra, attól még ki is meri élesíteni a rendszert? – Ha erre „nem” a válasz, az azt jelenti, hogy a csapat nagy valószínűséggel nem valósítja meg a Continuous Deliveryt.
Gyakran látom azt, hogy új üzleti funkciók fejlesztése esetén akár hónapokig is eltart, mire egy újabb verziót kitelepítenek a csapatok éles környezetbe, és közben meg mennek a sprintek folyamatosan, azt mutatva, hogy keményen megy a szállítás.
Sajnos, amíg nincs élesbe telepítés, addig biztosra vehetjük, hogy nincsenek készen a jóváírt sztoripontú sztorik, és jelentős munka szükséges még az élesítéshez: tesztelés, hibajavítások, éles telepítésre és működésre történő felkészítés (pl. performancia javítás, security issue-k megoldása, konfigurálhatóság, automata telepítő szkriptek elkészítése, adatbázismigráció).
Ahhoz, hogy a csapatok képesek legyenek gyakran release-elni, szükséges az is, hogy szervezeti szinten a műszaki kiválóságnak teret engedjenek, sőt, ez elvárás is legyen a teljes szervezetben, másképpen egy-egy csapat igen nehezen fog tudni érvényt szerezni az általuk fontosnak tartott műszaki szempontoknak.
Milyen műszaki gyakorlatokat követnek a technikai kiválóságot megvalósító szervezetek?
A DORA – State of Devops kutatást több mint 32.000 DevOps szakember bevonásával végezték világszerte már több alkalommal. Azt kutatták, hogy mik azok a gyakorlatok, amiket a különféle vállalatok alkalmaznak annak érdekében, hogy gyorsan szállítsanak. (Az Accelerate c. könyv ismerteti részletesen a kutatás eredményeit és az abból levonható konklúziókat.)
A kutatás során először is definiálniuk kellett a szállítási teljesítmény fogalmát, hogy összehasonlíthatóak legyenek a különféle csapatok, akiktől a válaszok érkeztek.
Ha már a scrumról esett szó, a leszállított sztoripontok nyilvánvalóan nagyon rossz metrikát szolgáltattak volna, hiszen ha benchmarkot szeretnénk, akkor nem összehasonlíthatóak sztoripont alapján a különféle csapatok (még egy szervezeten belül sem), mert a sztoripont egy relatív mértékegység, amit a csapat a saját működéséhez alakít ki. Másrészt pedig – ahogy említettem korábban –, nem is biztos, hogy a csapatok tényleg élesbe is szállítanak egy-egy sprint végén (arról nem is beszélve, hogy sokan nem használnak egyáltalán scrumot).
Négy dimenziót azonosítottak be a kutatásban, amik együttes mérése egyértelműsíti a szállítási teljesítményt, és ez lehetőséget biztosít az objektív összehasonlítására:
- Milyen gyakran történik élesbe telepítés? (deployment frequency)
- Mennyi ideig tart, amíg a fejlesztő commitja kikerül éles környezetbe? (lead time for changes)
- A szolgáltatás leállása esetén mennyi ideig tart a szolgáltatás visszaálláítása? (Time to restore service)
- Élesbe telepítés során milyen gyakorisággal történik szolgáltatás károsodás vagy -leállás? (Change failure rate)
Ezen négy dimenzió mentén a válaszok alapján a csapatokat – teljesítményüket tekintve – 4 szintbe sorolták: elite, high, medium és low.
Az elite csoportban lévők naponta többször is telepítenek éles környezetbe, míg a high csoportban lévők is heti 1 és havi 1 közötti gyakorisággal.
Akiknek nem volt még tapasztalatuk ilyen sebesség elérésével, jogosan „felhördülhetnének”, és azt mondhatják: minek telepíteni többször is éles környezetbe egy nap? Nem változnak ennyit a követelmények!
Úgy tűnik, üzletileg nem indokolt, hogy ennyire gyakran release-eljünk, de ez így nem igaz.
A DORA kutatás kiemeli, hogy azon cégek, akik az elite vagy high csoportba tartoznak, azok 2,5x nagyobb valószínűséggel valósítják meg az üzleti céljaikat, mint azok, akik a medium vagy low csoportba.
A következő kifogás, amit szoktam hallani a gyakori release-ek ellen, hogy persze, a „játék” startupok meg tudják csinálni, de a mi cégünk, akiknek meg kell felelniük a különféle piaci szabályzóknak (pl. bankoknál MNB) nem tudnak ilyet tenni. Sajnos vagy nem, de megint a DORA kutatásra hivatkozom, ami azt állítja, hogy nem függ az iparágtól és szektortól, hogy ki milyen gyakran telepít élesbe, mert vannak példák erősen szabályozott (pl. pénzügyi) környezetben dolgozó cégekről is, akik megvalósítják a gyakori release-adást stabil szállítás mellett. (Ld. fenti táblázat: akkor tudsz gyors lenni, ha stabil is vagy, illetve nem tudsz stabil lenni, ha nem vagy gyors is.)
Egyáltalán milyen előnyünk származik abból, ha gyakran release-elünk?
A gyakori release-adás (legfeljebb havonta 1x, de akár naponta vagy hetente többször is) többféle előnnyel jár. Egyrészt kis változások kerülnek ki, ezért sokkal kisebb az esélye, hogy valami elromlik, mintha egyszerre sok mindent változtatnánk. Ez talán elsőre nem tűnik evidensnek, hiszen azt is gondolhatnánk, hogy ha gyakran release-elünk, akkor gyakrabban romlik el valami. Nincs értelme eszetlenül tolni ki a release-eket, ha közben hibát hibára halmozunk.
Ez igaz, ezért a gyakori release-adásnak csakis akkor van értelme, ha közben olyan fokú tesztautomatizációt tudunk elérni, ahol a tesztek gyorsan lefutnak, és ha azok lefutottak, akkor bízhatunk abban, hogy nagy valószínűséggel élesben sem lesz nagy probléma a korábban már szállított funkciókkal. Ha egy ilyen test suite-ot felépítettünk, akkor az magabiztosságot tud adni a teljes csapatnak, és az ő stabil és gyors szállításukon keresztül a teljes szervezetnek is.
Az is fontos, hogy élesítés után is gyorsan, egyértelműen információt szerezhessünk a futó rendszerről, hogy az a tervezettek szerint működik (vagy ha hiba van, akkor mi a hiba oka), így még a felhasználók előtt tudomást szerezhetünk arról, ha valami „félre ment”, és van lehetőségünk korrigálni.
Szóval a gyakori release-ek tulajdonképpen csökkentik a kockázatot, hiszen ha hónapokig fejlesztünk valamit, akkor abban nagyon sok változás lesz, és nagyon nehéz megjósolni azt, hogy vajon ezek a változások hol rontják el majd a most élesben futó verzió jó működését. Nagyvállalatok ilyenkor gyakran teljes regressziós tesztelésbe kezdenek, ami igazán költséges, mert sok időt visz el ezzel feltartva nem csak az adott csapatot, hanem minden más rá épülő rendszer élesítését is, és ráadásul ugyanúgy nincs garancia arra, hogy nem lesznek hibák. Szóval élesbe telepítés után – akármennyit teszteltünk is – jöhetnek a váratlan hibák, amiket nem tudunk gyorsan javítani, mert nem a gyakori release-adásra vagyunk felkészülve.
Másképpen megfogalmazva: a gyakori és stabil release-eknek előnye a gyors feedback loop.
Ismeretes, hogy minél később fedezünk fel egy hibát, annak a kijavítása annál költségesebb. Valójában exponenciálisan nő a hiba létrehozása és annak észrevétele közötti idő függvényében a hiba kijavításának a költsége. Ezért, ha gyakran release-elünk, akkor hamar észrevehetjük a potenciális hibát is. Pl. ha hetente van a release, és valami hiba történik, akkor arra még van esély, hogy emlékezzünk, mit csináltunk az elmúlt 1 hétben, viszont hónapok távlatából ez már esélytelen.
A tudatosan felépített gyors és stabil feedback loopok magas fokú produktivitást tesznek lehetővé, és egyben a hibák javításának költségét is nagyságrendekkel csökkentik. Ezekkel egyidejűleg pedig óriási motivációs hatással bírnak, hiszen:
- azonnali visszajelzést kap a csapat a lefejlesztett funkciók helyességéről,
- ezáltal folyamatosan biztonságban érezhetik magukat, ez a velük együtt dolgozó csapatoknak, személyeknek is biztonságérzetet nyújt,
- folyamatos haladás érzetet élnek meg,
- sokkal kevesebb lesz később a tűzoltás, kevesebb a stressz,
- emiatt pedig sokkal több lesz az ún. deep work, azaz elmélyült munkavégzés, ami által gyakrabban megélhető a flow-élmény.
Milyen hátrányunk származik abból, ha gyakran release-elünk?
A gyakori release-adás ellen szólhat, hogy ha gyakran release-elünk, instabillabb lesz a rendszerünk, hiszen minden release egy potenciális veszélyforrás. Szemben, ha ritkán release-elünk, akkor a release környékén (előtte és utána) stresszt tapasztalunk, de ha az élesítés utáni hetekben stabilizáltuk a rendszert, akkor tulajdonképpen már nem lesz nagy gond a rendszerrel.
Az instabilitásból természetesen komoly problémák származhatnak, gondoljunk csak egy rosszul sikerült adatbázismigrációra, ami esetleg adatvesztéssel jár, amit kvázi lehetetlen szolgáltatás leállás nélkül javítani, hiszon azok a felhasználók, akiket érint, nem fogják tudni elérni a rendszert, amíg az adatokat valahogy vissza nem állították. Sok esetben még az is sokáig tart, mire egy incidens kapcsán beazonosítják az érintett felhasználók körét.
A Continuous Integration nélkül nincs Continuous Delivery
A Continuous Delivery azt jelenti, hogy a kód (lényegében) bármikor release-elhető állapotban van. Más megfogalmazásban, minden commit egy release candidate, aminek alkalmasságát az ún. deployment pipeline vizsgálja meg minden commit esetén. A deployment pipeline nagy része automatizálható (pl. buildelés, image-készítés, automata teszt futtatás, deployment szkriptek futtatása stb.), de egy része lehet manuális is (pl. manuális tesztelés, nyomógomb megnyomása az élesbe telepítéshez.)
Ennek megvalósításához a fejlesztői csapat szakmai felkészültsége, a műszaki kiválóság és az erre való szervezeti szintű törekvés kritikus tényező. Ennek kulcsa pedig, hogy a Continuous Delivery (CD) elveivel is tisztában legyünk és azt a gyakorlatba is át tudjuk ültetni. A CD megvalósítása mindenképpen erőfeszítést igényel, sokszor komfortzónából való kilépéssel nem csupán technikai, hanem szervezeti értelemben is. Hogy mást ne említsek:
Mindig fontosabb lesz az üzleti funkciókat termelni, mint „láthatatlan” technológiai feladatokon dolgozni, amiket nem ért a management.
A Continuous Delivery – definíciója miatt (bármikor release-elhető a kód) – nem megvalósítható (valódi) Continuous Integration (CI) nélkül. CI esetén mindenki merge-öl a masterre naponta legalább egyszer, ezek a változtatások pedig a build szerveren automata buildet és tesztelést indítanak, amik rövid időn belül visszajelzést adnak a keletkező hibáról (ha van), ezen hibák pedig azonnal javításra kerülnek (10 percen belül, akár rollback segítségével).
Tipikus probléma CI kapcsán, hogy nem jók a tesztek, mert:
- a tesztek lassan futnak (több óra is kell nekik),
- a tesztek külső rendszereket használnak (emiatt a tesztelési folyamat leáll vagy még rosszabb, megbízhatatlanná válik, ha valamelyik külső rendszer egyszer elérhető, egyszer nem),
- a tesztek nem adnak teljes képet a rendszer helyességéről (alacsony tesztlefedettség),
- átláthatatlanul megírt tesztek, sok duplikáció, mert a csapat nem karbantartja a teszteket, ezáltal romlik a minőség (a tesztek tisztán tartása legalább olyan fontos, mint a produkciós kódé!),
- instabil tesztek (flaky tests), amik minden előzmény nélkül kiszámíthatatlan módon törnek. Ilyenkor általában valamilyen időzítési vagy hálózati probléma áll a tesztek törésének hátterében (timeout). Tipikusan ilyenek a különféle felhasználói felület tesztek (UI tesztek, pl. Selenium tesztek), vagy olyan integrációs tesztek, amelyek külső rendszereket hívnak,
- nem világos, milyen stratégiával készülnek a tesztek: mire készül unit, integrációs teszt, mire UI, mit tesztelünk manuálisan, mit canary release-zel (ld. később), mit feature toggle-lel (ld. később) – a koncepció hiánya miatt lyukak keletkeznek a rendszeren és/vagy nem lesz hatékony a tesztelés.
Continuous Integration szempontjából az a jó automata tesztkészlet, ami a fejlesztő gépén is gyorsan lefut úgy, hogy a teszteknek nincs szüksége hálózati kapcsolatra. Azaz, lefutnak úgy, hogy a hálókábel le van húzva (vagy a WiFi ki van kapcsolva).
Hogyan valósul meg a gyakori release adás a legacy rendszereknél?
A legacy rendszerek szintén komoly korlátot szabnak a gyakori release-adásnak. Michael Featherstől, aki a Working Effectively with Legacy Code c. könyv szerzője származik a következő definíció:
Minden olyan rendszer legacy rendszer, ami nincs tesztekkel lefedve.
Így az a rendszer, amin egy fejlesztői csapat dolgozik úgy, hogy nem ír hozzá teszteket (mert nagy rajtuk a nyomás, vagy mert nem akarnak, vagy mert nem tudják, hogy szükség lenne rájuk – az ebből a szempontból most mindegy), az így sajnos azonnal legacy rendszerré válik. A legacy rendszerekben nincs olyan „biztonsági háló”, ami garantálná, hogy hiba esetén az automata tesztek eltörve mutatnák a meghibásodást, így nem valósítható meg a Continuous Integration és – így rajta keresztül – a Continuous Delivery sem.
Legacy rendszereknél az automata teszteket fokozatosan, a normál fejlesztés mellett beütemezve, fenntarthatóan és tervezetten lehet bevezetni. Az elején gyors sikereket lehet elérni (core üzleti folyamatok happy path lefedettsége), amik jelentősen növelik a stabilitást, azonban egy komolyabb lefedettség elérése (úgy, hogy rövid idő alatt fussanak a tesztek, azok megbízhatóan fussanak és karbantarthatóak legyenek) már komoly ráfordítást igényelhet, és akár hónapokig is eltarthat, ezért a tesztelés mindenképpen megfelelő stratégiát és tervezést igényel, amit üzleti szempontok mentén szükséges megtenni.
Mivel az automata tesztek hiányában nem valósulhat meg a Continuous Integration, hiszen a kód napi szintű integrációját nincs semmi, ami biztosítaná, ezért is nagyon fontos, hogy határozott lépésekben zárkózzon fel a csapat a produkciós kód tesztekkel történő lefedettségében.
A megírt automata tesztek mellé egy alap deployment pipeline-t is ki kell alakítani, ami a kód buildelését és az automata tesztek futtatását megbízhatóan elvégzi. Egy ilyen pipeline-ba hamar beköthető statikus kódelemzés is, ami további visszajelzéseket (pl. kódkomplexitás, sérülkénységi kockázatok aka DevSecOps) tud adni a csapatnak. Ezt szintén lehet a későbbiekben továbbfejleszteni és pl. triggerelten automatán deploymentet végrehajtani az egyes környezetekbe.
A kódbázis pragmatikus refaktorálása is ajánlott lehet (általában nem újra írásra van szükség), ezt szintén üzleti megfontolások alapján érdemes elvégezni. A QA folyamatokat pedig a manuális ellenőrzés irányából az automata tesztelés irányába szükséges tolni a gyakori release-adás megvalósítása érdekében.
Kihívás, hogy a UI és API tesztek nem szoktak stabilan működni (flaky tests) és lassúak is. Ezek kerülendők, de legacy rendszereknél sajnos nehéz a kódbázis részeként megvalósítani az egyes részek tesztelését (a környezet teljes feállítása nélkül), mert nem így lettek implementálva.
Gyakori release-adás outsourcing esetén
A DORA riport egyértelműen megállapítja, hogy olyan rendszereket, amelyek a cég üzletileg kritikus rendszerei, ne bízzunk teljesen egészében külső beszállítókra (outsourcing). Egyszerűen azért, mert külső beszállítókkal nem fogunk tudni napi vagy heti release-ek fenntartható módon fejlesztetni a beépítendő átadásátvételi/QA folyamat miatt. Vagy ha ezzel nem törődünk, akkor van egy óriási függőségünk a beszállítótól (vendor lock-in).
Hibrid megoldásként működhet az, hogy a csapatba a belsősökön túl külsősöket is delegálunk megfelelő arányban.
Projekt vs. termék szemléletmód
Projekt alapú működés szintén egy erőteljes korlátozó tényező lehet a gyakori release-ek tekintetében. A projekttagok (élén a projektvezetővel) sok esetben arra koncentrálnak, hogy a kitűzött projekt legyen sikeres: azaz időre leszállítsák a rendszert „átpasszírozva” azt a QA folyamaton.
A projekt rugalmatlansága miatt (határidő, scope) mindenki azon igyekszik, hogy minél hamarabb letudja a feladatát: teszteket nem biztos, hogy írnak, vagy nem jó minőségben. A csapat nem törekszik a fenntartható megoldásra, számukra a projekt teljesítése fontos (rövid távú szempont). A rendszer későbbi üzemeltetéséért és tovább fejlesztéséért ők már nem vállalnak felelősséget (átdobják a rendszert a falon az üzemeltetőknek).
A probléma megoldása nem könnyű, hiszen a projekt alapú működés valószínűleg a szervezet mélyéből fakad. A megoldás során felszínre kerül az éves büdzsétervezés és a teljes kontrolling rendszer tehetetlensége, és nem ritkán a tulajdonosi kör is érintett ebben a kérdéskörben.
A projektalapú szemléletet termék alapú szemlélettel célszerű felváltani. Dedikált csapattal (projekteken átívelően) vagy – kompromisszumosan – dedikált emberekkel törekedni lehet a fenntartható működésre, mert ezek a dedikált csapattagok abban lesznek érdekeltek, hogy olyan rendszert készítsenek, amivel nekik később nem lesz problémájuk. A dedikált emberek között üzemeltetők is lehetnek.
Inkrementális fejlesztés, azaz a feature-ök „leszeletelése”
Akik nem csináltak még gyakori release-adást, sokszor nem tudják elképzelni, hogy hogyan lehetséges azt megvalósítani, hogy fejleszt valamit a fejlesztő, ami még nincs kész, nincs is letesztelve, és mindenképp megy a heti release. (Branchen továbbra sem tartunk semmit, a fejlesztők legalább naponta merge-ölnek a masterre a Continuous Integration elvei szerint. Ideális esetben trunk-based development történik, azaz azonnal a masterre commitál mindenki. Legacy rendszerek esetén a korábban említett módon minél hamarabb fel kell zárkóztatni a tesztlefedettséget, hogy megvalósulhasson a CI.)
A „félkész” feature-ök ugyanúgy a kódbázis részei, azonban feltételes elágazásokkal (kapcsolók) el vannak rejtve a felhasználók elől, ill. csak egy bizonyos felhasználói kör számára (pl. maga a fejlesztői/tesztelői csapat számára érhetőek el). Így a fejlesztők napi szinten commitálnak ugyan a masterre (masterre, mainre, trunkra), de a „Feature Toggle”-ök (vagy Feature Flagek) segítségével konfigurálhatóvá teszik, hogy az adott feature elérhető legyen-e a userek számára vagy sem.
Ez customer facing alkalmazások esetén sok esetben azt jelenti, hogy egy új nyomógombot kiraknak-e a UI-ra vagy sem, backend alkalmazásoknál az API-hívásnál visszautasítják a beérkező kérést stb.
A Feature Toggle-ök segítségével magának az alkalmazásnak a bináris imidzse release-elve lesz (deployment), de magának a feature-nek release-elése (tehát hogy látszik-e az adott release a felhasználók számára) késleltetésre kerül. Ez lehetőséget biztosít különféle tesztelésekre az éles környezetben (pl. performancia tesztelés, valódi felhasználóktól visszajelzések gyűjtése).
A konfigurációt lehet egyszerűen és bonyolultan is megvalósítani. Pl. tárolhatjuk DB-ben, hogy az alkalmazás az adott környezetben támogatja-e az adott funkciót (ezt menet közben ki-be kapcsolhatjuk), de ez a beállítás lehet konfigurációs állomány része is, vagy akár egy központi szolgáltatás is “megmondhatja”, hogy egy adott rendszer, adott felhasználójának (vagy felhasználói csoportjának) van-e jogosultsága arra, hogy az új (kísérleti) funkciót elérje. Mindegyiknek megoldásnak van előnye, hátránya, célszerű adott környezetben kezdetben a legegyszerűbbet választani.
A Feature Toggle-ök nagyon hasznosak, de egyben nagyon károsak is lehetnek, ha nem figyelünk oda rájuk. Ha sok feltételes elágazás kerül be a kódba a toggle-ök miatt, az kombinatorikus robbanást eredményezhet a kódbázisban, amelynek eredményeképpen jelentősen megnő a tesztelendő elágazások száma, ami a végén átláthatatlan/tesztelhetetlen rendszert fog eredményezni.
A Feature Toggle-öket ezért lehetőség szerint minél kevesebb ideig szabad használni egy-egy feature-nél, ezért kritikus fontosságú a tervezés: az epic-ek méretét minimalizálni szükséges, vagy másképpen megfogalmazva: törekedjünk egy-egy feature esetén a minimálisan életképes változat elkészítésére, amit addig elrejtünk feature-toggle-lel, amíg azt ki nem fejlesztjük. Ha pedig kész, akkor kivesszük a toggle-t, és inkrementálisan fejlesztünk tovább apró lépésekben. Kritikusak a jól meghatározott user storyk, ami kicsi részekre szeletelnek egy nagyobb epicet is.
Elkészült új feature-ök rolloutja esetén érdemes lehet a Canary Releasing technikáját is alkalmazni (Feature Toggle alternatívájaként), azaz a felhasználók egy töredékének kiajánlani a funkciót az élesben (tesztelés élesben). A visszajelzések alapján pedig lehet javítani a hibákat vagy kiterjeszteni a funkciót a többi felhasználóra (fokozatosan). A Canary Releasing esetén infrastruktúra szintjén választják szét a futó szerveralkalmazások verzióját, ezért alkalmas lehet infrastruktúra szintű változtatások tesztelésére is (ez a Feature Toggle esetében nem lehetséges).
Hajmeresztőnek tűnhet elsőre az „élesben tesztelés”, hiszen a megírt automata tesztekkel pont azt szeretnénk elkerülni, hogy ne élesben jöjjenek ki a hibák, de valójában a Feature Toggle és a Canary Releasing is kontrollált és biztonságos módja a tesztelésnek (amennyiben jól alkalmazzuk). Természetesen nem minden rendszernél és cégnél van erre lehetőség, de érdemes challenge-elnünk magunkat, mert lehet, hogy meglepődünk, hogy mégis tudjuk ezt a módszert alkalmazni. Készüljünk fel arra azért, hogy erről majd meg kell tudnunk győzni jó pár embert a cégnél (QA, üzleti emberek), de ha ez sikerült, és a koncepció is beválik, az sokat fog gyorsítani egy-egy feature bevezetésén, és sokkal nagyobb magabiztosságot is fog adni, hiszen egyből élesből kapunk visszajelzést.
Az élesben tesztelés egyik fontos eleme, hogy az alkalmazás monitorozásánál ne csupán a technikai hibák felmerülésére (vagy inkább azok hiányára) összpontosítsunk, hanem bizonyos fő üzleti metrikák (KPI-ok) monitorozására is. Ha ezek elmozdulást mutatnak a normál tartományhoz képest, akkor feltételezhetjük, hogy valami probléma van a rendszerrel. Példaként említhetek pl. egy nagy forgalmú e-commerce site-ot, ahol monitorozhatjuk a percenkénti megrendelések számát. Ha deployment után ebben nagy változást találunk, akkor szinte biztos, hogy valami baj történt az élesítés során.
A Canary Releasing technikáját alkalmazzák a nagy cégek (pl. Facebook is) egy-egy funkció bevezetésénél. Vegyük észre, hogy szoftverszállítás esetén nem csak az a kérdés, hogy van-e “programozási” hiba a szoftverben, hanem az is, hogy a felhasználók hogyan reagálnak egy-egy változásra pl. ergonómiai szempontból. Ezt a típusú tesztelést egy belső QA csapat sok esetben nem tudja ellátni.
Függőségek
A fejlesztett rendszer függhet egy másik fejlesztés alatt álló rendszertől, ill. maga a fejlesztett rendszer is függősége lehet más rendszereknek.
Mit jelent ez? Van pl. egy másik rendszer, ami szolgáltat nekünk (és másoknak is) egy API-t, amire mi számítunk egy új feature-nél, így addig a mi feature-önk se fog működni, amíg a másik rendszerben lévő API-hívás nem működik. (Ilyenkor erősen megfontolandó, hogy mi nem fejlesztünk-e ki valamilyen csökkentett funkcionalitást átmenetileg, amíg a másik rendszer el nem készül. A time-to-market javul, és a költségek is valószínűleg csökkennek, hiszen hamarabb kapunk visszajelzést a rendszerünkről a tesztelőktől és a valódi felhasználóktól.)
Nem kell mondani, hogy a gyakori release-adást igencsak megnehezítheti a rendszerek közötti függőségek kezelése. A korábban említett Feature Toggle-ök segítségével ugyan technikailag ez is áthidalható (tehát attól, hogy még nem áll rendelkezésre a másik rendszerben az új API-hívás, attól mi még release-elünk, de nálunk is ki lesz kapcsolva a feature), azonban a függőségek kezelése általában túlmutat egyetlen csapaton, és több csapat/szakértő munkájának összehangolását igényli.
Valójában:
A megfelelő vállalati architektúra kialakítása mindenképpen stratégiai kérdés.
A cél az olyan architektúra irányába történő elmozdulás, ami a lazán csatolt rendszereket részesíti előnyben, így az architektúra decentralizálásra kerül és az egyes rendszerek fejlesztői csapatok munkájának egymástól függetleníthető.
A microservice architektúra túl-hype-olt, jelentősége véleményem szerint sokkal kisebb, mint azt sokan gondolják, több szempontból is.
A legtöbb csapat sajnos monolit alkalmazást sem készít megfelelően (clean code, refaktorálás, test driven development, valódi Continuous Integration), az elosztott rendszerek készítése (mint amilyet a microservice architektúra is eredményez) pedig legalább egy nagyságrenddel bonyolultabb feladat, amivel a fejlesztők nagy részének (meg merem kockáztatni, hogy 99%-nak) nincs igazán tapasztalata. Elég csak megkérdezni, hogy az eddigi monolit rendszerben lévő adatbázis tranzakciót hogyan kívánja megvalósítani egy-egy feature esetében microservice architektúrában, és máris üveges tekinteteket láthatunk magunk előtt.
Arra szeretném még felhívni a figyelmet, hogy ez (szakmai minőségi probléma) nem csak a fejlesztők miatt van így, hanem amiatt a nyomás miatt is, ami rájuk nehezedik attól az elvárástól, hogy gyorsan szállítsanak. És így most megint csak visszakanyarodtam oda, hogy az üzleti oldalnak is értenie kell valamennyire, hogy hogyan működik a fejlesztés, ill. a két terület közötti együttműködés során minél inkább a partnerség jellemző, annál jobb döntések fognak születni a fejlesztendő rendszerrel kapcsolatosan is.
Üzemeltetési szempontból pedig általában még nagyobb lemaradása szokott lenni a cégeknek a fejlesztőkhöz képest, amit a microservice architektúra csak még rosszabbá tesz, ami a teljes üzembiztonságot veszélyeztetheti. Ennek oka, hogy az üzemeltetést (ha külön szervezet) költséghelynek tekintik, és külön menedzselik, és a cél emiatt hogy minél olcsóbb legyen, nem az, hogy jobb.
Sokkal fontosabb lenne a megfelelő csapat topológia (team topologies), azaz először is: csapatokat hosszú távon hozzárendelni az egyes rendszerekhez termék szemléletben, másodszor pedig a csapatokat és a rendszereket úgy összerendelni, hogy a kognitív terhelés ne legyen magas az embereken.
Lassú, manuális QA folyamat
Sok esetben vannak dedikált tesztelők is a csapatban, akik ellenőrzik a fejlesztők munkáját, és ha ők nem mondanak “áment”, addig nem mehet ki élesbe a kód.
Ez a fajta működés, egyértelmű gátja lehet a gyakori release-adásoknak. Az teljesen világos, hogy ha készül egy új feature, akkor azt validálni (és nem csak verifikálni) szükséges, azaz azt is meg kell nézni, hogy a megoldás valóban kiszolgálja az üzleti elképzeléseket. Ez időbe telik. Viszont ezt kezelhetjük “félig elkészült” funkcióként, amit Feature Toggle-lel elrejtünk, amíg a funkció nincs letesztelve. Ettől függetlenül az automata tesztjeink az alkalmazás többi részét lefedhetik, és mehet a release.
A Feature toggle mellett a már említett Canary releasing technikája is alkalmazható, amennyiben a fejlesztés és egy „alap” tesztelés megtörtént, amivel élesben történik meg a tesztelése a feature-nek. Először a felhasználók egy szűk körét érintve, majd ezt a kört folyamatosan kiterjesztve egy nagyobb körre (ahol ez a módszer alkalmazható).
Konklúzió
A release-adás sok csapatnál stresszes folyamat, amire nem adnak választ önmagukban a scrum és más agilis keretrendszerek. Ezt azért fontos tudni, mert az agilis transzformációs törekvések gyakran érkeznek az üzleti oldalról, akik gyorsabb time-to-marketet szeretnének, azonban ha a szervezetben nincs támogatása a műszaki kiválóságnak, akkor nem lesznek gyakori release-ek, és igen korlátozott lesz a time-to-market csökkenés is. A műszaki kiválóság eléréséhez teljes szervezeti támogatás szükséges, ezzel együtt az üzleti oldalnak is szükséges értenie a fejlesztési folyamatokhoz (Continuous Delivery, agilis tesztelés).
Elsőre ellentmond a józan észnek, de épp a gyakori (és stabil) release-adás adja a megoldást, ami a Continuous Delivery megvalósításával lehetséges. Gyakori azt jelenti, hogy legfeljebb havonta kerül élesítésre szoftver, de inkább hetente vagy még sűrűbben.
Ha „megküzdünk” a gyakori release-ekkel, azzal folyamatosan fejlesztjük a folyamatainkat és a szervezetünk különböző részei között együttműködést. Ahelyett tehát, hogy halogatnánk a release-adást big-bang release-ekkel, oldjuk meg a fájdalompontjainkat („if it hurts, do it more often, and bring the pain forward”).
A biztonságosan és egyben gyakori release-adással dolgozó csapatok a DORA kutatás szerint 2,5x nagyobb eséllyel érik el az üzleti célkitűzéseket, ami mutatja, hogy a műszaki kiválóságra való törekvés game-changer. (Attól persze, hogy műszaki kiválóságra törekszünk, még nem biztos, hogy sikeresek is leszünk.)
A gyakori release-adást több tényező együttesen segíti elő, ezek közül bármelyiknek a megváltoztatása önmagában is kihívásos és hosszú távú folyamat:
- projekt szemléletből a termék szemlélet irányába való elmozdulás a szervezetben,
- üzleti és fejlesztési terület közötti partneri együttműködés elősegítése (agilis/lean szemlélet, inkrementális szemlélet),
- megosztott, agilis tesztelés (üzlet, fejlesztés és tesztelés együttműködése),
- fejlesztői és üzemeltetési terület együttműködésének szorosabbá tétele (DevOps kultúra),
- az outsourcing stratégiában a kiemelt rendszerek esetében mindenképp a belső csapatokra, személyekre történő erőteljes támaszkodás (teljesen belső csapatok, hibrid csapatok),
- műszaki kiválóság szemléletének erősítése a teljes szervezetben és csapat szinten is (Continuous Integration és Continuous Delivery),
- legacy rendszereknél automata tesztlefedettség mielőbbi kialakítása,
- függőségek tudatos csökkentése az architektúrában és a szervezetben.
Általában a fenti pontok közül egyszerre több (akár az összes) változtatása is aktuális lehet egy-egy szervezet életében. Minden fronton érdemes egyszerre „támadni”, megragadva a szervezetben kínálkozó lehetőségeket. Jó eséllyel bármelyik fejlesztése kihat az összes többire, ezáltal pedig a műszaki kiválóság megvalósulása is előtérbe kerülhet.
Ha tudatos és irányított változást szeretnénk, egy realisztikus megoldás az említett gátló tényezők szisztematikusan, lépésről lépésre történő felszámolása (vagy legalábbis enyhítése) és ennek a folyamatnak a során a szervezet edukálása minden területen. Pl. dönthetünk úgy, hogy egy kiválasztott projektre/termékre megvalósítjuk a gyakori release-adást (pl. hetente), majd ennek tapasztalataiból további projektekre térünk át.
Egy-egy projekt „rendbe tételét” nem fogjuk tudni 100%-osan meglépni, de egy-egy projekt fejlesztése magával fogja vonni a szervezet fejlődését, mivel a fejlesztés szervezeteken átívelő együttműködést igényel. További jó hír, hogy az induláshoz nem kell CEO szintű beleegyezés és óriási büdzsé.
Egy-egy fejlesztési folyamatból a szervezet különböző részei együtt tanulhatnak, és a tapasztalatok alapján tovább lehet lépni egy következő projektre vagy akár skálázni, ezáltal a bigbang transzformációkhoz képest (egész szervezetet egyszerre próbálunk transzformálni) egy sokkal egészségesebb (organikusabb) átalakítási folyamaton vezethetjük át a szervezetet.
A folyamat nem lesz könnyű, mert a meglévő szervezeti beidegződések, és működő folyamatok mind ellene dolgoznak a törekvéseinknek, ezen felül minden projektben mások a körülmények, a csapattagok, a környezet, a fenti módszerek megvalósítása is más és más súlyozást, konkrét megoldást és ütemezést kíván, amit ráadásul csakis csapatmunkában lehet megvalósítani a külön működő részek (pl. fejlesztés és üzemeltetés, fejlesztés és üzlet) együttműködésének szorosabbá tételével.
A törekvés mindenképp megéri, mert a vállalatoknál mindenki szeretne egy sokkal gördülékenyebb, de egyben stabil, stresszmentes környezetben dolgozni amellett, hogy csökken a time-to-market.
Ha segíthetünk neked abban, hogy a release-adás stresszmentes, gyakori és stabil legyen a szervezetetekben, legyetek kis, közepes cég vagy nagyvállalat, keress bátran minket!
Köszönöm Viczián Istvánnak és Palócz Istvánnak, hogy review-zták a cikket és hasznos tanácsaikkal segítettek tovább fejleszteni!