Een Design Structure Matrix geeft grip op softwareafhankelijkheden

Bij softwareontwikkeling is een hoog innovatietempo een vereiste. Door de aanhoudende tijdsdruk is er veelal weinig aandacht voor de softwarearchitectuur. Deze kan daardoor gaandeweg complexer worden, waardoor aanpassingen steeds duurder en tijdrovender worden. Johan van den Muijsenberg legt uit hoe gebruik van een Design Structure Matrix kan helpen om complexe softwareafhankelijkheden inzichtelijk te maken en de afhankelijkheidsstructuur te verbeteren.

Idealiter is software eenvoudig aan te passen, begrijpelijk, betrouwbaar en herbruikbaar. In praktijk blijft dit vaak een ideaal en wordt de software in de loop van de tijd steeds meer rigide, ondoorzichtig en fragiel. Ook zijn componenten moeilijk te isoleren en daardoor niet herbruikbaar en individueel testbaar. Aanpassingen worden steeds lastiger en op een gegeven moment is herschrijven goedkoper.

Al deze problemen worden veroorzaakt door softwareafhankelijkheden. Hoewel de regels voor goed ontwerp bekend zijn, blijken veel projecten er last van te hebben. Een van de redenen is dat de softwarearchitectuur vaak is vastgelegd op een conceptueel niveau dat onvoldoende precisie heeft ten aanzien van welke dependencies toegestaan zijn en welke niet. Daarnaast kunnen aanpassingen op broncodeniveau onbedoeld afhankelijkheden toevoegen, waardoor de gedocumenteerde en daadwerkelijke architectuur van elkaar gaan afwijken. Ook is de veelgebruikte UML-notatie ongeschikt voor representatie van grote hoeveelheden dependencies.

 

Figuur 1: Elementen met veel in- en uitgaande relaties maken een UML-diagram onoverzichtelijk.

Als voorbeeld toont Figuur 1 een UML-classdiagram met daarin een aantal typische situaties. Zo is er een cyclische relatie tussen A4 en A5, een relatie van A3 naar P3 tegen de gewenste layering in, een relatie van P5 naar D3 die een laag overslaat en een ongebruikte class A6 zonder ingaande relaties. Verder hebben U1 en U3 veel ingaande en heeft U2 veel in- en uitgaande relaties. Met name deze laatste maken het geheel erg onoverzichtelijk. Om die reden worden in een UML-diagram vaak niet alle relaties weergegeven maar alleen de meest essentiële, waarmee het slechts een incomplete view is van het model.

Belangrijke voordelen

Met behulp van een Design Structure Matrix (DSM) kunnen we de structuur weergeven van elk systeem dat een hiërarchie van elementen heeft en relaties tussen deze elementen. Algoritmes om de structuur te analyseren en te herordenen, vormen een essentieel onderdeel van de methodiek. Hoewel oorspronkelijk bedacht voor procesoptimalisatie zijn DSM’s ook toepasbaar voor de visualisatie en analyse van productarchitecturen, en daarmee zeer geschikt voor software.

Figuur 2: Waar weergave van alle relaties in een UML-diagram onoverzichtelijk kan zijn, vormt dit geen enkel probleem in een DSM.

Figuur 2 geeft het ontwerp uit Figuur 1 weer in een DSM. Deze bestaat uit een matrix met in de rijen en kolommen dezelfde elementen. De hiërarchie van packages en classes is zichtbaar aan de linkerzijde. In de cellen staan de relaties tussen de elementen. Dat kolom 5 (P4) van rij 16 (A2) bijvoorbeeld gevuld is, betekent dat P4 afhankelijk is van A2. Dit komt overeen met het UML-diagram van Figuur 1. Het nummer in de cel representeert de sterkte van de relatie en is meestal het aantal afhankelijkheden tussen de elementen. De cellen op de diagonaal representeren de relatie van een element met zichzelf en zijn meestal leeg.

Het kost weliswaar enige gewenning om de matrices te lezen, maar daarna zijn er een aantal belangrijke voordelen ten opzichte van UML. Ten eerste kan een DSM alle relaties in een enkele view vatten. Waar dat in een UML-diagram onoverzichtelijk kan zijn, zoals in Figuur 1, vormt dit geen enkel probleem in een DSM, zoals te zien is in de eerste drie rijen en kolommen van Figuur 2.

Figuur 3: In een DSM is de hiërarchie ook geheel of gedeeltelijk inklapbaar. De matrix is dan compacter maar inhoudelijk nog steeds correct.

Ten tweede is een DSM schaalbaar. Doordat de hiërarchie geheel of gedeeltelijk inklapbaar is, is het mogelijk er een systeem met duizenden classes in weer te geven. Als we de DSM in Figuur 2 volledig inklappen, krijgen we de matrix in Figuur 3. De relatiesterktes van de ingeklapte cellen worden daarbij eenvoudig samengevoegd. De DSM wordt hierdoor compacter, maar blijft inhoudelijk correct.

Ten derde kunnen we de layering van de software eenvoudig inzichtelijk maken door een partitioneringsalgoritme toe te passen. Een dergelijk algoritme probeert de DSM zo te herordenen dat zo veel mogelijk relaties onder de diagonaal komen. Toepassing op Figuur 3 levert de matrix weergegeven in Figuur 4. Hierin is te zien dat elementen met veel ingaande relaties (providers) naar de onderzijde zijn verschoven, terwijl de elementen met veel uitgaande relaties (consumers) omhoog zijn gegaan. Relaties die het algoritme boven de diagonaal zet, zijn een indicatie voor cyclische afhankelijkheden in de software. Deze zijn ongewenst omdat de betrokken elementen niet onafhankelijk zijn en aantoonbaar meer fouten bevatten.

Figuur 4: Door een partitioneringsalgoritme toe te passen, is de layering van de software eenvoudig inzichtelijk te maken in een DSM.

Ten vierde maakt een DSM het gemakkelijk om dependency-patronen te herkennen. Figuur 5 toont bijvoorbeeld een geval van relaxed layering, omdat ten minste één element van de presentatielaag rechtstreeks een element gebruikt uit de datalaag (paars), en een afhankelijkheid in ongewenste richting, omdat A3 in de applicatielaag P3 in de presentatielaag gebruikt (geel). Verder kunnen we zien dat A1 en A2 de publieke interfaces en A3, A4 en A5 interne elementen zijn van de applicatielaag omdat ze buiten (groen) respectievelijk alleen binnen deze laag worden gebruikt (rood), en dat A6 een ongebruikt element is omdat het geen enkele ingaande relatie heeft (roze). U1 en U3 zijn elementen die door de hele software heen worden gebruikt (lichtblauwe horizontale balken). Voor U2 geldt hetzelfde, maar dit element is problematisch vanwege de vele in- en uitgaande relaties (grijze horizontale en verticale balk).

Figuur 5: Een DSM maakt het bovendien gemakkelijk om afhankelijkheidspatronen te herkennen.

Ten slotte kunnen we een DSM gebruiken om de afhankelijkheidsstructuur te verbeteren. In de matrix kunnen we een element verplaatsen naar een andere component of laag, combineren met andere elementen of splitsen en vervolgens alle afhankelijkheden herberekenen om te kijken of dit een betere dependency-structuur oplevert. Stel bijvoorbeeld dat P3 in Figuur 5 eigenlijk thuishoort in de applicatielaag. Dan kunnen we dat element daarnaartoe verplaatsen. Na herberekening van de afhankelijkheden zien we dat de cyclische relatie tussen de presentatie- en applicatielaag verdwenen is. De voordelen van zo’n impactanalyse komen vooral tot hun recht bij verbeteringsscenario’s die zich afspelen op architectuurniveau en dus meerdere componenten raken. Zonder gebruik van een DSM zijn dergelijke analyses onbetrouwbaar omdat de ontworpen en werkelijke softwarearchitectuur vaak niet overeenkomen.

Controle krijgen

DSM’s kunnen we in elke fase van een project inzetten: niet alleen tijdens het ontwerp en de ontwikkeling maar ook tijdens het onderhoud. Een architectuur kunnen we vastleggen door in de matrix de hiërarchie van elementen en de afhankelijkheidsregels daartussen te definiëren. Een dergelijk model maakt de toegestane dependencies expliciet en vervult een brugfunctie tussen de conceptuele architectuur en de code. Door automatische validatie van de afhankelijkheidsregels in het softwarebouwproces kunnen we degradatie van de architectuur vroegtijdig signaleren.

Omdat dependencies in veel projecten vaak onvoldoende worden bewaakt, zal de methodiek vooral worden ingezet om weer controle te krijgen over een bestaande codebase. De eerste stap is om een DSM te maken van de codebase door deze te importeren in een DSM-tool. Vervolgens kunnen we verschillende verbeteringsscenario’s analyseren en aan de hand van herberekende afhankelijkheden bepalen welke het meest geschikt is. Ten behoeve van onderhoud kunnen we elementen markeren als ‘aangepast’ en afleiden uit de matrix welke andere elementen mogelijk worden geraakt door de aanpassingen.

De afgelopen periode heb ik samen met een softwarearchitect een bestaande codebase van ruim tweeduizend classes doorgelicht met Lattix, een DSM-tool specifiek gemaakt voor softwareanalyse. Hierbij hebben we snel een aantal pijnpunten in de afhankelijkheidsstructuur kunnen identificeren en een aantal verbeteringsscenario’s kunnen analyseren. Deze hebben ons doen besluiten een nieuwe softwarearchitectuurindeling te kiezen op basis van herkenbare domeinconcepten. In ongeveer twee dagen hebben we een DSM gebaseerd op de afhankelijkheden in de actuele codebase weten te transformeren naar een DSM van de nieuwe softwarearchitectuur. Het resultaat bevat veel minder afhankelijkheden en is beter communiceerbaar. De aanpak heeft zich hier bewezen als een effectieve manier om de afhankelijkheidsstructuur van software te verbeteren en daarmee de productiviteit en kwaliteit te verhogen. In goed gestructureerde software zijn wijzigingen namelijk in ongeveer de helft van de tijd te realiseren, met aanzienlijk minder defecten.

Auteur: Johan van den Muijsenberg is senior softwareconsultant bij ALTEN Technology

Johan Van Den Muijsenberg

neem contact op

*verplichte velden

‘Testing is hot’, maar wat is ‘hot’ in testing?

Regelmatig krijg ik de vraag wat er ‘hot’ is op het gebied van testen maar meestal moet ik dan toch [...]

Flexibele robotica binnen handbereik door Ros-Industrial

Om de inzet van robots in het mkb aantrekkelijk te maken, moeten ze overweg kunnen met veranderende processen, kleinere oplages [...]

Testers zouden eens wat vaker naar de tandarts moeten gaan…

Onlangs moest ik een behandeling bij de tandarts ondergaan waarbij ik geruime tijd volledig aan haar was overgeleverd. Want zo [...]

De 4 P’s van Testen

Wat is technisch testen en waarin verschilt dat dan van ‘gewoon’ testen? Dat is een vraag die mij nogal eens [...]