DDD - No Lazy loading - how to do certain tasks without draining the database? - domain-driven-design

I'm working on a module for a larger solution.
In this solution they tried in the past to work with DDD.
However that didn't turn out how it should of been because there was no DDD expert. (and there still isn't one present imo.)
Everything was under a single root aggregate, lazy loading was enabled, and so on.
Now for the new module we want to make it better.
However i'm failing to see how i can use DDD without lazy loading and not drain the entire database.
For example i have an object let's call it "B".
B has a flag let's say "AwesomeFlag"
B has children
If one of B's children is Awesome, then B is awesome as well.
If none of B's children is Awesome, then B isn't awesome.
Now if I would not work with DDD; I'd just get B and execute a linq query that check's if one of B's children is awesome without actually retrieving all of the children.
However if i got a domainobject where i am not allowed to perform queries, how can i do this?
Is DDD forcing me to get all of B's children just to get the calculated flag "IsAwesome" to work?
Or how am i supposed to do this correctly in a DDD environment?
A small hint in which direction i need to focus my research on would be appreciated.
UPDATE
As I was a bit broad in what my question is I'd like to rephrase whilst still using the same terms to be consistent.
B is awesome when one of it's children is awesome.
B itself, does not have a flag "awesome" as this is a calculated field based on the children.
B could have quite a few children, with the children each having allot of properties and data, which you do not want to retrieve just to check if one of the children is Awesome.
B has a method ShouldIBecomeADeveloper
If one of B's children is awesome, making B awesome, it should return a boolean "true"
If none of B's children are awesome, making B not awesome, it should return a boolean "false"

Disclaimer: although this is somehow a valid question, it is very broad, thus it may have many different valid answers.
You need to analyze the business requirements regarding the valid states in which the system is allowed to be. For this you need to answer the question: after a child of B becomes awesome, how fast needs B to become awesome as well?
There are two answers:
Immediately, in a strongly consistent matter. This means that the "awesome mutation" of a child of B and the "awesome mutation" of B are performed in an atomic fashion, they are in the same transaction. In this case you must load B and all its children before mutating one of its children awesomeness. The children of B are nested entities inside the B Aggregate.
It can be delayed, eventually changing its awesomeness to match the business rule, that is, the system can be for some time in a temporary invalid state. In this case, the children of B are also Aggregates. You need a way of mutating B when one of its "past childrens" mutate and for this you can use a Saga/Process manager.
In neither of the two cases you don't use lazy-loading, there is not such thing in case of DDD Aggregates. You can't anyway, if you have pure Aggregates, with no dependencies to Repositories (as you should).

B itself, does not have a flag "awesome" as this is a calculated field based on the children.
Even though "awesome" is a calculated field any operation you perform on the child entity has to go through "B" only, as it is the aggregate root. So you could have a state in "B" called numberOfAwesomeChildren and a child can become awesome/not awesome only when some operation happens on it and since all the operations are directed via "B" only, you can update the numberOfAwesomeChildren whenever a child becomes awesome/not awesome.
So "B" is awesome when numberOfAwesomeChildren is greater than zero.
Even this solution won't solve your lazy loading problem, since to perform an operation on a child entity you will end up loading all the child entity. You may have to have a re-look at your design.

Related

How can an immutable data structure NOT be thread safe?

In a post called What is this thing you call "thread safe"?, Eric Lippert says:
Thread safety of immutable data structures is all about ensuring that use of the data across all operations is logically consistent, at the expense of the fact that you're looking at an immutable snapshot that might be out-of-date.
I thought the whole point of immutable data structures is that they do not change and therefore cannot be out of date, and that therefore they are intrinsically thread-safe
What does Lippert mean here?
What does Lippert mean here?
I agree that the way I wrote that particular bit was not as clear as it could be.
Back in 2009 we were designing the data structures for Roslyn -- the "C# and VB compiler as a service" -- and therefore were considering how to do analysis in the IDE, a world where the code is almost never correct -- if the code were correct, why are you editing it? -- and where it can be changing several times a second as you type.
I thought the whole point of immutable data structures is that they do not change and therefore cannot be out of date, and that therefore they are intrinsically thread-safe.
It is the fact that they do not change that makes them possibly out of date. Consider a common scenario in the IDE:
using System;
class P
{
static void Main()
{
Console.E
}
}
We have immutable data structures which represent the world at the moment before you typed "E", and we have an immutable data structure which represents the edit you've just made -- striking the letter E -- and now a whole bunch of stuff happens.
The lexer, knowing that the previous lex state is immutable and matches the world before the "E" re-lexes the world just around the E, rather than re-lexing the entire token stream. Similarly, the parser works out what the new (ill-formed!) parse tree is for this edit. That creates a new immutable parse tree that is an edit of the old immutable parse tree, and then the real fun starts. The semantic analyzer tries to figure out what Console means and then what you could possibly mean by E so that it can do an IntelliSense dropdown centered on members of System.Console that begin with E, if there are any. (And we're also starting an error-reporting workflow since there are now many semantic and syntactic errors in the program.)
Now what happens if while we are working all that out on a background thread, you hit "backspace" and then "W"?
All that analysis, which is still in flight will be correct, but it will be correct for Console.E and not Console.W. The analysis is out-of-date. It belongs to a world that is no longer relevant, and we have to start over again with analyzing the backspace and the W.
In short, it is perfectly safe to do analysis of immutable data structures on another thread, but stuff perhaps continues to happen on the UI thread that invalidates that work; this is one of the prices you pay for farming work on immutable data out to worker threads.
Remember, these invalidations can happen extremely quickly; we budgeted 30ms for a re-lex, re-parse and IntelliSense update because a fast typist can get in well over ten keystrokes per second; having an lexer and parser that re-used the immutable state of past lexes and parses was a key part of this strategy, but you then have to plan for an invalidation that throws away your current analysis to happen just as quickly.
Incidentally, the mechanisms we needed to invent to efficiently track those invalidations were themselves quite interesting, and led to some insights into cancellation-based workflows -- but that's a subject for another day.
He means that you might be looking at a different snapshot than someone else. Consider how cons lists work: after adding another element to the head of a list, there are effectively two lists (snapshots). Both of them are immutable but not the same.

To Have An ID or Not To Have An ID - Regarding Value Object

Let's say two domain objects: Product and ProductVariety (with data such as color, size etc). The relationship between these two is one-to-many. Conceptually saying in the domain driven design, the ProductVariaty should be a value object, which is not the same object once its data is changed. From the implementation point of view, however, it is better to have some sort identification for the ProductVariaty so that we know which ProductVariety is selected and so on. Is an only solution to convert it to an entity class?
The following is a code segment to illustrate this situation.
#Embeddable
class ProductVariety {...}
#Entity
class Product {
#ElementCollection
private Set<ProductVariety> varities;
...
}
Conceptually saying in the domain driven design, the ProductVariaty should be a value object, which is not the same object once its data is changed
That's not quite the right spelling. In almost all cases (many nines), Value Object should be immutable; its data never changes.
Is an only solution to convert it to an entity class?
"It depends".
There's nothing conceptually wrong with having an identifier be part of the immutable state of the object. For example, PANTONE 5395 C is an Identifier (value type) that is unique to a particular Color (value type).
However, for an identifier like PANTONE 5395 C to have value, it needs to be semantically stable. Changing the mapping of the identifier to the actual color spectrum elements destroys the meaning of previous messages about color. If the identifier is "wrong", then the proper thing to do is deprecate the identifier and nominate a replacement.
Put simply, you can't repaint the house by taking the label off the old paint can and putting it on a new one.
In that case, there's no great advantage to using the identifier vs the entire value object. But its not wrong to do so, either.
On the other hand, if you are really modeling a mapping, and you want to follow changes that happen over time -- that's pretty much the definition of an entity right there.
What it really depends on is "cost to the business". What are the trade offs involved, within the context of the problem you are trying to solve?
Note: if you really do find yourself in circumstances where you are considering something like this, be sure to document your cost benefit analysis, so that the next developer that comes along has a trail of breadcrumbs to work from.

UML Circular reference with both aggregation and composition

A few days ago a friend pointed out to me that I had a wrong idea of composition in UML. She was completely right, so I decided to find out what more I could have been wrong about. Right now, there is one more thing that I have doubts about: I have a circular dependency in my codebase that I would like to present in UML form. But how.
In my case the following is true:
Both A and B have a list of C
C has a reference to both A and B to get information from.
C cannot exist if either A or B stops to exist
Both A and B remain to exist after C is deleted from A and/or B
To model this, I've come up with the following UML (I've ommited multiplicities for now, to not crowd the diagram.)
My question is, is this the right way to model such relations?
Problems
Some facts to keep in mind:
Default multiplicity makes your model invalid. A class may only be composed in one other class. When you don't specify multiplicity, you get [1..1]. That default is sad, but true.
The UML spec doesn't define what open-diamond aggregation means.
Your model has many duplicate properties. There is no need for any of the properties in the attribute compartments, as there are already unnamed properties at the ends of every association.
Corrections
Here is a reworking of your model to make it more correct:
Notice the following:
The exclusive-or constraint between the associations means only one of them can exist at a time.
Unfortunately, the multiplicities allow an instance of C to exist without being composed by A or B. (See the reworked model below.)
The property names at the ends of all associations explicitly name what were unnamed in your model. (I also attempted to indicate purpose in the property names.)
The navigability arrows prevent multiple unwanted properties without resorting to duplicative attributes.
Suggested Design
If I correctly understand what your model means, here is how I would probably reverse the implementation into design:
Notice the following:
Class D is abstract (the class name is in italics), meaning it can have no direct instances.
The generalization set says:
An instance cannot be multiply classified by A and B. (I.e., A and B are {disjoint}.)
An instance of D must be an instance of one of the subclasses. (I.e., A and B are {complete}, which is known as a covering axiom.)
The subclasses inherit the ownedC property from class D.
The composing class can now have a multiplicity of [1..1], which no longer allows an instance of C to exist without being composed by an A or a B.
Leave away the open diamonds and make them normal associations. These are no shared aggregations but simple associations. The composite aggregations are ok.
In general there is not much added value in showing aggregations at all. The semantic added value is very low. In the past this was a good hint to help the garbage collection dealing with unneeded objects. But nowadays almost all target languages have built-in efficient garbage collectors. Only in cases where you want an explicit deletion of the aggregated objects you should use the composite aggregation.

self-referencing core data model for specific use case

I have seen other posts that self-referencing a core data entity is possible, but I feel my use case is a little different and I am having a hard time understanding how to wire things up.
I have a Person entity and I want to track 2 things:
- an array of Person entities whose profile the user "visited"
- an array of Person entities who have viewed "this" users profile
The inverse logic is making it hard to understand.
I have User A, User B.
If user A visits user B, the following relationships should be set up:
- User A's visited profiles shows User B.
- User B should see that user A visited him.
This is a To-Many relationship as things are "interesting" only when you know who you followed and who's following you... :-)
Am I making this more complex than it is? :-(
What I tried:
Person Entity
-visitedProfiles : inverse is viewedProfiles (To-Many relationship)
-viewedProfiles : inverse is visitedProfiles (To-Many relationship)
Result:
User A --> User B (user A visists user B)
User A sees User B in BOTH (visitedProfiles and viewedProfiles) relationship.
Side-effect:
Also, regardless of how many profiles I visit, "visitedProfiles" and "viewedProfiles" always has only 1 item in the array (ie. the last profile I visited)
It's not an especially complicated case. I personally find your choice of words a bit confusing, though. "viewedProfiles" and "visitedProfiles" don't sound like inverses of each other to me. How about "viewedProfiles" and "viewers" instead?
Regardless of the word choice, though, set up the relationships as you have described. If you add B to "viewers of A", then B's "viewedProfiles" will also be updated.
Your side effect of knowing the most recent view/visit takes a little extra work. You could use an ordered relationship for the viewers/viewees; that feels like the simplest thing to do. Or you could add a new entity, a Visit, which notes the viewer, the viewee, and the time/date of the visit. But that second approach is indeed more complicated.
Your definition of the relationships looks OK. You can call either
[a addVisitedProfilesObject:b];
or
[b addViewedProfilesObject:a];
to add b to a.visitedProfiles and a to b.viewedProfiles.

Use Case relationship

can two use cases extend or include each other at the same time?
A extend/include B and B extend/include A
I'm pretty sure the answer is "NO".
You've just described the digital equivalent fo the chicken and egg problem.
Circular references are [almost] always Bad Things (tm). The only place I know it to not be horrible is in the context of a linked list, in which each entry has a pointer to another of its own type.
If (A includes/extends B and B includes/extends A) then A = B
Admitting that if A extends/includes B then A >= B
It seems likely not, though I'm sure you could do it if you went generic [and useless] enough. Do you have a specific example? There are always exemptions to the rules and I'd be curious to see one.
below is the senario for business use case (business modelling) not system use case:
USE Case A: Service Vehicle
Use Case B: Authorise Additional repair
Use Case C: Repair Vehicle
Additional repair could be identified during initial repair.
or repair could be identified as a new repair during service,
in both case, customer authorisation is required?
A extend B and B extend C (authorisation and start of repair identified during service)
C extend B (authorisation for additional repair identified during repair)
It's rare but in the general case, there's nothing that prevents use cases from including/using each other.
the answer is no. extend and include are mutually-exclusive relationship types. Most likely the use-cases are incorrectly factored/separated, or you've misunderstood the extend/include relationship definitions, or both.
given the example you posted (fyi it is better for you to edit the question rather than post an answer that does not answer the original question) i would venture that B extends A and B extends C, since in both cases A and C additional repairs (case B) may be identified.
alternately, use cases A and C could conditionally include use case B
offhand, i would model this as Work On Vehicle, which is a composition of 2 use-cases, Obtain Customer Authorization, and Service Vehicle, where the latter includes any kind of service or repair and requires the output of the former before starting the work. The notion of 'additional repairs' is just another instance of Work On Vehicle.
but i don't know the full business context, so your mileage may vary ;-)
EDIT: you wrote "but in this case: work is being carried out and further authorisation is required during the course of work", but i don't see how that really matters.
the first step is to eliminate the confusion about includes and extends. Try modeling each use-case completely and independently, and then look at what is common to see if includes/extends is warranted
"YES" - Checked the Spec.
I just read through the UML specification section for use cases:
http://www.omg.org/spec/UML/2.1.2/Superstructure/PDF/
There was no rule that would prevent doing this that I could find. Many people may conceptually have a problem with this, but that is ok, as you are just instinctively trying to objectize or structure use cases logically. Use Cases are a behavior (or set) and are not like classes/"objects". We are not talking about Java objects.
Even in Rational Software Modeler (IBM) allows this "circular reference".
In practice and in trying to map this to Java or other Object languages it may not make sense or get confusing.

Resources