Object Identity

 
06 juli 2008

Iets dat in de meeste platformen heden ten dage op het eerste gezicht goed geregeld is is het concept van object identity. In feite is dit onder water de pointer die we toewijzen (reference) aan bijvoorbeeld variabelen in onze code. Een object bevindt zich op een bepaalde plaats in het geheugen en dat is daarmee zijn unieke identificatie. Dit wordt voor je geregeld door respectievelijk een JVM of CLR of welke andere omgeving je maar mee werkt; het enige dat je moet beseffen is dat je als je echt OO bezig bent alleen referenties naar de objectstructuren heen en weer stuurt.

Lastiger wordt het als je je objecten op zeker moment uit je geheugen gaat halen om bijvoorbeeld op te slaan op disk of over een lijn te sturen in een gedistribueert systeem. Objecten zijn op verschillende manieren te ‘serialiseren’, d.w.z. platslaan om uit het geheugen te transporteren naar een andere omgeving. Dat kan een webpagina zijn maar ook een file of een database. De weg terug, de-serialiseren, maakt dat ik binnengekomen gegevens weer kan opblazen tot objecten die zich in het geheugen bevinden.
Ook dit soort scenario’s worden door resp. .NET en Java EE/SE prima ondersteunt, dat wil zeggen als ik mijn volledige objectboom vanuit mijn geheugen naar disk schrijf via zgn. binaire serialisatie. Alle referenties worden in dit proces keurig meegenomen zodat ik mijn volledige image kan wegschrijven en op later moment kan ophalen.

Lastiger wordt het als het om delen van de boom gaat; immers als ik bijvoorbeeld van een webpagina een geserialiseerd object terugkrijg hoe weet ik dan waar ik hem in de boom moet hangen? Of hetzelfde scenario van en naar databases, hetgeen overigens ook bij O/R mapping vaak voorkomt?

In mijn optiek is het in vrijwel alle gevallen van serieuze software ontwikkeling nodig om zelf zicht te kunnen houden van de identity van een object. Je wilt in verschillende contexten altijd kunnen weten om welke unieke instantie van je businessobject het gaat. Een veel gebruikt pattern ook door fowler omschreven is Identity Field. Vaak genoemd in de context van O/R mapping, maar in mijn optiek is identity veel meer iets dat centraal in je business logica geregeld moet worden. Immers, wie zegt dat je een database gebruikt in je systeem?

Ok, hoe implementeer je dat nou. Mijn voorkeur gaat uit naar een layer supertype waar je je businessobjecten van laat overerven. In principe is dit codefragment ongeveer universeel toepasbaar:

Guid id;
public Guid Id
{
     get {
          if(id==Guid.Empty)
               id = Guid.NewGuid();
          return id;
     }
     set {
          id = value;
     }
}

Andere benaderingen zijn die van geen gebruik van setter maar een constructor voor ‘bestaande’ objecten (eentje met parameter Id dus) en eentje voor nieuwe objecten die zelf een Id genereert. Afhankelijk van je O/R bridging strategie zou je een van beide kunnen kiezen. De bovenstaande werkt in elk geval goed met bijvoorbeeld NHibernate – gebruikmakend van property access. Als je field level access kiest dan zou je de setter weg kunnen laten (hetgeen in principe ook mooier is natuurlijk).

Onderwerpen die hier op volgen zijn equality en hashcodes, twee onderwerpen die sterk samenhangen met uniek identificeren van objecten in bepaalde contexten. Voor nu ben ik erg benieuwd naar ervaringen van anderen op dit gebied; hoe ga jij om met identity van je businessobjecten?


Werken met ?
Kijk dan bij onze mogelijkheden voor zowel starters als ervaren engineers.


Categorieën: Architectuur, Development

Tags: , , , , ,


Reacties (3)

  • Ivo Limmen schreef:

    Een GUID kan ook goed gebruikt worden om je data te beveiligen. Zo moest ik een (lange) tijd geleden een account validatie inbouwen bij een publieke website. Om je email te verifiëren staat er in het verstuurde email een link naar de website. In deze link kan uiteraard niet komen te staan: http://www.domijn.nl/VerifyEmail.html?id=5. Een GUID is dan erg handig en niet te gokken.
    Een GUID zal ook mensen ontmoedigen om te proberen om andere gegevens op het scherm te krijgen waar men normaal gesproken geen toegang tot hebben.

    Geplaatst op 16 juli 2008 om 19:11 Permalink

  • Stefan,

    Een interessante resource over GUIDs in databases is deze:
    http://www.sql-server-performance.com/articles/per/guid_performance_p1.aspx

    Wat dus hoofdzakelijk een bottleneck geeft is grote hoeveelheden inserts als je een newid() gebruikt om ze op de database te laten genereren. De tweede downside is afmeting van je database (Guids nemen meer plaats in dan integers) maar verder valt het qua indexering dus heel erg mee…

    Dat Guids wat lastig communiceren kan ik inkomen, maar getallen boven een miljoen zijn ook lastig en zouden in principe afgeschermd moeten zijn van (eind) gebruikers…

    Geplaatst op 16 juli 2008 om 16:22 Permalink

  • Stefan Bookholt schreef:

    Als je met grote hoeveelheden objecten gaat werken is het vaak performance-technisch niet handig guids te gebruiken. Guids zijn namelijk lastig te indexeren voor een computer. Een ander bezwaar is dat je guids niet kan gebruiken als recordnummer waar klanten mee kunnen werken. Het is lastig om tegen je collega te zeggen of hij wil kijken naar record 1FE17A3E-88B9-4bfe-BB42-D082FC2156CB. Om die twee redenen zou ik gaan voor integers. Het probleem is alleen wie die gaat uitgeven. Dat zal de centrale server moeten doen, dan heb je wel een uitdaging met offline werken.

    Geplaatst op 08 juli 2008 om 17:09 Permalink

Trackback & Pingback (1)

  1. Van While True » Blog Archive » O/Ado Mapping op 14 juli 2008 at 21:04

    […] are required to be of an IIdentifyable type. In this way we can map using the Id value (also see this Dutch blogpost). A depth for mapping object trees can be given in the GetDataSet() method so circulairities can be […]