Do forked nodes have to be joined? UML State Diagram

1k Views Asked by At

Do forked nodes have to be be joined in the end? And can outgoing fork nodes have guards?

Basically what I'm trying to do is return the change to the customer and continue with the car wash at the same time.

But, maybe there's a better way to do it?

UML State Diagram

3

There are 3 best solutions below

3
On BEST ANSWER

Do forked nodes have to be be joined in the end?

For me no, this is not mandatory, but the group will end when all the flows and linked elements will end too

can outgoing fork nodes have guards?

You mean outgoing flows, the norm says a fork segment must not have Guards or Trigger

Basically what I'm trying to do is return the change to the customer and continue with the car wash at the same time.

Yes they can be done in parallel, for the wash machine point of view all is done when it return the change and the wash is done too

4
On

Do forked nodes have to be be joined in the end?

It depends. If you want to continue with your split flow then yes. If you do not join them you just have two loose ends continuing independently until each of them terminates the one or other way.

And can outgoing fork nodes have guards?

P. 360 of UML 2.5 states

  • fork_segment_guards

A fork segment must not have Guards or Triggers.

inv: (source.oclIsKindOf(Pseudostate) and source.oclAsType(Pseudostate).kind = PseudostateKind::fork) implies (guard = null and trigger->isEmpty())

(I was wrong with that and fixed this after bruno noticed me about it.)

maybe there's a better way to do it?

Sure. There are many ways to describe things. But except for the superfluous guard that seems to be ok.

4
On

In short

It is not written black on white, but if you fork you will have some constraints that will sooner or later require you to join in practice. There is only one valid construct that let you avoid the join in practice.

In more details

It is an indirect consequence of the concurrent flow of tokens and the rules for ending the flow.

According to UML 2.5 specifications, a flow-final has the following behavior:

A FlowFinalNode is a FinalNode that terminates a flow. All tokens accepted by a FlowFinalNode are destroyed. This has no effect on other flows in the Activity.

You can use it to absorb the tokens on one of the concurrent flows, without impact on the other branches.

Similarly, the activity-final obeys the following principle:

An ActivityFinalNode is a FinalNode that stops all flows in an Activity. A token reaching an ActivityFinalNode owned by an Activity terminates the execution of that Activity.

But there is no rule that defines the speed of each flows, nor that each flow will perform all the expected activities if you do not have a join. This is the problem of the missing synchronisation.

Imagine that you have two forked flows that remain independent: each flow will then have to end somehow. If you have no join:

If an Activity owns more than one ActivityFinalNode, then the first one to accept a token (if any) terminates the execution of the Activity, including the execution of any other ActivityFinalNodes.

So the first flow that reaches the activity-final will interrupt the ongoing activity on the other flows, leaving the performance of the other flows incomplete.

The only way to ensure that both branches would end correctly without interruption, would therefore to have a flow-final on each branch.

If one of the flow cycles you have the problem of the multiplication of tokens du to the concurrent flows, that are reinjected in the circuit (which correspond to concurrent execution).

The only other way to avoid a join node, is to use an implicit join:

An ExecutableNode shall not execute until all incoming ControlFlows (if any) are offering tokens. That is, there is an implicit join on the incoming Control Flows. Specific kinds of ExecutableNodes may have additional prerequisites that must be satisfied before the node can execute.

But implicit or explicit, it's a join ;-)