Domain Driven Design met bootstrap delegatie

 
08 april 2008

Ik ben nu al een tijdje bezig om een library in elkaar te zetten die mij assisteert bij het opzetten van een project waar ik gebruik maak van Domain Driven Design. De library begint vorm te krijgen en zo ook de oplossing die ik hanteer voor het bootstrapping probleem dat bij DDD komt kijken.

Domain Driven Design
Lange ervaring met Domain Driven Design heb ik nog niet, ik heb net vorig jaar September de Masterclass DDD bij Sogyo afgerond.
Tijdens deze masterclass heb ik wel geleerd dat de genen van Domain Driven Design overeenkomen met mijn idee over coderen: alles willen ontkoppelen.
De cursus gaf mij dan ook de ‘push’ in de goede richting. Ik had al veel met Dependency Injection en Inversion of Control gewerkt (en legio andere patterns), maar alleen Domain Driven Design gaf mij tot nu toe een warm gevoel van binnen.

Bootstrapping
De Domain Driven Design voorbeelden die ik tot nu toe gezien heb hadden een redelijke forse bootstrapping nodig en waren allemaal gecentraliseerd. Dit betekent dat de bootstrapping over het algemeen dus plaats vind op het moment dat je applicatie start.
Ik wilde in mijn DDD voorbeeldapplicatie de bootstrapping mooi en elegant doen. Het liefst wilde ik dat de bootstrapping van mijn domei objecten automatisch ging, op het moment dat ik ze aanmaakte. Het volgende heb ik hiervoor gemaakt:

public abstract class DomainObject extends Observable {  

  public DomainObject() {
    DomainBootstapper.getInstance().bootstap(this);
  }

}

En warempel: het werkte! Wanneer ik nu een nieuw object instancïeer, deze vervolgens DomainObject extend, dan wordt deze automatisch gebootstrapped. Maar hoe kan ik het domein bootstrappen met dingen waar ik geen dependency op wil hebben?

Service Provider Interface
Ongeveer een jaar geleden ontdekte ik SPI: Service Provider Interface. Ik was meteen verkocht. SPI is een Java methodiek om libraries aan elkaar te knopen zonder een compile-time dependency te hebben. Wanneer je software is uitgerust met SPI, dan kunnen je classes gebruik maken van geïmplementeerde interfaces die de JVM vindt op het classpath. Wanneer de JVM niets vindt, betekent dat niet dat je programma meteen een foutmelding geeft, het betekent alleen dat je minder functionaliteit hebt (mits je alles goed geïmplementeerd hebt uiteraard).
Dit was dus mijn antwoord. Ik bedacht het volgende:

public interface DelegatedBootstrapper {
  public void wire(DomainObject object);
}

Elke library dat zichzelf wil bootstrappen kan deze interface implementeren en zichzelf kenbaar maken door middel van SPI aan het domein. Het domijn zal alle implementaties afgaan en elk object aanbieden door middel van de ‘wire’ methode.
Hieronder een voorbeeld van een ‘wire’ methode implementatie:

public void wire(DomainObject object) {

  if (object instanceof Customer) {

    CustomerDAO customerDAO = new CustomerDAO();
    InvokeAdapter invokeAdapter = new InvokeAdapter(new AspectAdapter(object, "modified"), this, "persist", Object.class);

    invokeAdapter.setArgument(customerDAO);

    new PushAdapter(new AspectAdapter(object, "firstName"), customerDAO, "firstName", String.class);
    new PushAdapter(new AspectAdapter(object, "lastName"), customerDAO, "lastName", String.class);
    new PushAdapter(new AspectAdapter(object, "accountName"), customerDAO, "accountName", String.class);
    new PushAdapter(new AspectAdapter(object, "password"), customerDAO, "password", String.class);
  }
}

public void persist(Object object) {

  Session session = getSessionFactory().getCurrentSession();
  Transaction transaction = session.beginTransaction();
  try {
    session.saveOrUpdate(object);
    transaction.commit();
  }
  catch (Exception e) {
    transaction.rollback();
    throw e;
  }
}

Even een kleine uitleg bij deze code: Als er een Customer object wordt aangeboden om te verbinden dan wordt er een nieuwe CustomerDAO aangemaakt. Als er wijzigingen plaatsvinden op Customer dan komen deze in de CustomerDAO terecht. Op het moment dat ‘persist’ word aangeroepen (intern het zetten van ‘modified’ op ‘true’) dan wordt CustomerDAO gepushed naar de ‘persist’ method (via de InvokeAdapter) op het ‘this’ object: oftewel de persist methode er onder.

Implementatie
Mijn DelagatedBootstrapper methodiek is uiteraard een van de vele en zal wel de nodige reacties uitlokken bij mensen die vinden dat dit niet puur genoeg is. Zelf zag ik geen andere methode om dit mooi en zo puur mogelijk te implementeren zonder dat het al te abstract/ingewikkeld werd. Bruikbaarheid en toepasbaarheid is tenslotte ook belangrijk.
Dit is dan ook de reden dat ik mijn ‘theorie’ wil gaan bewijzen door middel van een PetStore demo applicatie. De code voorbeelden zijn dan ook uit deze applicatie. Als hij af is dan zal ik dit kenbaar en beschikbaar maken op deze blog.


Werken met ?
Kijk dan bij onze mogelijkheden voor starters en/of ervaren IT'ers.


Categorieën: Architectuur, Development, Java (EE)

Tags: , , ,


Reactie

  • David Perfors schreef:

    Dit is erg interesant. Ook voor mij is het bootstrappen een moeilijk punt geweest in DDD. Een ander punt waar ik moeite mee had is hoe dingen als GUI en persistence gekoppeld worden aan domain objecten. Deze methode kan ook daar goed van te pas komen denk ik.

    Ik kijk uit naar de demo.

    Geplaatst op 09 april 2008 om 10:37 Permalink