I'm working through the Alloy tutorial and am just starting this chapter. My question is with the phrase that starts the chapter:
Now that we've built a model that ensures the structural correctness of our file system ...
When I run the model built so far I still get disconnected file systems, which seems to contradict this phrase.
This is with Alloy 4.2, build date 2012-9-25 downloaded from the website a few days ago. Am I doing something wrong or is this intentional? From my understanding I don't see anything in the model that prevents disconnects like this. But my understanding is still a bit fuzzy.
The relevant model is copied below:
// File system objects
abstract sig FSObject { }
sig File, Dir extends FSObject { }
// A File System
sig FileSystem {
live: set FSObject,
root: Dir & live,
parent: (live - root) ->one (Dir & live),
contents: Dir -> FSObject
}{
// live objects are reachable from the root
live in root.*contents
// parent is the inverse of contents
parent = ~contents
}
I could see the live: set FSObject line possibly requiring connection, but that's not my current understanding of the semantics of that line.
I take the tutorial's remark about structural correctness to mean that the model ensures the properties:
The filesystem root has no parent.
Every live object is reachable from the root via the contents relation.
The parent relation is the inverse of the contents relation.
Every object reachable from the root is live.
The contents and parent relations hold only on live objects. (Objects that aren't live have no parent and no contents.)
In the instance you show, note that Dir0 is not live, has no contents, and has no parent. So I think the instance obeys all the constraints I listed, and the file system (the tree rooted in Dir3) is in fact connected. Dir0 is not a counter-example and not a structural problem with the file system; it's just a file-system object that is not reachable from any file system root and thus not live. True?
Note that while the constraints do ensure that each FileSystem is a connected graph (a tree, in fact), they do not ensure that the file systems are connected to each other (nor that they are disjoint). This should be easier to see if you change the run command to ask for multiple file systems.
You might be able to get a good bar discussion going at an IETF meeting over whether these constraints constitute "structural correctness" for file systems in general, but I think in context the phrase is just intended to point back to what was done in lessons I and II of the file system example.
Related
I am wondering is the relationship between a Human and a Driver License an aggregation or a composition? It's clear for me that a Room and a Building relationship is a composition and a Chair and a Room is an aggregation. But a Driver License can exist without a Human but it makes no sense of its existence without a Human. I got stuck.
Since a driver license is not part of a human/person, but just related to her/him, there is neither a Composition nor an Aggregation between them, but just a plain Association.
The answer of Gholamali-Irani confuses the fact that a driver license must be associated with a person (that is, the resp. association end has an EXACTLY ONE multiplicty) with the (contingent) characteristics of many compositions to have inseparable parts, and mistakenly concludes that the Association must be a Composition.
In many cases, where we may wonder if an association is a composition, it is safer to model it as a plain association.
The only good reason for modeling an association (like Human-has-DriverLicense) as a composition is when the instances of the component type (here the driver licenses) are "weak entities" not having their own identity. But driver licenses do have their own ID, so there is no need, and no gain, to model them as components of their bearer.
I think that to answer the doubt in this question, we should define the following terms exactly:
the Context
Existing of an Instance in the Context
If the above terms are defined exactly, then there is not any doubt in using a Composition or an Aggregation.
I my idea, if I want to ask this question, in the my specific definition of terms:
Context : Real World
Existing of an Instance and destroying it: the usefulness of Instance is not related to it's Existence. Destroying it means to invalidating it. We should invalidate it after vanishing the owner. (But we do not do it immediately)
So, the relationship between a Human and a Driver License can not be a composition in the real world context. Because, by destroying a Human (vanishing, lose the life ,...), we do not destroy the Driver License immediately. It exists.
For example (in some countries), there is not any online and up-to-date invalidation mechanisms to invalidate a Driver License immediately, so it can be exist without the Driver until we invalidate it. So in this period of time (from vanishing the Driver to invalidating the Driver License) it exists and the usefulness of Instance is not related to it's Existence. Note that again: it is my definition of Context and Existence.
Edit (Based on #Thomas Kilian's comment):
For another example in the Context of Programming and it's technologies (like ORM), we should delete (invalidate) the Driver License immediately after deleting a instance of Driver (and we can do it in this Context). So the relationship should be a Composition.
Finally: I want to point the importance of the definition of terms (Context and Existing and other related terms) in modeling. If we do not define them exactly, many solutions appear to the problems (based on hidden definitions in their minds).
Hope to help.
Aggregation implies a relationship where the child can exist independently of the parent. Example: Class (parent) and Student (child). Delete the Class and the Students still exist.
Aggregation Example:
It's important to note that the aggregation link doesn't state in any way that Class A owns Class B nor that there's a parent-child relationship (when parent deleted all its child's are being deleted as a result) between the two. Actually, quite the opposite! The aggregation link is usually used to stress the point that Class A instance is not the exclusive container of Class B instance, as in fact the same Class B instance has another container/s.
Composition Example:
We should be more specific and use the composition link in cases where in addition to the part-of relationship between Class A and Class B - there's a strong lifecycle dependency between the two, meaning that when Class A is deleted then Class B is also deleted as a result
Composition implies a relationship where the child cannot exist independent of the parent. Example: House (parent) and Room (child). Rooms don't exist separate to a House.
Here is some additional information to elaborate the concept of Composition
As what Grady Booch Stated in the UML User's Guide, Addison Wesley
However, there is a variation of simple aggregation - composition - that does add some important semantics. Composition is a form of aggregation, with strong ownership and coincident lifetime as part of the whole. Parts with non-fixed multiplicity may be created after the composite itself, but once created they live and die with it. Such parts can also be explicitly removed before the death of the composite.
In addition, in a composite aggregation, the whole is responsible for the disposition of its parts, which means that the composite must manage the creation and destruction of its parts. For example, when you create a Frame in a windowing system, you must attach it to an enclosing Window. Similarly, when you destroy the Window, the Window object must in turn destroy its Frame parts.
(Source: UML User's Guide - by Grady Booch, James Rumbaugh, Ivar Jacobson, Addison Wesley)
Summing it up - (Read detailed Article)
To sum it up association is a very generic term used to represent when on class used the functionalities provided by another class. We say it's a composition if one parent class object owns another child class object and that child class object cannot meaningfully exist without the parent class object. If it can then it is called Aggregation.
Is it acceptable that my aggregate root holds a reference for a domain service in order to "save itself" while not holding reference to any repository?
The idea behind this is not have a application service with code like myDomainService.UpdateOrAdd(myAggregateRoot) but something like myAggregateRoot.Update()
Is it acceptable that my aggregate root holds a reference for a domain service in order to "save itself" while not holding reference to any repository?
DDD doesn't really have a standards body, or anything like that, so acceptable is going to be a subjective judgement.
It is weird, though, and if you were to bring that into a code review, I'd expect a lot of push back, simply because its contrary to the usual conventions.
The conventional approach is that the aggregate root object is just an entity in the domain model, and therefore the code within the implementation should look like domain code, not infrastructure code. Consequently, the responsibility for saving the state of the aggregate is normally assigned to the repository, rather than the object itself.
From the point of view of the application, there's very little to distinguish the code you describe, which probably looks something like
// TradeBook is the root of the aggregate
TradeBook book = repository.getById(...);
book.placeOrder(...)
book.update();
and the more usual spelling
TradeBook book = repository.getById(...);
book.placeOrder(...)
repository.save(book);
So, principle of least surprise; if you follow the usual pattern, the developer who inherits responsibility for your code is going to have an easier time of it.
what would be the best way to organize my event streams in ES. With event stream I mean all events to an aggregate.
Given I have a project with some data and a list of tasks.
Right now I have a Guid as AggregateID as my streamID.
So far I can
-> recreate the state for a given project with that ID
-> I can assemble a list of projects with a custom projection
The question would be how to handle todos?
should this also be handled below the project stream id or should it have it's own todo stream id?
If a todo has it's separate stream how would one link it to the owning project. How is the project aware of all the todo streams for a given project.
Meaning all changes to the todo list should be also recognized as Commands and Events (more Events) in the project.
And if I also want to allow free todo's without a relation to a project. Does it require to have its own type and stream to handle freeTodo on top. And the list of all todos whether project related or not would be a projection of all todo and freeTodo related streams?
So I guess the main question is how do I handle nested aggregates and how would one define the event store streams and the linking for that?
Any tips, tricks, best practises or resources will be highly appreciated.
// EDIT Update
First of all thank you #VoiceOfUnreason for taken your time to answer this question in great detail. I added the tag DDD because I got that strange feeling it correlates with the bounded context question which is most of the times no black or white decision. Obviously the domain has more depth and details, I simplified the exampled. Down below I shared some more details which got me questioning.
In my first thought I defined an aggregate for todo as well with a property for the project id. I defined this project property as option type (Nullable) to cover the difference between project related and free todo's. But following use cases/ business rules got me rethinking.
The system should also contains free todo's which allows the user to schedule personal tasks not project related (do HR training, etc). All todo's should appear either in their projects or in a complete todo list (both project related and free).
A project can only be finished/closed if all todo's are completed.
This would mix somehow information from aggregate project with information from aggregate todo. So no clear bounds here. My thoughts would be: a) I could leverage the todo read model in the project aggregate for validation. b) define some sort of listed structures for todo's within the project aggregate scope (if so how). This would handle a todo within the context of project and defines clear bounds
c) Have some sort of service which provides todo infos for project validation which somehow refers to point a.).
And all feels really coupled =-/
It would be great if you or someone finds the time to share some more details and opinions here. Thanks a million.
Reminder: the tactical patterns in ddd are primarily an enumeration of OO best practices. If it's a bad idea in OO, it's probably a bad idea in DDD.
the main question is how do I handle nested aggregates
You redesign your model.
Nested aggregates are an indication that you've completely lost the plot; aggregate boundaries should never overlap. Overlapping boundaries are analogous to an encapsulation violation.
If a todo has it's separate stream how would one link it to the owning project.
The most likely answer is that the Todo would have a projectId property, the value of which usually points to a project elsewhere in the system.
How is the project aware of all the todo streams for a given project.
It isn't. You can build read models that compose the history of a project and the history of the todos to produce a single read-only structure, but the project aggregate -- which is responsible for insuring the integrity of the state within the boundary -- doesn't get to look inside the todo objects.
Meaning all changes to the todo list should be also recognized as Commands and Events (more Events) in the project.
No, if they are separate aggregates, then the events are completely separate.
Under some circumstances, you might use the values written in an event produced by the todo as arguments in a command dispatched to the project, or vice versa, but you need to think of them as separate things having a conversation that may, or may not, ever come to agreement.
Possibilities: it might be that free standing todo items are really a different thing from the todo items associated with a project. Check with your domain experts -- they may have separate terms in the ubiquitous language, or in discussing the details you may discover that they should have different terms in the UL.
Alternatively, todo's can be separate aggregates, and the business adapts to accept the fact that sometimes the state of project and the state of the todo don't agree. Instead of trying to prevent the model from entering a state where the aggregates disagree, you detect the discrepancy and mitigate the problem as necessary.
I'm very new to CQRS/DDD, so there may be big holes in my understanding.
But let's suppose I have an aggregate object, Widget. Widget is composed with Note objects and Note objects can have a File object attached to them.
In CQRS I might have a command called AddNoteToWidget. I know from my reading that both command and event objects should be simple DTO's (I know they can also come in other forms, but the key thing being that they contain no behaviour).
I also understand that entities should never contain references to repositories since they should be persistence unaware.
Would my AddNoteToWidget contain a reference to the File object and just be serialized along with the command? If this is the case then my File object should be a value object. However, I have modelled it as an entity with it's own repository because I wanted to have central consistent file storage across the whole system.
From reading your question as well as the comments on it, it is clear that you currently treat File as both a sub-entity and an aggregate root. This is a problem, you should decide for one of the two:
Model File as an aggregate. Now only the ID of a File must be used outside of that aggregate, never the File itself. Also, File objects are retrieved through their own repository.
Model File as entity within the Widget aggregate. This means that you have the file readily available whenever you have a Widget. File objects don't have their own repository, they are loaded together with a Widget through the WidgetRepository.
Which of the two is better in your case I cannot tell from your question. As a guideline, aggregate boundaries are consistency boundaries, and aggregates are always persisted atomically. An app service should only modify a single aggregate.
I think the main problem that you currently have can be summarized as follows:
Repositories handle only whole Aggregates, never single Entities that are part of an Aggregate.
Of course, there may be simple aggregates that consist only of one entity, in that case, the entity and the aggregate are the same.
I'm one of many trying to understand the concept of aggregate roots, and I think that I've got it!
However, when I started modeling this sample project, I quickly ran into a dilemma.
I have the two entities ProcessType and Process. A Process cannot exist without a ProcessType, and a ProcessType has many Processes. So a process holds a reference to a type, and cannot exist without it.
So should ProcessType be an aggregate root? New processes would be created by calling processType.AddProcess(new Process());
However, I have other entities that only holds a reference to the Process, and accesses its type through Process.Type. In this case it makes no sense going through ProcessType first.
But AFAIK entities outside the aggregate are only allowed to hold references to the root of the aggregate, and not entities inside the aggregate. So do I have two aggregates here, each with their own repository?
I largely agree with what Sisyphus has said, particularly the bit about not constricting yourself to the 'rules' of DDD that may lead to a pretty illogical solution.
In terms of your problem, I have come across the situation many times, and I would term 'ProcessType' as a lookup. Lookups are objects that 'define', and have no references to other entities; in DDD terminology, they are value objects. Other examples of what I would term a lookup may be a team member's 'RoleType', which could be a tester, developer, project manager for example. Even a person's 'Title' I would define as a lookup - Mr, Miss, Mrs, Dr.
I would model your process aggregate as:
public class Process
{
public ProcessType { get; }
}
As you say, these type of objects typically need to populate dropdowns in the UI and therefore need their own data access mechanism. However, I have personally NOT created 'repositories' as such for them, but rather a 'LookupService'. This for me retains the elegance of DDD by keeping 'repositories' strictly for aggregate roots.
Here is an example of a command handler on my app server and how I have implemented this:
Team Member Aggregate:
public class TeamMember : Person
{
public Guid TeamMemberID
{
get { return _teamMemberID; }
}
public TeamMemberRoleType RoleType
{
get { return _roleType; }
}
public IEnumerable<AvailabilityPeriod> Availability
{
get { return _availability.AsReadOnly(); }
}
}
Command Handler:
public void CreateTeamMember(CreateTeamMemberCommand command)
{
TeamMemberRoleType role = _lookupService.GetLookupItem<TeamMemberRoleType>(command.RoleTypeID);
TeamMember member = TeamMemberFactory.CreateTeamMember(command.TeamMemberID,
role,
command.DateOfBirth,
command.FirstName,
command.Surname);
using (IUnitOfWork unitOfWork = UnitOfWorkFactory.CreateUnitOfWork())
_teamMemberRepository.Save(member);
}
The client can also make use of the LookupService to populate dropdown's etc:
ILookup<TeamMemberRoleType> roles = _lookupService.GetLookup<TeamMemberRoleType>();
Not so simple. ProcessType is most likley a knowledge layer object - it defines a certain process. Process on the other hand is an instance of a process that is ProcessType. You probably really don't need or want the bidirectional relationship. Process is probably not a logical child of a ProcessType. They typically belong to something else, like a Product, or Factory or Sequence.
Also by definition when you delete an aggregate root you delete all members of the aggregate. When you delete a Process I seriously doubt you really want to delete ProcessType. If you deleted ProcessType you might want to delete all Processes of that type, but that relationship is already not ideal and chances are you will not be deleting definition objects ever as soon as you have a historical Process that is defined by ProcessType.
I would remove the Processes collection from ProcessType and find a more suitable parent if one exists. I would keep the ProcessType as a member of Process since it probably defines Process. Operational layer (Process) and Knowledge Layer(ProcessType) objects rarely work as a single aggregate so I would have either Process be an aggregate root or possibly find an aggregate root that is a parent for process. Then ProcessType would be a external class. Process.Type is most likely redundant since you already have Process.ProcessType. Just get rid of that.
I have a similar model for healthcare. There is Procedure (Operational layer) and ProcedureType (knowledge layer). ProcedureType is a standalone class. Procedure is a child of a third object Encounter. Encounter is the aggregate root for Procedure. Procedure has a reference to ProcedureType but it is one way. ProcedureType is a definition object it does not contain a Procedures collection.
EDIT (because comments are so limited)
One thing to keep in mind through all of this. Many are DDD purists and adamant about rules. However if you read Evans carefully he constantly raises the possibility that tradeoffs are often required. He also goes to pretty great lengths to characterize logical and carefully thought out design decisions versus things like teams that do not understand the objectives or circumvent things like aggregates for the sake of convenience.
The important things is to understand and apply the concepts as opposed to the rules. I see many DDD that shoehorn an application into illogical and confusing aggregates etc for no other reason than because a literal rule about repositories or traversal is being applied, That is not the intent of DDD but it is often the product of the overly dogmatic approach many take.
So what are the key concepts here:
Aggregates provide a means to make a complex system more manageable by reducing the behaviors of many objects into higher level behaviors of the key players.
Aggregates provide a means to ensure that objects are created in a logical and always valid condition that also preserves a logical unit of work across updates and deletes.
Let's consider the last point. In many conventional applications someone creates a set of objects that are not fully populated because they only need to update or use a few properties. The next developer comes along and he needs these objects too, and someone has already made a set somewhere in the neighborhood fora different purpose. Now this developer decides to just use those, but he then discovers they don't have all the properties he needs. So he adds another query and fills out a few more properties. Eventually because the team does not adhere to OOP because they take the common attitude that OOP is "inefficient and impractical for the real world and causes performance issues such as creating full objects to update a single property". What they end up with is an application full of embedded SQL code and objects that essentially randomly materialize anywhere. Even worse these objects are bastardized invalid proxies. A Process appears to be a Process but it is not, it is partially populated in different ways any given point depending on what was needed. You end up with a ball mud of numerous queries to continuously partially populate objects to varying degrees and often a lot of extraneous crap like null checks that should not exist but are required because the object is never truly valid etc.
Aggregate rules prevent this by ensuring objects are created only at certain logical points and always with a full set of valid relationships and conditions. So now that we fully understand exactly what aggregate rules are for and what they protect us from, we also want to understand that we also do not want to misuse these rules and create strange aggregates that do not reflect what our application is really about simply because these aggregate rules exists and must be followed at all times.
So when Evans says create Repositories only for aggregates he is saying create aggregates in a valid state and keep them that way instead of bypassing the aggregate for internal objects directly. You have a Process as a root aggregate so you create a repository. ProcessType is not part of that aggregate. What do you do? Well if an object is by itself and it is an entity, it is an aggregate of 1. You create a repository for it.
Now the purist will come along and say you should not have that repository because ProcessType is a value object, not an entity. Therefore ProcessType is not an aggregate at all, and therefore you do not create a repository for it. So what do you do? What you don't do is shoehorn ProcessType into some kind of artificial model for no other reason than you need to get it so you need a repository but to have a repository you have to have an entity as an aggregate root. What you do is carefully consider the concepts. If someone tells you that repository is wrong, but you know that you need it and whatever they may say it is, your repository system is valid and preserves the key concepts, you keep the repository as is instead of warping your model to satisfy dogma.
Now in this case assuming I am correct about what ProcessType is, as the other commentor noted it is in fact a Value Object. You say it cannot be a Value Object. That could be for several reasons. Maybe you say that because you use NHibernate for example, but the NHibernate model for implementing value objects in the same table as another object does not work. So your ProcessType requires an identity column and field. Often because of database considerations the only practical implementation is to have value objects with ids in their own table. Or maybe you say that because each Process points to a single ProcessType by reference.
It does not matter. It is a value Object because of the concept. If you have 10 Process objects that are of the same ProcessType you have 10 Process.ProcessType members and values. Whether each Process.ProcessType points to a single reference, or each got a copy, they should still by definition all be exactly the same things and all be completely interchangeable with any of the other 10. THAT is what makes it a value Object. The person who says "It has an Id therefore is cannot be a value Object you have an entity" is making a dogmatic error. Don't make the same error, if you need an ID field give it one, but don't say "it can't be a Value Object" when it in fact is albeit one that for other reason you had to give an Id to.
So how do you get this one right and wrong? ProcessType is a Value Object, but for some reason you need it to have an Id. The Id per se does not violate the rules. You get it right by having 10 processes that all have a ProcessType that is exactly the same. Maybe each has a local deeep copy, maybe they all point to one object. but each is identical either way, ergo each has an Id = 2, for example. You get is wrong when you do this: 10 Processes each have a ProcessType, and this ProcessType is identical and completely interchangeable EXCEPT now each also has it's own unique Id as well. Now you have 10 instances of the same thing but they vary only in Id, and will always vary only in Id. Now you no longer have a Value Object, not because you gave it an Id, but because you gave it an Id with an implementation that reflects the nature of an entity - each instance is unique and different
Make sense?
Look i think you have to restructure your model. Use ProcessType like a Value Object and Process Agg Root.
This way Every Process has a processType
Public class Process
{
Public Process()
{
}
public ProcessType { get; }
}
for this u just need 1 agg root not 2.