By: Daniel Losvans

2017-11-01

Your Code as a Crime Scene

Jag har alltid varit intresserad av teori och praktik relaterat till utveckling. Varför utvecklar vi som vi gör? Vad kan vi lära av historien kring utveckling? Nyligen läste jag “Code as a Crime Scene” och här finns det massor av tekniker vi kan nyttja för att verkligen lära av den specifika historian kring din kodbas.

Kortfattat kan vi säga att boken visar olika analyser som du kan göra på din kodbas för att identifiera problem och hitta sätt att förbättra koden. Genom teori och praktik från kriminologi och beteendevetenskap kan vi undersöka vår mjukvaras utveckling för att förstå koden bättre. I små projekt kan det hjälpa oss att förstå om designen är bra och om den följs, för stora projekt kan vi hitta var faror lurar och om organisationen stämmer med hur vi arbetar. Om man nyttjar detta kan man applicera vissa tekniker kontinuerligt för att mäta sin kods hälsa och se om man är på rätt väg med sin tekniska skuld.

Varför kan man ta teori och praktik från kriminologi och beteendevetenskap och applicera på mjukvaruutveckling? Det är ju människor som utvecklar! Vi kan ta hjälp av psykologi och beteende för att bättre förstå hur koden har utvecklats och vad det troligen kommer att utvecklas mot.

Ett exempel på vad vi kan ta inspiration från inom kriminologi är geografisk gärningsmannaprofil. Det handlar om att för seriebrottslingar har vi flera olika brottsplatser. Utifrån deras geografiska position kan vi dra slutsatser kring vart brottslingen antagligen befinner sig eller bor och även få information kring vart nästa brott kan tänkas begås. För att föra över det till kod så finns det många studier som visar att där vi ändrar ofta är där vi har störst problem. Helt enkelt så lämnar varje ändring ett spår för oss att följa.

En annan teori handlar om ansvarskänsla. Att det finns många vittnen till ett brott betyder inte säkert att flera kommer att rapportera brottet, snarare tvärtom. Alla tror att någon annan gör det. Samma för kod, har vi många som ändrar i samma filer, klasser etc är det inte säkert att någon enskild kommer känna ansvar för koden. Sämre lösningar kommer in och ingen tar tag i eventuellt underhåll som behövs. Finns det dock en huvudutvecklare för en modul är det troligare att förbättringar sker och färre buggar kommer in. Det finns också studier som tydligt visar att antalet buggar per del (fil, klass etc) korrelerar med antalet utvecklare.

Hur får vi då fram denna data? Vi har ju sparat den hela tiden! Den sitter i versionshanteringssystem, oftast i vad vi skulle kalla metadata. I git t ex som jag främst tänker på så har vi för varje ändring (commit): en tidpunkt, vem som skrev det, en beskrivning på vad ändringen gäller och sedan självklart själva ändringen i sig. Det är massor av meningsfull information vi kan utnyttja! Sedan kan man också gå vidare för att analysera kommunikationen. Det genom att jämföra ändringar mot hur organisationen ser ut, vem är i vilket team etc.

Hur ska man då göra dessa analyser i praktiken? Jag kommer utgå från boken och visa exempel med git som versionshantering och verktyget code-maat.

Identifiera viktiga områden (hotspots)

Kod som ändras ofta har i flera studier visats innehålla mest problem (flest buggfixar etc)

Genom att identifiera dessa områden får man data på t ex:

  • Var man ska prioritera att göra designförbättringar
  • Vilka områden som är viktiga att titta på under kodgranskning
  • Vilka områden som behöver bättre testtäckning

Ett lätt sätt hitta viktiga eller heta områden är att se på antalet ändringar per fil:

>git log --pretty=format:'[%h] %an %ad %s' --date=short --numstat > evo.log
>code-maat -l evo.log -c git -a summary
>code-maat -l evo.log -c git -a revisions
>cloc . --by-file --csv –quiet

Första kommandot skapar en loggfil från git som vi sedan använder för olika analyser. Andra kommandot använder vi code-maat för att bara få en sammanfattning (hur du kör den själv på din dator hänvisar jag till verktygets beskrivning). Det ger oss en grund och även en check på att vi analyserar rätt data. Nästa analys (revisions) ger hur ofta varje fil har ändrats.

För att vikta resultatet kan vi jämföra mot hur stora filerna är (sista kommandot som använder cloc). Om de ändras mycket men inte är så stora kanske de ändå är lätta att förstå och inte behöver förbättras lika mycket som de andra. Namn på filer är också en bra bedömning av hur heta filerna egentligen är. Är de vaga, allmänna, innehåller ‘och’, suffix o.s.v. är det troligen bra kandidater att refaktorisera.

En annan analys på området för att se kodkvalitet är att mäta indentering i koden. Har man mycket och djup indentering tyder det på sämre design och svårläst kod.

Falska minnen och dåliga intervjuer

En annan teori vi kan ta inspiration från handlar om falska minnen och dåliga intervjuer. Vi kan få fel idé vid ledande frågor, komma ihåg saker fel o.s.v. Koden har en viss struktur och kopplingar som är direkta genom hur koden är uppbyggd (explicit couplings). En klass ärver av en annan, använder dessa klasser t.ex. Sedan har vi även gömda kopplingar (temporal couplings) som har egenskaper vi inte vill ha. Om vi bara ser till den direkta strukturen kommer vi missa andra viktiga samband. Undersökningar har visat att moduler med många gömda kopplingar ofta har fler buggar och framförallt fler allvarliga buggar. Orsaker till dessa gömda kopplingar kan vara t ex kopierad kod (vi har samma kod på flera ställen) eller gömda beroenden från datastrukturer t ex.

>code-maat -l evo.log -c git -a soc
>code-maat -l evo.log -c git -a coupling

Den första analysen är “sum of couplings” som kommer att ge totalt antal kopplingar en fil har. Kopplingar här är för varje ändring kommer de bli en koppling mellan de filer som är med i en ändring. Då får vi ett värde på vilka filer som sitter mest ihop med andra. Den andra analysen ger ett värde på hur mycket två filer sitter ihop. Vilket betyder: utifrån alla ändringar i filerna, hur ofta de ändras tillsammans. Något som typiskt brukar sitta ihop är enheter med dess enhetstester, det är en direkt koppling. Utifrån namn och att man känner till strukturen i projektet kan man lätt se kopplingar som sticker ut och kan vara gömda kopplingar.

Conways law, Brooks law

Som jag sa tidigare är jag fascinerad av hur vi utvecklar. Därför tycker jag att Conways law och Brooks law är intressanta. Jag tänker inte gå in på dessa i detalj här, vill man veta mer så se länkar i slutet.

Kortfattat säger Conways law att vi skapar en arkitektur/design efter hur vi är organiserade och det är p.g.a. kommunikation. Brooks law säger att tiden som läggs på att kommunicera ökar med antalet utvecklare, vilket ger en processförlust. Fler utvecklare garanterar alltså inte att att vi kan producera mer.

Några intressanta frågor relaterat till detta är:

  • stämmer organisationen med hur vi arbetar?
  • vilka moduler har flest olika utvecklare ändrat?

Några av svaren på de frågorna får vi genom att titta på antalet kopplingar för en dag, identifiera huvudkodare för dessa och jämföra med andra författare i filer som är kopplade till dessa.

>code-maat -l evo.log -c git -a authors
>code-maat -l evo.log -c git -a coupling --temporal-period 1
>code-maat -l evo.log -c git -a main-dev
>code-maat -l evo.log -c git -a entity-ownership

Första kommandot ger hur många olika författare (utvecklare) varje fil har. Den andra är samma som vi använt tidigare men räknar nu med att alla ändringar över en dag som kopplade. Nästa kommando ger vem som står för flest ändringar i varje fil. Det kan vi sedan jämföra mot sista kommandot som ger hur mycket varje författare för varje fil har ändrat. Men lite sortering och kombinering av resultatet från dessa kan man se om t ex olika utvecklare jobbar mycket på samma delar och jämföra med organisationen att de verkligen jobbar nära där också.

En annan snabb analys är att göra ett ordmoln på ändringsmeddelanden. Från det kan man få en snabb överblick, jobbar vi med de funktioner som är viktigast? Dyker det upp något ord som förvånar? Denna analys kan man göra per iteration, sprint etc beroende på hur man arbetar och då se för varje iteration om man lägger tid på det man tror.

Analyserna här kompletterar annan information vi har. Det bygger vidare på vad vi får reda på genom statisk-analys, tester osv. Det här tar även in historiken och informationen vi sparar i versionshanteringen. Det gäller då att nyttja den, för den enskilde utvecklaren kan det vara att veta vad man ska vara vaksam mot när man utvecklar själv och som stöd vid kodgranskningar. För teamet/organisationen ger det data på vilket ställe man ska prioritera för att minska tekniskskuld och om teamen är rätt organiserade. Och om vi har några luckor i kunskapen kring kodbasen etc. Mitt tips är att ta små kliv, gör den analysen som din kod har behov av och utgå från det.

Läs mer:

Att vara trainee på Dynabyte (traineeprogrammet vt 2017)

Hitta buggen med git bisect