[TYPO3-50-general] FLOW3 and DDD

Nino Martincevic don at zampano.com
Mon Jan 19 16:02:15 CET 2009


Ok Robert, here are some further thoughts on this...

Robert Lemke schrieb:
> There can be Domain Objects without connection to the repository which  
> are then not persisted. I call them "Transient Entities".

That was somehow misunderstood. Entities have no "connection" to a 
repository but are maintained, i.e. generally queried and in 
circumstances saved, by it. They should not know nothing about the 
existence of a repository, they just "are" (although there are dicussion 
about entities calling repositories...).

And in the domain model the question is: Who does create them?
(see below example of form)

> Do you've got a copy of Jimmy Nilsson's "Applying Domain-Driven Design
> and Patterns"? Check out p. 281, the table which gives a summary of
> the Semantics for the Life Cycle of Domain Model instances.

I have this book and have read it.
And I know of transient entities but in the following example you forgot 
to mention some details.

> $customer = new Customer;            // $customer is a Transient Entity
 > $customerRepository->add($customer); // $customer added to the
 > repository
 > $persistenceManager->persistAll();   // $customer becomes a Persisted
 > Entity
 >
 > $address = new Address;              // $address is transient
 > $customer->setAddress($address);     // $address now has connection to a
 >                                          repository through the
 > Customer Aggregate
 >
 > $persistenceManager->persistAll();   // $address will be persisted

(Sorry be being a little too extensive or sounding educational here, I 
noticed that you are firm with the material, sure you are. But perhaps 
people are reading this thread anyway, not that firm with DDD concepts 
but willing to learn some terms of it and get some more information out 
of it)

Creating an entity Customer without identity is simply not possible.
An entity without identity is a paradoxon. It may be a prototype or 
something else but not "the" domain object.

You forgot to mention that in Nilsson example there is only "create 
new", but create new Customer means create one with clear identity.
Without it: how can you add it to the repository when you don't know its 
identity, how will you get it back? Therefore you first have to check if 
one with that identity exists (via a repository).

And the address in that example is perhaps a value object.
If it were a entity, you also would first check its existence through an 
repository. If it does not exist you would create a new valid one.
Then you can even persist a few steps later.

So, the example should read:
$customer = new Customer(12345); // where 12345 is the identity, 
something like UUID
($addressRepository->find(bla, blub);)
none found
$address = new Address(bla, blub); // again "bla/blub" is identity
$customer->setAdress($adress);
$customerRepository->add($customer);
$persistenceManager->persistAll();

[Btw: that's a point where two sentiments exist and most of the DDD-guys 
I know tend to say that there cannot be an "invalid" entity. It has to 
be created with full identity.]

The goal of repository is to avoid entities with same identity at any 
price - there are simply not two identical entities in the system, they 
never have a copy.
Without a repository you could create two identical objects that would 
exist separately and you'll have a bunch of trouble, not at least at 
persistion time.

> Yes, for example you'll want to create a Customer object without  
> persisting
> it until it's valid. Imagine a multi step form which carries a  
> Customer in
> a session until the form is finally submitted.

That's perhaps the problem!?
This example would never be possible in an isolated layer and especially 
not in the domain model, never. This is domain leaking into application, 
that should be avoided by any circumstances.

If by "until it's valid" you don't only mean some of its attributes, 
that's fine. But if it is the identity that would mean you already have 
it persisted, how would you else know (if it is in memory or db) it?
E.g. username is the identity (stupid example). For creating new 
customers you have to check if no other with the same username exists 
and to reserve it you'd had to persist it (or check again if you want to 
do it later by risking that it throws an exception).

A form is not part of the domain, it's application. And in the 
application you can create 100 identical customers but when it comes to 
put them into the domain (for persistance or not) you only have one 
choice and one way. And this gatekeeper will only store the first one, 
the other forms will get an exception.
You can do it this way, of course (two people could try to register with 
same identity) but you would only have one, and only one, responsible 
place to check the identity and then add it to the repository.
Mostly this is done by some kind of gateway, facade etc., depending on 
you domain.

As I re-read this I think we both know what the problem is.
And perhaps it isn't really one:

The second method ($customerRepository->add($customer)) should be 
impossible because Customer is not a valid entity.
But that's primarly not the problem of Flow3 but of the developer.
This would throw at least an exception.

IMHO Flow3 should have these constraint:
Never save invalid Entities to the repository, i.e. they must have at 
least identity set.
Is that already provided? If not, that would not be much work, would it?
But that's your problem :-)

Nino






More information about the TYPO3-project-5_0-general mailing list