In a UML activity diagram, what is the difference between a decision node and a fork node?
answer
- Ask how many paths continue
- Choice of one, or all at once
- Diamond splits by guard, bar splits unconditionally
- Merge closes alternatives; join closes concurrency
basics
~20 sA decision node chooses exactly one outgoing path, selected by guards on its edges; a fork node starts every outgoing path at once as concurrent flows. A merge node reunites the alternatives; a join node waits for all the concurrent flows.
solid answer
~50 sBoth symbols split a flow, but into different things. A **decision node** is a diamond with one incoming edge and several outgoing edges, each carrying a guard in square brackets; exactly one of those edges is taken. A **fork node** is a thick bar that copies the incoming token onto *every* outgoing edge, so all of those flows become active together — it is concurrency, and its edges carry no guards. Each has a closing partner, and the pairing is what interviewers are really testing: alternatives opened by a decision node close with a **merge node**, which passes each arriving token straight through; concurrency opened by a fork node closes with a **join node**, which waits until a token has arrived on every incoming edge. Read the edge counts before the shape, because both diamonds look alike and both bars look alike.
code
pseudocode · 15 linesinitial -> receive request
receive request -> DIAMOND
DIAMOND -[urgent]-> triage now
DIAMOND -[else]-> queue for later
triage now -> MERGE-DIAMOND
queue for later -> MERGE-DIAMOND
MERGE-DIAMOND -> record outcome
record outcome -> BAR-SPLIT
BAR-SPLIT -> notify requester
BAR-SPLIT -> update record
notify requester -> BAR-SYNC
update record -> BAR-SYNC
BAR-SYNC -> close request
close request -> activity finalgo deeper
Be ready to name all four nodes on sight: a diamond is a decision or a merge, a thick bar is a fork or a join. Say plainly which one picks a single path and which one starts several at once.
Explain the token rule for each node — one outgoing edge for a decision, a copy on every edge for a fork, straight through for a merge, wait-for-all for a join — and show which node pairs with which when the paths come back together.
Show that you catch the two structural bugs in review: alternatives closed by a join node, which stalls the flow, and concurrency closed by a merge node, which runs the following action twice on partial results.
Own the convention for the team. Decide when concurrency belongs in a model at all, because a fork node the implementation cannot honour buys nothing and misleads every later reader of the diagram.
## Tokens: the rule behind every node An activity diagram models work as **actions joined by control flows**, and the way to read one is as a token game. An *initial node* drops a token into the flow; each **action** takes the token, performs its step, and puts it back on its outgoing edge; the token travels along the edges until a final node absorbs it. Every node type is nothing more than a rule about what it does with the tokens that arrive on it, and the four nodes people confuse differ only in that rule. A **decision node** is a diamond with one incoming edge and two or more outgoing edges. Each outgoing edge carries a **guard** written in square brackets. Exactly one outgoing edge is taken — the one whose guard is true — so a decision node is a *choice of one path*. A **merge node** is also a diamond, but with several incoming edges and one outgoing edge. It passes every arriving token straight through and waits for nothing. It is what you draw to bring alternative paths back together. A **fork node** is a thick bar with one incoming edge and several outgoing edges. It copies the token onto **every** outgoing edge, so all those flows become active at the same time. A fork node is *concurrency*, and its outgoing edges carry no guards. A **join node** is the same thick bar with several incoming edges and one outgoing edge. It waits until a token has arrived on every incoming edge, then emits a single token. It is the synchronisation partner of a fork node. ## The pairing rule | Node | Shape | Edges | Rule for arriving tokens | Closing partner | |---|---|---|---|---| | Decision | Diamond | 1 in, many out | leaves by the single edge whose guard is true | Merge | | Merge | Diamond | many in, 1 out | each token passes straight through, no waiting | Decision | | Fork | Bar | 1 in, many out | copied onto every outgoing edge at once | Join | | Join | Bar | many in, 1 out | held until every incoming edge has a token | Fork | The pairing is the whole trick: **a decision node closes with a merge node, a fork node closes with a join node**. Two shapes carry four meanings, so read the *edge count and direction* before you read the shape. One edge in and many out is a split — a choice if it is a diamond, concurrency if it is a bar. Many edges in and one out is a rejoin — pass-through if a diamond, wait-for-all if a bar. Some diagrams draw a single diamond with several incoming and several outgoing edges; read that as a merge immediately followed by a decision. ## The two failures interviewers listen for 1. **Closing alternatives with a join node.** The decision node sent the token down one of two paths, so only one incoming edge of the join will ever carry a token. The join waits for the other one forever and the flow stalls. On a whiteboard it looks tidy and symmetric, which is exactly why it survives review. 2. **Closing concurrency with a merge node.** A fork node put a token on both paths, and the merge passes each one through as it arrives, so the action after the merge runs **twice** — once early, on partial results. In a real workflow this is the duplicate notification, or the record written before half its content exists. A third, quieter mistake is hanging a guard on a fork node's outgoing edge. If a path is conditional it is a choice, and the honest model puts a decision node before or after the fork rather than smuggling a condition onto a concurrency bar. ## Concurrency here means 'unordered', not 'threaded' A fork node does not claim that the paths run on separate threads, processors or machines. It claims something weaker and far more useful: **the diagram places no ordering constraint between those flows**. They may interleave, run genuinely in parallel, or run one after the other — every one of those is a legal execution of the model. Draw a fork when the order truly does not matter, and a plain sequence when it does. A fork over work that must be ordered is a modelling error even if the implementation happens to serialise it anyway. ## A reading checklist - Count edges first: one-in-many-out is a split, many-in-one-out is a rejoin. - Diamond means choice or pass-through; bar means concurrency or synchronisation. - Every outgoing edge of a diamond split should carry a guard, including a catch-all. - No outgoing edge of a bar split carries a guard. - Trace one token by hand: it should reach exactly one outcome, and nothing after a rejoin should be reachable twice. - If a join node has an incoming edge that a token cannot always reach, you have drawn a deadlock. The pay-off for getting this right is that the diagram becomes executable in a reader's head. A colleague can put a finger on the initial node, walk the token, and find the duplicate run or the stall before anybody writes the code — which is the only reason to draw the picture at all.
- What happens if a join node is used where a merge node belongs?The join node waits for a token on every incoming edge, but the decision node upstream only ever produced one, so the other edge stays empty and the flow stalls at the bar forever. It is a modelled deadlock, and it reads as symmetric and tidy on the page, which is why it survives review. Alternatives always close with a merge node.
- Can the outgoing edges of a fork node carry guards?No — a fork node starts every outgoing flow unconditionally, and that is the entire content of the symbol. If one of the concurrent paths is conditional, model it honestly: put a decision node on that path after the fork, or before the fork when the condition decides whether concurrency starts at all.
- Does a fork node mean the flows run on separate threads?No. A fork node asserts only that the diagram places no ordering constraint between those flows, so interleaved, truly parallel and strictly sequential are all legal executions of the same model. Use one when order genuinely does not matter; an implementation that serialises forked flows is not violating the diagram.
A decision node is a railway switch: the train leaves on exactly one track. A fork node is a shunting yard that sends a copy of the train down every track at once, and the join node further along is the platform that will not dispatch until all the copies are back.
saying these in an interview costs you the question
- Calls every diamond a fork because both split the flow
- Thinks a fork node evaluates a condition before splitting
- Uses a join node to reunite mutually exclusive alternative paths
- Uses a merge node to reunite two concurrent flows
- Insists a fork node requires separate threads to be valid
- Writes the guard inside the diamond instead of on its edges