GISI: Gebufferde database communicatie

Gebufferde database communicatie door middel van adapters voor transactie-management en autorisatie. Dit artikel introduceert het Object Model en de koppeling van het domein model met andere subsystemen d.m.v. adapters.

Domein model

Het domein model is gebaseerd op een vereenvoudigde versie van het probleem domein zoals dat in GISI wordt gebouwd.

  • De nadruk ligt op de projecten zoals die landelijk en regionaal worden gedefinieerd.
  • Uitgangspunt van het object model is in eerste instantie het gedrag van de objecten, en niet de data-structuur (zoals die bijvoorbeeld van belang is voor de database).
    Uitgaande van het gedrag (dat wordt gerepresenteerd in de methodes) wordt vaak tot een andere object-structuur gekomen dan wanneer alleen de data wordt beschouwd. Bijvoorbeeld overerving op basis van gedrag leidt tot andere modellen.

Business Objecten

De huidige oplossing van GISI gebruikt zogenaamde business objecten (BO’s). Deze objecten noem ik applicatie modellen. Het is belangrijk deze termen even te definiëren omdat er anders gemakkelijk verwarring zou kunnen ontstaan met de bij GISI gebruikte termen.

Wat zijn domein objecten?

Drie-lagen-architectuur
Drie-lagen-architectuur

Het is belangrijk onderscheid te maken tussen applicatie modellen of business objecten en domein modellen. De eerste bevatten extra informatie om de koppeling met een ander subsysteem mogelijk te maken (bijvoorbeeld de user interface). De laatste is geheel onafhankelijk van deze andere subsystemen als user interface of persistente representatie.

  • De business objecten blijven hierdoor onafhankelijk van andere representaties
  • De business objecten blijven hierdoor eenvoudiger: er hoeft geen code te worden toegevoegd om data te valideren, koppelingen met tabellen of user interface controls te maken enz.
  • De business objecten kunnen zich concentreren op waar ze het meest belangrijk voor zijn, namelijk een zo compact mogelijke neerslag te geven van “corporate knowledge”
  • Het wordt relatief eenvoudiger om applicatie objecten te laten genereren door een tool vanuit de domein objecten (automatische generatie van adapters bijvoorbeeld)

Wat zijn applicatie modellen?

Applicatie modellen lijken in eerste oogopslag complexere objecten domein objecten. Dit is echter schijn, omdat voor het bouwen van applicatie modellen gebruik gemaakt wordt van adapters. Dit zijn generieke objecten, die verantwoordelijk zijn voor de koppeling tussen de subsystemen, bijvoorbeeld de domein objecten met de user interface. Omdat het gedrag van adapters eenduidig is (alle adapters hebben immers hetzelfde protocol om met de buitenwereld te communiceren) wordt hierdoor ook het applicatie object eenvoudiger.

Wel heeft elk applicatie object meer verantwoordelijkheid dan alleen het adapten van attributen. Reageren op veranderingen in de objecten bijvoorbeeld kan ook een deel van de verantwoordelijkheid van de applicatie objecten zijn.

Adapters

Adapters zijn generieke objecten (de mate van generiekheid kan verschillen). De adapters zorgen ervoor dat objecten zich lijken te gedragen als andere objecten. Bijvoorbeeld een input field control in de user interface verwacht een model te hebben dat de boodschap “getValue” begrijpt om de string te verkrijgen die in de interface getoond moet worden, en een boodschap als “setValue” wanneer de gebruiker de string in de user interface wijzigt.

Er zijn verschillende soorten van adapters mogelijk:

  • “Gewone” adapters – deze worden geparametriseerd met het object waarnaar een verwijzing is, en het protocol waarmee het object benaderd moet worden. Bijvoorbeeld: een naam adapter voor een persoon (die dus zelf weer een associatie heeft met een persoon applicatie model) heeft een verwijzing naar de persoon domein class, en de boodschap die gestuurd moet worden om deze naam op te vragen en de boodschap die gestuurd moet worden om deze naam te wijzigen (get en set operaties).
  • Gebufferde adapters — deze bewaren zelf een kopie van de data, bijvoorbeeld de string van de nieuw ingevoerde naam van de persoon. Bovendien bevatten deze adapters een verwijzing naar een speciaal object, een trigger channel. Dit laatste object is geshared object waar meerdere gebufferde adapters een verwijzing naar kunnen hebben. De “OK” button, of de “Commit” button heeft deze verwijzing ook, en kan door de trigger channel te activeren in één keer de data doorsturen naar het domein object, of in het geval van de koppeling met de database, naar de database via een SQL string.
  • “Pluggable” adapters — dit zijn de meest geavanceerde adapters, die geparametriseerd kunnen worden met drie stukken code: een stuk code dat uitgevoerd wordt wanneer de adapter de boodschap “getValue” krijgt, een ander stuk code wanneer “setValue” ontvangen wordt, en een derde stuk code wanneer “updateValue” ontvangen wordt. Niet alle omgevingen ondersteunen het runtime bewaren van code. In C++ wordt gebruik gemaakt van pointers naar methodes of van zogenaamde functors, pointers naar code.

De koppeling

Algemene relatie tussen subsystemen
Algemene relatie tussen subsystemen

De relatie tussen PersoonApp (het applicatiemodel) en Persoon is optioneel. Eventueel ligt deze relatie alleen via de adapters.

Om nieuwe attributen toe te voegen, bijvoorbeeld een adres voor Persoon, is het alleen nodig een nieuwe adapter te maken voor PersoonApp. Het object dat verantwoordelijk is voor het maken van een PersoonApp, misschien (zoals in bovenstaande illustratie) een PersoonHolder, kan dit zonder moeite doen. De adapter is een generiek object, de code om een nieuw object aan te maken is herbruikbaar, alleen de parameters zullen anders zijn. Zie hieronder een voorbeeld in pseudo-C++ code.

attribuut get set update
naam “getNaam()” “setNaam(name)” “nameChanged()”
adres “getAdres()” setAdres(adres)” “adresChanged()”

Hoe om te gaan met update boodschappen

Het kan onduidelijk zijn wat de betekenis is van de update boodschappen. Deze boodschappen worden verstuurd vanuit het domein object wanneer iets verandert aan de waarde van een bepaald attribuut. Bijvoorbeeld de naam van een persoon wijzigt doordat iemand elders dit doet. Hierdoor is het mogelijk een read-only editor op een persoon run-time de naam in het inputveld te laten wijzigen. Deze feature kan alleen geimplementeerd worden wanneer er een mechanisme bestaat om objecten (applicatiemodellen, of beter nog: de adapters) te registreren bij de database, en dat de database updates broadcast wanneer objecten gewijzigd worden.

Los hiervan kan in-memory deze structuur benut worden wanneer een gebruiker via verschillende wegen een object kan editen. De verschillende editors zullen dan consistent blijven in de data, nog voordat deze gecommit is naar de database. Hierbij treedt hetzelfde probleem op: het is noodzakelijk om de objecten die geïnteresseerd zijn in eventuele veranderingen van het domein object te registreren als zodanig. Let op: deze registratie, of het mechanisme dat registreren en de-registreren mogelijk maakt, moet op abstract niveau gedefinieerd worden (bijvoorbeeld in abstracte superclasses).

Applicatie model

Het applicatie model is een BO dat specifiek tot doel heeft de specifieke business objecten losser te koppelen met andere systemen.

Elk domein model heeft, net als in de huidige implementatie, een dubbel in de vorm van een applicatiemodel. De attributen (en associaties) van het domein model worden gerepliceerd in de attributen van het applicatiemodel, met de volgende verschillen:

  • het domein model bevat attributen die puur van het datatype zijn dat verwacht wordt, terwijl het applicatiemodel deze attributen “wrapped” in zogenaamde adapters.
  • het domein model bevat geen code om input validatie te doen, of wanneer dat zo is, alleen domein-specifieke validatie, bijvoorbeeld waardes die weliswaar mogelijk zouden zijn maar door de huidige configuratie van objecten niet. Constraints op input kunnen gelegd worden bij de adapters. Dit geldt ook voor autorisaties.
  • het domein model bevat geen informatie over wijzigingen

Transactie management

Zoals uit bovenstaande misschien duidelijk is, kunnen transacties getriggerd worden op een centrale plek. Hierbij zijn verschillende constructies mogelijk:

  • Bufferen van hele objecten (bijvoorbeeld een Persoon). Dit betekent dat kopieën van deze objecten gemaakt moeten worden
  • Bufferen van attributen (bijvoorbeeld de naam van een persoon)
  • Double-buffering is ook mogelijk. Hierbij wordt gebruik gemaakt van een combinatie van bovenstaande

Bovendien wordt gebruik gemaakt van een centraal object, de zogenaamde trigger channel, waar de verschillende adapters een relatie mee hebben, die wanneer gecommit wordt, een commit broadcast naar de verschillende gebufferde adapters, en de transactie een feit wordt.

Wat gebeurt er nu bij een transactie volgens deze architectuur? Laten we ervan uitgaan dat gebruik gemaakt wordt van een buffer doordat een werk-kopie van het object gemaakt wordt, en wanneer er een commit gegeven wordt deze kopie de oorspronkelijke persoon overschrijft.

Ten eerste is er een PersoonHolder, die een bepaald PersoonApp met een Persoon bevat die uit de database is gehaald. Deze PersoonApp heeft dus een relatie met een Persoon die geïnstantieerd is. Bovendien is er een kopie van deze persoon aanwezig, de werk-kopie.

Er bestaat altijd een user-interface die een relatie heeft met deze PersoonHolder. De PersoonHolder is een container voor een PersoonApp. Eventueel bevat de user-interface een geneste associatie met de PersoonApp (die de informatie heeft voor de user-interface). Wanneer de programmeeromgeving het mogelijk maakt om window-model combinaties te nesten is dit ideaal. Dan kunnen re-usable componenten gebouwd worden zowel voor de user-interface als voor de applicatie objecten.

De user-interface bevat een input field control waarin de naam van de persoon gewijzigd wordt. Dit resulteert in een wijziging van de werk-kopie van de Persoon. Wanneer de gebruiker op de OK button klikt, wordt een trigger geactiveerd die alle adapters die zich geregistreerd hebben als objecten geïnteresseerd in veranderingen van deze elementen. Dit resulteert in het updaten van de Persoon, en eventueel in een commit naar de database.

Samenvatting

De boven geschetste aanpak heeft een aantal voordelen. Er zijn echter ook nadelen.

  • Gehele of gedeeltelijke instantiatie van objecten is vaker nodig. Er zijn ook meer objecten in het werkgeheugen aanwezig, die ook geshared kunnen worden tussen applicatiemodellen (een gebruiker edit een project, opent een editor voor een inspectie, daarna van een bedrijf, etc.)
  • Er zullen meer abstracte classes in het object model komen. Een aantal van deze classes zal weinig gedrag bevatten (zgn. abstracte datatypes, bijvoorbeeld Persoonsnaam)

De voordelen zijn:

  • Eenvoudiger object model
  • Eenvoudiger communicatie tussen subsystemen (vanuit domein model via applicatiemodel naar user-interface en data-management)
  • Flexibeler systeem omdat uitbreiding met nieuwe domein objecten nauwelijks of geen uitbreiding behoeft van bestaande classes. Hierbij kan zelfs gebruik gemaakt worden van simpele zelfgemaakte tools om stukken code te genereren.
  • De code in veel methodes kan eenvoudiger. Deze zal korter worden doordat meer gedelegeerd wordt naar andere objecten.
  • Beheersing van commits, doordat deze op meerdere niveau’s plaats kunnen vinden
  • Verplaatsing van de business logica naar simpeler domein objecten
  • Er wordt een groot aantal generieke tot zeer generieke objecten gebouwd die herbruikbare componenten opleveren voor andere systemen

Geef een reactie

Deze website gebruikt Akismet om spam te verminderen. Bekijk hoe je reactie-gegevens worden verwerkt.


reflektis Logo
Over ons
Diensten

Copyright © 2019, reflektis & Rob Vens