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
}
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.