Dit artikel biedt een concreet advies om effectief en efficiënt te upgraden naar een nieuwe versie van de kern van je software systeem: Java. Daarbij worden ervaringen gedeeld die opgedaan zijn tijdens diverse grootschalige upgrade-trajecten.
Het is alweer twee jaar geleden dat de Java Standard Edition (SE) 7 uitgebracht is. Een mooie release van het Java platform met interessante verbeteringen. Toch draaien veel bestaande systemen nog op Java SE 6. Upgraden van Java SE is in de praktijk vaak een uitdagende klus.
Java SE vormt namelijk het hart van ieder op Java gebaseerd systeem. Upgraden betekent dat veel onderdelen moeten worden meegenomen: tools, gebruikte middleware, libraries en uiteraard de zelf geschreven software. Wat zijn de voordelen van upgraden, en nadelen van niet upgraden? Wat zijn risico’s en inspanning? Welke stakeholders zijn betrokken? Voor veel organisaties een lastig dossier.
Actieplan stap 1: Voordelen inzichtelijk maken
Verbeteringen in Java SE 7
Java SE 7 is de eerste grote major release van Java in vijf jaar tijd. Hofleverancier van Java, Sun Microsystems, werd gekocht door Oracle, en hiermee werden diverse grote projecten vertraagd. Ondanks de lange periode is Java SE 7 daarom een relatief milde upgrade met weinig grote innovaties.
Dat neemt niet weg dat Java SE 7 veel interessante verbeteringen bevat. Betere performance, toevoegingen in meer dan vijftig API’s, en een aantal kleine, maar zeer prettige vernieuwingen in de programmeertaal. Als je eenmaal aan de nieuwe features gewend bent voelt Java 6 wel degelijk oud.
Up2date met Java ecosysteem
Java SE staat niet op zichzelf. Het is onder andere bepalend voor de versies van het operating system die ondersteund worden, welke tools beschikbaar zijn en of de laatste versie van frameworks kunnen worden ingezet. Oracle heeft sinds afgelopen februari de ondersteuning van de gratis editie van Oracle Java ‘Hotspot’ VM 6 beëindigd. Een belangrijke mijlpaal in Java land: deze JVM is verreweg het meest populair. Einde support betekent dat veel third-party leveranciers van frameworks en tools hun ondersteuning ook stoppen.
Naast technische ondersteuning is het enthousiasme van ontwikkelaars enorm belangrijk. Onderhoudsteams die nog Java 1.4 code moeten onderhouden hebben vaak grote moeite om nog mensen te vinden die dit willen doen, laat staan met veel passie.
Het is daarom interessant om naar Java als ‘ecosysteem’ te kijken.
Voordat de upgrade naar een nieuwe versie van Java kan worden uitgevoerd, moet even geduldig gewacht worden tot zaken als kwaliteitstools, middleware of IDE’s voldoende aangehaakt zijn. Voor Java SE 7 is dit relatief vlot gegaan: de meeste producten ondersteunen SE 7 nu al ruim een jaar. Er is dus ruim voldoende ondersteuning om de stap te maken.
Uitstel betekent extra complexiteit en kosten
Bij upgrades wordt vaak alleen gedacht over de nadelen voor de dag van morgen. Dit terwijl veel systemen nog jaren moeten blijven werken. Het is beter om vanuit de end-of-life datum van het systeem te denken. Upgraden is op een gegeven ogenblik onvermijdelijk. Sommige organisaties wachten graag tot het allerlaatste moment, zodat de upgrade-inspanning ‘overgeslagen’ kan worden. De gedachte is dat één keer upgraden naar twee of drie versies hoger goedkoper is dan een upgrade per versie.
De technische waarheid is echter het tegenovergestelde. Des te groter het gat dat overbrugd moet worden, des te meer risico en inspanning tegelijkertijd. Ook hiervoor geldt dat de optelsom meer is dan de som der delen. Net als in een Agile aanpak geldt ook hier dat kleine stappen met vroege feedback het wint van ‘doe alles in een keer goed’.
Oracle heeft overigens aangegeven om toekomstige Java SE upgrades weer met tussenpozen van ongeveer twee jaar uit te brengen. Voor bedrijven die hun Java systemen nog tientallen jaren willen gebruiken, is het verstandig om deze kadans te volgen om upgradetrajecten beheersbaar te houden.
Legacy groeit niet
Los van technische upgrades zal de code in beheer nog steeds regelmatig bijgewerkt moeten worden. Er worden nog steeds aanpassingen gevraagd, problemen opgelost en nieuwe functies toegevoegd. Industriestandaard-metingen tonen aan dat gemiddeld tien tot twintig procent van de code per jaar wijzigt. Meer dan waarschijnlijk nodig is voor een upgrade van Java. Deze verhouding in wijzigingen kan worden gemeten per systeem en is als ‘code churn’ metriek snel op te vragen uit een versiebeheertool.
De Code churn metriek is een indicatie hoeveel extra technische schuld wordt opgebouwd als je niet zou upgraden. Logischerwijs kun je aannemen dat als je wél een upgrade toepast, de wijzigingen direct worden doorgevoerd op basis van de nieuwste versie.
Actieplan stap 2: Bepalen kosten en risico’s
Om een upgrade-besluit te kunnen nemen is vooraf goed inzicht nodig in de kosten en risico’s. Het helpt in de communicatie met stakeholders en geeft een basis voor het inplannen van de upgrade. In onze ervaring valt dit vaak in drie categorieën: ondersteunende tools, het platform en Java als programmeertaal.
Tools
Alle tools die gebruikt worden, moeten de nieuwe versie van Java gaan ondersteunen. Vooral tools die Java source- of bytecode lezen of schrijven, en tools die dicht aansluiten op interne platform features zijn gevoelig voor upgrades. Denk daarbij aan de ontwikkelomgeving IDE, maar ook aan ondersteunende tools voor codekwaliteit. Veelgebruikte tools zijn Checkstyle, Findbugs, Sonar, EclEmma, Cobertura of tooling die gebruikt wordt door externe audit partijen. Ook beheer-, performance- en probleem-analyse tools hebben vaak een upgrade nodig.
Meestal wordt ondersteuning van Java versies door de leverancier aangegeven, maar zeker niet altijd. Vaak voldoet Google, maar helaas is het soms een kwestie van uitproberen.
Een paar voorbeelden van tools waarvoor het niet transparant of vanzelfsprekend is dat het Java 7 ondersteunt.
- Source code compatibiliteit: JavaNCSS
JavaNCSS wordt vaak ingezet voor het berekenen van het aantal regels code. Hiervoor analyseert het de Java source code. Dit type tool blijft dus werken na een upgrade totdat de nieuwe taal features ingezet worden.
- Bytecode compatibiliteit: Cobertura
Het heeft even geduurd, maar inmiddels ondersteunt Cobertura Java 7. Voor veel uitgevoerde upgrades heeft het echter te lang geduurd en is men overgestapt naar Jacoco voor de code coverage berekeningen. De vorige versie van Cobertura brak namelijk het byte code contract door compile time extra informatie toe te voegen. Vanaf Java 6 is namelijk het StackmapTable attribuut geïntroduceerd, welke in Java 7 verplicht is geworden. Cobertura gebruikte een versie van ASM welke nog niet in staat was om valide bytecode te genereren, waardoor een VerifyError op trad bij gebruik van Java 7.
- Runtime compatibiliteit: JMX
Voor applicatiebeheer en monitoring wordt veelal gebruik gemaakt van JMX voor het weergeven van applicatie metrieken. Het gebruik van een andere JVM, welke in potentie ander gedrag vertoont voor sommige metrieken, kan betekenen dat je sommige dingen niet meer kan meten of andere resultaten ziet. Dergelijk gedrag van te voren inventariseren en communiceren.
Platform
Een Java systeem is vaak gebouwd op een flinke hoeveelheid middleware, frameworks en libraries. Producten zoals Tomcat, Websphere en Weblogic, maar ook Spring en Hibernate moeten Java SE 7 ondersteunen. Voor alle populaire producten was zeer snel ondersteuning beschikbaar. Zie tabel 1 voor een overzicht met de eerste versie van een product die ondersteuning voor Java 7 biedt.
Java programmeertaal
Java SE 7 is qua programmeertaal volledig backwards compatibel, maar bevat wel nieuwe taalfeatures die voor bestaande code zeer waardevol zijn om toe te passen. Het leidt immers tot beter leesbare en kortere code en zorgt ervoor dat de codebase als geheel consistenter blijft.
Veel Java IDE’s bieden refactorings om Java 7 taalfeatures automatisch toe te passen op bestaande code. De IntelliJ IDEA tooling bevat een feature om dit zelfs in bulk te doen; een veilige en goedkope manier om snel je codebase te moderniseren.
Op grote codebases is het daarnaast ook een goede aanpak om de ‘boy scout rule’ toe te passen. Bij iedere code aanpassing wordt de code beter achtergelaten dan daarvoor. Dit betekent dus ook inclusief de nieuwe taalfeatures.
In tabel 2 staan de resultaten van het toepassen van de IntelliJ refactorings op een codebase van ongeveer 800.000 Java source Lines.
Actieplan stap 3: Uitvoeren
Hou de winkel open
Voor technische upgrades wordt vaak een ‘feature freeze’ periode gehanteerd, zodat doorontwikkeling van functionaliteit niet wordt vermengd met de technische upgrade. Dit lijkt handig: alle focus kan op de upgrade gelegd worden, en bij problemen is altijd duidelijk dat het aan de upgrade ligt.
Het afkondigen van een feature freeze is echter pijnlijk voor de business die langer moet wachten op de fel begeerde functionaliteit. Deze behoefte zorgt er ten eerste voor dat de periode van de freeze vaak klein is en niet zo maar kan wijzigen. Ten tweede mag de freeze niet vaak voorkomen. Dat creëert weer de verleiding om in de beperkte upgrade-slots zo veel mogelijk tegelijk te upgraden, waardoor het risico toeneemt en de kans om in de freeze alles te upgraden geringer wordt. Daardoor wordt de angst voor upgrades nog verder aangewakkerd.
Het betere alternatief is om de winkel open te houden voor functionele wijzigingen en parallel technische upgrades uit te voeren. Dit vergt plannen in kleine stapjes die gemakkelijk kunnen worden teruggedraaid bij eventuele onvoorziene situaties.
Goed gereedschap is het halve werk
Een goede eerste stap is het upgraden van alle benodigde tools. De meeste tools zijn backwards compatible, en nieuwe versies van de tools kunnen al worden gebruikt zonder dat er aanpassingen gedaan hoeven te worden aan de broncode. Daarnaast kan iedereen alvast wennen aan de nieuwe tools. Ook biedt de nieuwe tool ondersteuning in de upgrade zoals taal refactorings.
Ervaring leert dat het upgraden van ondersteunende tooling een flinke, maar wel noodzakelijke, investering kan zijn. Veelal betekent het niet alleen een upgrade van de IDE, maar van de hele toolstraat. Bij verschillende langer lopende Enterprise projecten betekent dit soms een grote hoeveelheid tools die op verschillende omgevingen en machines bijgewerkt moeten worden.
Modulair upgraden
Een effectieve manier om de upgrade op te delen is per team, per systeem of andere modulaire doorsnede. Bij een aantal projecten werden feature teams toegepast. De ervaringen van het eerste feature team zijn dan hergebruikt voor het tweede etcetera. De meeste risico’s en complexiteit worden dan vroeg geadresseerd. Figuur toont dit principe waarbij in stap 1 feature team 3 als eerste overgaat.
Belangrijk in een dergelijke aanpak is om met een geïsoleerd deel van het systeem te beginnen. Dit voorkomt dat er een sneeuwbal effect ontstaat van wijzigingen waardoor alsnog het gehele systeem direct geüpgraded moet worden.
Stapsgewijze introductie Java 7 in de build
Na de upgrade van de tools kan de upgrade van Java ook in de build in kleine stappen worden opgedeeld, zoals getoond in tabel 3.
Een eerste eenvoudige stap is de Java 7 compiler inzetten om de bestaande source te bouwen. Dit is in te stellen met:
“javac -target 1.6 -bootclasspath jdk1.6.0\lib\rt.jar -extdirs "" OldCode.java”
Bepaalde exotische taal constructies worden soms door oudere versies van de Java compiler onterecht toegestaan. Nieuwere versies geven hier wel terechte meldingen op zodat de code constructies aangepast moeten worden.
Een vervolgstap is het inzetten van de Java 7 runtime om de, met Java 7 gecompileerde, Java 6 source code te executeren. Hierdoor kan worden beproefd of het systeem met minimale aanpassingen al zijn voordeel kan doen met de nieuwe runtime. Denk aan performance voordelen of verbeterde JMX mogelijkheden. Indien bij deze stap onverwachte situaties optreden kan men nog eenvoudig terug naar Java 6.
Tot slot kunnen de Java 7 taal- en API features volledig benut worden door ook te compileren tegen source level 7.
Conclusie
Upgraden naar een nieuwe versie van Java kan een flinke uitdaging zijn. Het actieplan begint met het verkrijgen van het noodzakelijke draagvlak door voor iedere stakeholder inzichtelijk te maken wat voor hen de voordelen zijn. Een soepel upgrade traject wordt gerealiseerd door een heldere kosten- en risico analyse en een stapsgewijze aanpak waarbij de winkel open blijft. Tot het allerlaatste moment wachten met de upgrade is op de lange termijn altijd duurder en risicovoller. En voor ontwikkelaars is het enorm fijn om de laatste versie van Java te gebruiken!