Nog steeds worden de kosten van het onderhoud van maatwerk applicatie en het belang van onderhoudbaarheid onderschat. Uit vele onderzoeken, onder andere van Gartner, blijkt dat de onderhouds- en beheerkosten van maatwerk software de bouwkosten ruimschoots overtreffen tijdens de lifecycle van de applicatie. De onderhoudsfase is veelal de langste fase in de levensduur van een applicatie, soms zelfs langer dan de technologielevensduur.
Om de total costs of ownership (tco) te verlagen, is de mate van onderhoudbaarheid zeer bepalend. Onderhoudbaarheid van software (ISO 25010) wordt kort gezegd bepaald door de modulariteit, herbruikbaarheid, analyseerbaarheid, wijzigbaarheid en testbaarheid van de code. Dit lijkt een open deur, en toch zien we vaak dat onderhoudbaarheid uit het oog wordt verloren bij het (door)ontwikkelen van (bestaande of nieuwe) software. Tegelijkertijd kent onderhoudbaarheid een optimum, doorslaan werkt averechts.
Na de eerste gemaakte functionaliteit begint al het onderhoud. Elke functionaliteit die wordt bijgebouwd, beïnvloedt de reeds bestaande code en wordt vooral ook beïnvloed door de bestaande code. Slecht opgezette code wordt steeds meer een last en verlaagt gaandeweg de productiviteit. Naar mate de hoeveelheid code groeit en de tijd verstrijkt, kan de productiviteit (en/of de kwaliteit) enorm dalen door de last van niet goed opgezette code. Dit wordt technical debt genoemd: schuld die nog uitstaat aan de techniek en die voor een goede werking en onderhoudbaarheid nog ingelost moet worden. In de volksmond spreken we dan snel over legacy.
Matige onderhoudbaarheid wordt dus vaak veroorzaakt door technical debt. Hoewel geen fijn woord, wordt het wel eens code cancer genoemd. Technical debt ontstaat doordat tijdens het ontwikkelen short cuts worden genomen om snelheid te maken. Code die werkt, maar moeilijk is te onderhouden. Er wordt op voortgeborduurd en beetje bij beetje wordt de code besmet. De snelheid van veranderingen die de business najaagt, wakkert dit alleen maar aan. Vroeg of laat wordt deze code onbeheersbaar en verliest de business alle snelheid. Het inlossen van deze schuld (technical debt) wordt refactoring genoemd.
Tip 1: Gebruik een Agile-ontwikkelaanpak
Er zijn veel boeken volgeschreven over Agile software development, Scrum en Kanban. De kern van de boodschap is dat software onderhevig is aan veranderingen (voortschrijdend inzicht) en communicatieproblemen (begrijpen we elkaar wel). Een Agile-aanpak speelt hierop in door iteratief te ontwikkelen: in korte sprints wordt de applicatie voorzien van steeds nieuwe of uitgebreide stukken functionaliteit die waarde hebben voor de gebruikers. Software groeit als een bloemkool.
De applicatie groeit van de eerste functionaliteit via vele sprints door naar een applicatie met vele functies. De eerste functionaliteit moet vaak snel worden opgeleverd om enerzijds het idee te bewijzen (mvp uit Lean Startup) en anderzijds om de concurrentie voor te blijven. Snelheid en toetsing zijn belangrijk. Onderhoudbaarheid, gezien de kleine omvang, minder. Vanaf dit moment gaat de hoeveelheid code groeien. Wanneer we dit ongecontroleerd laten gebeuren, is de bloemkool-metafoor zichtbaar en is de kans op Spaghetticode groot.
Wanneer we vooraf volledig zouden kunnen overzien welke functionaliteit de applicatie in detail zou gaan bevatten, zou de applicatie in één keer goed ontwikkeld kunnen worden: de watervalmethode. Refactoren zou niet nodig zijn. Dit dogma is hardnekkig en zorgt er mede voor dat aandacht voor refactoring tijdens het uitbreiden van de applicatie met nieuwe functionaliteit (en dus code) vaak beperkt is. Nadruk op snelheid, kostenbesparing en de overtuiging ‘het werkt toch’ overheersen. Terwijl uit onderzoek simpelweg blijkt dat de kwaliteit van beter onderhoudbare code hoger is, en de total costs of ownership lager is (The Economics of Software Quality – Jones & Bonsignour).
Kortom: door in het ontwikkelteam te erkennen dat software wijzigt, zal onderhoudbaarheid onderdeel worden van de mindset van het ontwikkelteam. Maak het team verantwoordelijk voor de consequenties van hun werk.
Werk met:
- DevOps principes als ‘you build it, you run it‘: laat developers de pijn van slechte onderhoudbaarheid voelen;
- korte iteraties (twee tot drie weken), gericht op functionaliteit: hierdoor worden de invloed van voortschrijdend inzicht en communicatieproblemen tijdens de bouw beperkt;
- een Definition of Done waarin testen en deployment zijn benoemd: testbaarheid draagt bij aan onderhoudbaarheid;
- opleveringen op een productie-omgeving (go-live kan desgewenst later): code bewijst zich pas in productie, dus doe dit zo snel mogelijk;
- review van code door andere ontwikkelaar in het team: zorg vroegtijdig voor kennisborging en gedeelde verantwoordelijkheid voor de code;
- pair programming voor complexe onderdelen; bouw direct gedeelde verantwoordelijkheid op voor de onderhoudbaarheid;
- refactoring ter beheersing van technical debt: wanneer de hoeveelheid technical debt onbeheersbaar wordt, daalt de productiviteit enorm. Wees transparant naar de product owner over de hoeveelheid technical debt, de impact op de productiviteit en de opties het te verminderen. Hierover in een volgend deel meer.
Tip 2: Maak analyseerbaarheid en complexiteit zichtbaar
Waarschijnlijk hebben we allemaal ervaring met een moeilijk onderhoudbare applicatie. Een applicatie die in de loop der tijd is uitgebouwd, waar diverse developers aan hebben gewerkt en die schijnbaar steeds lastiger is aan te passen. In de volksmond legacy genoemd. Enerzijds wordt de onderhoudbaarheid beïnvloedt door het gehanteerde ontwikkelproces en anderzijds direct door de kwaliteit van het product (de code) zelf. Een objectieve meting van deze kwaliteit is dan ook doorlopend noodzakelijk.
De grootste tijd- en geldslurpers van het doorvoeren van wijzigingen in een bestaande applicatie zijn het opsporen en corrigeren van defecte code regels. Dit wordt vooral bepaald door de complexiteit en daarmee analyseerbaarheid van de code. Kan snel worden bepaald waar de aanpassing moet worden doorgevoerd en of er ongewenste side effects zijn? Het is dan van belang oog te hebben voor de complexiteit van de code tijdens ontwikkeling. Dit kan zowel handmatig (review of audit) als geautomatiseerd met statische code analyse.
Door regelmatig reviews te laten uitvoeren op gemaakte code (bijvoorbeeld peer reviews) kan onnodige complexiteit worden voorkomen. Ook dient er gekeken te worden naar consequente opbouw, structuur, code conventions en design patterns. Voordeel van deze reviews is dat conclusies worden getrokken met de context van de applicatie en het team in het achterhoofd. Nadeel is dat het tijd kost van ontwikkelaars en een volwassen team vereist, waarin teamleden zich veilig voelen om bevindingen met elkaar te delen. In een onvolwassen team zien we vaak dat deze reviews weinig structurele problemen aan het licht brengen.
Voor statistische code analyse is tooling in te zetten die regelmatig de onderhoudbaarheid in kaart brengt. Deze tooling is te koppelen aan een Continuous Integration omgeving, zoals Jenkins of Microsoft Team Foundation Server. Voorbeeld hiervan is Sonarqube, dat inzicht geeft in onder andere potentiële bugs, afwijking van coding standaarden, duplicaten, code coverage, complexiteit, spaghetti-code en commentaar. Door middel van rule sets kunnen deze checks worden aangepast aan hetgeen belangrijk is binnen het team en de organisatie. Voordeel hiervan is dat er dagelijks inzicht is in de code kwaliteit (en daarmee de onderhoudbaarheid) en dat dit geen tijd kost van ontwikkelaars. Maar het belangrijkste voordeel is dat de trend zichtbaar wordt. Neemt de kwaliteit in de tijd juist toe of af? Dat is een belangrijk signaal om in het development-team te bespreken.
Idealiter werkt elk development-team met een statische code analyse tool om inzicht te krijgen in de trend van kwaliteit en onderhoudbaarheid. In het team wordt de uitkomst van elke sprint besproken en worden eventuele acties op de backlog geplaatst. Met deze aanpak wordt het development team structureel gewezen op de onderhoudbaarheid van de code, zo objectief mogelijk. Nu duidelijk is wat de onderhoudbaarheid is en waar de technical debt zich bevindt, kan gestart worden met refactoring.
Tip 3: Refactor met korte termijn doelen
Nu de hoeveelheid technical debt objectief in beeld is (en blijft) gebracht, is het zaak de business verantwoordelijke (de product owner in Agile-termen) hierover te informeren. Product owners sturen vooral op functionaliteit door de druk uit de business/markt. Het is aan het ontwikkelteam om continu het effect van technical debt onder de aandacht te brengen. Door hier geen aandacht aan te schenken gaat gaandeweg steeds meer tijd zitten in het opsporen en oplossen van issues (en het creëren van nieuwe) waardoor er steeds minder nieuwe functionaliteit kan worden opgeleverd.
Vanuit application lifecycle management dient de mate van onderhoudbaarheid te worden bepaald. Een applicatie in het primaire proces met een langere levensduur moet ‘meebewegen’ met de business/markt om de businessdoelstellingen te blijven halen. Voor applicaties met een tijdelijk of eenmalig karakter ligt het belang van onderhoudbaarheid anders, al zijn er legio voorbeelden van ’tijdelijke’ applicaties die gaandeweg een cruciaal onderdeel van de bedrijfsvoering werden.
Met de gewenste mate van onderhoudbaarheid in het achterhoofd, wegen we vanaf nu bij elke wijziging of toevoeging aan de source code refactoring mee. Refactoring om het refactoren is af te raden. Er wordt dan alleen aan onderhoudbaarheid gewerkt zonder dat deze hogere onderhoudbaarheid ook direct loont in de aanpassing. Beter is het om te refactoren wanneer een deel van de code toch aangepast dient te worden vanwege een functionele wijziging.
Wanneer bijvoorbeeld een nieuw stuk functionaliteit een week kost om toe te voegen, en het eerst refactoren ook een week plus één dag voor het toevoegen van de functionaliteit, kies dan voor het laatste opdat ook toekomstige functionaliteit makkelijk is toe te voegen.
Een aantal principes die zeer van nut zijn tijdens refactoring:
- Yagni
Waak voor ‘premature optimizations’, en dan bedoelen we optimalisaties waarvan nog niet vaststaat dat deze daadwerkelijk nodig zijn. Veelal zorgt dit op voorhand voor complexere, slecht leesbare code die uiteindelijk niet nodig blijkt te zijn. Ook wel bekend als het Yagni-principe: You aren’t gonna need it.
- Boy Scout Rule
Simpel gezegd ‘Leave your code better than you found it.’ Padvinders kennen de simpele regel het kampeerterrein netter achter te laten dan ze het hebben aangetroffen. Een goed principe om te hanteren tijdens refactoring. Door elke keer dat code wordt gewijzigd deze netter achter te laten, neemt de onderhoudbaarheid toe en is de impact te overzien. Stapje voor stapje wordt het ‘schoner’. Waak er voor niet in één keer voor perfectie te gaan, dat doen de padvinders ook niet.
- No Museum
Beschouw source code als de actuele beschrijving van de gemaakte functionaliteit. Dat betekent dat alle niet gebruikte, uit-gecommentarieerde code en commentaar verwijderd dient te worden. Dit zorgt alleen maar voor verwarring bij de ontwikkelaar die dit tegenkomt. Historie vind je in je code repository, niet in de source code.
- Dry
Het Don’t repeat yourself (Dry)-principe voorkomt het dupliceren van source code wat er toe leidt dat de onderhoudbaarheid toeneemt. Immers, wijzigingen in dit stuk code dienen op twee plaatsen te worden doorgevoerd. In object oriented programming is het paradigma: duplication in logic should be eliminated via abstraction; duplication in process should be eliminated via automation.
Naast deze tip sta ik graag nog stil bij de herbouwgedachte. Deze gedachte komt vaak bovendrijven wanneer de technical debt in de jaren flink is opgelopen (door weinig tot niet refactoren). De praktijk leert dat herbouw (greenfield) vaak niet tot kostenbesparing leidt en veel producten zien nooit het levenslicht. Tegelijkertijd impliceert het de volgende problemen: nieuwe code heeft zich nog niet in productie bewezen (risico), risico’s bij datamigratie van oud naar nieuw, fouten worden overgenomen of (extra) gemaakt, onduidelijkheid over impliciete functionaliteit (documentatie en code zijn niet gelijk) en veel tijdverlies door alle herbouw. Start dus niet opnieuw maar verbeter wat er is, zolang het technische platform dit mogelijk maakt. Bijvoorbeeld wanneer het gehele technische platform onhoudbaar is geworden zoals classic Visual Basic applicaties.
Meer weten over refactoring? Kijk eens op Pluralsight.
Tip 4: Automatiseer testen
Zoals in het eerste deel besproken betekent onderhoudbaarheid onder andere testbaarheid en wijzigbaarheid. Vaak zien we dat in de onderhoudsfase van een applicatie de complexe onderdelen niet door iedereen gewijzigd kunnen worden. Bijvoorbeeld dat ontwikkelaars een wijziging niet durven door te voeren, vanwege onvoorziene effecten op de applicatie. Wijzigingen moeten dan vaak door dezelfde personen uitgevoerd worden waardoor een applicatie aan mensen ‘blijft plakken’. Een onwenselijke situatie. Blijkbaar is de testbaarheid dermate laag, waardoor de wijzigbaarheid in het geding is. Wie brandt z’n handen aan een wijziging die onvoorziene(!) effecten heeft op de werking van een applicatie?
Door vanaf het begin te zorgen voor testbaarheid, wordt de wijzigbaarheid groter. Wanneer je door middel van een test zeker kunt zijn of de gewijzigde functionaliteit blijft werken volgens de specificatie, is de drempel lager voor het maken van de wijziging. Als ontwikkelaar kun je namelijk vertrouwen op de aanwezige testen (let op: niet tester).
Echter, elke regel code testen is simpelweg te duur en onnodig. Maak een risico-analyse en focus op de onderdelen die niet triviale business logica bevatten en waar veel schade mee veroorzaakt wordt bij disfunctioneren. Deze analyse voer je uit samen met de business verantwoordelijke(n), door te kijken naar kans en impact. Kennis van teststrategieën helpt tijdens deze exercitie.
Voor de hoog-risico-onderdelen moet gelden dat er geen fouten worden aangetroffen in de opgeleverde applicatie. Het ontwikkelteam dient dit als doel te hebben. En door het ontwikkelteam verantwoordelijk te maken voor de kwaliteit en daarmee de testen, worden testen sneller geautomatiseerd. Ontwikkelaars hebben namelijk de neiging repeterend werk te automatiseren, wat leidt tot testscripts. Dit geldt voor alle niveaus: unittesten, integratietesten, ketentesten, performancetesten, penetratietesten, et eterac. Wanneer je als ontwikkelaar vervolgens kunt vertrouwen op de aanwezige testen, is het doorvoeren van wijzigingen minder risicovol. Onvoorziene side effects worden namelijk direct zichtbaar in de testresultaten.
Toch worden onvoorziene side effects soms helemaal niet opgemerkt door falende testen. De testen gaan goed en toch is de werking incorrect. Hoe zit dat? Er moet niet alleen aandacht zijn of alle (te testen) code wordt afgevangen door testen (code coverage), maar ook of de testen daadwerkelijk juist zijn. Of te wel: Quis custodiet ipsos custodes (Wie zal de bewakers zelf bewaken)?
Met mutation testing worden ‘mutanten’ gegenereerd van de code, die er voor moeten zorgen dat de testen falen. Wanneer de testen niet falen, is een mutant ontdekt die zorgt voor een foutieve werken, zonder de testen te laten falen. Voorbeelden van mutanten zijn het omdraaien van booleans (true en false), wijzigen van operators (+, -, …) en verwijderen van statements.
Uitdaging bij het opzetten van testen zijn de specificaties. Testen worden vaak opgezet op basis van de specificaties, waarbij het uitgangspunt is dat deze kloppend zijn met de daadwerkelijk gebouwde functionaliteit. Naar mate een applicatie verder in de levensfase zit, zien we dat het lastig is dit vol te houden. Specificaties gaan afwijken (doordat deze bijvoorbeeld niet consequent zijn bijgewerkt) waardoor discussie ontstaat over de juiste werking. De laatste jaren zien we steeds vaker dat specificaties in de vorm van een testscenario worden opgesteld. We noemen dit Acceptance Test Driven Development (ATDD). Door specificaties op deze manier op te stellen, kan geen verschil ontstaan tussen de specificaties, de testscripts en daarmee de functionele werking van de applicatie. Over het algemeen wordt dit formaat gebruikt:
Given (setup) A specified state of a system;
When (trigger) An action or event occurs;
Then (verification) The state of the system has changed or an output has been produced;
Dit formaat zorgt ervoor dat ook business-verantwoordelijken in staat zijn de scenario’s te lezen, te begrijpen en na wat oefening op te stellen. Dit beperkt het risico op misinterpretatie, een ander bekend fenomeen binnen software development.
Tools als Cucumber en Specflow maken het mogelijk dit soort scripts te automatiseren waardoor ze uitvoerbaar worden. Hiermee is het gat tussen specificaties, testen en daadwerkelijke code gedicht. En testbare code is onderhoudbare code!
Naast geautomatiseerd testen is exploratory testen een manier om vast te stellen of de applicatie correct functioneert onder menselijk gebruik. Mensen zijn creatief in het gebruik van software. Creatiever dan testscripts kunnen afdekken. Het gaat hier dan ook niet om code coverage, maar logisch (menselijk) gedrag. Crowd testen is hier een goed voorbeeld van. Stel de applicatie beschikbaar aan een grote groep testers en betaal ze voor bevindingen i.p.v. de geleverde inspanning. Kijk bijv. eens naar platformen als Testbats.
Tip 5: Automatiseer de infrastructuur
Onderhoudbaarheid zit niet alleen in de specifieke applicatiecode, maar ook in de onderliggende infrastructuur. Zoals besproken bepalen onder meer de herbruikbaarheid, analyseerbaarheid en modulariteit de mate van onderhoudbaarheid van een applicatie. Elke nieuwe release komt uiteindelijk in een productieomgeving terecht en dient te functioneren volgens de gestelde eisen (beschikbaarheid, schaalbaarheid, performance, security, et cetera.). Pas wanneer ook deze laatste stap geslaagd is, kan de onderhoudbaarheid beoordeeld worden. Een applicatie waarvan de technical debt op een acceptabel niveau is en de testbaarheid hoog is, kan toch voor veel problemen zorgen bij het in productie nemen.
Bij het in productie nemen van een maatwerk applicatie komen vaak de volgende issues voor:
- Doordat beheerders van de productieomgeving de installatie handmatig uitvoeren, is een volledige en kloppende installatie-instructie nodig. Hier zitten geregeld onvolkomenheden in die niet eerder in het proces zijn opgemerkt, met een foutieve inproductiename tot gevolg;
- Doordat er verschillen zijn ontstaan tussen de specificaties van de infrastructuur en de daadwerkelijke infrastructuur, ontstaan issues bij de inproductiename. Waarom werkt het nu wel op de acceptatie-omgeving maar niet op de productie-omgeving?! Dit wordt configuration drift genoemd;
- Door toenemende modulariteit (en schaalbaarheid) is het aantal (virtuele) machines of containers steeds groter aan het worden. Dit verhoogt de complexiteit en de kans op fouten bij een handmatige update. Bijvoorbeeld wanneer onderdelen vergeten worden bij een installatie.
Door de opkomst cloud computing en infrastructure as a service (IaaS) is tooling voor infrastructure as code (IaC) steeds meer beschikbaar gekomen. Tevens groeide de behoefte om sneller applicaties in productie te nemen. Dit zorgde ervoor dat de traditionele silo’s (development en operations) en bijbehorende ‘overdracht’ niet meer wenselijk zijn. Ofwel te traag en te veel kans op fouten.
Met de opkomst van DevOps-teams (Agile-teams met een mix van development en operations die verantwoordelijk zijn voor de hele application lifecycle) is het mogelijk de infrastructuur te beschrijven in code. Net als de applicatie zelf. Hierdoor is het mogelijk vanuit code de infrastructuur op te tuigen, zonder handmatige handelingen.
Voordelen van infrastructure as code?
- De infrastructuur is bij elke deployment geautomatiseerd op te tuigen, is altijd hetzelfde en daardoor testbaar. Hiermee voorkomen we het ‘It works on my machine’ probleem;
- Wijzigingen in de infrastructuur (bijvoorbeeld patches op operating system, applicatie server, et cetera) worden nu in code gemaakt en getest. Door infrastructuur in code te beschrijven, kan gebruik gemaakt worden van de voordelen van continuous integration, zoals versiebeheer en automatische testen;
- Patches, versies van componenten, et etera, zijn nu eenvoudig te vinden in een bepaald deel van de infrastructuur. In feite niets anders dan een zoekopdracht in de code. De code is per definitie gelijk aan de productieomgeving. Wat niet gezegd kan worden van eventuele specificaties of een CMDB;
- Veel sneller en goedkoper door het wegvallen van handmatige handelingen. Tevens verkleint een geautomatiseerde uitrol de kans op fouten aanzienlijk.
Tooling die veel gebruikt worden voor het automatiseren van infrastructuur zijn Puppet, Chef en Ansible.
Hiermee past deze aanpak bij continuous deployment, waarin de deployment over alle Otao-omgevingen geautomatiseerd plaatsvindt en continu getest kan worden of de hele stack (van userinterface tot en met infrastructuur) voldoet aan de eisen, en dus werkt!
Tip 6: Overdraagbaarheid zorgt voor onderhoudbaarheid
Tijdens het ontwikkelen en onderhouden van software is ook nadruk op overdraagbaarheid van belang voor de onderhoudbaarheid. Het is moeilijk te voorspellen waar techniek en tooling zich op termijn naar toe ontwikkeld, waardoor er rekening gehouden moet worden met overdraagbaarheid.
Applicatieservers, tooling, frameworks en programmeertalen zijn aan corrosie onderhevig, wat onderhoudbaarheid op termijn in gevaar brengt. Waar Delphi en Visual Basic ooit solide keuzes leken, is de doorontwikkeling en hoeveelheid ontwikkelaars op een laag punt aanbeland. Aan een software stack worden steeds zwaardere eisen gesteld rondom onder andere productiviteit, schaalbaarheid, performance. Hierdoor ontstaan nieuwe combinaties en wijzigt de populariteit van stacks (en daarmee programmeertalen). Het is moeilijk te voorspellen of de gangbare enterprise platformen .NET en Java over tien jaar nog relevant zijn. Wat betekent dat voor al die enterprise maatwerk-applicaties die op deze platformen zijn en worden ontwikkeld? De overdraagbaarheid komt in het geding.
Waak tegelijkertijd voor de inzet van bleeding edge en cutting edge technologie. Deze technologie is vaak nog ‘onvolwassen’ en heeft zich maar ten dele bewezen. En het is maar de vraag of het ‘blijvertjes’ zijn. Grote kans dat dit op termijn moeilijk onderhoudbare componenten worden. Maak tenminste inzichtelijk wat de risico’s van het inzetten van deze technologie zijn.
Kortom, aandacht voor overdraagbaarheid tijdens ontwikkeling en in de onderhoudsfase, maakt onderhoudbaarheid op lange termijn mogelijk. Bijvoorbeeld door jaarlijks een inventarisatie te maken van de gebruikte stack, frameworks en tooling. De Thoughtworks Technology Radar kan daarbij helpen.
Wanneer er sprake is van een applicatie in productie met weinig functioneel onderhoud en beperkt zicht op de onderhoudbaarheid, is het zinvol de onderhoudbaarheid in kaart te brengen. Hiermee wordt de technical debt ingeschat en een advies gegeven welke stappen er gezet dienen te worden. We noemen dit een apk, zoals we dit gewend zijn in de autowereld. Alleen dan niet pas na drie jaar. Daarvoor verandert de omgeving te snel.
In dit soort applicaties zien we vaak dat de gebruikte frameworks, platformen en infrastructuur niet bijlopen met de laatste versies. Met vooral risico’s op het gebied van security. Ook laat de analyseerbaarheid en testbaarheid vaak te wensen over. Door de lage mate van functioneel onderhoud, is de achtergrond van de gemaakte keuzes tijdens bouw vaak verdwenen waardoor de onderhoudbaarheid bepaald wordt door de kwaliteit van de code (en documentatie). En daarmee is de cirkel rond.
Conclusie
Aandacht voor onderhoudbaarheid verlaagt de total costs of ownership van elke maatwerk-applicatie, doordat betere kwaliteit, wijzigbaarheid en testbaarheid zorgt voor een productiever development team.
Hanteer een Agile-aanpak, maak technical debt continu zichtbaar en refactor waar zinvol. Automatiseer testen van de infrastructuur en besteed aandacht aan de overdraagbaarheid!