Mijn loopbaan als software ontwikkelaar begon ik in een klein team. Elke collega werkte normaalgesproken aan zijn of haar eigen project. Soms kwam het voor dat we met z’n tweeën of drieën een project deden. Tijdens het tweewekelijks afdelingsoverleg kwam regelmatig het onderwerp van codekwaliteit voorbij. Meestal werd plechtig beloofd om wat meer en betere peer reviews te doen op elkaars code. En meestal bleef het ook daarbij: een belofte. Verschillende excuses passeerden de revue: “Te druk met mijn eigen project”, “Ik heb een deadline”, “Op welke urencode kan ik die tijd dan schrijven?”, “Ik ken die applicatie niet zo goed.”, tot en met “Het werkt toch? Dus prioriteit 0”.

De spaarzame momenten dat we wel een soort van code review deden was het vrij summier. Een check op code die eventueel was aangepast, wat commentaar op iets dat duidelijk niet klopte of wat kopieer- en plakwerk van code om het idee te geven dat er echt wat gedaan was.

Het was niet zo dat we het belang niet zagen van nette, betrouwbare en kwalitatief goede code. Nette, overzichtelijke code is beter te beheren en heeft hopelijk ook wat minder bugs. Maar het is lastig om iedereen op dezelfde lijn te krijgen. Niet alleen vanwege gebrek aan tijd en focus bij iedereen, maar vooral omdat codekwaliteit nogal subjectief is. Iedere ontwikkelaar heeft zo zijn eigen beeld van hoe kwalitatief goede code eruit ziet. Taak één is dus om ervoor te zorgen dat je als team vastlegt welke regels en richtlijnen de kwaliteit van code bepalen. Als je dat gedaan hebt moet je een meetmethode hebben om vast te stellen in welke mate je code voldoet aan die regels. Je hebt dus indicatoren nodig die verschillende aspecten van de programmacode beschrijven. Bovendien, niet bepaald onbelangrijk, moet dat meten herhaald kunnen worden. Liefst op een efficiënte manier die niet veel tijd kost. Anders is het lastig om te beoordelen of aanpassingen aan je code zorgen voor een verbetering of juist een verslechtering van de kwaliteit.

Gelukkig zijn er in de afgelopen 10 jaar veel practices en tools verschenen om ontwikkelaars hierbij te helpen. Enerzijds zijn er steeds meer en duidelijkere sets van indicatoren en kwaliteitsdoelen en anderzijds zien we meer tools om hierover gegevens te verzamelen en erover te rapporteren. Één van die tools is NDepend.

NDepend

Een paar weken geleden kreeg ik een mailtje van Patrick Smacchia, de maker van NDepend. Hij vroeg me of ik NDepend eens wilde proberen. Toevallig speelde ik al een tijdje met de gedachte om wat beter te kijken naar de ontwikkelingen op het gebied van codekwaliteit.

NDepend is een statische analyse tool voor .NET code. Je kunt de tool gebruiken via een extensie in Visual Studio, maar ook los. Statische analyse kijkt, in tegenstelling tot dynamische analyse, puur naar de broncode zonder dat deze wordt uitgevoerd. Je kunt het dus gebruiken tijdens het ontwerpen en bouwen van je applicatie, maar het is ook mogelijk de tool los te laten op bestaande projecten. De meest recente versie heeft 86 meetpunten die geanalyseerd worden en waarover je dus rapportages krijgt. Er is een 14-dagen proefversie en die heeft alle features. Als je tot de ontdekking komt dat het wel een handige tool is voor jouw projecten, dan kan je een licentie aanschaffen voor 399 euro. Dat is inclusief een jaar technische ondersteuning. Na dat jaar blijft de tool wel werken, maar krijg je niet meer automatisch updates en support.

Het eerste gebruik

In dit artikel laat ik NDepend een project analyseren waar ik een paar jaar geleden mee ben begonnen en sindsdien nog steeds onderhoud. Het is een vrij standaard project waarin je ziet dat de code verandert als gevolg van nieuwe inzichten, nieuwe features, en her en der bug-fixes die niet allemaal de schoonheidsprijs verdienen (sommige wel hoor). De Visual Studio solution bestaat uit 8 projecten, waarvan twee ASP.NET MVC webapplicaties. Logischerwijs, bij een build van de code zie je dit:


========== Rebuild All: 8 succeeded, 0 failed, 0 skipped ==========

Zodra je NDepend hebt geïnstalleerd zie je een nieuw menu-item in Visual Studio met de naam “NDepend”. De eerste optie in dit menu laat je een NDepend-project toevoegen aan de geopende solution.

Wanneer je die optie in het menu kiest krijg je een lijst te zien van de assemblies die gegenereerd worden door de projecten. Deze assemblies zijn dus onderdeel van de analyse.

De solution bevat een webapplicatie die dienst doet als front-end. Deze is publiek zichtbaar (voor degenen die geïnteresseerd zijn: https://www.opiniopro.com/). Er is ook een webapplicatie toegevoegd die dienst doet als beheerpanel en eenvoudig content management. De business logic en data access wordt afgehandeld in het Model-project. Standaard maakt NDepend een eigen projectbestand aan met de extensie .ndproj. Dit bestand wordt opgeslagen in de bron-map van de solution en bevat configuratiegegevens. Zoals je in de afbeelding hierboven ziet heb ik de optie Build Report aangevinkt gelaten. Dan wordt na het analyseren van de assemblies ook direct een rapport opgemaakt. Als je het rapport niet laat maken dan krijg je alleen een lijst van fouten, waarschuwingen en algemene berichten. Je kunt vanuit het menu via de opdracht Analyze and Build Report er altijd voor kiezen om alsnog een rapport te maken.

Dit rapport is een HTML bestand en bevat een lijst en details van elk gevonden issue. Dat kunnen er nogal veel zijn, en daarom probeert NDepend je via een dialoogscherm door de verschillende features te leiden.

Wat je volgende stap is hangt af van wat je met de resultaten van de analyse wilt doen. De rapportage is een handig document om de huidige staat van je applicatie vast te leggen en te gebruiken als startpunt voor je check op de kwaliteit van je code. Alles wordt ook opgeslagen in de folder NDependOut, dus je kunt die folder inpakken en doorsturen als het nodig is. Hieronder zie je een samenvatting van mijn project.

Het is vrij duidelijk, en confronterend, dat NDepend niet heel blij is met mijn code. Als je de tool zelf in Visual Studio gebruikt zie je ook een rode punt rechtsonder in de IDE. In mijn geval is die punt rood gezien de gevonden issues. Als je met je muis over die punt gaat krijg je een samenvatting van je project.

Wanneer je erop klikt wordt een overzicht in een Visual Studio venster zichtbaar. In mijn project trof ik een Failed Quality Gate aan. Een Quality Gate is een check op de codekwaliteit die verplicht moet slagen voordat je de code kunt inchecken en releasen. De status van een Quality Gate is PASS of FAIL, dus slagen of falen. Blijkbaar faalt mijn code en dus ik ben nieuwsgierig naar de bron van het probleem. Omdat we alleen een algmene melding krijgen, moeten we dieper in de tool graven om te zien of we de oorzaak van deze FAIL kunnen achterhalen en natuurlijk oplossen.

Issues verkennen

Om te zien waar de problemen in de code zitten heeft NDepend de Queries and Rules Explorer.

Wanneer je de Quality Gate node in het linkerdeel selecteert krijg je in het rechterdeel van het scherm de bijbehorende regels te zien. Daar kan je vervolgens klikken op de 3 issues die gevonden werden. De navigatie wordt nu wel een beetje krap.

Je kunt extra informatie zien door met je muis over een issue te zweven.

Je ziet dat er een probleem is met een dubbele klasse-definitie in verschillende assemblies. Het gaat om de klasse CrawlerLog, maar waar het probleem nu precies zit is nog niet helemaal duidelijk. We dubbelkikken op de regel om een stapje verder te komen.

Zoals we al zagen gaat het om de klasse CrawlerLog. De regel die overtreden wordt heet “Avoid duplicating a type definition across assemblies”. Maar nog altijd is het niet duidelijk waarom of waar dit issue gevonden is. We kunnen dubbelklikken op het issue, en dan verschijnt dit venster.

Het lijkt erop dat de klasse in twee bestanden is gedefinieerd. Dat is eigenlijk normaal, want het eerste bestand is gegenereerd door Entity Framework. Het tweede bestand bevat ook een partial class declaratie waarin de klasse wat extra eigenschappen en methoden krijgt. Het lijkt me niet dat NDepend klaagt over een normale en handige compiler feature zoals partial classes. Dus waar zit het probleem? Blijkbaar kan je ook dubbelklikken op de cel in de kolom typeDefs. Voordat we dat doen kijken we eerst eens even naar de manier waarop we ons een weg banen door de verschillende vensters.

Navigeren door de informatie

NDepend voegt 12 nieuwe vensters toe aan Visual Studio. Alhoewel ik in het dagelijks werk inmiddels drie schermen gebruik groeit mijn frustratie over de hoeveelheid tijd die ik verlies in het navigeren door de verschillende vensters in Visual Studio. NDepend legt er dus nog een schepje bovenop. Als een beginnende gebruiker merk je dat NDepend een nogal omvangrijke tool is. De meest praktische manier op focus te houden op de analyse is door de vensters Queries and Rules Explorer en Queries and Rules Edit op een tweede monitor te zetten. Dan kan de code in Visual Studio op het primaire scherm blijven. De informatiedichtheid van de nieuwe vensters is nogal groot. Als web-ontwikkelaar voor consumenten websites werk ik vaak met designers die tot taak hebben om de hoeveelheid informatie op een scherm op zo’n niveau te houden dat de bezoeker er niet door gehinderd wordt. Hoe meer informatie een webpagina bevat, hoe meer tijd het kost om een bepaalde taak uit te voeren. Als je informatiedichtheid te groot wordt krijg je analyse-verlamming (analysis paralysis). Een goed ontwerp betekent dat de gebruiker op ieder moment in de interactie weet wat hij moet of kan doen. Als de gebruiker niets meer doet omdat de hoeveelheid informatie hem alleen maar meer verwarring oplevert, dan heb je een probleem.

De hoeveelheid informatie die NDepend biedt is in hoge mate afhankelijk van het aantal issues dat gevonden wordt. Als je code veel problemen bevat, dan zal je je snel overspoeld voelen. Gelukkig hoef je niet alle issues gelijk op te lossen om verder te gaan met je project. Als dat het geval zou zijn gaat je projectleider ongetwijfeld protesteren. Je kunt de analyse gebruiken als een nulmeting, en naarmate je verder gaat met je project kan je vergelijkende analyses uitvoeren om te zien of je code verbetert of juist niet. Bovendien kan je je op deze manier in ieder geval concentreren op nieuwe problemen die meestal wat makkelijker op te lossen zijn.

Terug naar het probleem dat eerder gevonden was. Bij toeval kwam ik erachter dat je kunt dubbelklikken op de cel in de kolom typeDefs.

Nu wordt het duidelijker waar het probleem vandaan komt. Blijkbaar was een bestand gekopieerd naar een verkeerd project. De klasse-definitie zit niet alleen in het project Model, waar het hoort, maar er is een versie terecht gekomen in het project Web. Daar hoort het niet. Uiteindelijk was het dus simpel op te lossen door het bestand te verwijderen.

Als we nu de analyse herhalen zien we dat er nog steeds zes kritieke regels zijn met overtredingen. Kritieke regels zijn gedefinieerd als regels met een hoge prioriteit en impact die nooit overtreden mogen worden. Standaard heeft NDepend een aantal van haar 86 regels als zodanig gemarkeerd. Maar het is simpel om die markering weg te halen. Mijn solution bevat twee ASP.NET MVC projecten, een publieke website en een dashboard site voor de beheerder. Het gevolg is dat de analyse 32 issues vind van het zelfde type: Avoid having different types with same name.

De oorzaak van deze issues is duidelijk maar ik heb geen plan om de twee projecten samen te voegen of de view-models in een enkel project onder te brengen. Natuurlijk levert dit dubbele code op, maar het grootste deel ervan is toch gegenereerd. Dus dat laat ik zo en haal de markering ‘Critical’ van deze regel af via de toolbar.

De regels veranderen

86 verschillende meetpunten is best uitgebreid. Het is makkelijk om een nieuw project te starten en NDepend regelmatig laten controleren om je te waarschuwen voor fouten of overtredingen van best practices. Maar vaak werken we aan bestaande projecten, die misschien al een paar jaar meegaan. Dan moet je selectief zijn. Je kunt bijvoorbeeld een blik werpen op de Code Metrics View om de meest problematische assemblies in je project te vinden. De weergave kan je op verschillende metingen filteren, zoals cyclomatic complexity, aantal parameters, en codecommentaar. Zo krijg je een high level overzicht van je code.

Elke regel in de analyse heeft een bijbehorende verklaring. Het aantal regels code bijvoorbeeld. De regel is dat je klassen niet te veel regels code mogen bevatten. De verklaring hiervoor is dat grote klasse-definities lastig te onderhouden zijn. De vraag is natuurlijk: welk aantal regels code is te veel. Iedere regel is vastgelegd in CQLinq ofwel Code Query Linq. Een CQLinq query is een LINQ query die gebruik maakt van de types uit de NDepend.CodeModel namespace van de NDepend API. Je kunt deze queries zelf aanpassen, en daarmee dus de regels veranderen. Als je kijkt naar de regel “Avoid types too big” dan zie je dat deze controleert op het aantal regels code in een type en waarschuwt als dit er meer dan 200 zijn.


warnif count > 0 from t in JustMyCode.Types where
// First filter on type to optimize
t.NbLinesOfCode > 200

Om eventuele overtredingen van de regel op te lossen kan je dus ofwel voor alle klasse-definities zorgen dat deze onder de 200 regels blijft, ofwel je kunt de ondergrens aanpassen aan wat in je project meer gebruikelijk is. Als je nu iedere regel aanpast om alle issues uit je project op te lossen dan kan je natuurlijk net zo goed NDepend achterwege laten. Elke regel bevat ook commentaar en verwijzingen naar de achterliggende redenen voor de criteria.

Andere features

Behalve een goede analyse van je code helpt NDepend je ook bij het begrijpen van de structuur van je solution door middel van de verschillende visualisaties. Deze weergaven van je code zijn handig om een indruk te krijgen van structuur en opbouw van je code zonder dat je exact in alle projecten hoeft te duiken. Visual Studio heeft ook dergelijke tools. Als je de Enterprise Editie hebt kan je gebruik maken van sequence diagrams en de architecture explorer. Het gaat te ver om elke visualisatie te bespreken, vooral omdat je eigenlijk alleen in een video goed kunt zien wat de kracht is van deze grafische weergaven en de interactie hiermee. Bovendien staat er op de website van NDepend een uitgebreide beschrijving van de mogelijkheden: https://www.ndepend.com/docs/visual-studio-dependency-graph en https://www.ndepend.com/docs/dependency-structure-matrix-dsm.

Het is natuurlijk handig om de rapportage en analyse tools van NDepend beschikbaar te hebben in Visual Studio, maar de interactie daarmee werkt niet in continuous integration scenario’s. Hiervoor heb je NDepend.Console.exe, een command-line versie van de tools om de broncode te analyseren. Je kunt dus ook de NDepend analyse onderdeel laten uitmaken van je build proces en je krijgt automatisch de status van je code binnen. Er is ook een aparte extensie met een build task om code te analyseren en code coverage gegevens te verzamelen: https://marketplace.visualstudio.com/items?itemName=ndepend.ndependextension

Waarom niet Roslyn?

Visual Studio 2017 bevat ingebouwde analyzers die je C# en Visual Basic code analyseert terwijl te code schrijft. Je kunt extra analyzers toevoegen als een Visual Studio extensie, of per project via een NuGet-package. Deze analyzers kijken naar de codestijl, codekwaliteit, maintainability, code design en andere aspecten. Deze .NET Compiler Platform (“Roslyn”) analyzers gaan uiteindelijk statische code analyse vervangen. Veel van de statische code analyses uit FxCop zijn al vertaald naar Roslyn analyzers. Maar ze zijn niet zo eenvoudig om te schrijven of te onderhouden. Zeker niet zo makkelijk als CQLinq queries in NDepend.

Die Roslyn analyzers zijn vooral handig tijdens het schrijven van code, omdat ze live meekijken met wat je invoert en je kunt er issues mee oplossen via een enkele muisklik. NDepend is vooral praktisch als tool om de kwaliteit van je code tijdens de levensduur van je project in de gaten te houden. Allebei nuttig dus.

Conclusie

Als je NDepend installeert worden niet automagisch alle codekwaliteit issues voor je opgelost. Een project met veel legacy wordt er niet vanzelf beter van. Als je in een team werkt dat moeite heeft met peer reviews, door gebrek aan tijd of gebrek aan duidelijke regels, dan kan NDepend zeker helpen. De scope van NDepend is assemblies, dus je krijgt geen suggesties voor verbeteringen van een user interface of de manier waarop het datamodel is opgezet.

Wanneer je voor het eerst een analyse loslaat op een project, waar je al een tijd mee aan de slag bent, krijg je een flinke lading aanbevelingen. Je hoeft het niet eens te zijn met alle aanbevelingen maar wees ervan bewust dat de regels die NDepend gebruikt zijn vastgesteld en aangepast op basis van meer dan 10 jaar ervaring. Dus voordat je een aanbeveling negeert, lees op zijn minst de redenatie erachter in de uitgebreide commentaren, verwijzingen en documentatie. Zodoende kan je begrijpen waarom het volgen van een bepaalde regel de kwaliteit van je code kan verbeteren. Je kunt de lijst van gevonden issues in de eerste analyse ook gebruiken als een nulmeting en met de Diff-optie in het menu de verschillen bekijken ten opzichte van een nieuwe versie. Zodoende kan je je concentreren op nieuwe issues en niet tijd verliezen aan oude bestaande problemen.

In een wereld die steeds meer gedomineerd wordt door open source, en daardoor vaak gratis, software is het misschien lastig om 399 euro neer te leggen (of vrij te maken in een budget) voor een licentie. Niettemin laat NDepend je vrij goed zien hoeveel tijd je op de lange termijn kwijt zult zijn aan het oplossen van issues die voorkomen hadden kunnen worden door gedegen ontwerp en programmeerregels. Als het al te laat is, en de problemen zitten al in de code, dan zie je op zijn minst in de analyse hoeveel tijd het je nu kost om het te fixen. Zodat je niet later alsnog tijd verliest aan een lastige refactoring. De evaluatieversie heeft geen beperkingen en kan je 14 dagen gebruiken om je code te analyseren. Zodoende zie je snel of de prijs van een licentie wordt goedgemaakt door betere codekwaliteit.

Referenties