1

one aspect of AggregateRoots with children is not 100% clear to me. And I also found no complete example via Google.

Let's say I have an AggregateRoot "Customer". A customer can have multible projects.

I already learned that I have just one AggregateRoot "customer" and project is no Root, so far so good.

public class Customer : AggregateRoot
{
    private List<Project> _projects { get;set; }

    public void AddProject(Guid id, string name, int budget)
    {
        ?
    }
}

I have a few small questions.

  1. Is Project an Aggregate (Just no root) or just an POCO class?
    • Important for applying the state and what to save in the event store
  2. I have the business rule that projects per customer have a unique name.
    • Where is this business rule, inside the Customer or inside the Project?
  3. Does my command have the name "AddProject" and exist in the Customer namespace or "CreateProject" and exist in the Project namespace which then loads the customer aggregate in the background and executes "AddProject" on the customer aggregate?

Kind regards

SharpNoiZy
  • 1,099
  • 2
  • 11
  • 22

3 Answers3

2

Is Project an Aggregate (Just no root) or just an POCO class?

Well it looks like an Entity as you are passing in an ID when adding one.

I have the business rule that projects per customer have a unique name. Where is this business rule, inside the Customer or inside the Project?

The aggregate exists to enforce consistency and invariants inside it, so the concept of uniqueness per customer has to live inside the Customer. When someone tries to add a Project to the Customer, this rules needs to be enforced, and only the Customer knows what other projects it has.

Does my command have the name "AddProject" and exist in the Customer namespace or "CreateProject" and exist in the Project namespace

Same as above - this logic needs to live inside the Customer in order to enforce the business rule of uniqueness for the project names.

tomliversidge
  • 2,339
  • 1
  • 15
  • 15
1

Is Project an Aggregate (Just no root) or just an POCO class?

It's both an Entity and a POCO. POCO just means that your class is bare metal C# and not tainted by data access or infrastructure library stuff. Aggregate Roots are POCOs too.

Project is not an AR since it already lives under the Customer AR.

I have the business rule that projects per customer have a unique name. Where is this business rule, inside the Customer or inside the Project?

"Per customer" clearly indicates a customer-wide invariant, so it concerns the Customer aggregate. Aggregate invariants are enforced by the Aggregate Root - class Customer in this case.

Does my command have the name "AddProject" and exist in the Customer namespace or "CreateProject" and exist in the Project namespace which then loads the customer aggregate in the background and executes "AddProject" on the customer aggregate

First, don't confuse namespaces with domain model design. Namespacing doesn't really come into play when determining which domain object has which method. It's actually common to see entire domain layers with a single namespace.

Namespaces are a more or less blurry reflection of the organization of your code, not the organization itself.

That being said, I've seen implementations where Commands were either

  • in the Domain layer

or

  • in the Application layer.

Also, since Commands are per-Aggregate, it can make sense to add a sub-namespace for each Aggregate.

Concretely, it would mean something like

YourApplication.Application.Commands[.Customer].AddProject

or

YourApplication.Domain.Commands[.Customer].AddProject

guillaume31
  • 13,738
  • 1
  • 32
  • 51
  • Thanks for your long answer! Your namespace suggestion taken further would mean for queries: YourApplication.Domain.Queries[.Project].GetProjectByName Or also YourApplication.Domain.Queries[.Customer].GetProjectByName – SharpNoiZy Jan 31 '17 at 14:29
  • No, the namespace for queries shouldn't have anything to do with the domain at all. Command Query Responsibility Segregation. It's the essence of CQRS. I have a blog post with an overview of a typical CQRS architecture. You can find it [here](http://danielwhittaker.me/2014/10/02/cqrs-step-step-guide-flow-typical-application/) – Codescribler Feb 01 '17 at 09:28
0

An aggregate root shouldn't contain another aggregate root. So Project should be just an entity withing the Customer aggregate root. As for the rule apparently I'd place it at Project level because in order to check this rule you'll need to have access to other Projects inside the the single customer which shouldn't be a responsibility of Project entity as it shouldn't "know" about a way how it's kept or referenced by other entities.

Dmytro Mukalov
  • 1,949
  • 1
  • 9
  • 14
  • Thank you for your answer. I think you mean on your third sentence "at Customer level", correct? And I add a third question to my post, maybe you can give your opinion to that one also? – SharpNoiZy Jan 31 '17 at 10:46
  • Yeah, sorry I meant Customer level. As for the commands it depends on the semantic which level should these command exist on but definitely not on the Project level as again both commands suppose modification of some state which references Project but at the same time Project shouldn't be aware about the state structure or even its existence. – Dmytro Mukalov Jan 31 '17 at 14:28