De huidige J2EE-software-architectuur is een opgeblazen kikker. Dit komt door de misvatting dat een bedrijfsmodel moet worden gerealiseerd door een aparte bedrijfslaag boven op de datalaag. Een interactieve applicatie met als belangrijkste doel het manipuleren en opvragen van data valt beter via een tweelaagse architectuur te realiseren. Niet een statisch domeinmodel maar een flexibel contentmodel zou leidend moeten zijn in het ontwerp van de applicatie.
Wanneer een organisatie besluit om Java-applicaties te gaan maken, duurt het niet lang of de keus valt op een J2EE-architectuur. Dit geldt zeker als het gaat om een bedrijf met een behoorlijke omvang of waar de bedrijfsgegevens bijzonder gevoelig zijn.
De bedrijfsgrootte, de gevoeligheid van de data en zelfs grote aantallen gebruikers zijn echter geen criteria om te kiezen voor de drielaagse J2EE-architectuur. Het management krijgt vaak een verkeerd advies. Het laat zich overtuigen door argumenten als robuustheid, schaalbaarheid, integratie, beveiliging en (globaal) transactiemanagement. Bovendien is J2EE gebaseerd op standaarden die gedragen worden door veel leveranciers, en draait dezelfde code op applicatieservers van verschillende leveranciers en besturingssystemen. De leverancier blijft zo op de juiste afstand.
Objectgeoriënteerd
Zijn transacties over meerdere databases wel zo belangrijk voor de te bouwen applicatie? Willen we een duidelijke machinescheiding tussen de presentatie-, bedrijfs- en datalaag (drielaagse architectuur)? Wellicht de belangrijkste vraag luidt: moet de data tijdens de uitvoering van een programma in een objectgeoriënteerd model gerepresenteerd worden?
Een meerwaarde van een objectgeoriënteerd model is overerving. We kunnen hiermee generalisaties gebruiken, zoals ‘klant’, en vervolgens specificeren, bijvoorbeeld ‘particulier’ of ‘bedrijf’. Een relationeel model heeft geen tegenhanger voor overerving. Willen we de gemakken van overerving en andere objectgeoriënteerde eigenschappen direct gebruiken, dan moeten we een odbms (objectgeoriënteerd database management systeem) inzetten. Dit gebeurt nog weinig omdat relationele databases bekender zijn. Bovendien zijn ze na vele jaren van ontwikkeling robuust en schaalbaar.
In een objectgeoriënteerd model kunnen we relaties eenvoudig definiëren zonder ons te bekommeren om de implementatie. In een genormaliseerd relationeel model daarentegen ontstaan veel extra tabellen, zoals tussentabellen bij ‘veel op veel’-relaties. Dit maakt een relationeel model technischer.
In de praktijk worden ‘object to relational mappings’ gebruikt om toch een relationeel dbms te kunnen inzetten. Dan blijkt dat het niet zo moeilijk is om objectgeoriënteerde associaties om te zetten in tabelrelaties. Daarbij zijn in een rdbms meerdere tabellen als één tabel te representeren. Dit kan met behulp van ‘stored procedures’, waarbij we via een functie met parameters de data overdragen. Het kan ook met behulp van ‘views’, zodat het net lijkt of er maar één tabel is, of met Java-classes waarin we zelf een ‘object to relational mapping’ implementeren. Er zijn gratis raamwerken op internet te vinden om deze code te genereren. Hiermee is bijvoorbeeld overerving te ondervangen door de extra tabellen ‘particulier’ en ‘bedrijf’ te definiëren die via de primaire sleutel één op één worden gerelateerd aan de ‘klant’-tabel.
Te veel wijzigen
De datadefinities in een rdbms komen grotendeels overeen met de bedrijfslogica in een objectgeoriënteerd model. Het gaat om de lengte van velden, het datatype, de geldige waardes, de relaties tussen records enzovoort. Deze ‘constraints’ zijn grotendeels vast te leggen in het dbms met behulp van declaratieve regels, ‘stored procedures’ en triggers. Ze maken het onnodig om een OCL (Object Constraint Language) te gebruiken. SQL is sterk in het bevragen van de data. Allerlei zoekvragen zijn op eenvoudig wijze te definiëren. Hierbij is een aparte OQL (Object Query Language), zoals in J2EE gedefinieerd is, niet nodig, zeker als we gebruik maken van ‘views’.
Als een rdbms alle mogelijkheden kan bieden die vereist zijn om bedrijfsdata op te slaan en terug te vinden, wat is dan nog de noodzaak van een aparte laag met bedrijfsobjecten? Een sterk argument voor een aparte bedrijfslaag is het centraliseren van bedrijfsfuncties. Denk aan het uitvoeren van complexe berekeningen of een reeks samenhangende acties in de context van een transactie. Bekende transactiemonitoren als Cics en Tuxedo ontlenen hieraan hun bestaansrecht. Daarnaast gebruiken bedrijven rpc’s (remote procedure call, tegenwoordig webservices) om hun b2b-comunicatie (business-to-business) te regelen.
Het is denkbaar om voor het invoeren, verwijderen en actualiseren van records, speciale rpc’s te bouwen. Het voordeel is dat we deze code vanuit verschillende applicaties kunnen aanroepen. De nadelen doen dit voordeel echter teniet. Als er een kolom toegevoegd wordt aan een tabel, zullen de parameters van de rpc waarschijnlijk wijzigen. Deze wijziging moet in de rpc-naamserver geregistreerd worden. Vervolgens moet de presentatielaag, de aanroeper van de rpc, gewijzigd worden. Dit alles is meer werk dan alleen de presentatielaag van de applicaties aanpassen, zeker als de rpc een eigen leven is gaan leiden in de loop van de tijd. Dan moet ook nog een strategie bedacht worden voor oudere applicaties die we niet zomaar kunnen wijzigen. Bovendien moeten we de externe partners bewegen hun code aan te passen aan de nieuwe signatuur. Wanneer de applicatie via SQL (Jdbc) met de database communiceert, vereist een extra kolom niet noodzakelijkerwijs een aanpassing. Belangrijk is dat er met expliciete kolomnamen gewerkt wordt en niet met wildcards (select * from …).
Scheiding
Er is niets op tegen om een rdbms op een objectgeoriënteerde manier aan te spreken. Het probleem ontstaat als het objectgeoriënteerde model wordt geïmplementeerd in een aparte bedrijfslaag. Hierbij worden de bedrijfsobjecten als Enterprise Java Beans geïmplementeerd en in een aparte applicatieserver beheerd. Deze extra applicatieserver introduceert veel overhead tijdens zowel de ontwikkeling als de exploitatie van de applicatie, terwijl de interactieve database-applicatie er geen profijt van heeft.
In de praktijk blijkt dat het bouwen van een drielaagse applicatie moeilijk te managen is. Als het ontwikkelteam groeit, wordt meestal een scheiding aangebracht op basis van de drie lagen. De mensen die bezig zijn met de presentatielaag zijn vaak afgeschermd van de mensen die aan de bedrijfs- en de datalaag werken. Bij het bouwen van een traditionele SQL-applicatie is de kans groter dat de programmeur van de presentatielaag besef heeft van de datalaag.
Stel dat er een veldje op het scherm moet komen met daarin het aantal bestelde producten. De programmeur van de presentatielaag heeft het nu eenvoudig. Roep gewoon een methode aan op het klant-object om de verzameling bestelde artikelen van deze klant op te vragen. Het klant-object is immers gerelateerd aan deze verzameling volgens het objectgeoriënteerde model. Als de applicatie door deze aanroep trager is geworden omdat er heel veel data wordt opgehaald, is het goed denkbaar dat de wens voor optimalisatie blijft steken bij de projectmanager.
Hier is het principe van de ‘scheiding van verantwoordelijkheden’ verkeerd toegepast. Het is een goed idee om het ophalen en beheren van de data over te laten aan een aparte laag. We hebben daarvoor het dbms dat voor ons allerlei technische zaken ‘vanzelf’ regelt, inclusief authenticatie, autorisatie en allerlei fraaie rapportage- en backup-faciliteiten.
Ontwikkelproductiviteit stijgt
Het is een slecht idee om een aparte bedrijfslaag te bouwen om de datalaag heen. We kunnen niet anticiperen op wat de mogelijke databehoefte is. De presentatielaag, ofwel de gebruiker, bepaalt welke gegevens relevant zijn. Net als bij bijvoorbeeld cms’en (content management systeem) moeten dit soort applicaties ook content-gedreven zijn, waarbij de zoekopdrachten snel aan te passen zijn aan nieuwe wensen zonder dat we de hele applicatie overhoop moeten halen.
Is een webapplicatie zonder aparte applicatieserver nog robuust, schaalbaar en veilig? Het antwoord hierop luidt ‘ja’. De schaalbaarheid kan toenemen en de complexiteit kan dalen. Daardoor kan de ontwikkelproductiviteit stijgen en de exploitatie eenvoudiger worden.
Een standaard webserver levert robuustheid, schaalbaarheid en beveiliging. Door gebruik te maken van een goede database met faciliteiten voor caching en clustering kunnen we bereiken dat deze geen knelpunt wordt. Een applicatie waarbij veel gegevens gemuteerd worden en waarvan verwacht wordt dat iedereen de mutaties direct ziet, moet een geavanceerde cache bieden. De presentatielaag kan door middel van J2EE-standaarden als servlet en JSP vorm krijgen. Andere technieken gebaseerd op XML en Xslt in combinatie met bijvoorbeeld Apache Cocoon zijn ook mogelijk.
Valkuil
We moeten ervoor waken dat we bij de presentatielaag niet dezelfde fout maken. Veelal wordt een ‘model view controller’-paradigma toegepast. Voor je het weet groeien de modelcomponenten uit tot een compleet objectgeoriënteerd datamodel, terwijl het bedoeld is als vergaarbak voor alle data op het scherm (en de subschermen).
Een andere valkuil is het in het geheugen opslaan van alle data wanneer er meer gegevens zijn dan op het scherm passen. Dit is vaak het geval bij resultaatschermen na een zoekopdracht. Deze strategie leidt tot een enorm geheugengebruik van de webserver en moet daarom afgeraden worden. Beter is het om de zoekvraag telkens af te vuren op de database en ervoor te zorgen dat de resultaten vanaf het laatste vorige resultaat worden opgehaald. Dit vereist een veld waarop gesorteerd kan worden en een snelle en brede verbinding met de database. De database moet ook een uitstekende (alleen lezen) cache hebben. Eventueel kan de webserver zelf data cachen, maar dan wel voor alle gebruikers. Het is echter de vraag waarom je de webserver zou belasten met iets dat de database bij uitstek kan verzorgen.
Elegante oplossing
Het aanbieden van generieke functies moet wel door een derde laag gerealiseerd worden, maar deze laag mag nooit een proxy voor het normale dataverkeer zijn. Een functionele laag moet ook werkelijk extra gedrag hebben. Neem de applicatie Coach van het Jaar van de Noordelijke Dagblad Combinatie. Daar wordt het uitrekenen van competitieranglijsten via aparte functies op afstand uitgevoerd vanuit een beheerapplicatie. Omdat deze berekeningen lang duren, worden de functies asynchroon (in een aparte thread) op de webserver uitgevoerd. Het resultaat van de berekeningen, de nieuwe ranglijst, wordt weggeschreven in een tabel in de database. De gebruikersapplicatie kan vervolgens de ranglijst via de gewone datalaag ophalen. Dit is een elegante oplossing met een duidelijke scheiding van verantwoordelijkheden en acceptabele prestaties voor de tienduizenden deelnemers.< BR>
Kees Broenink, software-ontwikkelaar