en dybdegående forklaring på kode kompleksitet

det er ingen hemmelig kode er en kompliceret ting at skrive, debug, og vedligeholde, som er nødvendig for høj programmel kvalitet. Desuden medfører høj kodekompleksitet et højere niveau af kodefejl, hvilket gør koden dyrere at vedligeholde.

så ved at reducere kodekompleksitet kan vi reducere antallet af fejl og mangler sammen med dets levetidsomkostninger. Hvad er kompleks kode? Hvordan kan vi objektivt vurdere, hvor komplekst et stykke kode er, uanset om det er en hel kodebase eller en lille funktion?

i denne artikel vil jeg gennemgå tre kompleksitetsmålinger til vurdering af kodekompleksitet. Disse er:

  • Cyclomatic kompleksitet
  • Skift erklæring og logik tilstand kompleksitet
  • Udvikler dygtighed

jeg vil også gå igennem nogle af fordelene ved at vurdere og forstå kode kompleksitet.

Cyclomatisk kompleksitet

i 1976 foreslog Thomas McCabe Snr en metrisk til beregning af kodekompleksitet, kaldet Cyclomatisk kompleksitet. Det er defineret som:

et kvantitativt mål for antallet af lineært uafhængige stier gennem et programs kildekode…beregnet ved hjælp af programmets kontrolstrømsgraf.

hvis du ikke er bekendt med en Kontrolstrømsgraf:

det er en repræsentation ved hjælp af grafnotation af alle stier, der kan krydses gennem et program under dets udførelse.

sagde mere ligetil, jo færre stier gennem et stykke kode, og jo mindre komplekse disse stier er, jo lavere Cyklomatisk kompleksitet. Som følge heraf er koden mindre kompliceret. For at demonstrere metrikken, lad os bruge tre, noget vilkårlige, go-kodeeksempler.

eksempel en

func main() { fmt.Println("1 + 1 =", 1+1)}

da der kun er en sti gennem funktionen, har den en Cyklomatisk Kompleksitetsscore på 1, som vi kan finde ved at køre gocyclo på den.

eksempel to

func main() { year, month, day := time.Now().Date() if month == time.November && day == 10 && year == 2018 { fmt.Println("Happy Go day!") } else { fmt.Println("The current month is", month) }}

i dette eksempel henter vi det aktuelle år, måned og dag. Med disse oplysninger kontrollerer vi derefter, om den aktuelle dato er den 10.November 2018 med en if/else-tilstand.

hvis det er, så udskriver koden “Happy go day!”til konsollen. Hvis det ikke er tilfældet, udskrives det “den aktuelle måned er” og navnet på den aktuelle måned. Kodeeksemplet gøres mere kompliceret som hvis betingelsen er sammensat af tre underbetingelser. I betragtning af det, det har en højere kompleksitetsscore på 4.

eksempel tre

func main() { _, month, _ := time.Now().Date() switch month { case time.January: fmt.Println("The current month is January.") case time.February: fmt.Println("The current month is February.") case time.March: fmt.Println("The current month is March.") case time.April: fmt.Println("The current month is April.") case time.May: fmt.Println("The current month is May.") default: fmt.Println("The current month is unknown.") }}

i dette eksempel udskriver vi den aktuelle måned, baseret på værdien month, hentet fra opkaldet til time.Now().Date(). Der er syv stier gennem funktionen, en for hver af case-udsagnene og en for standard.

som følge heraf er dens Cyklomatiske kompleksitet 7. Hvis vi havde tegnet sig for alle årets måneder sammen med en standard, ville dens score dog være fjorten. Det sker, fordi Gocyclo bruger følgende beregningsregler:

1 er basiskompleksiteten af en funktion
+ 1 for hver’ hvis’,’ for’, ‘sag’, ‘&&’ eller ‘||’

ved hjælp af disse tre eksempler kan vi se, at ved at have en standardmåling til beregning af kodekompleksitet, kan vi hurtigt vurdere, hvor komplekst et stykke kode er.

vi kan også se, hvordan forskellige komplekse sektioner af kode er i sammenligning med hinanden. Imidlertid er Cyclomatisk kompleksitet ikke nok alene.

Skift sætning og logik tilstand kompleksitet

den næste assessor af kode kompleksitet er kontakten sætning og logik tilstand kompleksitet. I kodeeksemplet nedenfor har jeg taget det andet Go-eksempel og opdelt forbindelsen, hvis tilstanden er i tre indlejrede betingelser; en for hver af de oprindelige betingelser.

func main() { year, month, day := time.Now().Date() output := fmt.Sprintf("The current month is %s", month) if month == time.November { if day == 13 { if year == 2018 { output = fmt.Sprintf("Happy Go day!") } } } fmt.Println(output)}

hvilket er lettere at forstå (eller mindre kompliceret), den oprindelige eller denne? Lad os nu bygge videre på dette ved at overveje følgende tre spørgsmål.

  • hvad hvis vi havde, som vi gør ovenfor, flere if-betingelser, og hver enkelt var ret kompleks?
  • hvad hvis vi havde flere, hvis betingelserne og koden i hver enkelt krop var ret komplekse?
  • ville koden være lettere eller sværere at forstå?

det er rimeligt at sige, at jo større antallet af indlejrede forhold og jo højere kompleksitetsniveauet inden for disse forhold er, jo højere er kodens kompleksitet.

Programmeludviklerens færdighedsniveau

hvad med udviklerens færdighedsniveau? Se på C-versionen af det andet Go-eksempel nedenfor.

#include <stdio.h>#include <time.h>#include <string.h>int main(){ time_t t = time(NULL); struct tm tm = *localtime(&t); const char * months = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; if (tm.tm_year == 2018 && strncmp(months, "November", strlen(months)) == 0 && tm.tm_mday == 10) { printf("Happy C Day!.\n"); } else { printf("The current month is %s.\n", months); }}

teknisk set gør det, hvad de andre eksempler gør. Det kræver dog mere kode for at opnå det samme resultat. For at være retfærdig, hvis jeg havde en større fortrolighed med C, koden er muligvis ikke længere end Go-eksemplet.

lad os dog sige, at dette er det minimum, der kræves for at opnå det samme resultat. Hvis du sammenligner de to, i betragtning af den mere detaljerede karakter af C ‘ s syntaks sammenlignet med Go, er det sværere at forstå.

hvad mere er, hvis du ikke havde nogen tidligere erfaring med C, på trods af en forholdsvis lignende Cyklomatisk Kompleksitetsscore, hvad ville din opfattelse være?

vil du betragte koden som mindre eller mere kompliceret? Så dette er en anden vigtig faktor i forståelsen af kodekompleksitet.

fordelene ved at måle Programmelkompleksitet

der er fire kernefordele ved at måle kodekompleksitet plus en ekstra.

bedre test

ved at vide, hvor mange uafhængige stier der er gennem et stykke kode, ved vi, hvor mange stier der skal testes.

jeg er ikke fortaler for 100% kode dækning ved den måde—det er ofte en meningsløs programmel metric. Imidlertid, jeg går altid ind for et så højt niveau af kodedækning, som det er både praktisk og muligt.

så ved at vide, hvor mange kodestier der er, kan vi vide, hvor mange stier vi skal teste. Som et resultat har du et mål for, hvor mange tests der kræves, som minimum for at sikre, at koden er dækket.

reduceret risiko

som det gamle ordsprog siger:

det er sværere at læse kode end at skrive det.

hvad er mere:

  1. kode læses langt mere end den er skrevet
  2. en god Udvikler bør aldrig vurderes af de kodelinjer, de har skrevet (eller ændret), men af kvaliteten af den kode, de har opretholdt.

i betragtning af at du ved at reducere kodekompleksitet reducerer risikoen for at indføre mangler; uanset om de er små eller store, lidt pinlige eller konkursfremkaldende.

lavere omkostninger

når risikoen for potentielle fejl reduceres, er der færre fejl at finde—og fjerne. Som følge heraf reduceres vedligeholdelsesomkostningerne også.

vi har alle set og kender omkostningerne forbundet med at finde fejl på de forskellige stadier i et programs levetid, som eksemplificeret i nedenstående diagram.

stigende fejlomkostninger

så det giver mening, at hvis vi forstår kompleksiteten af vores kode, og hvilke sektioner der er mere komplicerede end andre, så er vi i en langt bedre position til at reducere kompleksiteten.

så ved at reducere denne kompleksitet reducerer vi sandsynligheden for at indføre fejl. Det flyder ind i alle faser af et programs liv.

større forudsigelighed

ved at reducere programmelkompleksitet kan vi udvikle os med større forudsigelighed. Hvad jeg mener med det er, at vi bedre kan sige—med tillid—hvor lang tid en sektion af kode tager at fuldføre. Ved at vide dette er vi bedre i stand til at forudsige, hvor lang tid en frigivelse tager at sende.

baseret på denne viden er virksomheden eller organisationen bedre i stand til at sætte sine mål og forventninger, især dem, der er direkte afhængige af programmet. Når dette sker, er det lettere at indstille realistiske budgetter, prognoser og så videre.

hjælper udviklere med at lære

at hjælpe udviklere med at lære og vokse er den endelige fordel ved at forstå, hvorfor deres kode betragtes som kompleks. De værktøjer, jeg har brugt til at vurdere kompleksitet indtil dette punkt, gør det ikke.

hvad de gør er at give en samlet eller granulær kompleksitetsscore. Imidlertid, en omfattende kode kompleksitet værktøj, såsom Codacy, gør.

filkompleksitetsliste

i skærmbilledet ovenfor kan vi se, at man af de seks nævnte filer har en kompleksitet på 30, en score, der normalt betragtes som ret høj.

Cyclomatisk kompleksitet er en god indikator for at forstå, om kodekvaliteten forringes for en given ændring. Cyclomatisk kompleksitet kan være sværere at begrunde, når man ser på det eller sammenligner hele moduler i betragtning af dets uendelige skala og ikke er relateret til modulstørrelsen. Men noget, som du måske finder nyttigt, er at se på Codacy ‘ s filliste sorteret efter prioritet, hvilket vil hjælpe dig med at forstå, hvilke filer der er kandidater af dårlig kodekvalitet og derefter som følge heraf deres moduler.

det er en indpakning

dette har også været en dybdegående diskussion om, hvad kode kompleksitet er, hvordan det vurderes, samt de betydelige fordele ved at reducere det. Mens der er mere at forstå kode kompleksitet end jeg har dækket her, har vi gået langt for at forstå det.

Hvis dette er første gang du hører om udtrykket eller lærer om et af værktøjerne, opfordrer jeg dig til at udforske de linkede artikler og værktøjer, så du lærer mere. Hvis du ikke kode i Go eller C, derefter google “kode kompleksitet værktøj” plus dit program sprog. Du er sikker på at finde mange værktøjer til rådighed.

for flere tips til at forbedre kode kvalitet tjek nogle andre blogindlæg fra Codacy.

endelig, hvis du vil have et omfattende værktøj til vurdering af kodekvalitet, og et, der hjælper dine udviklere med at lære og vokse, så prøv Codacy.

Codacy bruges af tusindvis af udviklere til at analysere milliarder af linjer kode hver dag!

det er nemt at komme i gang – og gratis! Brug bare din GitHub, Bitbucket eller Google-konto til at tilmelde dig.

KOM I GANG

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.