I am building a questionnaire creator. A questionnaire consists of sections, sections consist of pages and pages consist of questions. Questionnaire is the aggregate root.
Sections, pages and questions can have what are called shortcodes which should be unique within a questionnaire (but not unique within the database hence they are not strictly an identity). I intended to make the shortcode a value object and wanted to include the business rule that it should be unique within the questionnaire but I am unsure how to ensure that. My understanding is that the value object should not access the repository or service layer so how does it find out if it is unique?
Thanks for any help.
Darren
You could assign the responsibility of generating shortcodes to the questionnaire aggregate. It can be based on a simple counter embedded into questionnaire object. Every entity that want to create a shortcode would call its containing questionnaire's NextShortCode() method to obtain next unique (in scope of current questionnaire) shortcode value.
Clearly, you are going to need a PK field in the database. How you implement that is up to you, but if it were me, I'd carry the PK field into your value object so that it is handled automatically.
You would want to use something like a Guid or UUID. Exactly how you would generate one would depend on what language you are using for your application though.
Related
I'm new to DDD and I want to clearly understand each domain object structure and role:
Aggregate Root:
1.1. The only contact point the client can interact with the domain objects, the client should not be able to modify or create new Entities or value objects whiteout the aggregate root? (Yes/No)
1.2. Can an aggregate root contain only value objects ? for example User root, it contain only address, phone, things which are value objects as far as I understand. So is it a sign of bad design when your aggregate root contain only value objects? shall it contain only entities and via entities interact with value objects?
Entities: Shall the entities contain only value objects? or it can also contain other entities? can you give me a simple example please ?
Value Objects: shall I go ahead and encapsulate every primitive type in an value object? I can go deep and make every primitive type as an value object, for example: PhoneNumber can be a string or an value object which contains country code, number. the same thing can be applied to all other primitive type value such as name, email. So where to draw the line ? where to say "Ok I'm going to deep", or going deep is the right way of doing DDD?
Factories: Do I really need them? I can go ahead and write an static method within the domain object which knows more precisely how to construct it, am I doing wrong ?
Sorry for the long questions, but I'm feeling little lost despite of continues reading, if you can help me I would be glad.
I'll try to answer all your questions:
1.1. The only contact point the client can interact with the domain objects, the client should not be able to modify or create new Entities or value objects whiteout the aggregate root? (Yes/No)
Entities live within ARs and allowing the client to create them would violate encapsulation, so for entities you are correct, ARs create their own entities which don't get exposed to the outside (copies/immutable views could be).
On the other hand, value objects are generally immutable and therefore there's no harm in having them supplied to the AR as data inputs.
In general all modifications needs to go through the AR so that the AR is aware of the modification. In special situations the AR could detect modifications within it's cluster by listening to events raised by internal entities when it's impractical to go through the root.
1.2. Can an aggregate root contain only value objects ? for example User root, it contain only address, phone, things which are value objects as far as I understand. So is it a sign of bad design when your aggregate root contain only value objects? shall it contain only entities and via entities interact with value objects?
Favor value objects as much as you can. It's not unusual for all parts of an AR being modeled as values. However, there's no limitation or law stating whether or not an AR should have only values or entities, use the composition that's fit to your use case.
Entities: Shall the entities contain only value objects? or it can also contain other entities? can you give me a simple example please ?
Same answer as above, no limitation nor law.
Value Objects: shall I go ahead and encapsulate every primitive type in an value object? I can go deep and make every primitive type as an value object, for example: PhoneNumber can be a string or an value object which contains country code, number. the same thing can be applied to all other primitive type value such as name, email. So where to draw the line ? where to say "Ok I'm going to deep", or going deep is the right way of doing DDD?
Primitive obsession is worst than value object obsession in my experience. The cost of wrapping a value is quite low in general, so when in doubt I'd model an explicit type. This could save you a lot of refactoring down the road.
Factories: Do I really need them? I can go ahead and write an static method within the domain object which knows more precisely how to construct it, am I doing wrong ?
Static factory methods on ARs are quite common as a mean to be more expressive and follow the UL more closely. For instance, I just modeled as use case today where we had to "start a group audit". Implemented a GroupAudit.start static factory method.
Factory methods on ARs for other ARs are also quite common, such as var post = forum.post(author, content) for instance, where Post is a seperate AR than Forum.
When the process requires some complex collaborators then you may consider a standalone factory though since you may not want clients to know how to provide and setup those collaborators.
I'm new to DDD and I want to clearly understand each domain object structure and role
Your best starting point is "the blue book" (Evans, 2003).
For this question, the two important chapters to review are chapter 5 ("A model expressed in software") and chapter 6 ("the life cycle of a domain object").
ENTITIES and VALUE OBJECTS are two patterns described in chapter 5, which is to say that they are patterns that commonly arise when we are modeling a domain. The TL;DR version: ENTITIES are used to represent relationships in the domain that change over time. VALUE OBJECTS are domain specific data structures.
AGGREGATES and FACTORIES are patterns described in chapter 6, which is to say that they are patterns that commonly arise when we are trying to manage the life cycle of the domain object. It's common that modifications to domain entities may be distributed across multiple sessions, so we need to think about how we store information in the past and reload that information in the future.
The only contact point the client can interact with the domain objects, the client should not be able to modify or create new Entities or value objects whiteout the aggregate root?
Gray area. "Creation patterns are weird." The theory is that you always copy information into the domain model via an aggregate root. But when the aggregate root you need doesn't exist yet, then what? There are a number of different patterns that people use here to create the new root entity from nothing.
That said - we don't expect the application to be directly coupled to the internal design of the aggregate. This is standard "best practice" OO, with the application code coupled to the model's interface without being coupled to the model's implementation/data structure.
Can an aggregate root contain only value objects ?
The definition of the root entity in the aggregate may include references to other entities in the same aggregate. Evans explicitly refers to "entities other than the root"; in order to share information with an entity other than the root, there must be some way to traverse references from the root to these non-root entities.
Shall the entities contain only value objects?
The definition of an entity may include references to other entities (including the root entity) in the same aggregate.
shall I go ahead and encapsulate every primitive type in an value object?
"It depends" - in a language like java, value objects are an affordance that make it easy for the compiler to give you early feed back about certain kinds of mistakes.
This is especially true if you have validation concerns. We'd like to validate (or parse) information once, rather than repeating the same check every where (duplication), and having validated vs unvalidated data be detectably different reduces the risk that unvalidated data leaks into code paths where it is not handled correctly.
Having a value object also reduces the number of places that need to change if you decide the underlying data structure needs improvement, and the value object gives you an easily guessed place to put functions/methods relating to that value.
Factories: Do I really need them?
Yes, and...
I can go ahead and write an static method within the domain object
... that's fine. Basic idea: if creating a domain object from so sufficient set of information is complicated, we want that complexity in one place, which can be invoked where we need it. That doesn't necessarily mean we need a NOUN. A function is fine.
And, of course, if your domain objects are not complicated, then "just" use the objects constructor/initializer.
I have an aggregate called Order which has a big list (upwards of 20) of fields that the Business has identified as mandatory fields.
An order cannot be in a valid state without these mandatory fields.
In my domain layer, when I create the Order aggregate, there is some domain logic involved which requires just a few of these 20 mandatory fields (just about 5-6 are required for the domain logic).
If I go purely by the principles of DDD and treat these mandatory values as invariants, I have to create my Order domain object with all fields, most of which should merely pass a not-null/empty validation. It does feel like there could be a better way to handle this scenario.
So what should be my approach? Should I create the domain object with just those 5-6 fields that are required for domain logic? Wouldn't that mean the Order aggregate is then in an invalid state from a business perspective? But the domain object is much simpler if created with a smaller set of values.
I have checked with the Business about whether they really require all those fields, and yes, they have a very real need for an order to be created with all those mandatory fields.
I found the answer to my question here:
https://softwareengineering.stackexchange.com/questions/301928/aggregate-root-with-many-fields
From the link above:
Think of it this way: while you order something from an e-commerce website you might be filling out your order in several distinct steps, going through a number of screens to enter the products, shipping information, payment information, etc...
The order is saved in between steps, even though it is lacking in the needed information to fullfill the order! The only difference is that before an order can be shipped it needs that information. It does not mean that it cannot be created.
I am modeling my entities, and have been struggling with this for a long time. Here is my Person Entity:
Person
ID
Name
Email
Password
City
Phone
Biography
Rating
Description
I have tried to divide these properties into Value Objects, but so far I only have been able to convert them to VOs (for example, City is a VO made with a city name, and country name).
Should I try to create larger VOs, by putting together, for example, Email and Password into a Credentials VO ? Am I going too deep in the separation into VOs ?
Any help is greatly appreciated
[EDIT]
After some discussion, it appears that the best solution is to keep every property in it's own VO, except for Email and Password that should be grouped in a "Credentials" VO.
Value objects are things who's values uniquely identify them I.e. equality is done by the values, rather than an explicit property (like ID) to provide uniqueness. Two value objects are equal if all their fields are equal
When trying to identify them, follow the language the domain experts use. What words do they use when discussing People? Do they refer to credentials, or email and password?
Also look to identify groups of properties that are always used together. For example, if Password is always used alongside Email it makes sense to group them in a Credentials object, as you can then push behaviour there (i.e. Credentials.Validate())
[UPDATE]
All of the following properties are candidates for value objects depending on the invariants you need to enforce
Name
are there min / max values for names?
are there any characters not allowed?
Email
is it a valid email address
can two people have the same email address?
Password
min / max length?
required characters?
invalid characters?
Phone
is it a valid phone number?
how do you deal with international dialing codes?
Rating
is there a min and max value allowed for a rating?
how is it calculated? (is it calculated?)
Description
Biography
City
etc....
If you create Value Objects for the above concepts instead of using primitive values such as int or string, you can encapsulate your business rules inside the value objects.
You might want to combine Email and Password into a Credentials Value Object if you use the two things cohesively. i.e. login with credentials etc... You can still access Credentials.Email if you need to use the Email outside of the Credentials object.
What you have there looks suspiciously as a data structure (CRUD). In proper DDD you start with the business case like "Create Person" and then you find out the model representing the Person concept.
The model is defined by a group of components and business rules. Your components are usually VOs , because they are models representing minor concepts that can be expressed as a simple or composite value with no explicit identity and they encapsulate specific business constraints. For example, the Email VO makes sure you have a valid email value.
You should let the domain tells you if it makes sense to create bigger VO; usually you start with a VO and you discover it's made up from other VOs. Generally, we go top to down. You can see here a modelling example.
It's hard when you don't have a domain expert but you can still try to think in business cases and identify whatever specific model for each case. If you end up with mainly simple structures and some data validation rules, perhaps you have a simple enough domain to just use a CRUD approach.
Don't try to impose a particular domain model structure, you need to approach domain modeling from the use cases perspective.
Should I try to create larger VOs, by putting together, for example, Email and Password into a Credentials VO ?
You should do that only if the two tend to be used together. If they don't, leaving them along is just fine.
Note that sometimes it makes sense to extract a single property into its own value object if the number of invariants it needs to support is high enough to justify introducing a new concept. Take a look at this article for more details.
it is not always clear a concept in your domain is a value object or entity and unfortunately there are no objective attributes you could use to get to know it whether or not a notion is a value object fully it depends on the problem domain, a concept can be an entity in one domain model or a value object in another. most of times a money class is a value object but not all money objects are value object. how you can find out a value object? first of all you should check the notion of identity if it is structurally equal (it means two objects are same if objects values are same, not ids of objects), you can safety replace an instance of class which has same set of attributes. that is good sign this concept is a value object.
a good way of thinking value object is thinking if it is an integer, do you really care if integer 5 is same as 5 you used in other function? definitely not all 5 in your application are same, regardless how they were instantiated. that's make integer essentially a value object, now ask your self the object in your domain is like an integer? if answer is yes then it is a value object. also, value objects are immutable and more light weight as entities.
Quotes are from DDD: Tackling Complexity in the Heart of Software ( pg. 150 )
a)
global search access to a VALUE is often meaningles, because finding a
VALUE by its properties would be equivalent to creating a new instance
with those properties. There are exceptions. For example, when I am
planning travel online, I sometimes save a few prospective itineraries
and return later to select one to book. Those itineraries are VALUES
(if there were two made up of the same flights, I would not care which
was which), but they have been associated with my user name and
retrieved for me intact.
I don't understand author's reasoning as for why it would be more appropriate to make Itinierary Value Object globally accessible instead of clients having to globally search for Customer root entity and then traverse from it to this Itinierary object?
b)
A subset of persistent objects must be globaly accessible through a
search based on object attributes ... They are usualy ENTITIES,
sometimes VALUE OBJECTS with complex internal structure ...
Why is it more common for Values Objects with complex internal structure to be globally accesible rather than simpler Value Objects?
c) Anyways, are there some general guidelines on how to determine whether a particular Value Object should be made globally accessible?
UPDATE:
a)
There is no domain reason to make an itinerary traverse-able through
the customer entity. Why load the customer entity if it isn't needed
for any behavior? Queries are usually best handled without
complicating the behavioral domain.
I'm probably wrong about this, but isn't it common that when user ( Ie Customer root entity ) logs in, domain model retrieves user's Customer Aggregate?
And if users have an option to book flights, then it would also be common for them to check from time to time the Itineraries ( though English isn't my first language so the term Itinerary may actually mean something a bit different than I think it means ) they have selected or booked.
And since Customer Aggregate is already retrieved from the DB, why issue another global search for Itinerary ( which will probably search for it in DB ) when it was already retrieved together with Customer Aggregate?
c)
The rule is quite simple IMO - if there is a need for it. It doesn't
depend on the structure of the VO itself but on whether an instance of
a particular VO is needed for a use case.
But this VO instance has to be related to some entity ( ie Itinerary is related to particular Customer ), else as the author pointed out, instead of searching for VO by its properties, we could simply create a new VO instance with those properties?
SECOND UPDATE:
a) From your link:
Another method for expressing relationships is with a repository.
When relationship is expressed via repository, do you implement a SalesOrder.LineItems property ( which I doubt, since you advise against entities calling repositories directly ), which in turns calls a repository, or do you implement something like SalesOrder.MyLineItems(IOrderRepository repo)? If the latter, then I assume there is no need for SalesOrder.LineItems property?
b)
The important thing to remember is that aggregates aren't meant to be
used for displaying data.
True that domain model doesn't care what upper layers will do with the data, but if not using DTO's between Application and UI layers, then I'd assume UI will extract the data to display from an aggregate ( assuming we sent to UI whole aggregate and not just some entity residing within it )?
Thank you
a) There is no domain reason to make an itinerary traverse-able through the customer entity. Why load the customer entity if it isn't needed for any behavior? Queries are usually best handled without complicating the behavioral domain.
b) I assume that his reasoning is that complex value objects are those that you want to query since you can't easily recreate them. This issue and all query related issues can be addressed with the read-model pattern.
c) The rule is quite simple IMO - if there is a need for it. It doesn't depend on the structure of the VO itself but on whether an instance of a particular VO is needed for a use case.
UPDATE
a) It is unlikely that a customer aggregate would have references to the customer's itineraries. The reason is that I don't see how an itinerary would be related to behaviors that would exist in the customer aggregate. It is also unnecessary to load the customer aggregate at all if all that is needed is some data to display. However, if you do load the aggregate and it does contain reference data that you need you may as well display it. The important thing to remember is that aggregates aren't meant to be used for displaying data.
c) The relationship between customer and itinerary could be expressed by a shared ID - each itinerary would have a customerId. This would allow lookup as required. However, just because these two things are related it does not mean that you need to traverse customer to get to the related entities or value objects for viewing purposes. More generally, associations can be implemented either as direct references or via repository search. There are trade-offs either way.
UPDATE 2
a) If implemented with a repository, there is no LineItems property - no direct references. Instead, to obtain a list of line items a repository is called.
b) Or you can create a DTO-like object, a read-model, which would be returned directly from the repository. The repository can in turn execute a simple SQL query to get all required data. This allows you to get to data that isn't part of the aggregate but is related. If an aggregate does have all the data needed for a view, then use that aggregate. But as soon as you have a need for more data that doesn't concern the aggregate, switch to a read-model.
I am working on an application where users can follow each other, in a similar fashion to Twitter.
After reading up on DDD, I understand that my users are Entity Objects - I refer to them using their unique ID.
When one user 'follows' another (i.e. forms a Connection), the relationship is stored in a many-to-many table. Its fields include FollowerID, TargetID, and Status. There can be only two records for each Follower/Target combination (one Active, the other Inactive), so I can safely identify objects based on their attributes.
So, I think my Connection objects are Value Objects, not Entity Objects, but I'm not sure. Can you help me with this decision?
You are correct that entities are unique and carry the notion of having an identity (i.e. only one unique user can exist). A Connection is dependent on other User entities. It represents some aspect between two users. That aspect is whether there is an active or inactive connection. Without containing the data of which users are connecting, a connection has no identity. It may even have it's own primary key in the database, but from a domain perspective, it has no identity of it's own.
Therefore, I would say that Connection is a value object.
To support my conclusion, Microsoft.Net Architecting Applications for the Enterprise, page 187, says:
A value object class represents an entity in the domain that mostly
contains data and lives for the data it contains. A value object is
fully identified by a combination of values it contains. An entity
object, on the other hand, has its own life and rich behavior
regardless of the data it contains. Entity objects are usually objects
with a longer lifetime. A value object represents an aspect of an
entity and can live only in relation to an entity.
And also on page 189:
One further comment is needed to explain the difference between
entities and value objects. You don’t need a repository or a data
mapper for a value object. You need a repository only for an entity.
The repository (or the mapper) for a given entity will certainly take
care of all value objects that depend on a given entity.
Some time ago, I saw a cartoon about scientist that had invented cloning. Every time he cloned himself, he destroyed previous version. Then person that was watching demonstration decided to interrupt and sabotaged destruction part so there were two scientists. Cartoon ended with some interesting existential questioning.
Values vs entities is not about having or not having id fields in one or another form. Point is - how we are looking at those objects through our domain perspective. If they are value objects, then only their value matters - 1st, 3rd and 53rd scientist are the same. If we care about identity, if we think that cloning 3rd scientist will never be like 1st one, then our object is an entity.