Microservices zijn op dit moment enorm in opkomst. Bekende namen als Netflix, Amazon en Twitter passen de aanpak al jaren toe, met veel succes. Java blijkt voor al deze bedrijven een goede basis: vrijwel iedereen gebruikt de JVM als universeel platform voor al hun microservices. De gevestigde standaard voor serverside development, Java Enterprise Edition (EE), wordt echter nergens genoemd bij deze hippe bedrijven. Waarom niet?
Het kan wel!
Om één misverstand maar meteen uit de wereld te helpen: ook met Java EE technologie kan een microservice worden gemaakt. Een microservice is vooral een architectuuraanpak, en de minimum technologie eisen zijn bescheiden: zelfstandig in een proces kunnen draaien en met open standaarden services kunnen aanbieden/gebruiken (vaak HTTP REST interfaces met JSON). Die opzet kun je prima kiezen op je favoriete Java EE applicatieserver.
Not invented here?
Waarom doen die succesvolle bedrijven dan iets anders? Java EE is al vijftien jaar een begrip, het is zonder twijfel het best gedocumenteerde, meest gebruikte framework voor serverside development. Het bevat een enorme bak aan API's: voor web development, business logica, database toegang, enterprise integratie en ga zo maar door. Hier bovenop is ook een flink ecosysteem van allerlei frameworks en libraries beschikbaar. Is dit weer een gevalletje "not invented here", waar bij een nieuw buzzword alles opnieuw bedacht moet worden? Of hebben deze bedrijven een goede reden om Java EE te mijden? Daarvoor moeten we iets verder kijken dan de minimum instapeisen voor microservices.
Grote systemen met kleine teams
Het belangrijkste doel van de microservices aanpak is om grotere systemen met meerdere kleine, zelfstandige agile teams tegelijk te kunnen ontwikkelen. Om teams voldoende zelfstandig te kunnen laten werken wordt het systeem opgeknipt in feature georiënteerde microservices, waar één team in de ideale situatie dit feature van user interface tot storage volledig in eigen hand heeft.
Dit maakt het mogelijk de agile practices volledig te blijven hanteren op een veel grotere schaal dan vroeger. Het maakt het ook mogelijk sneller nieuwe technologie in te zetten, specifiek voor features die er ook echt iets aan hebben.
Zelfstandigheid door te ontkoppelen
Zelfstandigheid voor een individueel team/microservice wordt ver doorgevoerd. Iedere service kan verschillende technische keuzes maken voor bijvoorbeeld een andere database technologie of programmeertaal, als dit beter aansluit bij het specifieke probleem wat de service moet oplossen. Een service kan individueel worden gedeployed in productie, ideaal gezien zonder enkele afstemming met de rest van de omgeving. Een team kan ook zelf besluiten wanneer de service naar productie gaat, en bewaakt zelf de kwaliteit.
Dit betekent veel minder afstemming met centrale architectuurgroepen, beheerafdelingen of teststraten. De grootste voordelen van microservices zitten uiteindelijk daar: in het ontkoppelen van mensen, niet van de technologie.
Ondersteuning
Die centrale groepen hoeven echter niet helemaal te verdwijnen. Voor de beheersing van een microservice heb je best wat ondersteuning nodig: het provisionen van machines, installatie en configuratie, monitoring, routing en fail-over zijn zaken die je niet ieder feature team zelf wil laten uitzoeken. Deze centrale concepten worden vaak door ondersteunende teams opgezet en doorontwikkeld, op een manier die zo min mogelijk technische keuzevrijheid afneemt. Bekende voorbeelden zijn provisionen met Docker, of configureren door platte tekst bestanden te regexen. Adrian Cockroft, lange tijd architect bij Netflix, heeft hier het volgende handige overzicht voor, waarmee duidelijk wordt dat deze beheersing flink verder gaat dan een paar deploy scripts delen:
Java EE op dieet
Voor een microservice willen we dus een kleine, gefocusde service op een standalone proces, die simpel automatisch kan worden deployed. Met een paar basis-stappen komen we al een heel eind:
- Stop alles in één WAR. Dit is de meest eenvoudige manier van packagen en voor kleine services prima.
- Eén WAR per applicatieserver instantie. Dat levert een goede scheiding van andere services op. Let wel op eventuele licentiekosten voor je server: die zijn vaak per instantie.
- Eén configuratie-eenheid per service. Veel applicatieservers bieden uitgebreide opties om meerdere servers in één configuratie te managen. Dat wil je vermijden zodat direct scripten op losse configuratie xml praktisch blijft.
- Provision de applicatieserver met een unzip installatie. Dit is simpel, en prima te automatiseren met tools als Puppet of Docker.
- Deploy de WAR door het package in een “deployment” directory te kopiëren, een eenvoudige deploy optie die door de meeste applicatieservers wordt ondersteund.
Met dit 5 stappen dieet is Java EE zo ver mogelijk afgeslankt en is de boel al een stuk gemakkelijker in te passen in algemene tooling. Toch blijven er helaas nog een paar flinke nadelen over.
Too little, too late
Het wellicht belangrijkste nadeel is het relatief lage tempo waarin EE standaarden kunnen worden veranderd. Java EE is een design-by-committee initiatief, dat eens in de drie jaar een update uitbrengt, waarna leveranciers hun producten aanpassen voor de nieuwe versie. Op het moment van schrijven is anderhalf jaar na de laatste release, Java EE 7, er nog maar één applicatieserver die deze standaard volledig ondersteunt.
Helaas blijken nieuwe standaarden in Java EE vaak pas na enkele releases goed bruikbaar. Adoptie van Dependency Injection begon in EE 5, maar was pas bij versie 6 volwaardig. JSON ondersteuning, nu ook twee versies verder, kent nog de nodige beperkingen. En asynchroon programmeren wordt ondanks een paar aardige eerste stapjes in Java EE 7 vrijwel niet ondersteund.
Die voor huidige IT begrippen gigantische doorlooptijd van vijf tot acht jaar maakt dat EE al lang niet meer de one-stop shop is waar alle moderne technieken beschikbaar zijn: het is vooral een basisplatform, wat vrijwel altijd moet worden uitgebreid met extra libraries. Waarom dan niet direct de library gebruiken?
Complexiteit die je niet nodig hebt
Java EE bevat een hoop zaken die voor een microservice niet nodig zijn. Java EE is ontworpen is voor het runnen van meerdere complete enterprise applicaties op één JVM instantie. De classloader complexiteit die hier voor nodig is zit bij een microservice alleen maar in de weg. Hetzelfde geldt voor configuratie en deployment; ondanks het dieet zul je met veel abstracties en tussenstappen de boel moeten instellen.
Een aparte tussenlaag met Enterprise Java Beans (EJB) is niet meer nodig. Serverside web frameworks als JSF en JSP worden vaak vermeden, omdat ze worden vervangen door JavaScript oplossingen in de browser.
Deze overbodige en overmatige complexiteit is ballast bij allerlei taken: het provisionen, configureren en testen vereist bijvoorbeeld meer werk, duurt langer en is moeilijker te begrijpen. Daarnaast is het soms een blokkerend conflict met nieuwe technologie.
In de weg
Java EE stelt een aantal strikte runtime voorwaarden, zoals specifieke eisen voor classloaders, threading, state management en I/O. Bepaalde ontwerpkeuzes, zoals integratie met security, serialisatie en initialisatie, zijn strak gefixeerd. Dit maakt een aantal innovaties moeilijk te combineren met Java EE. Voor zaken als reactive programming, actor gebaseerde frameworks, of big data oplossingen is het vaak moeilijker, of onmogelijk, dit fatsoenlijk te verenigen met Java EE.
De alternatieven
Nu begint duidelijk te worden dat Java EE inderdaad een aantal stevige nadelen kent als basis voor een microservice. Maar hebben we een keuze? Zoals met alles in Java is er al een flinke lijst aan alternatieve microservice frameworks aan het ontstaan. Ter illustratie kijken we naar een paar van de meer gebruikte en langer bestaande frameworks: Dropwizard en Vertx, omdat ze beiden een heel andere aanpak kiezen voor serverside Java development.
Dropwizard
Dropwizard is oorspronkelijk ontwikkeld door Yammer in 2011, en wordt inmiddels door diverse organisaties ingezet. Het heeft als vertrekpunt een minimale set van bestaande populaire frameworks (Jersey en Jackson) voor het maken van HTTP REST microservices, die je zelf start vanaf een Java “main” methode.
Voor een simpele HTTP REST service met een relationele database kun je met Dropwizard direct aan de gang. Zeker voor ontwikkelaars die Java EE al kennen is Dropwizard een kleine stap; met bekende frameworks, en een simpel configuratie en deploymentmodel dat je na een kwartier onder de knie hebt. De geavanceerdere features zoals database migratie worden aangeboden als "drop-in", wat betekent dat je er geen last van hebt als je ze niet gebruikt.
Wil je meer dan een simpele REST service met een database, dan zul je zelf Dropwizard moeten uitbreiden. Voor enterprise integratie is het niet zo geschikt als een Java EE applicatieserver, en voor het aansluiten op bijvoorbeeld een in-memory datagrid of nosql database zul je zelf iets moeten bedenken voor configuratie, caching van connecties enzovoorts. Dit kan even knutselen zijn, maar dank zij het lichtgewicht model heb je wel veel vrijheid om extra libraries toe te voegen.
Vertx
Vertx is een alternatief serverside Java framework, gestart door Tim Fox in 2011, ook bekend van de Netty networking library. Door velen beschouwd als de “Node.js voor Java”, is het volledig gericht op het ondersteunen van "reactive programming". Reactive programming is een stijl van programmeren waarbij je de thread niet blokkeert bij het wachten op een potentiële langdurige operatie (bijvoorbeeld een database operatie), maar in plaats daarvan met een callback definieert wat je volgende stap is. De applicatie kan hierdoor veel verder schalen op één machine dan traditionele frameworks, die één dure thread per actieve connectie opeisen. Reactive programming is potentieel ook eleganter; er zijn veel raakvlakken met concepten in functioneel programmeren.
Vertx schaalt enorm goed, zonder moeilijke tuning. Het framework is minimalistisch opgezet en snel te leren, en er zijn zelfs voorzieningen om meerdere talen te gebruiken, zoals Groovy, Scala en JavaScript. Hiernaast is ook hot code replace en een handig integratietest-framework beschikbaar.
Er zijn wel flinke verschillen met veel andere Java frameworks. Vertx biedt out of the box een mooi stuk infrastructuur, maar de API is vergelijkbaar met Servlets, en is te low-level om direct veel applicatielogica in te schrijven. Er is ook relatief beperkte keuze uit extra libraries om je hierbij te helpen. Met name het threading model van Vertx stelt andere eisen (je mag niet zelf threads maken, en niet blocken op de event handling thread). Dit is logisch gezien de focus op reactive programming, maar dit sluit veel bestaande libraries uit of maakt het nodig hier workarounds voor in te zetten. Het is de hoop en verwachting dat, nu reactive programming in bredere zin meer aandacht krijgt, dit probleem minder zal worden.
Conclusie
Dat microservices belangrijk gaan worden voor onze applicaties is onvermijdelijk. Wat is nu de beste keuze? De traditionele Java EE aanpak is waarschijnlijk nog steeds superieur als je integreert met andere enterprise technologie, zoals durable messaging, gedistribueerde transacties, mainframes of ERP oplossingen. Wil je op een bekende manier HTTP REST services tegen een relationele database zetten, dan is Dropwizard een eenvoudigere en flexibelere manier om vlot microservices te maken. En heb je services waar je verwacht dat duizenden gebruikers tegelijk op gaan beuken, dan biedt Vertx een mooie tussenlaag om dit snel en met weinig machines voor elkaar te krijgen.
Als je microservices écht omarmt zie je dit niet als een keuze tussen één van de drie. Het idee is dat we juist stoppen met het zoeken naar die ene gouden hamer waar we alles mee moeten kunnen. Iedere organisatie zal, op basis van de specifieke uitdagingen, meerdere soorten gereedschap kiezen.
Dat opent nieuwe wegen om te verkennen hoe serverside Java development anders kan dan Java EE. En voor Java EE zelf biedt het, naast nieuwe ideeën, ook gezonde concurrentie om relevant te blijven. Microservices blijken daarnaast momenteel een katalysator voor veel andere vernieuwingen in deployment, testen en monitoring. Kortom, 2015 wordt een mooi jaar voor de Java serverside developer!