HelloWorld logo
11.07.2022. ·
5 min

Kognitivna kompleksnost koda

Siniša Nimčević Siniša Nimčević

Ciklomatska kompleksnost je termin skovan od strane Thomas J. McCabe-a davne 1976. (u Fortran okruženju), da bi se opisao proces merenja “lakoće testiranja i održavanja” kontrolnog toka nekog modula. Njegov pristup je primena matematičkih modela kojima otkrivamo koliko je testova potrebno da se u potpunosti “pokrije” neki metod. U novije vreme, G. Ann Campbell je primetila da je Ciklomatska analiza kompleksnosti manjkava kada dođe do merenja toga koliko je lako razumeti i održavati neki kod. Ona je uvela novu metriku koju zovemo “Kognitivna kompleksnost”. Kognitivna kompleksnost ima za cilj da reši ovaj problem, odnosno, unapredi način na koji analiziramo naš kod. Inače, sa Kognitivnom kompleksnošću se u praksi srećemo ako koristimo SonarCube analizu kvaliteta koda.

Kao i svaki programer, možemo misliti da smo najpametniji na svetu i da, kada nam ova metrika digne “crvenu zastavicu” i traži da refaktorišemo kod da bi “pipeline” prošao, automatski kažemo - ovo je suvišna provera, moj kod je savršen takav kakav je! Međutim, ako pokušamo da razumemo na koji način se ova metrika dobija (i zašto baš tako) stvari postaju jasnije, a postavljanjem ove dodatne “prepone”, kvalitet naše baze koda će dugoročno biti osetno podignut.
 

Osnovni kriterijumi i metodologija 

Kognitivna kompleksnost ima za cilj da, napuštajući matematičke modele u korist jednostavnih pravila, bolje oponaša programersku intuiciju koja nam uvek može reći koje parče koda je čitljivo (i samim tim lakše za održavanje), a koje nije. U tu svrhu dodajemo “bodove”, koji, kada se nakupe u jedan zbir, mogu kvantitativno da nam ukažu gde je naš kod previše komplikovan i (manje više) kako bi ga valjalo refaktorisati pre nego što ga pustimo u neki “zajednički prostor”. 

 Tri osnovna pravila su: 

  1. Ignorisati strukture koje dozvoljavaju da se na čitljiv način više izvedbi skrati u jednu (skraćenice uglavnom smanjuju kompleksnost) 
  2. Dodati poene za svaki prekid linearnog toka koda (ako nas nešto tera da se zamislimo kuda ovaj kod ide dalje, znači da ono dodaje kompleksnost) 
  3. Dodatno inkrementovati zbir kada se prekid linearnog toka gnezdi u drugi (ako smo bili u nedoumici u prošlom koraku, sada je nesigurnost duplo veća) 

Na osnovu tih pravila, dodajemo poene u jedan rezultujući zbir koji odražava kongitivnu kompleksnost nekog modula.  

 Postoje konkretno 4 izvora kompleksnosti koji dodaju poene na spomenuti zbir: 

  1. “Nesting” - pojava kada su strukture koje kontrolišu tok izvršavanja koda napisane jedna u drugoj 
  2. Strukturalna kompleksnost - pojava struktura koje kontrolišu tok izvršenja koda, koje su pod uticajem “nesting” kompleksnosti i koje povećavaju broj “nestinga” 
  3. Fundamentalna kompleksnost - odnosi se na izvedbe koje dodaju kompleksnost ali NISU pod uticajem “nesting” kompleksnosti 
  4. Hibridna kompleksnost - pojavljuje se na strukturama koje kontrolišu tok izvršavanja koda koje NISU pod uticajem “nesting” kompleksnosti, ali povećavaju broj “nestinga”
     

Ignorisanje skraćenica 

Vodeći princip u stvaranju Kognitivne kompleksnosti je bio dizanje kvaliteta koda tj, u zbir kompleksnosti ne treba da dodajemo strukture koje čine kod čitljivijim. Na primer, razbijanje klase na metode ne podiže njenu kompleksnost (samo po sebi) jer oslanjanjem na pozivanje metoda dobijamo čitljiviji kod. Takođe se ignoriše “null-coalescing” jer, iako kontroliše tok izvršavanja, zauzvrat štedite broj linija koda (manje koda je lakše održavati, mada bih odmah dodao da igranje code golf-a nije prečica do jasnog i čitljivog koda).
 

Penali za razbijanje linearnog toka izvršavanja 

Kompleksnost se povećava dodavanjem “loop” sturktura i kondicionala (uslova), bili ti kondicionali klasični kao if, ili hibridni kao elif. Ovde se ubraja i catch iz trycatch strukture koju neki jezici imaju (ali ne i njegovi rođaci try i finally).
 

Zanimljivo je da switch structura (sa svim svojim case-ovima) dodaje samo jedan poen u svetu Kognitivne kompleksnosti. Pri Ciklomatskoj analizi, svaki case bi bio dodatno penalizovan, jer se u Ciklomatskoj analizi switch struktura tretira kao niz elseif-ova. Iz iskustva znamo da je uredno napisana switch struktura osetno čitljivija za programera od gomile elseif uslova i stoga je bilo potrebno napraviti ovu razliku u interesu realnijeg kognitivnog zbira.
 

Serija logičkih operatora na primer, dodaje samo jedan poen, ali pod uslovom da su ti logički operatori isti. Ukoliko u istoj izvdebi mešamo and i or operatore (primera radi), penali su strožiji jer su takve strukture teže za protumačiti na prvi pogled.
 

Rekurzija je takođe penalizovana jer je vrsta “meta-loop” strukture, a znamo da svaka “loop” struktura dodaje poteškoće pri shvatanju pročitanog koda. 

 Penali za ugnežđene strukture (koje razbijaju linearni tok izvršavanja) 

Prilično je očigledno da je nekoliko if-ova jedno za drugim mnogo čitljivije, nego isti taj broj uslova napisan jedan u drugom. Ovo pakovanje kontrolnih struktura u strukturu se zove “nesting” (ili nezgrapno prevedeno “gnežđenje”). 

 Kognitivna kompleksnost posebno tretira pojavu “nestinga”. Iako bi neke strukture same po sebi dodavale samo jedan bod na kompleksnost, ukoliko su ugnežđene jednom, dva ili više puta, one dodaju proporcionalno više poena budući da je sada modul mnogo teži za shvatanje na prvi pogled. 

 Zaključak i izvori za dalje čitanje 

Dok je Ciklomatična kompleksnost bila čisto matematička metrika, Kognitivna kompleksnost pokušava da napravi odraz neke naše intuitivne, subjektivne slike stanja koda. Posebno je vođeno računa da bukvalno “odokativno” možemo uporediti dve verzije koda i reći koja ima manju, odnosno veću Kognitivnu kompleksnost. Uvođenje ovakvih metrika u proces je posebno važno, jer programeri imaju tendenciju da izgrade neki svoj stil pisanja koda. Ovo je i simpatično i lepo - čak i u branši koja je toliko “cerebralna” imamo momenat samoizražavanja, a samoizražavanje je izvor umetnosti, zar ne? Međutim, kako ekipa raste, bitno je pisati što “neutralniji” kod - idealno, ne bismo trebali da budemo u stanju da odredimo ko je pisao neki metod bez alata za praćenje verzija. Da bismo naveli grupu (tvrdoglavih) programera da prave gotovo uniformne odluke pri pisanju, moramo podupreti pravila sa “najbolji-način-da-se-piše” metrikama, teorijom i statistikom i to je upravo ono što nam Kognitivna kompleksnost (u moru drugih alata) donosi. 

 - p.s. 

Za više detalja i primere predlažem origialni uradak https://www.sonarsource.com/docs/CognitiveComplexity.pdf , kao i slične članke drugih autora: https://docs.codeclimate.com/docs/cognitive-complexity , zatim https://www.c-sharpcorner.com/blogs/cognitive-complexity-vs-cyclomatic-complexity-an-example-with-c-sharp .
 - p.p.s. 

Ukoliko koristite VS Code kao IDE, mogu da preporučim simpatičan mali plugin https://marketplace.visualstudio.com/items?itemName=ampcpmgp.cognitive-complexity-show 

Pogledaj komentare
Siniša Nimčević Siniša Nimčević

Nakon frilans rada u zlatno doba Elance platforme i putešestvija (i radnog iskustva) po Londonu, vraća se u rodnu Suboticu leta gospodnjeg 2018. Sa oko 10 godina iskustva u vebu, specijalizuje se u javaskriptu i piskara ne bi li dublje istražio neke teme i preneo znanje. Uvek otvoren za ćaskanje, savete i konstruktivnu kritiku.

Iz ove kategorije