---
title: 'Use Case Diagrams'
source: 'https://academia.sh/en/courses/modeling-and-representation/use-case-diagrams'
course: 'Modeling and Representation'
language: en
updated: '2026-08-17T18:08:15+00:00'
license: 'CC BY-SA 4.0'
---

# Use Case Diagrams

Counting separately what the actor, scenario, and system-boundary notation carries and what it drops: seven internal steps omitted on purpose, two links dropped by accident, and 512 systems collapsing into the same diagram.

The previous topic measured the static side of a system: which class is linked to which,
which direction a link runs, how many distinct component partitions the same class set
collapses into. Every question asked there looked at the system in its state of not
running.

This topic looks at the moment the system runs: who starts what, in what order messages
travel, in what order work can be done, what states an object passes through. The first
of the four behavioral notations carries **the least information** of the four — and
that is not a flaw. The use case notation deliberately leaves the inside of the system
empty. This lesson's job is to count that emptiness, because until it is counted, there
is no way to know whether a gap was **left on purpose** or **fell through unnoticed**.

The lesson's question is not which diagram type fits which question; that measurement
was made over a set of eighteen questions in the Architectural Decisions and
Documentation course of the Software Architecture curriculum, and is not repeated here.
The question here begins **after** a type has been chosen: how many distinct systems
does the chosen type fail to tell apart.

## The Four Fields the Notation Carries

The use case notation carries four kinds of information: the **actor**, the
**scenario**, the **link** connecting an actor to a scenario, and the **system
boundary**, which states what is the system's own work and what belongs to a neighbor.
That is the whole list. There is no order, no condition, no internal step, no data.

In the repair-shop example, these four fields correspond to the following. There are
two actors: the customer and the intake clerk. There are three external facts: opening
a work order, checking status, picking up. All three are started from outside the
system, and all three are the workshop's own work — that is what the boundary states,
and these three ownership decisions are three separate facts. Inside the system, by
contrast, seven internal steps run — allocating stock, assigning a technician,
reserving a workbench, processing a line item, generating a document, computing cost,
keeping records — and none of them is started by an actor.

Total: **20 facts** — 2 actors, 3 scenarios, 5 actor–scenario links, 3 ownerships, 7
internal steps.

## Building and Counting the Diagram

The model below does not draw a diagram; it builds the **list of fields the diagram
carries** and finds, by exhaustive count, how many distinct systems produce that same
list. The real set of links has five links (**DD1**); the drawn diagram writes three of
them (**DD2**).

```python
"""Use case notation: intentionally omitted facts and inadvertently dropped
facts are counted separately. The count is exhaustive, not an estimate."""
from itertools import product

INTERNAL_FACTS = ["allocating stock", "assigning a technician", "reserving a workbench",
                   "processing a line item", "generating a document", "computing cost",
                   "keeping records"]
EXTERNAL_FACTS = ["opening a work order", "checking status", "picking up"]

# DD1: the workshop's real actor-scenario links and each scenario's owner
ACTORS = ["Customer", "IntakeClerk"]
REAL_LINKS = [("Customer", "opening a work order"), ("Customer", "checking status"),
              ("Customer", "picking up"), ("IntakeClerk", "opening a work order"),
              ("IntakeClerk", "picking up")]
REAL_OWNER = {s: "system" for s in EXTERNAL_FACTS}   # all three are the workshop's own work
# DD2: the drawn diagram writes three of the five links
DRAWN = [("Customer", "opening a work order"), ("Customer", "checking status"),
         ("Customer", "picking up")]


def notation(links, internal, owner, drawn_links, drawn_internal=(), boundary=True):
    """The notation carries only this: actor, scenario, actor-scenario link,
    system boundary. An undrawn link or internal step never appears in the
    notation; if the boundary is not drawn, whether a scenario is the
    system's own work or a neighbor's is never stated."""
    return (tuple(ACTORS),
            tuple(EXTERNAL_FACTS) + tuple(sorted(i for i in internal if i in drawn_internal)),
            tuple(sorted(b for b in links if b in drawn_links)),
            tuple(owner[s] for s in EXTERNAL_FACTS) if boundary else None)


def symbol_count(drawn_links, drawn_internal=(), boundary=True):
    return (len(ACTORS) + len(EXTERNAL_FACTS) + len(drawn_links) + (1 if boundary else 0)
            + 2 * len(drawn_internal))


def systems_collapsed(drawn_links, drawn_internal=(), boundary=True):
    """How many distinct systems produce the same diagram: exhaustive count."""
    target = notation(REAL_LINKS, INTERNAL_FACTS, REAL_OWNER, drawn_links,
                       drawn_internal, boundary)
    count = 0
    for link_mask in product((0, 1), repeat=len(REAL_LINKS)):
        links = [b for b, m in zip(REAL_LINKS, link_mask) if m]
        for internal_mask in product((0, 1), repeat=len(INTERNAL_FACTS)):
            internal = [i for i, m in zip(INTERNAL_FACTS, internal_mask) if m]
            for owner_mask in product(("system", "neighbor"), repeat=len(EXTERNAL_FACTS)):
                owner = dict(zip(EXTERNAL_FACTS, owner_mask))
                if notation(links, internal, owner, drawn_links, drawn_internal, boundary) == target:
                    count += 1
    return count


total_facts = (len(ACTORS) + len(EXTERNAL_FACTS) + len(REAL_LINKS) + len(EXTERNAL_FACTS)
               + len(INTERNAL_FACTS))
print("SYSTEM  :", total_facts, "facts =", len(ACTORS), "actors +", len(EXTERNAL_FACTS),
      "scenarios +", len(REAL_LINKS), "links +", len(EXTERNAL_FACTS), "ownerships +",
      len(INTERNAL_FACTS), "internal steps")
print("NOTATION:", symbol_count(DRAWN), "symbols")
print("COST    :", systems_collapsed(DRAWN), "systems collapse into the same diagram")
print()
print("  intentionally omitted (notation cannot carry) :", len(INTERNAL_FACTS), "internal steps")
print("  inadvertently dropped (could have been carried):",
      len([b for b in REAL_LINKS if b not in DRAWN]), "links")
for b in REAL_LINKS:
    if b not in DRAWN:
        print("     not drawn:", b[0], "->", b[1])
print("  drawn diagram             : symbols", symbol_count(DRAWN),
      "| collapses to", systems_collapsed(DRAWN))
print("  all five links drawn      : symbols", symbol_count(REAL_LINKS),
      "| collapses to", systems_collapsed(REAL_LINKS), "<- BASELINE of the notation")
print()
print("what happens to the baseline when a field is dropped")
print("field set                    symbols  collapse  bits carried")
BASELINE = systems_collapsed(REAL_LINKS)
for name, links, boundary in (("actor+scenario+link+boundary", REAL_LINKS, True),
                               ("link dropped", [], True),
                               ("boundary dropped", REAL_LINKS, False),
                               ("both dropped", [], False)):
    d = systems_collapsed(links, (), boundary)
    print(f"{name:29s} {symbol_count(links, (), boundary):7d} {d:9d} {(d // BASELINE).bit_length() - 1:14d}")
print()
# DD3: second configuration. Two internal steps are drawn as an "included use case."
EXTRA = ("generating a document", "computing cost")
print("if two internal steps are drawn as an included use case:")
print("  symbols", symbol_count(REAL_LINKS), "->", symbol_count(REAL_LINKS, EXTRA),
      "| collapse", BASELINE, "->", systems_collapsed(REAL_LINKS, EXTRA))
print("  cost: number of actorless scenarios 0 ->", len(EXTRA),
      "| external-fact ratio", f"{len(EXTERNAL_FACTS)}/{len(EXTERNAL_FACTS)}",
      "->", f"{len(EXTERNAL_FACTS)}/{len(EXTERNAL_FACTS) + len(EXTRA)}")

# DD4: if the two actors are merged into a single role
POSSIBLE = [(a, s) for a in ACTORS for s in EXTERNAL_FACTS]


def merged(links, internal, owner):
    """Single-actor diagram: only 'is some actor linked' per scenario."""
    return (("User",), tuple(EXTERNAL_FACTS),
            tuple(any(b[1] == s for b in links) for s in EXTERNAL_FACTS),
            tuple(owner[s] for s in EXTERNAL_FACTS))


target = merged(REAL_LINKS, INTERNAL_FACTS, REAL_OWNER)
count = 0
for link_mask in product((0, 1), repeat=len(POSSIBLE)):
    links = [b for b, m in zip(POSSIBLE, link_mask) if m]
    for internal_mask in product((0, 1), repeat=len(INTERNAL_FACTS)):
        internal = [i for i, m in zip(INTERNAL_FACTS, internal_mask) if m]
        if merged(links, internal, REAL_OWNER) == target:
            count += 1
print()
print("if the two actors are merged into a single role:")
print("  symbols", symbol_count(REAL_LINKS), "-> 8 | collapse", BASELINE, "->", count,
      "| ratio", count // BASELINE, "x")
```

```
SYSTEM  : 20 facts = 2 actors + 3 scenarios + 5 links + 3 ownerships + 7 internal steps
NOTATION: 9 symbols
COST    : 512 systems collapse into the same diagram

  intentionally omitted (notation cannot carry) : 7 internal steps
  inadvertently dropped (could have been carried): 2 links
     not drawn: IntakeClerk -> opening a work order
     not drawn: IntakeClerk -> picking up
  drawn diagram             : symbols 9 | collapses to 512
  all five links drawn      : symbols 11 | collapses to 128 <- BASELINE of the notation

what happens to the baseline when a field is dropped
field set                    symbols  collapse  bits carried
actor+scenario+link+boundary       11       128              0
link dropped                        6      4096              5
boundary dropped                   10      1024              3
both dropped                        5     32768              8

if two internal steps are drawn as an included use case:
  symbols 11 -> 15 | collapse 128 -> 32
  cost: number of actorless scenarios 0 -> 2 | external-fact ratio 3/3 -> 3/5

if the two actors are merged into a single role:
  symbols 11 -> 8 | collapse 128 -> 3456 | ratio 27 x
```

Three numbers stand side by side: the system has **20 facts**, the notation has **9
symbols**, the cost is **512 systems**. Five hundred twelve distinct repair shops look
identical through this diagram; someone looking at the diagram cannot know which one
they are looking at.

## Two Distinct Losses

The number five hundred twelve comes from two different sources, and they are useless
unless kept apart.

**Intentionally omitted facts.** None of the seven internal steps find a place in the
notation's information set. The use case notation has no field for writing an internal
step; even if it did, it would not be written, because this notation's reason for
existing is to close off the system's inside and show its outside. This loss **binds
the type, not the drafter**: every use case diagram drops these seven facts, no matter
how carefully it is drawn.

**Inadvertently dropped facts.** The intake clerk's two links were of a kind the
notation could carry — an actor–scenario link, the third item on the list. They were
not written. This loss **binds the drafter, not the type**, and can be fixed
without drawing a different diagram.

The difference between the two cannot be seen by looking at the diagram. The reader sees
the same thing in both cases: information that is not there. Whether a piece of
information is missing **on purpose or by carelessness** can only be shown by holding
the system itself and comparing it against the notation. This is why a loss cannot be
known as intentional until it is counted; an uncounted gap is not a defended gap, only
an unseen one.

## Baseline Ambiguity Comes with the Type

When the two links are written, the ambiguity drops from 512 to **128** — a factor of
four. The entire drop is credited to the drafter, because the price paid is only two
symbols — 9 symbols becomes 11.

The number 128 does not go any lower from there. This is the use case notation's
**baseline ambiguity**: each of the seven internal steps either exists in the system or
does not, the notation writes none of them, and so $2^7 = 128$ distinct systems collapse
into the same diagram. The baseline is a number that does not change with drafting
skill; **it comes with the type**.

There are two numbers to look at when evaluating a notation. The baseline states how
much of the chosen type refuses, from the start, to show. The gap between the baseline
and the actual ambiguity states how much the drafter lost unnecessarily. The first is a
design decision, the second is a defect, and they cannot be told apart when referred to
by a single number.

## A Symbol Is Not Always One Bit

The middle table drops the fields one at a time and measures where the baseline lands.
Dropping the five link symbols sends the baseline from 128 to 4096: five symbols were
carrying **5 bits**. Exactly one bit per link, because each link either exists in the
system or does not.

The boundary does not behave this way. Dropping the single boundary symbol sends the
baseline from 128 to **1024** — one symbol was carrying **3 bits**. The reason: the
boundary does not state a single fact but the ownership of all three scenarios at once.
In a diagram where the boundary is not drawn, the reader cannot know whether opening a
work order is the workshop's own work or a neighboring system's; three unknowns remain
for three scenarios.

This differs from the ratio measured in the structural notation, where every added
symbol carried exactly one bit of ambiguity, because every symbol there wrote a single
binary field. In the use case notation, the number of bits a symbol carries depends on
how many facts that symbol fixes at once. When both are dropped, the baseline rises to
32768 and the notation drops to 5 symbols: what remains is nothing but two actor names
and three scenario names, and **8 bits** of information have been lost. The rule that
follows is that counting symbols alone is not a measure by itself; what should be
counted is not the symbol but **the fact the symbol fixes**.

## The Count of Merging Roles

The same measure also works in the opposite direction. If the customer and the intake
clerk are merged into a single user role (**DD4**), the diagram simplifies: 11 symbols
becomes 8, the link count drops from five to three, the drawing shrinks. Ambiguity, on
the other hand, rises from 128 to **3456** — a factor of **27**.

The number twenty-seven can be read directly. The single-actor diagram states, for each
scenario, only that "some user is linked to it," not which role is linked. For each of
the three scenarios, at least one of the two roles has to be linked, which gives $2^2 -
1 = 3$ possibilities per scenario, and $3^3 = 27$ for three scenarios. Multiplied by the
128 of the seven internal steps, this gives 3456.

Here the justification for keeping the roles separate is not a matter of style but a
measured quantity of information. Three symbols were saved, and roughly 4.75 bits of
information were given up in exchange. The question to ask when simplifying a notation
is not whether the drawing looks cleaner, but which facts have become indistinguishable.

## Bringing an Internal Step into the Notation

There is exactly one way to bring the ambiguity below the baseline: make the
untransportable fact transportable. Generating a document and computing cost can be
drawn as second-level scenarios included inside the scenario (**DD3**). The number drops
immediately: the baseline goes from **128 to 32**, two bits are gained, and the notation
rises from 11 symbols to 15.

The cost is not the symbol count. The two newly drawn scenarios have **no actor link at
all** — no actor starts them, because both are the system's own work. The number of
actorless scenarios rises from 0 to 2. The ratio of external facts in the diagram drops
from 3/3 to 3/5: only three of the diagram's five scenarios are now started from outside
the system.

What this means is that the system boundary no longer separates anything. What the
boundary carried was the information "the inside is closed, the outside enters through
these three doors"; once the internal steps move to the same side of the door, that
information becomes void. Ambiguity dropped by a factor of four, but **what the notation
says changed** — it no longer describes the face visible from outside, but part of the
work itself. The gain is 2 bits and can be counted; the loss is the meaning of a field,
and it can only be counted once it is noticed.

## Summary

- The use case notation carries four fields: actor, scenario, actor–scenario link,
  system boundary. Order, condition, internal step, and data are not in this list.
- Of the workshop's 20 facts (2 actors, 3 scenarios, 5 links, 3 ownerships, 7 internal
  steps), the drawn diagram writes 9 symbols, and **512 distinct systems** collapse into
  the same diagram.
- Five hundred twelve comes from two sources: **7 internal steps** the notation cannot
  carry, and **2 links** it could have carried but that were not drawn. The two cannot
  be told apart by looking at the diagram.
- Once the two missing links are drawn, ambiguity drops to 128; 128 is the notation's
  **baseline ambiguity**, it comes with the type, and it does not change with drafting
  skill.
- The five link symbols carry 5 bits, the single boundary symbol carries 3 bits: how
  many bits a symbol carries depends on how many facts that symbol fixes at once.
- Merging two actors into a single role brings 11 symbols down to 8 but raises
  ambiguity from 128 to 3456: a factor of 27. Drawing two internal steps as an included
  scenario brings the baseline down to 32 but raises the number of actorless scenarios
  from 0 to 2 and drops the external-fact ratio from 3/3 to 3/5.

## Next Step

The use case notation deliberately closed off the inside of the system, and the cost of
that was counted. The next notation does the opposite: it lifts the lid and shows the
inside, laying messages out along a time axis. At first glance this looks like a choice
that zeroes out the loss — every message, every participant, every sequence number is
written.

The next lesson measures why this is a misreading. The workshop's flow, because of the
two branches of allocation, the two branches of finding a technician, the variable
number of line items, and optional document generation, produces **24 distinct traces**.
A sequence diagram is, by definition, **a single trace**; its coverage is 1/24, that is,
0.0417. Four diagrams make 0.1667. The lesson counts where the alternative-fragment and
loop-fragment notations move this ratio, and at what cost raising the ratio to 1.0
comes.
