I'm looking at creating activity streams to represent the activity of a museum collection. In this case the actors are the artists & makers of the museums' objects, and (ideally) their streams they can be followed, to see what is happening with the collection. However I'm not sure if this maps across very well to the user model, as I assume that's really intended for real life users. Is there some other way to map this grouping into the activity streams format, to create an activity stream something like:
John Constable feed:
1 Jan 2019: Painting 'The Hay Wain' has been moved to Gallery 20.
(I'm assuming here 'moved' is the verb, Gallery is the object, and 'The Hay Wain' is a collection)
A couple of possible solutions to this are:
use a collection entry as the actor for these activities, for instance an artist collection with all the artist.
use a user as the actor, but make sure that the user ID of artist is different than your real life users. For instance by prefixing it with artist-.
Related
I have an aggregate called Survey - you can create a Survey, send a Survey and respond to a Survey.
I also have an aggregate called Person. They can receive a Survey and respond to a Survey. This aggregate includes demographic information that describes the Person.
I think my Survey aggregate should contain a list of people that have received the Survey. That would include the date they received it and any of their answers, if they have responded. But I feel like I don't need most of the demographic information that would normally come along with my existing Person aggregate.
I tried playing around with different concepts, like calling a send a "Delivery" and calling the employees "Recipients", but the business doesn't speak in those terms. It's just - "I create a Survey and then I send that Survey to people".
So does it make sense to create a different Person aggregate just within Survey? The action of sending a Survey to someone exists as records in the DB, along with responses to the Survey. Is this a better use case for Value Objects?
As soon as you use phrases like "I don't need all of the...data" or "this is like that but with a few more attributes but not these original ones" you are implicitly introducing the notion of a projection of an entity from one bounded context into another bounded context.
In your case a Person is in a different bounded context from a Person taking a survey (I will call the latter a SurveyParticipant) because even though it's the same actual person taking the survey, the focus of the two entities is different.
Here's a possible solution to your problem (expanded a bit, just for context).
Person is projected into the Survey Taking bounded context as a SurveyParticipant. As a bonus, Survey is really the definition of a survey, but SurveyInstance is a Survey that can be/is taken by these SurveyParticipants.
SurveyParticipant is not a Person. A SurveyParticipant is a person who is (going to) participate in completing a SurveyInstance.
Bottom line,
Can you use a simplified existing Aggregate in a different Aggregate Root
Yes. You do this by projecting the data from one aggregate to an entity in another context (at least in my proposed solution).
So does it make sense to create a different Person aggregate just within Survey?
Sort of. An aggregate can never contain another aggregate, but it can refer to one in the same bounded context. I didn't do this in this solution. The alternative, as shown, is that an aggregate can contain information from another aggregate as a projection of that other aggregate.
This is a strategic design problem.
I think you have two Bounded Contexts here, so you should split your Person domain model between them. Person from Survey Context will contain only data and behavior you need for your Surveys. Person from other one (Marketing Context for example) covers marketing team needs.
Here is an example from Martin Fowler's blogpost about BC's
So you're almost right with other aggregate, but it is not a simplified version, it's a separate one.
Lets say an Invoice was generated for a Customer. This specific event would look something like this:
invoice.raised {
"id": "4dbcff82-6f35-4155-9aec-f8185c1f932f",
"total": "50.00",
"description": "Order 01133",
"customer_id": "c2206843-414d-454f-9894-57c6b11b9c00"
}
This is fairly simple example and it refers to customer aggregate that an invoice belongs to.
Difficulty manifests itself when I want to create Invoices view and I want to embed Customer's name in an invoice. I could do two things - enrich the original event to contain Customer's name or load up the Customers view to find out what the name is when I am building my Invoices view.
Now this is not a very complicated example, but in some cases it becomes almost unmanageable to enrich events anymore as I end up with a lot of properties of various aggregates copied into the event that is very specific to some other aggregate.
Is there a universally accepted way of dealing with this apart from enriching events? Because everytime now the invoice.cancelled event is raised I will have to also include the amount of the invoice once again, so that I can update Customers view with new balance for instance.
in some cases it becomes almost unmanageable to enrich events anymore as I end up with a lot of properties of various aggregates copied into the event that is very specific to some other aggregate.
That's right, it makes your events less manageable.
So I'd say that it's enough to have just customer_id and ask for customer name when you build your read model:
It can be at projecting time, when denormalised view is built.
It can be at querying time, when resulted view model is built based on invoices and customers (for this use case you can have dedicated list of customers with customer_id and customer_name only)
Because everytime now the invoice.cancelled event is raised I will have to also include the amount of the invoice once again, so that I can update Customers view with new balance for instance.
invoice.cancelled event is triggered by Invoice aggregate root, I expect, and it owns amount so it is natural to put amount into invoice.cancelled event.
invoice.raised event is triggered by Invoice aggregate root too but it does not own customer name. It cannot check if customer name is consistent at specific point in time anyway. That's why instead of embedding customer name you can simly query it when you build your read model.
BTW there is a good reading about designing events - 6 Code Smells with your CQRS Events – and How to Avoid Them
Difficulty manifests itself when I want to create Invoices view and I want to embed Customer's name in an invoice.
Is there a universally accepted way of dealing with this apart from enriching events?
You don't want to go down the road of enriching events if you can possibly help it -- that increases the coupling in your implementation, which makes changing your model more expensive.
UI Composition techniques might guide you in a useful direction. Udi Dahan wrote about them a number of times. Some examples
UI Composition Techniques...
Secret of Better UI Composition
The basic plot - instead of InvoiceView fetching Customer state, and using that state to produce a view of the customer, instead the InvoiceView delegates a share of the responsibility to the Customer component itself
InvoiceView (e : invoice.raised) {
InvoiceWidget(e.id)
CustomerWidget(e.customer_id)
}
I am doing UML class diagram for the first time. I have put a data store in class diagram I am not sure if I can . Also, is it possible to get feedback on this class diagram I have uploaded?
Basically its a hotel management system.
I am explaining the story point wise here. I have removed the unwanted stuffs from the story.
1) Login - Allow user to search room if he is a registered user. If not he/she should be able to register to hotel management system.
2)User should be able to search the available rooms from the system and select a type of room-Available rooms based on check in and check out dates.
3)Hotel employee should be able to charge for the facilities availed.
4)Store user information for marketing Purposes.
5)User should be able to cancel made reservation of rooms.
6)Make payments online.
7)User/receptionist should be able to modify/update rooms booked, User information from the information they have. - I added data store.
Placing login method in the class which gains login does not seem to be reasonable. Authorization should be a class of its own and a user may gain access through it.
There is nothin modeled which shows the occupation of rooms. I'd expect some Occupation class which links rooms to time ranges.
The same. What is the basis for the occupation? There needs to be an Occupation class which relates Room with time frames.
What are marketing purposes? You could implement some user statistics that traces when a user has booked rooms, how punctual he paid, etc. Those are not modeled.
Since you have not modeled a Reservation you will not be able to cancel it.
The Payment is related to nothing. So you don't know for what a payment was made. Your book keeping will love you for that :-(
As above: no reservation modeled - no modification possible.
You should probably find some mentor to sit together and do some basic modeling.
Edit (as on the updated model): This is not the way to go. The datastore will serialize the single objects, and not be a class of its own. The way you need to do it is to construct a model with the relevant classes. Those will finally result in persistent objects in the database. FacilityAvailed does not look sensible. This looks like information you can compute from Reservation (which needs a relation to Room which is now missing completely). Well, you should dump this approach and start all over. Just model the business objects (BO): Room, Reservation, User, Payment, etc. Relate those meaningful. What are the attribute of each BO (Room: Number, Size, Cost,... User:Role, Name, ...). Then try to relate them. E.g. a Reservation may relate Room and User, but could also be simply for refurbishment/cleaning etc.
I'm struggling with some implementation details when looking at the terms mentioned in the title above.
Can someone tell me whether my interpretation is right?
For reference I look at a CRM Domain
As a AggregateRoot I could see a Customer.
It may have Entities like Address which contains street, postal code and so on.
Now there is something like Contact and Activity this should be at least aggregates. Right? Now if the Contacts and Activities would have complex business logic. For example, "Every time a contact of the type order is created, the order workflow should be started"
Would then Contact need to be an Aggregate root? What may be implementation implications that could result from this?
Further more when looking and Event Sourcing, Would each Aggregate have its own Stream? In this scenario A Customer could have thousands of activities.
It would be great if someone could guide em in which part my understanding is right and which I differ form the common interpretation.
What do you mean by “at least aggregates”?
An aggregate is a set of one or more connected entities. The aggregate can only be accessed from its root entity, also called the aggregate root. The aggregate defines the transactional boundaries for the entities which must be preserved at all time. Jimmy Bogard has a good explanation of aggregates here.
When using event sourcing each aggregate should have its own stream. The stream is used to construct the aggregates and there is no reason to let several aggregates use the same stream.
You should try to keep your aggregates small. If you expect your customer object to have thousands of activities then you should look at if it is possible to design the activities as a separate aggregate, just as long as its boundaries ensures that you do not leave the system in an invalid state.
I am quite familiar with dealing with simple entity relationships, such as making a group that contains a collection of many items. However, I'm wondering how to achieve a particular relationship within my data structure.
Currently my data structure is made of entity Group and entity Item which has a one-to-many relationship from Group. The item exists only in a single group. However, it can also provide a link to another group as required.
So an analogy for the situation could be: Group = House, Item = Inhabitants. I live at a particular house, but I can also provide information about where to find other houses.
Another analogy could be: Group = Playlist, Item = Songs. I listen to the songs of the playlist, then when I get to a particular song I can (optionally) decide to switch to another playlist.
Now I am pretty sure this is not the way to achieve this behaviour. I had the notion that it should be an attribute rather than a relationship, but I don't know if there is a way to link attributes unrelated NSManagedObjects (that I know of).
I'm thinking that it's not impossible, just that it requires a little more understanding of databases to achieve. Any advice, tutorials would be greatly appreciated!
EDIT: This is my second attempt at the data structure. Instead of it being a relationship, I've made a integer identifier on the group, and particular items can store this identifier as necessary in the form of an attribute.
The otherGroupIdentifier would store a value equal to identifier on the Group entity. That way I can link through to it as explained previously. However, this certainly does not seem to be the cleanest way to implement Core Data. Maybe what I am looking for is not possible or too complex for a Core Data system?