Search code examples
domain-driven-design

Do repositories break the rule of DDD?


The repositories layer in a project will need to create an instance of the aggregate root so it can reuse the data its stores, and return an instance of the aggregate toot yes?

If so... this means the aggregate root client (the other developers working on service layer maybe) can use the same functionality used by the repository layer to create their own version of the aggregate root (break the idea of encapsulation) ... I know they should not but how the aggregate root boundaries rules are not broken if such functionality exists and is there any way to enforce the client behavior.

I created an aggregate root that encapsulates the behavior and the data contained inside its boundaries, this aggregate root provided a factory for the code client to create a new instance of this aggregate root where default values are initialized, and input are validated.

Now I noticed that the factory I created is not enough for the repository since it need to provide more specific information (related to the entities and the value object the aggregate use's).

Code example, you can see the repository cannot use the factory func New since it initializes ID and date (maybe other) every time and creating another factory is not a solution since it can be abused by the client.

// customer-aggregate.go


// customer struct/class
// private accessible only with in the namespace
type customer struct {
    user  entities.User
    date  time.Time
    "....etc"
}

// customer factory, return new instance of customer
// validate errors and initiate the internal data (ID and date maybe other)
func New(name, ...etc) (customer, error){
    if name != "" {
        // validate name and other input if needed
    }
    
    user := &entities.User{
        ID:    uuid.New(),
        Name: name
        "...etc"
    }

    return &customer{user, time.Now()}, nil
}


Solution

  • The repositories layer in a project will need to create an instance of the aggregate root so it can reuse the data its stores, and return an instance of the aggregate toot yes?

    Repository is a facade pattern: it affords the illusion that there is an in memory collection of aggregates. In other words, we're hiding from the clients the details of where aggregates come from.

    If your repository is separately packaged from the methods it needs to implement that illusion, then yes; other code will also be able to access those methods to create transient representations of aggregates.

    For instance, a repository implementation might have a runtime dependency on a factory that accepts general purpose data structures as inputs and returns an instance of a "root" entity.

    It's fairly common to have implementations of client code that use published methods to create transient instances of aggregates, and then "store" those instances within the repository.

    This isn't a violation of any "rules" of DDD. (DDD doesn't really have "rules", as such - it has "patterns", which flex a bit when context requires it. Chapters 5 and 6 of the "blue book" describe patterns, not rules.)

    That said, yes: many programming languages only afford coarse grained access control for packages. If people using public/published methods that they shouldn't is a significant problem, then you need to other countermeasures to address the problem.