2

If have the following Code.

public class CountryFactory : IEntityFactory
{
    private readonly IRepository<Country> countryRepository;

    public CountryFactory(IRepository<Country> countryRepository)
    {
        this.countryRepository = countryRepository;
    }

    public Country CreateCountry(string name)
    {
        if (countryRepository.FindAll().Any(c => c.Name == name))
        {
            throw new ArgumentException("There is already a country with that name!");
        }

        return new Country(name);
    }
}

From a DDD approach, is the the correct way to create a Country. Or is it better to have a CountryService which checks whether or not a country exists, then if it does not, just call the factory to return a new entity. This will then mean that the service will be responsible of persisting the Entity rather than the Factory.

I'm a bit confused as to where the responsibility should lay. Especially if more complex entities needs to be created which is not as simple as creating a country.

Shane van Wyk
  • 1,870
  • 1
  • 26
  • 62
  • 1
    I think the problem might come from the vocabulary you are using. That *create* method is actually a find with a default value if it doesn't exist... it's not really a *create*... and as such I find it difficult to think that it's part of a ubiquitous language. I find it difficult to say anything else without knowing how that entity is used and what is related to, as sometimes the logic might be in a domain service, an application service, a factory, a repository or just a *new instance* depending on the situation. – Augusto Mar 04 '16 at 01:30
  • 1
    Well I really need to know if it is valid / good practice to Inject a repo into a Factory. And does all entities have factories that create them. It really comes down do, Do I create an entity based on what is persisted, or create the entity, try to persist it and worry if it errors then. – Shane van Wyk Mar 04 '16 at 01:43

2 Answers2

3

In DDD factories are used to encapsulate complex objects and aggregates creation. Usually, factories are not implemented as separate classes but rather static methods on the aggregate root class that returns the new aggregate.

Factory methods are better suited than constructors since you might need to have technical constructors for serialization purposes and var x = new Country(name) has very little meaning inside your Ubiquitous Language. What does it mean? Why do you need a name when you create a country? Do you really create countries, how often new countries appear, do you even need to model this process? All these questions arise if you start thinking about your model and ubiquitous language besides tactical pattern.

Factories must return valid objects (i.e. aggregates), checking all invariants inside it, but not outside. Factory might receive services and repositories as parameters but this is also not very common. Normally, you have an application service or command handler that does some validations and then creates a new aggregate using the factory method and adds it to the repository.

There is also a good answer by Lev Gorodinski here Factory Pattern where should this live in DDD?

Besides, implementation of Factories is extensively described in Chapter 11 of the Red Book.

Community
  • 1
  • 1
Alexey Zimarev
  • 17,944
  • 2
  • 55
  • 83
1

Injecting a Repository into a Factory is OK, but it shouldn't be your first concern. The starting point should be : what kind of consistency does your business domain require ?

By checking Country name uniqueness in CountryFactory which is part of your Domain layer, you give yourself the impression that the countries will always be consistent. But the only aggregate is Country and since there is no AllCountries aggregate to act as a consistency boundary, respect of this invariant will not be guaranteed. Somebody could always sneak in a new Country that has exactly the same name as the one being added, just after you checked it. What you could do is wrap the CreateCountry operation into a transaction that would lock the entire set of Countries (and thus the entire table if you use an RDBMS) but this would hurt concurrency.

There are other options to consider.

  • Why not leverage a database unique constraint to enforce the Country name invariant ? As a complement, you could also have another checkpoint at the UI level to warn the user that the country name they typed in is already taken. This would necessitate another "query" service that just calls CountryRepository.GetByName() but where the returned Countries are not expected to be modified.

    Soon you'll be realizing that there are really two kinds of models - ones that can give you some domain data at a given moment in time so that you can display it on a user interface, and ones that expose operations (AddCountry) and will guarantee that domain invariants always hold. This is a first step towards CQRS.

  • What is the frequency of Countries being added or modified ? If it is that high, do we really need a Country name to be unique at all times ? Wouldn't it solve a lot of problems if we loosened up the constraints and allowed a user to temporarily create a duplicate Country name ? A mechanism could detect the duplicates later on and take a compensating action, putting the newly added Country on hold and reaching out to the user to ask them to change the name. A.k.a eventual consistency instead of immediate consistency.

  • Does Country need to be an Aggregate ? What would be the cost if it was a Value Object and duplicated in each entity where it is used ?

Community
  • 1
  • 1
guillaume31
  • 13,738
  • 1
  • 32
  • 51
  • @Shane Van Wyk have you figured it out eventually? I got guillaume31's point on domain entity invariant, but still how should it be handled when the unique constraint is needed and there's no way to make it a Value Object? – Sergio Jun 26 '17 at 01:22