Re: Why can't each Aggregate Root have its own collections of entities/ARs?

Simon Fox <[email protected]>
Newsgroups gmane.comp.programming.domain-driven-design
Message-ID <CANxHNgEGDiUKjOZEsX+FkwbzNkbinJ3rme_eHxD7t_+KYNFJGw@mail.gmail.com>
Hi Jorge

Totally understand what your saying around the simplification, and I
suppose my answer in response to "the example actually clearly exemplifies
the crux of my question -- my lack of understanding of the advantages of
replacing multiple-instance-collections (the "standard") by
singleton-system-repositories"
is that there is no advantage in the example you have given.

However, you have stated that the entities in your example are ARs of your
system which implies that they are responsible for some sort of business
process in your system. Fowler's definition of Domain Model talks about
complicated and ever changing business rules, involving validation,
calculations and derivations and so far your example doesn't have any of
that and so I would argue that it is not a Domain Model at all. If the
number of continents that belong to a world is a piece of data that the
World AR requires to perform it's responsibilities then that is potentially
all that needs to be maintained by the World AR and it can be kept valid
through subscription to events like ContinentAddedToWorld and
ContinentRemovedFromWorld
that are published by the Continent AR.

Now if you take that further and say that a World needs to know how many
Countries each Continent has to perform it's responsibilities, the only
data that the World AR needs to hold is a map of ContinentID to Country
count, again maintained via domain events.

I still don't think I've really answered your question, but hopefully I've
sort of clarified my point around your question being hard to answer with
the given example.

Cheers
Simon

/*
Email: [email protected]
Twitter: @simonmfox
*/


On 28 August 2013 20:13, Jorge Branco <[email protected]> wrote:

> **
>
>
> Hi all,
>
> I recognize there are several factors at play here. DDD is generally
> applicable to large and complex domains. I am well aware that simple
> examples, as the depicted on the original post, may look odd because they
> are just that -- examples, and that in the real-world, large scaled
> application patterns here looking awkwardly convoluted may reveal
> themselves quite satisfactory. Yet...
>
> I'll try to answer your comments/questions and I'll throw a couple of
> ideas back into the pool, hoping we don't end up with circular arguments in
> the way :)
>
> @ Simon
>
> I think you probably need to think more about the behaviour of the system.
>> You have described a data model that is a representation of the actual
>> world, but does that actually support the behaviour you would like the
>> system to display/implement? Once you have created the web of objects as
>> described, what do you actually want to do with it?
>
>
> I was actually wittingly stripping out the most I could as I was a bit
> afraid a more complex example would fall in the category of TL;DR. Although
> a more mature model would undeniably lead to a more fruitful discussion, it
> would also raise the bar to anyone reading it. IMO the example actually
> clearly exemplifies the crux of my question -- my lack of understanding of
> the advantages of replacing multiple-instance-collections (the "standard")
> by singleton-system-repositories (in which all the World instances in the
> system are kept/persisted behind a single instance of a WorldRepository).
> This is more of a tactical pattern issue than a strategic one. I believe my
> described solution to be generally in full agreement with the basic
> DDD tenet -- and that's why I find it particularly disconcerting not to
> find a single example on the web in accord with it. It makes me think I
> must be missing something..
>
> I'll try to illustrate my point again with some more code:
>
> //definition
> class World {
>   private String name;
>   private IContinentRepository continents;
>
>    public World(String name, IContinentRepository continents) {
>     this.name = name;
>     this.continents = continents;
>   }
>
>   void addContinent(Continent continent) {
>     continents.add(continent);
>   }
>
>   ...
> }
>
> interface IContinentRepository {
>   void add(Continent continent);
>   Continent continentNamed(String continentName);
>   void remove(String continentName);
>   Set<Continent> allContinents();
>   int size();
> }
>
> //usage
> IContinentRepository continentRepository = new
> InMemoryContinentRepository();
> World world = new World("earth", continentRepository);
> world.addContinent(new Continent(...));
>
>
> This is a basic example, devoid of a lot of details. But the idea is that
> instead of having a single ContinentRepository in our system, we'll have
> one per World instance. From some preliminary tests, I acknowledge this may
> yield a generally more complex repository implementation than the "vanilla"
> Repository pattern seen elsewhere.
>
> @Mauro:
>
> using( var universe = repositoryFactory.BigBang() )
>> {
>>     var world = worldFactory.CreateNewWorld();
>>     var continent = continentsFactory.CreateContinent();
>>     world.AddContinent( continent.ContinentId );
>>
>>     universe.Store( world );
>>     universe.Store( continent );
>>     universe.CommitChanges() );  //here the universe raises events that
>> allows the creation of the read model
>> }
>
>
> My "distress" with the example is the major undertaking involved -- 3
> factories -- bearing no clear advantage in the process (occam's razor). I
> may be missing something, though. Plus, as originally stated, the world in
> your example has continents -- their primary id, but to actually make
> something with them, for instance, to know how many continents a given
> world has, you'll need to *know* some outside class -- a repo, a domain
> service.
>
> Getting the number of continents from a World object in my example would
> only require a simple
>
> int numberOfContinents = world.numberOfContinents();
>
>
> implemented as
>
> public int numberOfContinents() {
>   return continents.size();
> }
>
>
> I'm curious as of how you'd get the number of continents given a world
> instance. Would you put that logic in the ContinentRepository? In the
> WorldRepository? In a service? In the World class, passing a repository as
> argument?
>
> @Tom:
>
> I understand the motivation of Vernon of choosing the disconnected
>> implementation, but I whole heartily agree with your statements that the
>> natural usage of the domain model is getting impaired.
>
>
> So it's not only me, lol.
>
>
>> In my insight Vernon chooses this approach to allow dynamic scaling from
>> simple DB to distributed storage like Cassandra, by implementing the model
>> already suited for distributed storage.
>
>
> I was expecting some kind of answer in this line. I assumed that a lot of
> what I saw in Vernon's book was done targeting that kind of technologies
> (that I do not use at the moment, and that I do not foresee to be using in
> a near future) but I was yet waiting for a confirmation.
>
>
>> Personally I feel not many systems will ever need that level of storage,
>> so I'm inclined to keep my model more "sane". The same goes for the amount
>> of usage of events; inter-domain, yes. Intra-domain; not if I can avoid it.
>
>
> That makes a lot of sense. That's my case in point, I believe.
>
> jorge
>
>
>
>
>
> On Wed, Aug 28, 2013 at 6:44 AM, Tom Eugelink <[email protected]> wrote:
>
>> **
>>
>>
>> I understand the motivation of Vernon of choosing the disconnected
>> implementation, but I whole heartily agree with your statements that the
>> natural usage of the domain model is getting impaired. In my insight Vernon
>> chooses this approach to allow dynamic scaling from simple DB to
>> distributed storage like Cassandra, by implementing the model already
>> suited for distributed storage. Personally I feel not many systems will
>> ever need that level of storage, so I'm inclined to keep my model more
>> "sane". The same goes for the amount of usage of events; inter-domain, yes.
>> Intra-domain; not if I can avoid it.
>>
>> Tom
>>
>>
>>
>>
>> On 2013-08-27 04:57, jorgedfbranco wrote:
>>
>>
>> Consider the following context:
>>
>>  A World(Entity) has Continents. A Continent(Entity) has Countries. A
>> Country has Cities(Entity). Let's for the sake of argument assume there are
>> invariants involved for each one of the referred entities. As such, they
>> are not only entities but ARs as well.
>>
>>  Were I asked in a standard OO course to implement the classes that
>> model the shown text, and I'd write the following:
>>
>>  class World {
>>   String name; //identifies this entity globally
>>   Set<Continent> continents = new Set<Continent>();
>>   ...
>> }
>>
>>  class Continent {
>>   String name; //identifies the continent uniquely in a world context
>>   Set<Country> countries = new Set<Country>();
>>   ...
>> }
>>
>>  etc
>>
>> **
>> **
>> Using this code is as simple as
>>
>>  Continent europe = new Continent("Europe");
>> europe.addCountry(new Country("Germany"));
>>  europe.addCountry(new Country("Poland"));
>>  World world = new World("Earth");
>> world.addContinent(europe);
>>
>>
>>  Now, from what I've gathered from Eric's and Vernon's book, though, is
>> that I should replace this kind of design by one in which instead of having
>> each Entity class have its own collections of child entities, to have a
>> Repository by Aggregate Root type. I'd then have something of the like of
>>
>>    class World {
>>     String name; //identifier globally
>>     Set<ContinentId> continents = new Set<ContinentId>(); //ContinentId
>> is a wrapper of a string
>>     ...
>>   }
>>
>>  class ContinentRepository {
>>   ...
>> }
>>
>>  etc
>>
>>
>>  This IMO raises a couple of issues:
>>
>>    1. It obscures the code.
>>    2. Entities transversion stops being possible without using an
>>    outside class (that, or each Entity must either have repositories injected
>>    or have its much needed repositories set as static singletons). That
>>    outside class may either be a Repository or a Domain Service.
>>    3. Something as simple as adding a Country to a Continent will now
>>    need a Domain Service or a Repository, as Continent doesn't have what it
>>    takes to do the task at hand.
>>    4. Shouldn't we strive for a architecture-neutral domain
>>    implementation? Just looking at these centralized repositories (instead of
>>    one collection by each entity object instan ce at runtime) makes me thing
>>    of a database-oriented application.
>>
>> When first reading about DDD's repositories, I got the impression they
>> would be nothing more than an abstraction of a collection. But from what I
>> gather from the examples abounding on the web and on Vernon's book, they
>> sure seem more like an abstraction of a *singleton* collection. I call them
>> singleton collections because in reality there is only one per type on a
>> given system (there's always only a CountryRepository in memory! Only a
>> ContinentRepository in memory!).
>>
>>   I'm at the moment quite confused on the matter. It almost seems as all
>> the examples I see regarding DDD are database(sql/nosql)-oriented , which
>> is acceptable as that is the norm, but some of us work on "purer" grounds
>> where no database is involved. What is really the problem with my initial
>> bit of code?
>>
>>
>>
>  
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.