I softwareverdenen kan fem år betyde både et system, der stadig er meget godt rustet til videre udvikling, og et teknologisk problem, som vil koste mere og mere for hver måned der går.
Appens alder alene er dog ikke en grund til at udskifte den.
Det er en af de vigtigste ting at sige fra starten.
Der findes ingen universel grænse, efter hvilken en app bør skrives om fra bunden. Der findes systemer, der har fungeret i adskillige år, og som stadig har en fornuftig arkitektur, opdaterede afhængigheder, god dokumentation og en gennemprøvet deployproces. Der findes også langt yngre apps, hvis udvikling er blevet hæmmet af forkerte arkitekturbeslutninger, mangel på tests, ukontrollerede afhængigheder eller en række hurtige rettelser.
Problemet er altså ikke antallet af år.
Problemet er systemets evne til fortsat at ændre sig.
Det vigtigste spørgsmål er ikke: "Er appen gammel?"
Et bedre spørgsmål er: "Hvad koster den næste ændring os?"
Hvis det kræver stadig flere timer at tilføje en ny funktion, inddrage flere teams, lave manuelle tests og omgå begrænsninger i den gamle arkitektur, begynder systemet at skabe en omkostning, som ikke ses i selve koden.
Det er netop et af de praktiske tegn på voksende technical debt.
Technical debt kan forstås som omkostningen ved fremtidige ændringer, der opstår som følge af tidligere tekniske beslutninger. Martin Fowler beskriver det som den ekstra indsats, der skal ydes, når systemet ændres, fordi den interne kvalitet gør udvikling vanskeligere.
Og netop derfor kan en app stadig fungere korrekt og samtidig blive stadig sværere at videreudvikle.
10 funktioner senere ser systemet helt anderledes ud
Projektets begyndelse er ofte enkel.
Der skabes et MVP.
Derefter kommer flere krav til:
- integration med CRM,
- onlinebetalinger,
- adminpanel,
- mobilapp,
- nye brugerroller,
- rapportering,
- automatiseringer,
- API,
- integrationer med eksterne tjenester,
- flere sprogversioner.
Hver ændring for sig kan være begrundet.
Problemet opstår, når arkitekturen ikke blev designet med en sådan udviklingsretning for øje.
Så bliver de næste funktioner ikke længere føjet til en stabil konstruktion.
De bliver føjet til tidligere undtagelser, omveje og kompromisser.
Hvordan kan man se, at systemet begynder at blive gammelt?
Man behøver ikke vente på et totalt nedbrud.
Advarselssignalerne viser sig meget tidligere.
1. En ny funktion tager længere og længere tid
Før tog en funktion et par dage. I dag kræver en lignende ændring et par uger.
Det betyder ikke nødvendigvis, at teamet er langsommere.
Det kan betyde, at mere og mere tid går med at forstå det eksisterende system og beskytte det mod ændringens konsekvenser.
2. Hver ændring udløser en dominoeffekt
Ændring af ét modul skaber problemer flere andre steder.
Det er et tegn på, at komponenterne er for tæt koblet, eller at ansvarsgrænserne mellem dem er defineret forkert.
3. Testene er hovedsageligt manuelle
Hvis hver større ændring kræver manuel kontrol af dusinvis af funktioner, stiger implementeringsomkostningen.
Problemet er ikke selve manglen på automatisering.
Problemet er manglen på hurtigt at kunne få pålidelig information om, hvorvidt en ændring har ødelagt noget.
4. Teamet er bange for at røre bestemte dele af systemet
Det er en meget praktisk indikator.
Hvis der findes moduler, som udviklerne undgår, fordi "ingen ved præcist, hvad der sker efter ændringen", er den tekniske risiko allerede en reel forretningsomkostning.
5. Systemet er afhængigt af forældede teknologier
En gammel framework betyder i sig selv ikke et problem.
Problemet opstår, når:
- det ikke længere understøttes,
- det er svært at finde specialister,
- afhængigheder ikke kan opdateres sikkert,
- runtime-miljøet er problematisk,
- integration med nye løsninger er vanskelig.
Så begynder teknologien at begrænse forretningsmulighederne.
Skal man altid skrive appen om fra bunden?
Nej.
Det er en af de mest almindelige fejl i tilgangen til legacy software.
En fuld rewrite kan være berettiget, men det er et projekt med høj risiko.
Et gammelt system indeholder ofte dusinvis eller hundredvis af forretningsregler, undtagelser og adfærd, som ikke findes i dokumentationen. Når man skriver det om fra bunden, kan man meget let skabe et system, der er teknologisk nyt, men forretningsmæssigt ufuldstændigt.
Derfor er gradvis modernisering i mange tilfælde en bedre løsning.
Én del af systemet forbliver aktiv, mens de næste områder gradvist erstattes af nye komponenter.
Denne tilgang er bl.a. kendt som Strangler Fig-mønsteret. Det gør det muligt at modernisere systemet skridt for skridt, levere værdi tidligere og reducere risikoen ved en engangs-migrering af hele løsningen.
Hvornår giver modernisering mening?
Det er værd at overveje, når:
- systemet stadig udfører vigtige forretningsprocesser,
- arkitekturen gør det muligt at udskille mindst en del af funktionaliteten,
- data kan migreres eller integreres sikkert,
- problemet vedrører konkrete områder og ikke hele konstruktionen,
- appen skaber værdi, og en fuld udskiftning ville være risikabel,
- systemet kan moderniseres i etaper.
Det er især en god løsning for systemer, som ikke bare kan lukkes ned i nogle måneder.
Hvornår giver modernisering måske ikke mening?
Der er også situationer, hvor det ikke længere er økonomisk at forsøge at redde det gamle system.
For eksempel når:
- arkitekturen er fundamentalt uforenelig med de nuværende krav,
- centrale teknologier ikke længere understøttes,
- systemet har hverken pålidelige tests eller dokumentation,
- sikkerheden kræver en gennemgribende ombygning,
- hver større ændring kræver indgreb i næsten hele systemet,
- der mangler folk, som forstår, hvordan det fungerer,
- vedligeholdelses- og udviklingsomkostningerne overstiger værdien af fortsat brug.
Så er det værd at beregne ikke kun omkostningen ved modernisering.
Man skal også beregne omkostningen ved at blive ved den nuværende løsning.
Den dyreste app er ikke altid den dyreste at vedligeholde
Man kan have et system, hvis månedlige drift koster relativt lidt.
Og samtidig kan hver ny funktion koste langt mere, end den burde.
Det er netop derfor, at fakturaen for hosting, server eller support ikke alene fortæller, hvad teknologien koster.
Den reelle systemomkostning omfatter også:
- udviklingstid,
- testtid,
- omkostninger ved fejl,
- implementeringstid,
- omkostninger ved nedetid,
- ansættelsesvanskeligheder,
- sikkerhedsrisiko,
- omkostninger ved tab af viden,
- forsinkelse af nye funktioner,
- forretningsmæssige begrænsninger som følge af teknologien.
På et tidspunkt holder teknologien op med at være et værktøj, der understøtter forretningen.
Den begynder at blive en begrænsning for forretningen.
Hvordan griber man beslutningen an?
Før beslutningen "vi skriver det hele om" træffes, er det værd at gennemføre en teknisk audit.
Den bør som minimum omfatte:
Arkitekturen - hvordan systemet er opdelt, og hvordan dets elementer kommunikerer.
Koden - kvalitet, kompleksitet, gentagelser og særligt vanskelige steder at vedligeholde.
Afhængigheder - frameworks, biblioteker, versioner og deres support.
Sikkerheden - sårbarheder, måde at administrere adgang på og risici som følge af forældede komponenter.
Testene - omfanget af automatisering og muligheden for sikkert at indføre ændringer.
CI/CD - måden applikationen bygges, testes og udrulles på.
Data - databasens struktur, migrationer, integrationer og afhængigheder.
Overvågning - om man ved, hvad der sker med systemet efter udrulning.
Udviklingsprocessen - hvor meget det faktisk koster at levere den næste funktion.
Først på dette grundlag kan man rationelt overveje tre scenarier:
- vi vedligeholder og videreudvikler,
- vi moderniserer i etaper,
- vi bygger et nyt system.
Der findes ikke ét rigtigt svar. Der findes derimod en rigtig måde at nå frem til svaret på.
Teknologi bør muliggøre udvikling, ikke blokere den
God arkitektur handler ikke om, at systemet ser moderne ud.
Det handler om, at man kan ændre det, når forretningen kræver det.
Derfor er det værd at se på applikationen ikke kun ud fra, om den virker i dag.
Man skal også undersøge, hvad det vil koste at tilføje flere funktioner om et år, to år eller fem år.
For et system, der virker, men forhindrer effektiv udvikling, kan være et langt større problem end et system, der blot kræver modernisering.



