In de wereld van software kan vijf jaar zowel betekenen dat een systeem nog steeds zeer goed is voorbereid op verdere ontwikkeling, als dat het een technologisch probleem is dat elke maand meer gaat kosten.
Alleen de leeftijd van een applicatie is echter geen reden om haar te vervangen.
Dat is een van de belangrijkste dingen om aan het begin te zeggen.
Er bestaat geen universele grens waarna een applicatie volledig opnieuw moet worden geschreven. Er zijn systemen die al tientallen jaren draaien en nog steeds een zinvolle architectuur, actuele afhankelijkheden, goede documentatie en een bewezen uitrolproces hebben. Er zijn ook veel jongere applicaties waarvan de ontwikkeling is bemoeilijkt door verkeerde architecturale keuzes, gebrek aan tests, ongecontroleerde afhankelijkheden of opeenvolgende snelle fixes.
Het probleem is dus niet het aantal jaren.
Het probleem is het vermogen van het systeem om zich verder te wijzigen.
De belangrijkste vraag is niet: "Is de applicatie oud?"
De betere vraag is: "Hoeveel kost een volgende wijziging ons?"
Als het toevoegen van een nieuwe functie steeds meer uren kost, meerdere teams vereist, handmatige tests vraagt en workarounds voor beperkingen van de oude architectuur nodig maakt, begint het systeem kosten te genereren die je niet in de code zelf ziet.
Dat is juist een van de praktische symptomen van oplopende technical debt.
Technical debt kan worden begrepen als de kosten van toekomstige wijzigingen die voortkomen uit eerdere technische beslissingen. Martin Fowler beschrijft het als de extra inspanning die nodig is bij het aanpassen van een systeem wanneer de interne kwaliteit de ontwikkeling belemmert.
En juist daarom kan een applicatie nog steeds correct werken en tegelijk steeds moeilijker worden om verder te ontwikkelen.
10 functies later ziet het systeem er totaal anders uit
Het begin van een project is vaak eenvoudig.
Er wordt een MVP gebouwd.
Daarna komen er steeds meer eisen bij:
- integratie met CRM,
- online betalingen,
- beheerderspanel,
- mobiele app,
- nieuwe gebruikersrollen,
- rapportage,
- automatiseringen,
- API,
- integraties met externe diensten,
- nieuwe taalversies.
Elke wijziging afzonderlijk kan gerechtvaardigd zijn.
Het probleem ontstaat wanneer de architectuur niet is ontworpen met zo'n ontwikkelingsrichting in gedachten.
Dan worden nieuwe functies niet langer toegevoegd aan een stabiele constructie.
Ze worden toegevoegd aan eerdere uitzonderingen, omwegen en compromissen.
Hoe herken je dat een systeem oud begint te worden?
Je hoeft niet te wachten op een totale storing.
Waarschuwingssignalen verschijnen veel eerder.
1. Een nieuwe functie duurt steeds langer
Vroeger kostte een functie een paar dagen. Vandaag vraagt een vergelijkbare wijziging enkele weken.
Dat hoeft niet te betekenen dat het team trager is geworden.
Het kan betekenen dat er steeds meer tijd opgaat aan het begrijpen van het bestaande systeem en het beschermen ervan tegen de gevolgen van de wijziging.
2. Elke wijziging veroorzaakt een domino-effect
Een aanpassing in één module veroorzaakt problemen op verschillende andere plekken.
Dat is een signaal dat componenten te sterk met elkaar verweven zijn of dat de grenzen van verantwoordelijkheden ertussen verkeerd zijn gedefinieerd.
3. Tests zijn vooral handmatig
Als elke grotere wijziging handmatige controle van tientallen functies vereist, stijgen de implementatiekosten.
Het probleem is niet het gebrek aan automatisering zelf.
Het probleem is het ontbreken van een snelle manier om betrouwbare informatie te krijgen over de vraag of een wijziging iets heeft stukgemaakt.
4. Het team durft bepaalde delen van het systeem niet aan te raken
Dat is een zeer praktische indicator.
Als er modules zijn die ontwikkelaars vermijden omdat "niemand precies weet wat er gebeurt na een wijziging", dan is technisch risico al een reële zakelijke kostenpost.
5. Het systeem is afhankelijk van verouderde technologieën
Een oud framework op zichzelf is niet per se een probleem.
Het probleem ontstaat wanneer:
- het niet langer wordt ondersteund,
- het moeilijk is specialisten te vinden,
- afhankelijkheden niet veilig kunnen worden bijgewerkt,
- de runtime problematisch is,
- integratie met nieuwe oplossingen wordt bemoeilijkt.
Dan begint technologie de zakelijke mogelijkheden te beperken.
Moet je een applicatie altijd helemaal opnieuw schrijven?
Nee.
Dat is een van de meest voorkomende fouten in de benadering van legacy software.
Een volledige rewrite kan gerechtvaardigd zijn, maar het is een onderneming met een hoog risico.
Een oud systeem bevat vaak tientallen of honderden bedrijfsregels, uitzonderingen en gedragingen die niet in de documentatie staan. Als je het vanaf nul herschrijft, kun je heel gemakkelijk een technisch nieuw systeem creëren dat zakelijk onvolledig is.
Daarom is in veel gevallen een gefaseerde modernisering een betere oplossing.
Eén deel van het systeem blijft actief, terwijl andere onderdelen geleidelijk worden vervangen door nieuwe componenten.
Deze aanpak staat onder meer bekend als het Strangler Fig-patroon. Het maakt het mogelijk om het systeem stap voor stap te moderniseren, eerder waarde te leveren en het risico van een eenmalige migratie van de hele oplossing te beperken.
Wanneer heeft modernisering zin?
Het is de moeite waard om het te overwegen wanneer:
- het systeem nog steeds belangrijke bedrijfsprocessen ondersteunt,
- de architectuur het mogelijk maakt om ten minste een deel van de functionaliteit af te scheiden,
- gegevens veilig gemigreerd of geïntegreerd kunnen worden,
- het probleem betrekking heeft op specifieke gebieden en niet op de hele constructie,
- de applicatie waarde oplevert en volledige vervanging ervan riskant zou zijn,
- het systeem in fasen gemoderniseerd kan worden.
Dat is vooral een goede oplossing voor systemen die je niet zomaar enkele maanden kunt uitschakelen.
Wanneer heeft modernisering misschien geen zin?
Er zijn ook situaties waarin verder repareren van een oud systeem economisch niet meer verantwoord is.
Bijvoorbeeld wanneer:
- de architectuur fundamenteel onverenigbaar is met de huidige eisen,
- kerntechnologieën niet worden ondersteund,
- het systeem geen betrouwbare tests of documentatie heeft,
- beveiliging een ingrijpende herbouw vereist,
- elke grotere wijziging ingrijpen in bijna het hele systeem vereist,
- er een tekort is aan mensen die de werking ervan begrijpen,
- de kosten voor onderhoud en ontwikkeling hoger zijn dan de waarde van verder gebruik.
Dan is het de moeite waard om niet alleen de kosten van modernisering te berekenen.
Je moet ook de kosten berekenen van blijven bij de huidige oplossing.
De duurste applicatie is niet altijd de applicatie die het duurst is in onderhoud
Je kunt een systeem hebben waarvan het maandelijkse onderhoud relatief weinig kost.
En tegelijk kost elke nieuwe functie vele malen meer dan zou moeten.
Daarom zegt de factuur voor hosting, server of support op zichzelf nog niet hoeveel de technologie kost.
De werkelijke kosten van een systeem omvatten ook:
- ontwikkelingstijd,
- testtijd,
- kosten van fouten,
- implementatietijd,
- kosten van stilstand,
- wervingsmoeilijkheid,
- beveiligingsrisico,
- kosten van kennisverlies,
- vertraging van nieuwe functies,
- zakelijke beperkingen die voortvloeien uit de technologie.
Op een gegeven moment houdt technologie op een hulpmiddel te zijn dat het bedrijf ondersteunt.
Ze wordt een beperking voor het bedrijf.
Hoe pak je de beslissing aan?
Voordat de beslissing "we bouwen alles opnieuw" valt, is het de moeite waard een technische audit uit te voeren.
Die zou ten minste het volgende moeten omvatten:
Architectuur - hoe het systeem is opgebouwd en hoe de onderdelen met elkaar communiceren.
Code - kwaliteit, complexiteit, herhaling en plekken die bijzonder moeilijk te onderhouden zijn.
Afhankelijkheden - frameworks, bibliotheken, versies en hun ondersteuning.
Beveiliging - kwetsbaarheden, de manier waarop toegang wordt beheerd en risico's die voortkomen uit verouderde componenten.
Tests - de mate van automatisering en de mogelijkheid om wijzigingen veilig door te voeren.
CI/CD - de manier van bouwen, testen en uitrollen van de applicatie.
Gegevens - databasestructuur, migraties, integraties en afhankelijkheden.
Monitoring - of men weet wat er met het systeem gebeurt na de uitrol.
Ontwikkelproces - hoeveel het werkelijk kost om een volgende functie op te leveren.
Pas op basis hiervan kan men op een rationele manier drie scenario's overwegen:
- we onderhouden en ontwikkelen verder,
- we moderniseren stapsgewijs,
- we bouwen een nieuw systeem.
Er is niet één juist antwoord. Er is wel een juiste manier om tot het antwoord te komen.
Technologie moet groei mogelijk maken, en niet blokkeren
Goede architectuur gaat er niet om dat het systeem er modern uitziet.
Het gaat erom dat het kan worden aangepast wanneer het bedrijf dat vereist.
Daarom is het de moeite waard om naar een applicatie te kijken niet alleen door de lens van of ze vandaag werkt.
Je moet ook nagaan, hoeveel het zal kosten om over een jaar, twee of vijf jaar nieuwe functies toe te voegen.
Want een systeem dat werkt, maar verdere ontwikkeling onmogelijk maakt, kan een veel groter probleem zijn dan een systeem dat simpelweg modernisering nodig heeft.



