A Network is composed of Nodes that are connected with Fibers. The Network is responsible for making sure that:
both ends of any fiber are connected to a Node;
that no two ends are connected to the same Node;
that no two nodes can be in the same (x, y) location;
a network has a limit of 10 nodes and 10 fibers.
Both the Network, the Node and the Fiber are information-rich (they have a name, a date when they were deployed, etc), and it looks to me as if Network is an Aggregate Root (as its the container of both Nodes and Fibers and forces invariants between them).
I'm at this point also sure that Node and Fiber are entities, and that they are also probably Aggregate Roots.
One possible implementation of the Network class might be as follows:
class Network {
private final NetworkId id;
private String name;
private Location location;
...
private final Map<FiberId, Fiber> fibers = new HashMap<FiberId, Fiber>();
private final Map<NodeId, Fiber> nodes = new HashMap<NodeId, Node>();
}
which poses a big problem if my use case is just to edit the location or the name of the Network. In that case I just don't care about fibers and nodes and realistically, it is expected them to be quite possible for their numbers to be on the order of 10k-100k nodes/fibers!
How should I approach this issue? Should I separate the definition of a Network (containing fibers and nodes and their invariants) from the rest of the fields?
I've always thought of Aggregate Roots as Entities that have a set of invariants to hold over its attributes, in contrast with Entities that just don't care abouts the state of their attributes (for instance, a Person defined with a name and age wouldn't probably need to have any kind of checking for invalid combinations of name and age).
Following this philosophy, I generally tend to decide whether some domain concept is either a Value, Entity, Value or Event and then if it's an Entity, if it's an Aggregate Root. Is my assumption flawed?
Thanks
First of all, don't waste time thinking which is an entity or value objects. Technical details like this come up by themselves. The important thing is to model correctly the concepts. So, what does the domain understand by Network? Is it the container of Nodes or Fibes or itself a logical unit?
Can you have a network without any Node or Fibe? Can an empty Network exists in the domain? Does the Network contains Node and Fibe or the Node and Fibe are organized (grouped by) in a Network? You have to determine if a collection of Node or Fibe really define a network i.e you simply can't have a valid Network concept without those concepts.
Also it does matter the bounded context, the Network concept is specific to one context, it might look a bit different in other context. There is no one single Model valid everywhere. So, in what context are you defining the Network? You need to define only things relevant to THAT context not everything that might be part of Network at some point.
Don't do DDD as a recipe, looking for technical patterns to identify an aggregate root (AR). Do it organically, just try to design the model according to the specific domain context. You'll know when something is an AR not only an entity.
As a thumb rule, an AR is not a container it's still a domain concept which happens to act as a facade for other related concepts.
What about delegate the invariant protection to smaller aggregate root?
1.both ends of any fiber are connected to a Node;
2.that no two ends are connected to the same Node;
I think these two could be protected by Fiber. While this one below is kind of tricky, a simple solution is to use database constraint on the location.
3.that no two nodes can be in the same (x, y) location.
Then the network is just an aggregate root with identity and some information.
Related
I researched about repositories in DDD and found too much different thing. Everyone says different things about repositories and that made me confused.
I want to know:
What methods should repositories contain?
What should repositories definitely (or closer that) return?
Thanks.
For each aggregate root (AR) you should have a repository. As a minimum the repository would probably have a void Save(Aggregate aggregate) and a Aggregate Get(Guid id) method. The returned aggregate would always be fully constituted.
I sometimes add methods for specific use cases in order to update only certain bits of data. For instance, something like void Activate(Guid id) or some such. This is simply to avoid manipulating more data than is necessary.
Querying on a repository is usually problematic since you should typically avoid querying your domain. For such scenarios my recommendation is to use a query mechanism that is closer to the data and in a more raw format than a domain object or object graph. The query mechanism would more-then-likely return primitives, such as int Count(Query.Specification specification) or perhaps return a list of read model instances.
You are right, a repository has different meanings in different contexts - and many authors have their own interpretation. The way I understand them is from multiple perspectives:
They abstract away underline storage type
They can introduce interface closer to the domain model
They represent a collection of objects and thus serve as aggregate
in-memory storage(collection of related objects)
They represent a transaction boundary for related objects.
They can't contain duplicates - like sets.
It is valid for the repository to contain only one object, without
complex relations internally
So to answer your questions, repositories should contain collection related methods like add, remove, addAll, findByCriteria - instead of save, update, delete. They can return whole aggregate or parts of aggregates or some internal aggregate relation - it is dependent on your domain model and the way you want to represent objects
Eric Evans coined "domain driven design" in 2003; so the right starting point for any definitions in that context is his book. He defines the repository pattern in chapter 6 ("Lifecycle of a Domain Object").
A REPOSITORY represents all objects of a type as a conceptual set (usually emulated). It acts like a collection, except with more elaborate querying ability. Objects of the appropriate type are added and removed, and the machinery behind the repository inserts them or deletes them from the database.
...
For each type of object that requires global access, create an object that can provide the illusion of an in-memory collection of all objects of that type.
The primary use case of a repository: given a key, return the correct root entity. The repository implementation acts as a module, which hides your choice of persistence strategy (see: Parnas 1971).
I recurrently run into an scenario similar to this:
A container business class that models a hierarchy.
A business class that participates in this hierarchy and is aggregated by the aforementioned class.
Let me give you an example.
A Map has Countries. Now the Map should know where each Country is, since its main responsability besides containing all countries is to know the locations and proximity of each. From this point of view, a functionality such as isNeighbour(Country A, Country B) seems like a correct addition to Map. However, each Country should also offer a method to know if a country is nearby. Say spain.isNeighbour(italy). This is indeed useful. Now, if I don't want to duplicate functionality and responsability, what approach should I take?
The current example I am working on is something for my university, each course requires other courses and also blocks the next level ones. The major is the one that contains all courses and dictates which course precedes which. Say I want to add a dependency of a course over another, e.g to take Calculus 2 you need Calculus 1... Should I go calculus.addRequired(calculus2) and then pass it to the major object, or maybe computerScience.addRequired(calculus1, calculus2)...
I don't want to have both alternatives because to me it seems it can lead to error, but at the same time I want each course to be able to answer what are its requirements. I don't really know how to distribute responsabilities correctly.
First thing is, that there is no problem calling each other.
You can have
boolean Map.isNeighbour(Country A, Country B) { return A.isNeighbour(B); }
or
boolean Country.isNeighbour(Country other) { return map.isNeighbour(this, other); }
Second seems to need reference to global map. First makes Map look like simple facade.
Second thing is that you say it is persisted. There also might be good idea to create a service, that will query DB with related parameters. This can be either Map or some repository service. This will also allow you to query with only identities of entities (eg. countryId) instead of full objects.
I believe neither of the solutions is better or worse. Only point of difference is where other developers expect the methods to be located. But when I think about it, this would mean Map will have all responsibilities of Country, thus breaking SRP, especially if it is not call-through to the country method.
I would put the isNeighbour() method into Country.
Country would contain a map of neighbours. And then the container can call this method on the country instance in question.
This way the logic is maintained by the countries, and the container simply delegates to answer the question to them.
In case of courses it is possible that Course-1 is required for Course-2 in Major-1, but not in Major-2. In this case I would introduce another class, e.g. CourseInMajor that would contain the required courses for a given course in a given Major.
I’ve been persuaded by Eric Evans’ book and am integrating DDD into my framework. All basic elements (services, repositories, bounded contexts, etc) have been implemented and now I’m looking for feedback on how to correctly integrate this.
I have some business logic which has to be performed when an entity is created or modified. This example is a very simple one. Most business logic will become much more complex.
This business logic can be split up into the following actions:
Update calculated fields;
Update a child record inside the aggregate root. When creating the aggregate root this entails creating a default child record. When updating the aggregate root this entails removing the existing child record and creating a new one if a specific field on the aggregate root has changed;
Propagate start and end date of the aggregate root to the start and end date of the child records inside the aggregate root. These must be kept in sync under certain circumstances;
Propagate a field of the aggregate root to a different aggregate root.
My first attempt is to put all of this on the aggregate root, but I feel this is not going to work. I have the following problems integrating this logic:
All these actions have to be completed as a single whole and should not be made available as separate actions. This has the result that this is going to be very difficult to test (TDD);
I am not clear on whether any of these actions can be moved out to a service. The reason for this is that they make no sense outside of the aggregate root, but it would make TDD a lot easier;
Some logic changes depending on whether a new entity is created or an existing one is modified. Should I put these two branches inside the update logic or should I make two entirely different paths that share the business code that does not differentiate based create/modify.
Any help on the above issues would be greatly appreciated and other feedback in general.
The algorithm you've described should remain in the aggregate root, elsewise you end up with an anemic domain model, excepting propagating a field to another aggregate root where I will describe what I think you should do later.
As far as TDD is concerned, a method with "package" access on the aggregate root (e.g. "calculate()", should coordinate the entire action, which either the service or repository object would normally call. This is what tests should exercise in conjunction with setting different combinations of instance variables. The aggregate root should expose its instance variables, the children collection, and each child should expose its instance variables, through getters - this allows tests to validate their state. In all cases if you need to hide information make these getters package or private access and use your unit testing framework to make them public for the purpose of testing.
For your testing environment consider mocking the repository objects (you're using dependency injection right?) to return hard coded values. Short of this consider using something like dbunit to work with a database in a known state.
As far as logic changes are concerned create vs. modify, are you referring to how to persist or is there an actual algorithm to consider? If the former, I would make the repository responsible, if the latter I would make two separate methods (e.g. "calculateCreate()" & "calculateUpdate()") which calculate() would delegate as appropriate.
Also, there's a concurrency issue to think about as well because it sounds as if calculated values rely on mutable fields. So either need to have careful locking or aggregate roots that can only be used by a client once at a time. This also applies to propagating a field across aggregates - I would probably use the repository for this purpose - but you need to think carefully on how this should or should not impact other clients who are using the repository object.
Take this simple, contrived example:
UserRepository.GetAllUsers();
UserRepository.GetUserById();
Inevitably, I will have more complex "queries", such as:
//returns users where active=true, deleted=false, and confirmed = true
GetActiveUsers();
I'm having trouble determining where the responsibility of the repository ends. GetActiveUsers() represents a simple "query". Does it belong in the repository?
How about something that involves a bit of logic, such as:
//activate the user, set the activationCode to "used", etc.
ActivateUser(string activationCode);
Repositories are responsible for the application-specific handling of sets of objects. This naturally covers queries as well as set modifications (insert/delete).
ActivateUser operates on a single object. That object needs to be retrieved, then modified. The repository is responsible for retrieving the object from the set; another class would be responsible for invoking the query and using the object.
These are all excellent questions to be asking. Being able to determine which of these you should use comes down to your experience and the problem you are working on.
I would suggest reading a book such as Fowler's patterns of enterprise architecture. In this book he discusses the patterns you mention. Most importantly though he assigns each pattern a responsibility. For instance domain logic can be put in either the Service or Domain layers. There are pros and cons associated with each.
If I decide to use a Service layer I assign the layer the role of handling Transactions and Authorization. I like to keep it 'thin' and have no domain logic in there. It becomes an API for my application. I keep all business logic with the domain objects. This includes algorithms and validation for the object. The repository retrieves and persists the domain objects. This may be a one to one mapping between database columns and domain properties for simple systems.
I think GetAtcitveUsers is ok for the Repository. You wouldnt want to retrieve all users from the database and figure out which ones are active in the application as this would lead to poor performance. If ActivateUser has business logic as you suggest, then that logic belongs in the domain object. Persisting the change is the responsibility of the Repository layer.
Hope this helps.
When building DDD projects I like to differentiate two responsibilities: a Repository and a Finder.
A Repository is responsible for storing aggregate roots and for retrieving them, but only for usage in command processing. By command processing I meant executing any action a user invoked.
A Finder is responsible for querying domain objects for purposes of UI, like grid views and details views.
I don't consider finders to be a part of domain model. The particular IXxxFinder interfaces are placed in presentation layer, not in the domain layer. Implementation of both IXxxRepository and IXxxFinder are placed in data access layer, possibly even in the same class.
I'm not quite sure of the most elegant solution for what I am trying to do.
I have a page which lists music listings, there can be thousands of these so they are paged in batches of 20, I also have 4 links at the top of the page to change the way these listings are ordered.
The sort by properties could be located on different entities such as Audio.AudioStats.NumComments or Audio.Artist.NumProfileViews.
I am using the repository pattern, and a service layer. My controllers can only access the service layer, then the service layer accesses my repositories.
I can do the paging fairly easily, i simply pass in my current page, and the page size to my data layer...but how would i safely let the user decide on the ordering of my entities.
I am using S#arp Architecture 1.5.2 if that makes any difference.
Thank you in advance.
You are going to have to map the users' desires to an order by clause somehow.
Presumably you're doing something like skip(n).take(m) which will need an orderby() clause too.
Given that you have a fixed set of (known) possibilities, you can map those to an enum or similar which you then translate to the relevant orderby() call.
This means you don't expose the properties at the UI layer but only pass through the intent to the repository layer (as a Sortby.ArtistProfileViews value or whatever). What how that intent is mapped to the properties on you domain objects is isolated in your repository layer.