IT audit - amikor nagyító alá kerül a kód (1. rész)
Szoftverrendszerek üzemeltetésének és fejlesztésének átadás-átvételekor, illetve cégek felvásárlásakor gyakran merül fel az IT-rendszerek átvilágításának fogalma. Mit is jelent ez pontosan? Miért érdemes ezt elvégezni? És egyáltalán, hogyan kell elképzelni egy ilyen audit folyamatot? Kétrészes összeállításunkban 9 témakört mutatunk be, amelyet érdemes megvizsgálni egy audit során. Az első részben ebből 4 témára térünk ki: az adott rendszer funkcionalitásának és üzleti folyamatainak dokumentáltságára, az alkalmazott technológiák feltérképezésére, a szoftver méretének becslésére, a szoftverminőségre.
Milyen előnyei vannak az IT auditnak?
Egy legacy rendszer üzemeltetésének és továbbfejlesztésének átvétele során elengedhetetlen, hogy tisztán lássuk a rendszer komplexitását, erősségeit és gyengeségeit, így pontosan meg tudjuk becsülni az üzemeltetési és továbbfejlesztési feladatok munkaigényét és költségeit.
Az átvilágítás során feltárt technikai, üzemeltetési és jogi tényezők együttese világosan mutatja, hogy egy szoftver átadása és átvétele nem merül ki a kódbázis átadásában. A gyakorlatban elengedhetetlen a legfontosabb dokumentációk frissítése, a biztonsági kockázatok értékelése, valamint az üzleti követelmények és SLA-elvárások felülvizsgálata. Egy jól strukturált audit eredményeképpen már az átadás-átvételi folyamat legelején megszületnek azok a konkrét tervek, amelyek megelőzhetik a későbbi problémákat, legyen szó technológiai adósságról vagy adatvédelmi hiányosságokról.
Az átvilágítás természetesen idő- és erőforrásigényes folyamat, ám éppen ez teremti meg azt a stabil alapot, amelyre a megrendelő és az üzemeltető nyugodt szívvel építheti szerződését és együttműködését.
Ha mindkét fél tisztán látja a rendszer jelenlegi állapotát, a potenciális kockázatokat és a fejlesztési igényeket, akkor a későbbi vitákat vagy váratlan költségeket is jó eséllyel elkerülhetik. Hosszú távon ez nem csupán anyagi előnyökkel jár, de a partneri viszony szilárd alapjait is megteremti, ami nélkülözhetetlen a szoftver folyamatos és sikeres működtetéséhez.
Ahhoz, hogy részletekbe menően megismerjünk egy szoftver rendszert, több szempont alapján kell megvizsgálnunk. Következzen 9 témakör, amelyet érdemes megvizsgálni az IT audit során.
1. Funkcionalitás és üzleti folyamatok megismerése
Egy szoftverrendszer átvilágítása során kiemelten fontos kérdés az adott rendszer funkcionalitásának és üzleti folyamatainak dokumentáltsága. Jelentősen segíti a szoftver elvárt működésének megértését, ha ismerjük az üzleti igényeket, amelyekre a szoftver épül.
Bármilyen, naprakészen tartott üzleti dokumentáció nagy segítséget jelenthet az átvilágítás során.
Ha a dokumentáció részlegesen vagy egyáltalán nem áll rendelkezésre, érdemes utánajárni, hogy a vállalaton belül elérhető-e még az a csoport vagy személy, aki a szoftver rendszer kialakításában és az üzleti követelmények megfogalmazásában részt vett. Ha szerencsénk van, és ezek az emberek még a cégnél dolgoznak, a velük folytatott beszélgetések és interjúk során megismerhetjük az elvárt működést, esetleg utólag elkészíthetjük a hiányzó dokumentációt.
Mindezek hiányában sem reménytelen a helyzet, de ilyenkor a forráskód alapján kell feltérképeznünk a rendszer működését. Ebben a folyamatban könnyen felmerülhetnek olyan kérdések, mint például: vajon egy adott funkcionalitás jelenlegi megvalósítása „bug vagy feature?”
2. Használt technológiák felmérése
A technológiai részletek megismerését érdemes az alkalmazott technológiák feltérképezésével kezdeni. Ilyenkor fontos áttekinteni a használt programnyelveket, valamint az SQL- és NoSQL-adatbázisokat, és a MessageQueue-megoldásokat. Vizsgálni kell továbbá az adott technológiákhoz tartozó verziók naprakészségét, illetve támogatottságát a szoftver életciklusának terve alapján (például elérhetők-e még biztonsági frissítések az adott verzióhoz).
Egy elavult, már nem támogatott verzió használata a biztonsági kockázatok mellett az újabb keretrendszerek és könyvtárak használatát is gátolhatja, és ezáltal lassítja a fejlesztéseket. Ilyen esetekben már az átadás-átvételkor érdemes megtervezni a szükséges verziófrissítést.
A tervezést az is nagyban segítheti, ha megvizsgáljuk, mennyire elérhetők, illetve milyen bérköltséggel számolhatunk az adott technológiákhoz értő szakemberek esetében, akár házon belül, akár a munkaerőpiacon. Például egy Delphi-projekthez manapság nehezebb fejlesztőt találni, és előfordulhat, hogy a cégen belül sem lesz olyan kolléga, aki szívesen bővítené a kompetenciáját ezen a területen. Illetve, egy másik példát említve, teljesen más bérigénnyel szembesülhetünk, ha egy PHP-fejlesztőt kell alkalmaznunk a projektben, mintha egy senior Java-fejlesztőre lenne szükség. E felmérésben olyan eszközök is segítségünkre lehetnek, mint a LinkedIn Talent Insights, a Glassdoor Salary Insights, a Stack Overflow Developer Survey vagy a GitHub Trends.
Minden programnyelv, keretrendszer, könyvtár és egyéb technológia esetén javasolt ellenőrizni a rá vonatkozó licencfeltételeket, és biztosítani a megfelelő használatot. Ha a projektben „commercial license” alatt használt technológia is felmerül, akkor az üzemeltetési szerződésben mindenképpen érdemes tisztázni, ki viseli annak a költségeit.
3. IT-rendszer méretének és komplexitásának becslése
A rendszer méretének és komplexitásának tisztánlátása elengedhetetlen ahhoz, hogy megfelelően fel tudjuk mérni az üzemeltetés és a továbbfejlesztés ráfordításait. Egy szoftver méretének becslésére használhatunk mennyiségi mérőszámokat – ezek előállítása egyszerűbb, ám csak körülbelüli képet adnak –, míg a komplexitás elemzése pontosabb eredményt kínál, de jóval munkaigényesebb.
Mennyiségi mérőszámok elemzése
Ha egy szoftver méretét szeretnénk megbecsülni, sokaknak elsőként a LOC (Lines Of Code) mérőszám jut eszébe. Ez a kódbázis alapján viszonylag könnyen előállítható, így kiindulópontnak megfelelhet, ugyanakkor a komplexitás szempontjából félrevezető is lehet.
A kódbázis méretéről és modularizáltságáról tájékoztatást adhat a verziókezelő is. A kezdeti feltérképezésnél további mennyiségi mutatók vizsgálata is hasznos: például a rendszer által kezelt adatok (adatbázisok száma, a táblák száma és azok egymáshoz való kapcsolatai), illetve az infrastrukturális mérőszámok (fizikai vagy virtuális szerverek száma, konténerizált környezetben futó konténerek száma).
Komplexitás elemzése
A szoftver mérete mellett annak komplexitását is fontos feltárnunk, hogy reálisabban tudjuk felmérni az üzemeltetési és továbbfejlesztési igényeket. A méret és a komplexitás együttes értékelése szilárd alapot ad a feladatok megtervezéséhez.
A komplexitás feltérképezéséhez több statikus és dinamikus kódelemző eszközt hívhatunk segítségül, amelyek a kódbázis és a működés elemzésével különböző mérőszámokat szolgáltatnak. Ilyen statikus kódelemző például a SonarQube, a Codacy, a Deepsource vagy a JetBrains Quodana.
Cyclomatic Complexity (CC) mérése és értékelése
Gyakran használt mérőszám a Cyclomatic Complexity (CC), amely a kódban található döntési ágak száma alapján méri a kód logikai összetettségét. Ez a mutató meghatározható a teljes kódbázisra, modulonként vagy akár kisebb egységekre (osztályok, függvények) is.
A CC-mérőszámok általános skálája:
- 1–10: Alacsony komplexitás, könnyen érthető és karbantartható kód
- 11–20: Mérsékelt komplexitás, még mindig viszonylag kezelhető
- 21–50: Magas komplexitás, refaktorálás javasolt a jobb olvashatóság és karbantarthatóság érdekében
- 51 felett: Extrém komplexitás, az újrafeldolgozás erősen ajánlott, mert a kód nehezen érthető és fenntartható
Halstead-metrikák
A Halstead-metrikák a kód komplexitásának és olvashatóságának mérésére szolgálnak, az operátorok és operandusok számán alapulnak.
Alapmennyiségek:
- n1 = különböző operátorok száma
- n2 = különböző operandusok száma
- N1 = operátorok összes előfordulása
- N2 = operandusok összes előfordulása
Származtatott metrikák:
- Program szókincs (Vocabulary): n = n1 + n2
- Program hossz (Length): N = N1 + N2
- Térfogat (Volume): V = N × log2(n)
- Nehézség (Difficulty): D = (n1/2) × (N2 / n2)
- Munkaigény (Effort): E = D × V
- Becsült implementációs idő: T = E / 18 (másodpercben)
- Hibaarány (Bugs): B = V / 3000
Értékelés:
- Alacsony térfogat (~1000 alatt): Könnyen érthető és karbantartható
- Közepes térfogat (~1000–3000): Mérsékelt komplexitás, figyelni kell az olvashatóságra
- Magas térfogat (3000 felett): Nehezen karbantartható, refaktorálás javasolt
Code Coupling & Cohesion, Dependency Graph Metrics
- Coupling (Kapcsolódás): Az osztályok és modulok közötti függőségek számát méri. Ha ez magas, nehezebb az egyes modulokat külön módosítani, ami megnehezítheti a hibajavítást és a továbbfejlesztést, és növeli az átfutási időt.
- Cohesion (Kohézió): Az osztályon belüli függőségeket méri. A magas kohézió azt jelzi, hogy egy modul jól szervezett, és egyetlen felelősségi kört lát el, így könnyebben karbantartható és érthető.
- Dependency Graph Metrics (Függőségi gráf): A rendszer komponensei és moduljai közötti kapcsolatok számbavétele és komplexitásuk elemzése. Egy bonyolult, ciklikus függőségekkel terhelt rendszer nehezen skálázható, és nagyobb meghibásodási kockázatot jelent üzemeltetés közben.
A fenti mérőszámok meghatározásában és elemzésében a korábban említett statikus kódelemző eszközök is segítségünkre lehetnek. Az így kapott eredményeket összevetve pontosabb képet kaphatunk a rendszer méretéről és komplexitásáról, ami megkönnyíti az üzemeltetési és fejlesztési tervek kidolgozását.
4. Szoftverminőség ellenőrzése, technológiai adósságok
Egy szoftverrendszer karbantarthatóságára és a továbbfejlesztési feladatok erőforrásigényére – a mérete és komplexitása mellett – jelentős hatással van annak implementációs minősége. Előfordulhat, hogy egy jó minőségben elkészített, magas komplexitású rendszer kevesebb erőforrást igényel, mint egy közepes komplexitású, de rossz minőségben implementált megoldás.
De mit is jelent pontosan a szoftverminőség? Hogyan mérhetjük? Ezekre a kérdésekre keressük a választ a következőkben.
A technológiai adósságok (technical debt) olyan, a fejlesztés során hozott kompromisszumos döntések, amelyek bár rövid távon gyorsíthatják a fejlesztést, hosszabb távon azonban karbantartási és továbbfejlesztési nehézségeket okozhatnak. Ezek lehetnek tudatos döntések eredményei, de a megfelelő kompetenciák hiánya is okozhatja őket.
Minél több technológiai adósság halmozódik fel egy rendszerben, annál több erőforrást igényelhet a karbantartása és továbbfejlesztése. A technológiai adósság növekedésével egyre több időt kell fordítani a napi működés támogatására és hibajavításra, ami csökkenti az új funkciók bevezetésére szánt kapacitást.
A technológiai adósságok azonosításában és mérésében hasznos segítséget nyújthatnak a statikus kódelemző eszközök, amelyek a kódbázis átvizsgálásával csoportosítva összegyűjtik a „code smell”-eket, vagyis a rossz minták alapján kialakított kódrészeket.
Architekturális adósságok
Az architekturális adósságok a rendszer moduljainak és architektúrájának kialakításában rejlő hiányosságokból adódnak.
Moduláris struktúra kialakításának hibái
A monolitikus architektúra például azt jelenti, hogy az alkalmazás minden komponense egyetlen egységként működik. Ez megnehezíti a skálázást, a karbantartást és az új funkciók hozzáadását. Ugyancsak problémás, ha a moduláris struktúrát rosszul tervezték meg, és az egyes komponensek túlzottan egymásra vannak utalva. Ilyenkor egyetlen módosítás más részekre is kihat, növeli a regressziós hibák esélyét és a hosszú távú fejlesztési költségeket.
A hibás architekturális kialakítások azonosításában a következő mérőszámok lehetnek hasznosak:
- Függőségek száma (Fan-in / Fan-out): Egy-egy modulra mutató és általa hivatkozott modulok száma.
- Kapcsolódás (Coupling Between Objects – CBO): A magas érték erős függőségekre utal, ami növeli a technikai adósságot.
- Kohézió (Lack of Cohesion in Methods – LCOM): Az alacsony érték jelzi, hogy az osztályok jól strukturáltak és egységes felelősségi körrel rendelkeznek.
- Modulok mérete és eloszlása: Megmutatja, hogy a rendszer mennyire van kisebb, független komponensekre bontva.
Üzleti logika és I/O-kezelés nem megfelelő elkülönítése
Ha az üzleti logika és az adatkezelés (például adatbázis-lekérdezések, fájlműveletek, API-hívások) nem különül el megfelelően, akkor egy komponens módosítása számos más területet is érinthet. Ennek következtében nehezebb lehet az automatikus tesztek kialakítása vagy egy-egy adatkezelő-technológia cseréje. Hosszú távon ez egyre nehezebben skálázható, sérülékeny rendszert eredményez.
A következő tervezési minták (design patternek) segíthetnek a megfelelő struktúra kialakításában:
- Üzleti logika elkülönítése – például Service Layer vagy Domain-Driven Design (DDD) alkalmazása
- Repository Pattern – a perzisztenciaréteg leválasztására
- Dependency Injection – a rétegek lazább kapcsolódása érdekében
Ha ezek a megoldások hiányoznak, az intő jel lehet a nem megfelelő kódstruktúra tekintetében.
Kódminőségi adósságok
Az architektúra kialakításának ellenőrzése mellett a forráskód minősége is fontos szempont egy átvilágítás során. A rossz minőségű kód ugyanis jelentősen megnehezíti a karbantartást.
A kódminőség vizsgálatához is igénybe vehetjük a statikus kódelemző eszközöket, illetve az alábbi jellemzőket érdemes kiemelten figyelni.
Rossz elnevezések, nehezen olvasható kódformázás
A rossz elnevezések és a nehezen olvasható kódformázás komoly technikai adósságot képez, mert csökkenti a kód érthetőségét, és növeli a karbantartási költségeket. Ha a változók, osztályok vagy metódusok nevei nem egyértelműek, az új fejlesztők számára nehézkessé válik a rendszer megismerése. Az inkonzisztens, rossz formázású kód pedig tovább csökkenti az olvashatóságot, és a hibakeresés során időveszteséget okoz. E problémák kiküszöbölésében segíthetnek a kódolási standardok, az automatikus formázó eszközök (pl. Prettier, Black) és a linting szabályok használata.
Duplikált kód
A duplikált kód növeli a karbantartásra fordítandó időt, mivel egy módosítás esetén több helyen is frissíteni kell ugyanazt a kódrészletet. Ez hibalehetőségeket hoz létre és csökkenti a rendszer átláthatóságát. A duplikált kódok azonosítását az alábbi mérőszámok segíthetik:
- Kódduplikáció százaléka – a teljes kódbázison belüli ismétlődő kódrészletek aránya.
- Kódklónok száma – az azonos vagy nagyon hasonló kódrészletek száma.
Magas cyclomatic complexity:
A cyclomatic complexity magas értékei, különösen sok helyen a kódbázisban, azt jelzik, hogy a kód nehezebben átlátható és módosítható. Ha az átvilágítás során több ilyen egységet is találunk, számolnunk kell vele, hogy a fejlesztési és karbantartási költségek megnőnek.
SOLID elvek és technológiai adósság:
- Single Responsibility Principle (SRP): Minden osztálynak csak egyetlen felelőssége legyen. Ennek megsértése magas karbantartási költséget eredményez, mert egy osztály módosítása több funkcióra is kihat.
- Open/Closed Principle (OCP): Az osztályok legyenek nyitottak a bővítésre, de zártak a módosításra. Ha ez sérül, egy új funkció bevezetése folyamatosan megváltoztathatja az alapvető kódot, növelve a regressziós hibák kockázatát.
- Liskov Substitution Principle (LSP): Az alosztály legyen helyettesíthető az ősosztállyal anélkül, hogy a rendszer működése megváltozna. Ha ez nem teljesül, váratlan hibák léphetnek fel.
- Interface Segregation Principle (ISP): Egy interfész ne tartalmazzon olyan metódusokat, amelyeket az implementáló osztályok nem használnak. Ellenkező esetben felesleges függőségek, és átláthatatlan kód jön létre.
- Dependency Inversion Principle (DIP): A magasabb szintű modulok ne függjenek az alacsonyabb szintű moduloktól, hanem közös absztrakcióra épüljenek. Ennek megsértése nehezen tesztelhető és módosítható kódot eredményez.
A „Design Patterns” használatának hiánya
Ha a rendszer nem alkalmaz jól ismert tervezési mintákat (pl. Factory, Service Locator, Strategy, Command, Adapter, Decorator, Observer), akkor kódszintű inkonzisztenciák, magas kapcsolódás (coupling) és alacsony kohézió (cohesion) alakulhat ki. Ez különösen gondot okozhat nagyobb projektek esetében, ahol egységes struktúrára és skálázhatóságra van szükség. A megfelelő design pattern használata fenntarthatóbbá és rugalmasabbá teszi a fejlesztést, ezért az átvilágítás során érdemes ennek meglétét is ellenőrizni.
Hiányzó vagy hibás kivételkezelés
A kivételkezelés (exception handling) minősége kritikus a rendszer stabilitása szempontjából. Ha a kivételek elkapása és kezelése nem megfelelő, akkor rejtett hibák, váratlan összeomlások és nehezen nyomon követhető problémák jelentkezhetnek. Az általános exception blokkok vagy a túlzottan specifikus hibaüzenetek megnehezítik a hibaelhárítást és növelik a technológiai adósságot. A megfelelő logolás, a részletes hibakezelési stratégiák és a szabványos exception handling minták (pl. try-catch-finally, circuit breaker) használata hozzájárul a problémák minimalizálásához.
Hardkódolt értékek és konfigurációk
A kódban található hardkódolt értékek és konfigurációk csökkentik a rugalmasságot, és növelik a karbantartási költségeket. Ha például az adatbázis elérési adatok, API-végpontok vagy beállítási paraméterek közvetlenül a kódban szerepelnek, akkor módosításuk nehézkes, és megnő a hibázás lehetősége. Az ilyen értékeket érdemes konfigurációs fájlokban, környezeti változókban vagy titkosított tárolókban (pl. Vault, AWS Parameter Store) elhelyezni a biztonság és a skálázhatóság érdekében.
Standard keretrendszerek és könyvtárak használata vs. saját implementáció
Az átvilágítás során vizsgáljuk meg, hogy a nem üzleti logika specifikus feladatokra (például logkezelés, PDF-generálás, e-mailkezelés) standard könyvtárakat és keretrendszereket használtak-e, vagy saját megoldásokat fejlesztettek. A bevált, jól dokumentált és széles körben használt megoldások csökkentik a karbantartásra fordított időt és megkönnyítik a működés átlátását.
Automatizált tesztek felmérése és tesztlefedettség
A rendszer stabilitását és minőségét nagyban növeli, ha a főbb üzleti logikák megfelelő tesztekkel vannak lefedve. Az átvilágítás során érdemes ellenőrizni a tesztlefedettséget – akár az egész rendszerre vonatkozóan, akár modulonként. Minél magasabb ez az érték, annál kisebb kockázattal végezhetők el a szükséges módosítások, hiszen a tesztek időben jelzik az esetleges hibákat.
Dokumentáció ellenőrzése
Végül, de nem utolsósorban a naprakész és releváns dokumentációk megléte is kulcsfontosságú. A magas szintű architekturális és folyamatleíró dokumentációk segítik a rendszer megértését, míg az API- és interfészleírások a funkcionalitást teszik átláthatóvá.
Ha a dokumentáció elavult vagy hiányos, a frissítése jelentős erőfeszítést kívánhat. Szükség esetén olyan statikus kódelemző eszközöket, illetve már elérhető AI-megoldásokat is bevethetünk, amelyek a forráskódból képesek automatikusan (legalább részben) naprakész dokumentációt generálni.
A fenti szempontok mind hozzájárulnak a szoftver minőségének és a benne rejlő kockázatoknak a reálisabb felméréséhez. Egy alapos átvilágítás során nemcsak a jelenlegi állapotot térképezhetjük fel, hanem megtehetjük a szükséges lépéseket is annak érdekében, hogy a rendszer hosszú távon is stabil, fenntartható és költséghatékony maradjon.
A következő 5 témakört az összefoglaló anyag második részében olvashatod!