Advice on domain modeling - domain-driven-design

New to DDD here and have a architecture question which should be a typical problem.
I have a StockItem entity and a Store entity. I assign a StockItem to multiple Stores and set different ParLevels for each store. I then need to have transactions (sale, purchase, transfer-in etc) that adjust the quantity on hand at the various store.
What is the preferred way to model this solution? In my DB I would have the following simplied table structure:
[StockItem]
StockItemID pk,
Name
[Store]
StoreID pk,
Name
[Store_StockItem]
StoreStockItemID pk,
StoreID fk,
StockItemID fk,
ParlLevel,
QuantityOnHand
[StockItemTransaction]
StockItemTransactionID pk,
StockItemStoreID fk,
StockItemTransactionTypeID fk,
Quantity
Any advice greatly appreciated

I don't think that anyone here can really give you the answer you want, because the whole point of Domain Driven Design is that your own specific business domain should guide the object model.
The only piece of advice I would offer is that you shouldn't worry about how the database models these relationships when working on the domain. You should normalise your database according to the rules of normalisation, and create your domain model according to the actual business domain.
Remember that the data model and the domain model don't map to each other in a 1:1 way.

Related

How to handle relationships in domain when they are part of the database normalization

You have Job *--1 Board, so in your database you will have a board_id in your jobs table.
Now, in the domain, Job can live without Board. So thinking about adding a boardId property to it doesn't seam logical to me.
Is it ok to manage it through the BoardRepository? for example calling to BoardRepository.addJob(Board board, Job job)? so the repository will map the Job to a database object and then add the board_id field when insert it?
The problem is...
What if I want to query the Job through /jobs/{id}, I will need to have the boardId attribute in the domain class, so it will not be mapped to the right DTO.
Hope I'm being clear.
normally you have one aggregate per repository. So Repository.addJob(Board board, Job job) seems not a good choice. I don't know your problem domain .. but when we have Board as an aggregate or Root Entity of an Aggregate then Board is responsible for managing its jobs. So it keeps a list of its jobs, where Job is probably another entity. In general an aggregate is a cluster of connected domain objects and acts like a Facade for manipulating its state and the state of its entities and value objects.
By applying these principles you would end with maybe something like this:
Board.addJob(Job job)
BoardRepository.add(Board board)
If you queries are getting too complex and don't fit with your DDD model, then it's completly ok to logically seperate the write and the read model by simply adding an additional QueryService which maps simple dtos to your database.
Hope i could help a bit :)
Repositories are your abstraction to your persistence strategy. So you would have one interface for your repository in your domain layer:
interface BoardRepository {
add(Board board);
update(Board board);
delete(BoardId id);
get(BoardId id);
}
If you would use a SQL Persistence Strategy, then you would implement this interface in e.g. your infrastructure layer like this.
class SqlBoardRepository implements BoardRepository {
...
}
So yes Repositories are responsible for persisting aggregates. You'll have one repository per Aggregate! Not one Repository for every Entity!
Primary Keys and foreign keys are a database related topic and normally you don't care about them in your domain models. Entities in you domain model are identified by business keys (which also can be used as primary key). For example an isbn identifies a book world wide and would be the business key of a Book entity and could also be used as a primary key in the database. Sometimes when using business key is too complex in your persistence model then you could use an additional surrogate key in your entities, which identifies your entity primarly on the persistence layer.
You model your relationships between your domain objects with your business or surrogate keys in the db and a sql repository is responsible for mapping your domain models to database and vice versa.
Maybe you should read a bit about it, then you'll understand better. The blue book from Eric Evans or Implementing Domain Driven Design from Vaughn Vernon is a good start :)

How to identify Entities, ValueObjects and Aggregates for a particular project in DDD pattern?

I am developing an online job portal using DDD patterns.
There are many "objects" that i have figured out like Users, Jobs, Roles, Expertise, ExperienceRange, Country, State, City, Address, Subscriptions, etc
My question is how do i figure out which of these is an entity or a value object or an aggregate? Please advice me if you have ever faced the same dilemma.
I have made the following decision:
Entities - User, Job, SubscriptionPackage
ValueObjects - Role, Expertise, ExperienceRange, City, State, Country
I know that we should not think about persistence while doing DDD modelling but a doubt has surfaced that whichever value objects i am storing in database should have an id or not?
if they have an id do they not violate the fundamental principal of ValueObjects and if we do not save them with ids then how to reference them in foreign key fields?
Please help me answer these queries.
If you can suggest which of the above mentioned objects are entities, which are value objects and which are aggregates that would be great.
Thanking in advance
When thinking of DDD, leave the DB mapping to a later stage. I know I'm repeating what you said, but just because it's true. A value object might have a DB id for other reasons (normalisation, reporting , etc).
First come up with your object model and then figure out how to map it. In some (rare) cases you might need to change slightly your object model if there's something that is too expensive to map properly (I cannot think of an example, but I don't want to be extremist).
So once more, forget about the DB - think about objects. For what reason does an entity have an id? I would say so then later it can be retrieved and modified, while keeping the same id.
And if it is a VO is because the identity is implicit in the values of the object. Does it make sense for a User to have an id? What about an Address? Or a City?... It depends.
To give the example of a city value object, if you need to map that as FK to 'cities' table, then your City object will probably have an id, but the id is not exposed. It's a detail of the implementation. While the user id would be exposed. For example a city might be linked to a province/state and that to a country.
But in another application, where users can add cities and information about them, the city might be an Entity or even an Aggregate. It really depends on your requirements.
Having said that, the list of Entities and VOs you provided looks ok in a general way, but I don't know your requirements.
To answer the first question: you can read Entities, Value Objects, Aggregates and Roots as there are some rules about what is a VO, Entity or Aggregate. The difficulty comes from how to apply them, and experience is the solution to that.
As a summary:
Entities
Many objects are not fundamentally defined by their attributes, but rather by a thread of continuity and identity.
Value Objects
Many objects have no conceptual identity. These objects describe characteristics of a thing.
Aggregates
Aggregates draw a boundary around one or more Entities. An Aggregate enforces invariants for all its Entities for any operation it supports.

Domain model and EF Core model

When looking at the post "Should Entities in Domain Driven Design and Entity Framework be the same?" the accepted answer states that domain entities and EF Entities can only be the same when using code first. This so that the entities can remain "pure".
However, because of this inpediment: "Discussion on many-to-Many relationships (without CLR class for join table)" it is not possible to create an order entity with a collection of product entities without specifying a special entity for the association table (orderline entity).
I now see colleagues taking these association tables into their domain entities and i feel that is wrong because it hints towards coping with persistence and not towards being true to the domain. They are not "pure" anymore in my opinion.
Would you say that it is impossible to have the same Domain entities in EF Core because of the association table entities? How can i cope with this in EF Core?
But in a regular/classic Ordering domain there is a need for an orderline (or order-line-item or whatever you want to call it) because you need to store the quantity and the item price along the product ID.
In most DDD examples this item is a Value object from the DDD point of view and an Entity from the Persistence point of view. If you are wondering how a Value object could be an ORM Entity you should read Persisting Value Objects from the book Implementing Domain Driven Design by Vaughn Vernon.
There are, however cases when the Domain model does not fit 100% percent with the Persistence model. In such cases one needs to attach some meta information to the Domain models in order to match the Persistence models. In general you have two options:
you can add the metadata to some external files, like XML-files;
it has the advantage that it keeps the Domain model agnostic in regard to the persistence but
it has the disadvantage that one must remember to change the external files when the Domain model changes
you can annotate the Domain models
it has the advantage that it is easy to change at the same time the Domain model and the Persistence model by having the information in the same file; it follows the principle: "things that change together stay together" (Common Closure Principle)
it has the disadvantage that it pollutes the Domain model with Infrastructure concerns
If I have to choose, I tend to choose to annotate the Domain models, but you should make that decision by yourself.

Modeling relationships with domain models

In my system, an User can be member of a Team.
I got a domain model called Team which contains id, name, member_count and is_channel. So when I fetch teams in the repository I retrieve the Team domain model.
How would I model the relation between a User and a Team? Because when talking about the relation I don’t care about the member_count and is_channel from the Team model. I even have extra data in the relation which is a role_type.
Should I create a domain model for the relation called TeamScope or something? That contains id, user_id, team_id, role_type?
See my comments on your question regarding your use of terms (model, class, association). I'm assuming you are misusing them when I wrote my answer.
How would I model the relation between a User and a Team? Because when talking about the relation I don’t care about the member_count and is_channel from the Team model (sic). I even have extra data in the relation which is a role_type.
You could use an association class in your domain model to represent this.
Membership can capture the role_type, which really is linked to the association as you have figured out.
member_count is represented with a / at the start, indicating that you'll derive its value from the multiplicity (it's a count of the number of members associated with the team).
You tagged node.js in your question, so I'm going to point to how to implement association classes in Java (not exactly your case, but in Node.js it should be easy to apply).
You should almost definitely model a TeamMember object which contains both a link to the User, a link to the Team, and the role the user plays on that team.
Teams have a list of TeamMembers, Users have a list of TeamMembers. Teams have a MemberCount (not sure if this is static, or dynamic from the count of TeamMembers), and I have no idea what is_channel means...

Loading a Value object in List or DropdownList, DDD

I need to clarify something.
Have Person Aggreagate , 2 VOs (Country, StateProvince).
I want to load all country in my presentation layer (i am using mvc)
Evan says you only use repository (IPersonRepository) to work with root entity (it should always return just a reference to the Aggregate Root)
public interface IPersonRepository()
{
void savePerson(Person p);
void removePerson(Person p);
Ilist<Person> getPerson();
}
what i usually do to solve this :
Add in IPersonRepository this method
IList<Country> LookupCountrysOfPerson();
In Infra layer implement the Domain interfaces like this:
public IList<Person> LookupCountrysOfPerson()
{
return Session.CreateQuery("from Countrys").List<Person>());
}
My partner says im wrong.
Sometimes you have to sacrifice your domain model in order to accomplish some task
What is the best way to do this?
with code please! :)
I would say it's unlikely that you need country to be an entity. I suspect that country is nothing more than reference data, much like a person's title would be. Is there any behavior associated to country in your domain? I suspect it's just what's printed onto letters/envelops.
This question is somewhat similar to this one which I answered a while back:
Simple aggregate root and repository question
My suggestion is that you implement a Lookup service that your client can make use of and which is cached. Ignore the rules of DDD and anything to do with aggregates or repositories for this. As someone else has mentioned, this is where CQRS's ideology comes into play; the client shouldn't have to go through the domain in order to get data. The domain is purely transactional, not designed for queries.
This article explains how to build a generic lookup service for reference data for things that typically fill dropdowns in the UI (i.e. Title, Country etc)
http://wtfperminute.blogspot.com/2011/02/working-with-reference-data-lookups.html
Evans also says (pg 170) "An entity as basic as Location may be used by many objects for many reasons..."
I would also consider making Country an entity for the reasons given above. Perhaps more importantly, it is a low level object. You probably are also even supplying Country by configuration rather than through any actual domain activities. Therefore I would remove it from the Person and make it a standalone entity.
Also for this type of object you may not really need a dedicated repository, consider creating a single lookup service that provides query access for a group of similar objects of this nature.
If in your domain country is actually a VO (you don't want to maintain a thread of identity in the country name was changed etc.) which is the most common scenario, I would add a specialized class in the data access layer to return a list of all countries as VOs. I would also add caching (2nd level cache in NHibernate) to the country entity and list all countries query so that I don't have to hit the DB each time.
Actually, this is where CQRS really shines. CQRS acknowledges that you don't have to go through the domain layer in order to get some data for presentation purposes. In CQRS you just grab some data.
It sounds like countries are not in fact value objects here; they have distinct identities and are important for business purposes outside of your Person objects. They should become entities, and be treated in the fashion appropriate to them.
Think of it this way: let's say some volatile country had their current dictator overthrown and got a name change. The Person object's reference to a Country should still be valid, because the Country is not defined by its attributes (i.e. the string denoting its name), but by its identity.

Resources