Let's say I have the following relationship ):
Aggregate A (contains E1, E2, E4)
- Entity of type E1
- Entity of type E2 (contains E3)
- Sub-entity of type E3
- Entity of type E4
All entities implement the following signature:
fun handleCommand(command: Command): List<Event> // returns a list of events that can be applied on itself
fun handleEvent(event: Event): Entity // returns itself with the new event applied
When handling a command on say E4, that should logically cause some side-effect (events) on E2, what is the best-practice? Note that this should not be confused with sagas, but this is rather a general question about how resulting side-effects on parent entities should be generated when handling a command on a child entity.
This is the point of an Aggregate. It would coordinate this process. External code would not be able to issue a command directly on E4 as it would be encapsulated in the Aggregate. Rather the command would be routed to the aggregate and the aggregate would issue and coordinate the process internally.
Hope that helps
The literature is pretty weak on non-trivial aggregates.
When handling a command on say E4, that should logically cause some side-effect (events) on E2, what is the best-practice?
Probably the most important thing to note is this: cause and effect is part of the business logic, not part of the state. We don't need to consider the hollistic interconnectedness of all things when we are integrating events, because the other things are written down elsewhere.
When we are reconstituting entities from their histories, the business rules no longer apply - each entity state is derived from its own events in isolation.
Because the entities are all part of the same aggregate, their events should be written together, to a single persistent storage in a single transaction.
Because the entity states are logically isolated from one another, the order of events doesn't particularly matter - entity behaviors are concurrent. Each entity should see its own events in the "right" order, but it doesn't particularly matter is entity E4 is reconstituted from its events before or after E2.
(Order of events in a single entity may still be relevant.)
Related
Given a class inheritance hierarchy:
which says:
class S inherits A1 and A2
class A1 and A2 inherits B1
class A2 inherits B2
class B2 inherits C1
and for class A1, B1, B2, C1, they have classifierBehavior attribute setted, while
the class S has no classiferBehavior.
Now the question is, when I run simulation for class S, then what behavior should be executed?
In Cameo Systems Modeler, the simulation engine will execute classifier behavior of A1, B1, and B2.
Is this the correct way and can be derived from UML spec?
The UML specification doesn't tell us how to deal with multiple inherited classifierBehaviors. However, the fUML specification says:
fUML 1.5 (page 151): [5] startBehavior [...] create a classifier behavior invocation for each of the types of the object of this object activation which has a classifier behavior [...].
So, I think the Cameo simulation engine works as specified, since the supertypes are in the list of types an object has. And, it really makes sense. If something is of two types, it should exhibit the behavior of both types. For example an inverter-charger will react to the events an inverter and a charger reacts to.
One thing I didn't find in the specification is, that when a Class has a classifierBehavior, the inherited behaviors should be replaced by it. I think it makes sense, because otherwise the inherited behaviors could never be changed. The simulation engine does exactly this.
Now, it is possible, that you want to select one of the inherited behaviors instead of defining a new one or executing them concurrently. This could be done by defining an empty Behavior with a generalization to the inherited classifierBehavior and assign this as classifierBehavior. This doesn't work in the simulation engine though. fUML excludes redefinition of ActivityNodes, so this could be an explanation why Activity generalization doesn't work. However, the "Precise Semantics of State Machines" specification allows redefinition of states.
So the only way I found was to create a new classifierBehavior and call one of the inherited behaviors.
The situation for resolving the method of an operation is different. For example it could have an output. Here only the modeler can decide, which output shall be returned. This is done by defining a new version of the operation that redefines both old versions and select the behavior from the desired ancestor as method of the new operation. I think this is fairly straight forward and no reason for rejecting multiple inheritance.
I skimmed the UML 2.5 specs and found this paragraph on p. 288:
If the Class of the receiving object owns a method for the Operation identified in the CallEvent, then that method is the result of the resolution. Otherwise, the superclass of the Class of the receiving object is examined for a method for the Operation, and so on up the generalization hierarchy until a method is found or the root of the hierarchy is reached. If a Class has multiple superclasses, then all of them are examined for a method. If no method is found, or a method is found in more than one ancestor Class along different paths, then the model is ill-formed for this resolution process and it results in no method.
So there you are. It's not valid to have multiple behaviors defined. Other than that you can/must override the behavior with something new.
I have three classes one is called
WorkCoordinator and it calls different service classes depending on an event passed to it, so if the event is trackIssue there is a TrackService class that handles some operations specifically for tracking and there is also a Track object. So you could have the following
WorkCoordinator -- (track issue) --> TrackService (has a list of Track objects)
How would you correctly represent these three in a UML diagram ? where everything starts with the workcoordinator which uses a TrackService and TrackService may have a function like add(Track track), where you would pass it a Track object to add to an array list within it say:
private ArrayList<Track> tracks;
and as add gets called, then a track is added to tracks.
Appreciate any insights, I was thinking something like this but may be totally wrong.
I have three classes one is called
Contrarily to an operation a class cannot be called, but it can be used.
WorkCoordinator -- (track issue) --> TrackService
when the event string is trackIssue the class WorkCoordinator uses the class TrackingService, but how ? Because in your diagram the class TrackingService only has the operation add that means that operation is called, even I have some doubt about that, more the fact we don't know from where the instance of Track given in argument comes from. If an other operation is called add it in the diagram.
About your diagram :
the role of the line between WorkCoordinator and TrackingService is unknown as it is, and then invalid. Because of the attribute trackingService probably you wanted to also show it as a relation, in that case the relation must completed.
TrackingService has two lists of Track, one though the attribute trackItems and an other one through the relation tracks. This is probably not what you wanted, and trackItems must be renamed tracks or the reverse.
to show the same thing through an attribute and a relation is legal in UML, but quite heavy because the reader must check they are the same thing, I encourage you to use only one of them, and to favor the relation when both classes are drawn.
your aggregation says TrackingService is composed of Track, are you sure this is the case and an aggregation must be used ?
How would you correctly represent these three in a UML diagram ?
The class diagram does not indicate at all that when the processed event is trackIssue the operation add (or an other) is applied on trackingService (with the right argument). Of course you can add a note to say that, but that note is a free text and only human can understand it.
To show that in a diagram you can use a sequence diagram or an activity diagram, depending on what you want to show.
The sequence diagram showing what happens during the execution of process can be (supposing a new instance of Track is created to be given in argument to add) :
event is supposed to be the argument of process, to name the instance of TrackingService I used trackingService being the name of the attribute, and item represents the created instance of Track to use it in the message add.
All of that seems vague, but this is normal because an interaction is not a behavior, and a sequence diagram focuses on message interchange between lifelines.
If you want to fully model the behavior of the operation process without ambiguity you can use an activity, and the diagram can be :
Additional remarks :
An event is generally much more than a name like trackIssue, so the parameter of process is not a string or that string is a complex form.
Track has getter/setter for the id but not for the name, seems strange. Are you sure the id is not only set (with name) when an instance is created ?
The task:
Each field has place for multiple entities and have 1-10 neighbors.
The fields are different. Some of them are trapped and if an entity
steps on them they will not be able to leave. There are also
radioactive fields and if an entity spends too much time on them,
they dies. Fields can not be trapped and radioactive at the same time.
There are two different entities. Some of them are able to escape from trapped fields (E1) and some of them are immune for radioactivity (E2). Entities can move between neighboring tiles.
From this I have got the following class diagram (only the classes):
So I want to know how can I represent that if E1 steps on Radioactive and if it stays there too long dies? Furthermore how can it handle that case when a new E1 comes and it does not die when the first one?
First I tried with something like this, but it can not handle that event
EDIT:
My soloutin:
First diagram (first version on the question)
Your generalizations if they exist are in the wrong direction, currently a Field is a Trapped and a Radioactive and an Entity is a E1 and a E2, but you wanted the reverse.
Anyway there is nothing in the statement saying a field cannot be both trapped and radioactive, in that case rather than to use generalizations better to use properties.
For the Entities it seems there are only E1 and E2 so you can use generalization (in reverse direction)
Second diagram
Note if Radioactive implements a Timer that means someone else has to kick each Radioactive and only them (no other Field).
Concerning the time to die, if it is the same whatever the instance of E1 and Radioactive that attribute can be static.
I do not understand the operation KillEntity because the moment an E1 is killed depends on when each instance enter in the field so cannot be general
You can handle the delay to die for a Field in a Radioactive in that least, for instance :
each time an Entity enter in a Radioactive the Entity is added in dying for instance initializing duration to 0
each time an Entity exit in a Radioactive the Entity is removed in dying
each time tick is called each duration is increased and when becoming timeToDie the corresponding Entity is removed from dying and the operation die called on it
the operation dies does noting on Entity but on E2 indicates the instance is killed (it is also possible to have that operation abstract on Entity and defined but doing nothing on E1)
Note you can replace the class-association by an association with a qualifier valuing the duration etc
But you can also handle the delay to die in E2 :
tick on Entity/E2 is applied by a Radioactive on its Fields each time it is itself ticked, tick does nothing on Entity but manages the duration on E2 to kill the instance after the required delay (a static attribute can be shown again)
each time an E2 moves to a new Field the duration is reset to 0
Note your multiplicity 1..* is wrong because a Field may not have Entity, on the opposite side the multiplicity is 1 if a dead E2 stay in a Radioactive else 0..1
I was wondering whether it would be considered bad practice to use an aggregate identifier across a service in another (extensipn) aggregate which shares that they are both revolving about the same identifiable entity.
The problem I am currently having is that we want to split some logic (bounded context if you so will) into a different service as the one originally creating the aggregate.
In general, this seems to work, as when I send a Command within the second service, it is picked up and updates its state. As I can use EventSourcingHandler to also use Events created in the other service to manipulate its state, I get state information from a source applied by the first services aggregate.
I was worried that the snapshot mechanism would work against me, but apparently it is smart enough to store snapshots separately as long as I make sure the aggregate "type" name is not the same.
So far, so good, the only thing that's a smell for me is that the second aggregate does not have (needs) an initial constructor CommandHandler, as the creation is done in the first aggregate.
So, am I going against the way axon framework intends aggregates to be used, or is this a viable use case?
#Aggregate
#Getter
#NoArgsConstructor
public class Foo {
#AggregateIdentifier
private String fooIdentifier;
#CommandHandler
public Foo(CreateFooCommand command) {
apply(FooCreatedEvent.builder()
.fooIdentifier(command.getFooIdentifier())
.build());
}
#EventSourcingHandler
public void on(FooCreatedEvent event) {
this.fooIdentifier = event.getFooIdentifier();
}
}
#Aggregate
#Getter
#NoArgsConstructor
public class Bar {
#AggregateIdentifier
private String fooIdentifier;
private String barProperty;
#CommandHandler
public void on(UpdateBarCommand command) {
apply(BarUpdatedEvent.builder()
.fooIdentifier(this.fooIdentifier)
.barProperty(command.getBarProperty())
.build());
}
#EventSourcingHandler
public void on(FooCreatedEvent event) {
this.fooIdentifier = event.getFooIdentifier();
}
#EventSourcingHandler
public void on(BarUpdatedEvent event) {
this.barProperty = event.getBarProperty();
}
}
The case for why I tried to split is that we wanted to separate the base logic (creation of the aggregate, in this case a vehicle) from the logic that happens and is handled in a different bounded context and separate microservice (transfers from and to a construction site). Since I cannot publish a creation event (CommandHandler in the constructor, sequence 0) for the same aggregate identifier but different aggregate type twice, I could not separate the two states completely.
So my only options right now would be what I presented above, or use the creation of the second aggregate to set a different aggregateId, but also add internally the aggregateId of the first aggregate to allow for events to be published with the aggregateId information of the first as a reference Id. To make this work I would have to keep a projection to map back and forth between the two identifiers, which also does not look too good.
Thanks in advance,
Lars Karschen
Very interesting solution you've come up with Lars. Cannot say I have ever split the Aggregate logic in such a manor that one service creates it and another loads the same events to recreate that state in it's own form.
So, am I going against the way axon framework intends aggregates to be used, or is this a viable use case?
To be honest, I don't think this would be the intended usage. Not so much because of Axon, but more because of the term Bounded Context you are using. Between contexts, you should share very consciously, as terms (the ubiquitous language) differs per context. Your events are essentially part of that languages, so sharing the entirety of an aggregate's stream with another service would not be something I'd suggest normally.
Whether these services you are talking about truly belong to distinct Bounded Contexts is not something I can deduce right now, as I am not your domain expert. If they do belong to the same context, sharing the events is perfectly fine. Then still I wouldn't recreate a different aggregate based on the same events. So, let me add another concept which might help.
What I take from your description, is that you have something called a Vehicle aggregate which transitions different states. Wouldn't a Polymorphic Aggregate be the solution you are looking for? That way you can have a parent Vehicle aggregate with all the basics, and more specific implementations when necessary? Still, this might not fit your solution completely, something I am uncertain about given your description.
So, I am going to add a third pointer which I think is valuable to highlight:
Since I cannot publish a creation event (CommandHandler in the constructor, sequence 0) for the same aggregate identifier but different aggregate type twice, I could not separate the two states completely.
This line suggests you want to reuse the Aggregate Identifier between different Aggregates, something which comes back in the question's title too. As you've noted, [aggregate identifier , sequence number] pairs need to be unique. Hence, reusing an aggregate identifier for a different type of aggregate is not an option. Know however that Axon will use the toString method of your aggregate identifier class to fill in the aggregate identifier field. If you would thus adjust the toString() method to include the aggregate type, you'd be able to keep the uniqueness requirement and still reuse your aggregate identifier.
For example, the toString method of a VehicleId class containing a UUID would normally output this:
684ec9f4-b9f8-11ea-b3de-0242ac130004
But if you change the toString to include the aggregate type, you would get this:
VehichleId[684ec9f4-b9f8-11ea-b3de-0242ac130004]
Concluding, I think there are three main points I'd like to share:
Axon Framework did not intent to reuse Aggregate Streams to recreate distinct Aggregate types.
Polymoprhic Aggregates might be a means to resolve the scenario you have.
The [aggregateId, seqNo] uniqueness requirement can reuse an aggregateId as long is the toString method would append/prepend the aggregate type to the result.
I hope this helps you on your journey Lars. Please let me know of you feel something is missing or if I didn't grasp your question correctly.
I am new to Flutter and the BLoC design pattern. However, the concept of BLoC looks pretty straightforward and I think I understand it pretty well.
Occasionally, when reviewing my coworkers' code, I see that when implementing a BLoC, they tend to store data inside the BLoC class. I believe this is wrong, and that the data belongs in the state class. If it needs to be passed around or stored somewhere until the state can be created, it should be stored in the event instance that triggers the change, not the BLoC itself.
My understanding is that the BLoC class is a state machine whose sole purpose is to map events to states and have no other state besides the defined "state" class. This is separation of concerns - the event class(es) should store the data triggering the change, the state class(es) should store the data after the change, and the BLoC should handle the operations manipulating that data and mapping it from event to state.
If you store data inside the BLoC class, the state machine changes its functionality from (event, state0) => state1 to (event, state0, blocData) => state1. It's clear that if you want to unit-test your BLoC, the complexity of your tests increases, because you will need to test |event| X |state| X |blocData| cases instead of |event| X |state| cases (meaning cartesian multiplication of number of possible values for each type). One can claim that it doesn't really affect the number of possible values, because we would just move blocData to state. However, my claim is that if you encapsulate the data together, you will usually find that they are dependent and some combinations are irrelevant, but you can maintain this dependency only when encapsulating them together, or at least protect it from breaking only when encapsulating together.
Another reason is that your application code that sees a state and sends an event, may potentially produce indeterministic results. This is because the BLoC instance has a "dirty" state that has an effect on its functionality.
I'd like to hear opinions from developers that have some more experience in this design pattern. If you can post some references to articles on this issue, that'd be great too. I didn't find anything specific about this issue.