System modelling is the engineering practice of producing selective abstractions of a system, each one emphasising a single concern (interaction, structure, behaviour, deployment) and ignoring the rest. The Unified Modelling Language (UML, ISO/IEC 19505 since 2012; current version 2.5.1, 2017) is the OMG-standardised notation in which these models are drawn. This companion covers the discipline's origin in the work of Booch, Rumbaugh, and Jacobson (the Three Amigos, 1994 to 1997), the four families into which models sort, accurate notation for the seven diagrams the course uses in depth, and a worked example that follows one user requirement from elicitation to first-cut design.
Software engineering is the discipline that builds large, useful programs without their complexity becoming the dominant cost. Modelling is one of the levers that keeps complexity under control: a model shows part of the system clearly precisely because it hides everything else. Different stakeholders need to see different parts, which is why there is no single diagram type that captures a system, and why this companion treats seven of them.
The idea of a "model" in engineering predates software. In mechanical, civil, and electrical engineering, drawings replace prose because they are denser, more checkable, and (when standardised) less ambiguous. The same case applies to software, with one extra wrinkle: the artefact we are modelling does not yet exist, so the model has to do double duty as both description (of what we intend to build) and specification (of what counts as having built it correctly). Sommerville (Software Engineering, 10th ed., 2015, ch.5) captures this in a one-sentence definition that is worth taking apart:
"A model is an abstract view of a system that ignores some system details. Complementary system models can be developed to show the system's context, interactions, structure, and behaviour."
Sommerville (2015), Software Engineering, 10th ed., chapter 5, opening definition.Two words in that sentence carry the weight: ignores and complementary. A model ignores by design; if it captured every detail, it would be the system itself, and would offer no leverage. And no single model is enough: a use case diagram says nothing about how data is structured, a class diagram says nothing about how messages flow over time, a sequence diagram says nothing about how the system is deployed across machines. Complementary models compose into a full picture because each ignores something different, and the engineer's job is to know which complement to add next.
The shorter, practitioner-facing summary is: a model is the language of the designer; a description of the system-to-be-built (or as-built) from a particular perspective; a tool for communicating with stakeholders; and a means of reasoning about some characteristic of the system without holding the whole of it in your head. UML, the Unified Modelling Language, is the standardised vocabulary in which those models are now drawn. The rest of this chapter develops where UML came from (§2), where it is used in practice (§3), how to choose which model to draw (§4 through §6), and how to draw each of the seven course diagrams correctly (§7 through §13). Section 14 ties them together with a worked example from elicitation to first-cut design; section 15 lists the marking pitfalls.
Before you draw a model, you should know which two questions it answers, because if it answers neither, it is not earning its place on the page:
Every diagram in this companion is paired with a short "where it earns its place" panel that names the reader and the decision. Keep those two anchors in mind as you read; they are what separates a useful diagram from a textbook one.
Underneath the fourteen UML diagram types are just three modelling moves you make again and again. Recognising which move you are making is the easiest way to pick the right diagram:
If you find yourself drawing a diagram without doing one of these three moves, the diagram is probably not adding value; you are decorating.
"All models are wrong; some are useful."
George E. P. Box, 1976. The aphorism is the standard justification for model-based work in any engineering discipline: a model that captured every detail of the system would be the system itself, and would therefore be no easier to reason about.A model earns its place by what it makes discussable. A use case diagram makes the system's interactions with its users discussable in a single page; a class diagram makes its static structure discussable; a sequence diagram makes one specific interaction discussable. None of them captures the system, and that is exactly the point.
UML did not arrive whole. It was the result of a deliberate, three-year unification at Rational Software (1994 to 1997) of three competing object-oriented modelling notations, led by the engineers who had created them. Understanding that backstory matters, because every UML diagram type still bears the fingerprint of which of the three contributed it.
The 1980s and early 1990s were the boom years of object-oriented analysis and design. Smalltalk had been released in 1980; C++ in 1985; Java arrived in 1995. As industry adopted these languages, the demand for diagrammatic notations to plan large object-oriented systems exploded. By the early 1990s the field had no fewer than fifty published methods, each with its own conventions for classes, associations, inheritance, and behaviour. Fowler later called the period the "method wars" (UML Distilled, 2003, ch.1): teams that adopted one method could not exchange diagrams with teams that adopted another, and reading the OO literature meant learning a different graphical vocabulary every few months.
Three of the methods dominated by 1994. Each was associated with one prominent author, each came out of a different industrial setting, and each was strongest in a different part of the lifecycle:
| Author | Method | Strength | What it contributed to UML |
|---|---|---|---|
| Grady Booch (Rational Software) | Booch method (1986, refined 1991 and 1994 in Object-Oriented Design with Applications). | Architectural and design-level modelling. Introduced the distinctive "cloud" class symbol and a granular notation for module dependencies and visibility. | Class diagrams (the three-compartment box), package diagrams, component diagrams, and most of UML's structural-modelling vocabulary. |
| James Rumbaugh (General Electric R&D) | Object Modeling Technique (OMT) (Rumbaugh, Blaha, Premerlani, Eddy, and Lorensen, 1991). | Analysis-level modelling for large data-rich systems. Strong on associations, multiplicities, and the data model. | The now-universal class-diagram notation with associations and multiplicities, plus the state-machine notation derived from Harel statecharts. |
| Ivar Jacobson (Ericsson, then Objectory) | Object-Oriented Software Engineering (OOSE) (1992), out of his earlier work on Ericsson's AXE telephone switches. | Requirements engineering and process. Originated the concept of the use case. | Use case diagrams, the actor / system-boundary notation, and the include / extend stereotypes covered in section 7 of this companion. |
The three were complementary in scope (analysis, design, requirements) and convergent in spirit (all object-oriented, all diagrammatic), but stubbornly incompatible in notation. A class drawn in OMT looked nothing like a class drawn in Booch, and Jacobson's use case bubbles had no equivalent in either. Teams that mixed methods spent disproportionate effort translating between them.
The first move came in October 1994: Rumbaugh left General Electric to join Booch at Rational Software, with the explicit goal of merging OMT and the Booch method. They circulated a draft "Unified Method" version 0.8 in October 1995. Jacobson sold Objectory to Rational the same month and joined the team; from that point the three were collaborating in one company, on one notation. Industry shorthand quickly named them the Three Amigos, after the 1986 film.
The unification was not a vote between three favourites; it was a re-engineering of the combined notation around what each method did best. Rumbaugh's class-and-association notation became UML's structural backbone; Jacobson's use cases were lifted in essentially unchanged; Booch's emphasis on design-level diagrams supplied component and deployment views. The result was published as UML 0.9 in June 1996, renamed Unified Modelling Language rather than Unified Method (a deliberate distinction: a language is a notation only, not a prescribed process).
In November 1997, the Object Management Group (OMG) adopted UML 1.1 as a standard. The OMG is an industry consortium founded in 1989 to standardise object-oriented and distributed-system technologies (it also maintains CORBA and SysML). UML's transfer to OMG was the moment it stopped being a Rational product and became a public standard. Major revisions since:
| Year | Version | What changed |
|---|---|---|
| 1996 | UML 0.9 | First published draft from Rational; merged Booch and OMT notations with Jacobson's use cases. |
| 1997 | UML 1.1 | Adopted by the OMG. Notation frozen for the first time. |
| 2005 | UML 2.0 | Major revision. Added the sequence-diagram interaction fragments (alt, opt, loop, par, ref) covered in section 11. Introduced composite structure diagrams. Refined activity diagrams along business-process-modelling lines. |
| 2015 | UML 2.5 | The version Sommerville's 10th edition uses; mostly a clean-up of the 2.0 specification. |
| 2017 | UML 2.5.1 | The currently published standard. Stable; the language has not changed substantively in nearly a decade. |
The OMG specification runs to several hundred pages and is the authoritative reference when a notation question is genuinely contested. For day-to-day use, Fowler's UML Distilled (3rd ed., Addison-Wesley, 2003) remains the most-cited compact practitioner reference; the "three amigos" themselves jointly published The Unified Modeling Language User Guide (2nd ed., 2005) as the official user-level companion.
Before UML, learning object-oriented modelling meant choosing a method and then being unable to read diagrams from teams that had chosen differently. After UML, a diagram drawn at Microsoft was readable at IBM, in a university research lab, and in a textbook. The standardisation did not improve the diagrams themselves; it improved the ability of the industry to communicate about them. This is the same value proposition behind every other notation standard in engineering (electrical schematics, P&ID diagrams in process engineering, GD&T in mechanical drawings): the diagram is only as useful as the population that can read it.
A common confusion is to expect UML to tell you when to draw each diagram. It does not. UML is a notation only: it standardises the shape of an ellipse for a use case, the rules for an include arrow, the compartments of a class box. The decisions about which diagrams to draw, in what order, and how much detail to put on them belong to the process, which is a separate concern. The most-cited process built around UML is the Rational Unified Process (RUP, Kruchten, 2003), but agile teams routinely use a small subset of UML inside Scrum or XP without adopting RUP at all. The course's structure follows this separation: chapter 3 covers the process by which requirements are produced; this chapter covers the language in which the resulting models are drawn.
UML's status today is uneven across the industry. Knowing where it is heavily used and where it is light-touch is part of using it correctly.
Heavily used. Regulated domains (medical devices, automotive safety, avionics, rail), where traceability from requirements to design is a certification requirement; Model-Based Systems Engineering (MBSE), where SysML (a UML profile) is the primary modelling notation; teaching, where UML's diagrammatic vocabulary is still the standard way to introduce object-oriented design; and large enterprise architecture work, where component and deployment diagrams remain the standard medium for documenting system structure.
Lighter use. Agile teams often use only a subset (use cases or activity diagrams for requirements; class diagrams sketched on whiteboards) and rarely produce the full UML model that the textbook describes. The reasons are pragmatic, not ideological: keeping a heavyweight model in sync with rapidly changing code is expensive, and teams have learned to invest in the diagrams that pay back in conversation rather than those that pay back in documentation.
Areas of growth. The rise of safety- and security-critical AI systems has brought renewed interest in MBSE and formal modelling, including UML-derived notations. The diagrammatic vocabulary has also re-emerged in domain-specific contexts (database modelling tools, infrastructure-as-code visualisers, sequence diagrams generated automatically from distributed traces).
For the COMP433 student, the practical takeaway is that the seven diagrams treated in depth here are all in current use somewhere, and being fluent in them is genuinely portable knowledge. The diagrams treated more briefly (object, communication, timing, interaction overview) are still in the standard but are encountered much less often in industry.
Sommerville (2015, ch.5) groups system models into four families by what they make discussable. The families are not mutually exclusive (one diagram can belong to two), but knowing the family helps decide what kind of question the diagram is being drawn to answer, and which UML diagram types are the natural fit. Hover any card below for a worked example and a sharper definition.
Where the system sits and what it talks to. Show the system as a single opaque box with its external environment (users, other systems, devices, regulatory interfaces). Answer the scoping question: what is in, what is out, what does it touch?
Who talks to whom, in what order, with what messages. Show the dynamic exchange between a defined set of participants (objects, components, actors). Answer the question: given that the parts exist, how do they cooperate?
Parts and their static relationships. Show the organisation of the system without time. Nothing moves; the diagram captures what exists, not what happens. Answer the question: what is the system made of, and how are the parts connected?
What the system does over time, in response to internal or external stimuli. Dynamic view; states change. Answer the question: given an event, what does the system do next, and could it get stuck somewhere?
The families are not partitions. A use case diagram is partly context and partly interaction; an activity diagram can be either interaction or behavioural depending on the level it is drawn at; a component diagram is structural but its interface contracts already imply interaction. The classification is a thinking aid, not a rigid taxonomy: when a team realises it has drawn three interaction diagrams and no structural one, it has a signal that an important class diagram is still missing.
The diagrams in this chapter do not exist in isolation. Each one sits at a particular point in the software lifecycle, takes its input from the artefact that precedes it, and produces an output that the next artefact builds on. This section is the map that the rest of the companion fills in.
A common misconception is that UML diagrams are alternatives ("should I draw a use case or a class diagram?"). The right framing is sequential: each diagram answers a question the previous one raised, at the right level of abstraction for the stage you are in. Knowing which question is on the table is what tells you which diagram to draw next.
Three observations worth pausing on:
Cost estimation is treated in depth in the Ch.3 companion, which includes an interactive calculator. The view from this chapter is about when and why, not how. The key implications:
To make the pipeline concrete, follow one user requirement through it. The example is the Library System used as the running example in the rest of this companion:
| Step | What it produces for "members can borrow books" |
|---|---|
| 1. Elicitation | Interview with the head librarian surfaces the rule "no more than six books on loan at once" and the existence of three loan periods (ShortLoan, MediumLoan, LongLoan). |
| 2. Requirements doc | UR3: "A library member shall be able to borrow up to six copies of books at one time." SR3.1, SR3.2: derived system requirements with the loan periods and the maximum-loan check. |
| 3. Effort estimation | UR3 is estimated at 2 developers × 1.5 person-weeks = 3 person-weeks. Sums into the project total; the customer signs the contract on the price that includes this number. |
| 4. Use case | "Borrow copy of a book", with <<include>> "Compute return date" and <<extend>> "Refuse loan [too many books]". Use case description fully written out. |
| 5. Activity | Swimlane diagram showing BookBorrower, Librarian, and System; covers the success path, the "too many books" branch, and the damaged-barcode error. |
| 6. Class | Classes LibraryMember, Book, BookCopy, Loan (association class), Librarian. Method borrow() on LibraryMember; method isAvailable() on Book. |
| 7. Sequence | Sequence diagram for the success scenario: BookBorrower → Librarian → System; messages for checkAllowance(), createLoan(), updateStatus(). |
| 8. State machine | BookCopy lifecycle: Available → OnLoan → Overdue → Lost with the transitions and guards. |
| 9. Component | LibraryFront (UI) component requires LoanManagement (app) component; LoanManagement requires PersistenceStore (infra). |
| 10. Deployment | LibraryFront runs on each librarian desktop; LoanManagement on the library server; PersistenceStore on the central university database node. |
One user requirement, ten artefacts. Most of the value is not in any single artefact; it is in the traceability from UR3 to the deployment node, which is what lets the team change the design and know which other artefacts to update. The rest of this companion is the toolkit for producing the entries in column two correctly.
The UML 2.5 specification defines fourteen diagram types, split into structural (seven) and behavioural (seven). Nine of these are conventionally treated as the "standard" set you will encounter on real projects, and seven are covered in depth in this companion (and used in the COMP433 project). The map below lists all fourteen for completeness; the italicised types are part of the standard but encountered less often in practice.
The seven types covered in depth below are: use case, activity, class, sequence, state machine, component, and deployment. Together they cover the full life cycle of a typical project: requirements (use case, activity), analysis and design (class, sequence, state machine), and architecture (component, deployment).
A use case diagram is a one-page picture of who interacts with the system and the named tasks they perform. It is the first UML diagram drawn on most projects: it converts the list of User Requirements into something that fits on one A4 page, makes scope confirmable with the customer, and produces the index of tasks that downstream diagrams (activity, sequence, class) refine.
The diagram serves three decisions, and only three:
It does not show: the order of work inside a use case (use an activity diagram), the messages between objects realising a use case (use a sequence diagram), what data the system holds (use a class diagram), or where the system runs (use a deployment diagram). A use case ellipse is, deliberately, an opaque label; the substance lives in the textual description.
In the project pipeline (section 5, figure 1), the use case diagram is the bridge between requirements and design. It is drawn for the Phase 2 deliverable: each User Requirement that names a clear actor and a clear goal becomes one use case, and the diagram makes the relationships between them (sub-tasks, conditional alternatives) visible alongside the textual UR / SR list. It is then revised at the start of Phase 3 as design begins, because the design pass surfaces additional sub-tasks (which become <<include>> use cases) and alternative paths (which become <<extend>> use cases).
A use case diagram has three building blocks: actors, use cases, and the system boundary. Actors are drawn as stick figures (or sometimes labelled boxes for non-human actors) outside the boundary; use cases are ellipses with a verb-phrase label inside the boundary; the system boundary is a rectangle that contains the use cases and explicitly excludes the actors. Associations are simple solid lines between an actor and a use case they participate in (no arrow head, because participation is undirected). Refinement relationships between use cases are drawn as dashed arrows with one of three stereotypes: <<include>>, <<extend>>, or generalisation (inheritance).
<<include>> relationships; they point from the base case to the included case (Borrow and Renew both include Compute return date). The warm-rust dashed arrow at the top is the <<extend>> relationship; it points from the extending case to the base (Refuse loan extends Borrow when the guard [too many books] holds). The two stereotypes are kept on different horizontal bands and given different ink colours so it is unambiguous which label belongs to which line. Mnemonic: an include's base cannot run without its include; an extend's base usually runs without its extension.Capturing what the system has to do for whom, before any commitment to how. They make the system's external surface explicit and let stakeholders confirm or contest scope on one page.
Internal algorithms, data structures, performance behaviour, security mechanisms, transaction boundaries. Use cases are a contract sketch, not a design.
Enterprise Architect (Sparx), Visual Paradigm, Lucidchart, draw.io, PlantUML (text-driven, popular in GitHub-based teams), and increasingly Mermaid for inline-in-Markdown documentation.
An actor is a role someone or something plays when interacting with the system. Actors are not specific people; the same person can be two actors at different times. A doctor who also borrows books at the staff library is a Doctor in one system and a BookBorrower in the other. The course conventionally splits actors into two kinds:
How to identify actors:
Notation convention. Each actor's name is a noun (CamelCase, no spaces), and the actor is documented in one sentence covering its role and how it interacts with the system. For example: "BookBorrower: a member of the library who borrows physical copies of books (Principal)." The description belongs in the requirements document next to the diagram; the diagram itself only carries the name.
A use case is a task an actor needs to perform with the help of the system. Two rules from the course notes:
How to find use cases:
Once you have more than a handful of use cases, you will start to see that some use cases share sub-tasks with each other, others fire only in exceptional circumstances, and others are variations on a common theme. UML 2.5 gives three stereotypes for these refinements. Each has a precise meaning and a precise arrow direction, and confusing them is the single most common notation error on this material.
| Stereotype | Semantics | Arrow direction (dashed) | Library example |
|---|---|---|---|
<<include>> | Unconditional reuse. The base use case ALWAYS uses the included one as part of its normal flow. The included use case is a sub-task factored out so two or more base use cases can share it, and so it can be changed in one place. | From base to included. The base 'knows about' the include. | Borrow includes Compute return date; Renew includes Compute return date. Both ALWAYS need a return date. |
<<extend>> | Conditional alternative. The extending use case fires ONLY IF a guard at a declared extension point in the base is true. Used for alternative or exceptional paths that should not clutter the description of the base. | From extending case to base. The extension 'knows about' the base (the OPPOSITE direction from include). | Refuse loan extends Borrow when [too many books]. The Borrow flow is unchanged in the normal case; Refuse loan exists only to describe what happens when the guard fires. |
| Generalisation (also called <<inherit>> informally) | Specialisation. One use case is a more specific version of another, in the same sense as a subclass. The specialisation inherits the base's behaviour and may override or extend it. Rare; usually a sign that a base use case should be factored. | Solid line with a hollow triangle head pointing at the base. From specialised to general (same convention as class generalisation). | Pay by credit card specialises Pay fine; Pay by mobile wallet specialises Pay fine. Both inherit the general 'pay fine' workflow but add payment-specific steps. |
The two arrows go opposite ways and this is the single most-marked notation error. The rule: the arrow tail is on the use case that knows about the other one. With <<include>>, the BASE knows it includes a sub-task (the base description literally contains "include Compute return date" as a step), so the arrow tail sits on the base. With <<extend>>, the EXTENSION knows which base it modifies (the extension description names the base and the extension point), so the arrow tail sits on the extension. Generalisation follows the class-diagram convention: tail on the specialised case, head pointing at the general one.
The Library example shows the mechanics; an ATM example shows when the stereotypes pay back in a different domain.
<<include>>-d from Withdraw cash (and from every other transactional use case: Deposit, Transfer, Check balance). It is factored out because the authentication policy will change later (PIN, biometric, multi-factor) and all five base use cases must change together.<<extend>>-ed from Withdraw cash, at the extension point "after dispensing cash", with guard [customer chose receipt]. Most withdrawals do not print a receipt; the extension exists to keep the Withdraw description clean.<<extend>>-ed from Withdraw cash, at the extension point "after balance check", with guard [insufficient funds]. This is structurally identical to the Library's Refuse loan, and demonstrates that the same pattern recurs across very different domains.The teaching point: <<include>> exists to avoid duplication when two or more base use cases share a sub-task (Authenticate customer is shared by Withdraw, Deposit, Transfer, and Check balance). <<extend>> exists to keep the base description clean when an optional or exceptional behaviour would otherwise crowd it (Print receipt and Refuse transaction only run sometimes; they belong on a separate ellipse, not as a footnote inside Withdraw).
A common question is "where in the base does the extension fire?" The answer is given by an extension point: a named position in the base's workflow, declared inside the base ellipse (in a third compartment) or in the base's textual description. Borrow copy of a book typically declares two extension points:
maxItemsCheck, located after the system has counted the borrower's current loans. The Refuse loan extension fires here with guard [items on loan == 6].identityValidation, located after the BookBorrower's identity has been confirmed. A separate extension (say, RequireGuardian) might fire here with guard [member is minor].Extension points keep the base's flow auditable: a reader of the base description sees the named hooks and can look up which extensions attach to each. Without them, an <<extend>> arrow is just "this fires somewhere in here", which is too vague to be useful in a contract.
A diagram with more refinement arrows than associations is over-modelled. Three signs that you are overusing the stereotypes:
<<include>> with one parent. If only one use case includes a particular sub-task, the sub-task is not being reused; it is being prematurely factored. Inline it into the description.<<extend>> with no extension point. Without a named extension point, the extension is just an alternative path of the base. Document it as an alternative scenario in the base's description (section 8) rather than as a separate ellipse.<<include>> for shared sub-tasks and <<extend>> for variants, and reach for generalisation only when the two are genuinely the same use case at different specificity levels.For larger systems, a single top-level diagram becomes unreadable. The standard pattern is to draw a high-level diagram with composite use cases (each one labelled with a verb phrase like "Manage patient registration"), and to draw a separate first-level diagram for each composite that decomposes it into its constituent use cases. A second-level diagram may decompose a particular first-level use case further, if needed.
For the Mentcare system (the same running example as in Ch.3), this is the pattern used in the course: the top-level diagram shows "Manage patient registration", "Manage patient medical record", "Generate reports", and "View patient info". The "Generate reports" composite is then expanded in a first-level diagram with sub-cases like "Generate admitted patient report" and "Generate discharged patient reports". Treat the top-level diagram as a map of the system, and each first-level diagram as a magnified region of that map.
A use case ellipse on a diagram is barely a label. The use case itself is fully specified in a structured description. This is the same template the requirements companion uses in Section 8; here it is applied to use cases specifically.
The fields are: System Name, Use Case Title, Description, Actors, Data, Stimulus/Trigger, Pre-conditions, Workflow (or Sequence/Flow of Events), Post-conditions/Response, Comments. Below is the course's canonical worked example.
| System Name: Library System · Use Case Title: Borrow Copy of a Book | |
|---|---|
| Description | A BookBorrower may borrow a copy of a book from the library. A book must exist in the library and be available to borrow; it will be issued by the Librarian. The status of the copy of the book will change to <on-loan> and the loan period of the copy will be decided by the type of the book: ShortLoan 2 days, MediumLoan 2 weeks, LongLoan 3 months. |
| Actors | BookBorrower, Librarian. |
| Data | Book information; borrow information; book status information. |
| Stimulus / Trigger | User command issued by Librarian on behalf of BookBorrower. |
| Pre-conditions | 1. The BookBorrower is a member of the library. 2. The BookBorrower has not already borrowed more than the permitted number of books on loan. |
| Workflow (sequence of events) |
1. The BookBorrower asks the Librarian to borrow a book. 2. The system (or Librarian) checks whether the BookBorrower is allowed to borrow. 3. If yes: 3.1 Librarian records the copy of the book on the BookBorrower's borrowed list; 3.2 Issues the borrowed copy on loan. 4. Else (alternative or error path): the system reports the reason and does not issue the loan. |
| Post-conditions | 1. The system has updated the number of books the BookBorrower has on loan, if successful. 2. The copy's loan status is updated to <on-loan>, if successful. |
| Comments | The Librarian must have appropriate security permissions to access BookBorrower information. |
Each time an actor interacts with the system, the triggered use case instantiates a scenario: a specific path through the use case with no branching. Scenarios are typically documented as text alongside the diagram and serve as the readable narratives that customers and testers can confirm against. For each non-trivial use case, the course expects at least three scenarios:
Worked scenarios for "Borrow copy of a book":
| Normal | BookBorrower Joe borrows a copy of "Using UML" from the library. Joe has no other books on loan; he takes the copy to the Librarian, who checks Joe's allowance, scans the copy's barcode, and issues the book. The system is updated accordingly. |
| Alternative | BookBorrower Joe borrows a copy of "Using UML". Joe has no other books on loan. Joe takes the copy to the auto-Librarian kiosk; the kiosk scans his library ID and the barcode on the copy, checks his borrowing allowance, and automatically issues the book to him. The system is updated accordingly. |
| Error 1 | BookBorrower Joe brings a book to the Librarian, who checks his allowance and finds that he has six books already on loan (his maximum). The loan is refused; no system update. |
| Error 2 | BookBorrower Joe brings a book to the Librarian, who attempts to scan the barcode but finds it damaged. The copy is not issued; the staff log an exception against the copy for replacement. |
Notice that the two error scenarios describe quite different failures: one is a business rule violation (too many books), the other is a physical/data integrity issue (damaged barcode). Both are equally valid sources of requirements: the first generates "the system shall enforce a maximum of six items on loan"; the second generates "the system shall provide a manual barcode entry option".
A use case ellipse is a label, the description is the contract, and the scenarios are the readable narratives that anchor the conversation with the customer. What none of them captures is the order of work, the parallelism, or the cross-actor coordination that a non-trivial workflow has. That is exactly what the next diagram (the activity diagram) is for. Pick the use case that has the most decisions or the most actors and draw its activity diagram first.
An activity diagram captures the workflow of a use case or a business process. It is the right diagram when the team needs to talk about the order of work, the decisions that branch the flow, and the activities that can run in parallel.
Activity diagrams have a small, fixed vocabulary. Once the symbols are known, the diagram reads like a flow chart with two added powers: it can show parallelism explicitly, and it can assign activities to actors using swimlanes.
| Symbol | Meaning |
|---|---|
| Filled black circle | Initial node. Where the activity starts. Exactly one per diagram. |
| Filled black circle with ring | Final node. Where the activity ends. There may be more than one. |
| Rounded rectangle | Action (or activity). A unit of work. |
| Diamond | Decision (one input, several outputs with guards) or merge (several inputs, one output). The same symbol is used for both; context disambiguates. |
| Thick horizontal bar | Fork (one input, several parallel outputs) or join (several parallel inputs, one output). |
| Vertical columns (swimlanes) | Partitions that assign activities to actors, departments, or systems. |
Activity diagrams pay back when the workflow has at least one of: a non-trivial number of decisions, parallel work that the team needs to discuss explicitly, or coordination across multiple actors. They are over-engineering for use cases with a single linear path of three or four steps.
Two practical conventions:
Making the order of work visible: where decisions branch the flow, where activities can proceed in parallel, and which actor (or system) is responsible for each step. The forms and forking of work are the most common source of subtle bugs in business and clinical systems; an activity diagram makes them discussable on one page.
Data structure (use class diagrams), message exchange between objects at the code level (sequence diagrams), or the full state space of a single object (state machine diagrams). Activity diagrams are about flow, not state.
Camunda Modeller and Bizagi for BPMN-style enterprise work; Cameo Systems Modeler and MagicDraw for SysML/MBSE; PlantUML and Mermaid for inline-in-Markdown documentation; Lucidchart and draw.io as general-purpose drawing tools.
An activity diagram answers what happens, in what order, and who does it. It says nothing about the objects that carry the activities (the Book, the Loan, the LibraryMember), or the data each one holds. To talk about those, you need a static-structure diagram. That is the job of the class diagram, the next stop on the journey.
A class diagram shows the classes in a system and the associations between them. It is the longest-lived diagram on most projects, because the static structure changes more slowly than any particular flow through it.
UML's visibility markers map directly to access modifiers in mainstream OO languages, with one or two extra options:
+ public: accessible by any client of the class.- private: accessible only by members of the same class.# protected: accessible by members of the class or any subclass.~ package: accessible by classes in the same package./ derived: a value computed from other attributes, not stored independently (e.g., /age computed from birthDate).Multiplicity on an association end answers: how many instances of this class can participate in the relationship at one time? Standard values:
| Notation | Meaning |
|---|---|
1 | Exactly one. |
0..1 | Optional: zero or one. |
* or 0..* | Zero or more. |
1..* | One or more. |
m..n | At least m, at most n. Example: 3..7. |
m | Exactly m. Example: 5. |
Both denote "part of" relationships, but with different lifetime semantics:
Modern style is to avoid aggregation where composition would do, because aggregation is semantically weak: most tools and reviewers cannot distinguish it from a plain association. Composition, by contrast, has bite.
When an association itself has attributes that do not belong to either of the connected classes, those attributes live on an association class. Example: a Loan between a LibraryMember and a BookCopy has its own startDate and returnDate; these are attributes of the borrowing relationship, not of the member or of the copy. The association class is drawn as a regular class box, connected to the association line by a dashed link.
The standard recipe, introduced by Shlaer and Mellor in the late 1980s and used in the course, is the noun-verb analysis: read through the requirements document and underline every noun phrase; collect those noun phrases as a candidate class list; discard inappropriate ones (redundant, omnipotent, vague, meta-language, outside the system scope, or really attributes of something else); then identify every verb and assign verbs to candidate classes as operations. The result is a first-cut class diagram that is grounded in the requirements you wrote, rather than the developer's imagination.
Six categories of "inappropriate" noun, worth memorising because they recur in reviews of analysis-level class lists:
Heuristic categories from Booch's Object-Oriented Analysis and Design for which nouns make good classes:
Five criteria, drawn from Cooper, Larman, and the broader OO design literature, that practitioner reviews look for:
Capturing the static structure of an object-oriented system: which classes exist, what they contain, and how they are connected. The class diagram is the longest-lived diagram on most projects because the static structure changes more slowly than any particular flow through it.
Runtime behaviour (use sequence or state diagrams), concurrency (no concept of threads or processes), data flow (use activity diagrams), or deployment topology (use deployment diagrams). A class diagram tells you what exists; it tells you nothing about what happens.
IDEs (IntelliJ IDEA, Eclipse, Visual Studio) reverse-engineer class diagrams from code automatically. PlantUML and Mermaid render text descriptions to diagrams in Git workflows. Lucidchart, Visual Paradigm, and Enterprise Architect support full forward and reverse engineering.
The class diagram tells you what exists; it tells you nothing about what happens. A method borrow() on LibraryMember might involve calls to Book, BookCopy, Loan and PersistenceStore in a specific order, with possible authorisation checks and error returns. That story (messages over time between a fixed cast of objects) is what the sequence diagram captures. Pick the use case scenario whose call chain is least obvious and draw that sequence diagram next.
A sequence diagram shows one specific interaction: who sends what message to whom, in what order. Time runs top to bottom; participants are arranged left to right. Unlike a class diagram, which captures the system at rest, a sequence diagram captures the system in motion.
alt fragment encloses two alternative behaviours separated by a horizontal dashed line. The guard in square brackets after each branch label indicates which one fires. Solid arrows are synchronous calls; dashed arrows with open heads are returns.UML 2.0 added interaction fragments to make sequence diagrams expressive enough for non-trivial flows. The five most common operators:
| Operator | Meaning |
|---|---|
alt | Alternative paths. Two or more branches separated by dashed horizontal lines, each labelled with a guard. Exactly one branch executes per execution of the fragment. |
opt | Optional behaviour. Executes only if the guard is true. Equivalent to an alt with a single branch. |
loop | The fragment may execute zero or more times. The guard indicates the iteration condition. Optionally loop(n) for exactly n times. |
par | Parallel execution. Two or more branches execute concurrently; the order between them is not defined. |
ref | Reference to another sequence diagram. Used to avoid drawing the same sub-interaction repeatedly across diagrams. |
The interactive below plays a sequence diagram one message at a time. Use it to see how activation bars grow and shrink as messages flow.
Pinning down the order of messages between objects, components, or services in one specific scenario. Sequence diagrams catch race conditions, missing returns, forgotten error paths, and unrealistic latency assumptions before code exists.
Static structure (use class diagrams), the full set of states an object can be in (use state machines), the workflow of a long-running business process (use activity diagrams), or system topology (use deployment diagrams). A sequence diagram captures one path through one scenario; do not try to capture the whole system in one.
PlantUML and Mermaid are now the dominant tools for text-driven sequence diagrams in API documentation and Git workflows. swimlanes.io is popular for ad-hoc sketches. WebSequenceDiagrams and SequenceDiagram.org cover dedicated diagramming. Distributed-tracing systems (Jaeger, Zipkin) generate sequence-like views from runtime data.
A sequence diagram is a horizontal cut: one scenario, many objects. The next diagram is the vertical cut: one object, many scenarios over its lifetime. The state machine asks "what states does this object pass through, and which events cause which transitions?", which is the question you should be asking about a Loan, an Order, or any other object whose behaviour depends on its current state.
A state machine diagram captures the states an object passes through during its lifetime and the events that cause transitions between them. It is the right diagram whenever a class has a meaningful "current state" that callers must reason about.
event [guard] / action. Any of the three parts can be omitted.entry / action, do / action, exit / action.BookCopyOverdue state has an entry action; the OnLoan state has a do activity that continues while the state is active. A copy that is reported lost transitions directly to the terminal Lost state.State machines pay back when at least one of the following is true:
Most classes do not need a state machine. Data carriers, value objects, and pure functions have no state in this sense. Drawing a state machine for them is over-engineering. Conversely, every domain object whose lifecycle is meaningful (Order, Loan, Ticket, Patient, Account) is a candidate.
Making the lifecycle of a single object or system explicit. Every state, every event, every guard, every action laid out so a reviewer can answer: "Is there a state where event E does nothing?" "Is there an unreachable state?" "Can the system get stuck?" These questions are central to safety and protocol correctness.
Interactions between multiple objects (use sequence diagrams), static structure (use class diagrams), or business workflow across actors (use activity diagrams). State machines are about one object's life, not the system as a whole.
MATLAB Stateflow for safety-critical embedded work; XState (and Statecharts.dev) for web applications; PlantUML and Mermaid for documentation; Yakindu and SCXML for executable statecharts in industry. AWS Step Functions are an executable, cloud-hosted state machine implementation.
State machines, sequence diagrams, class diagrams and activity diagrams all describe what one application does. The remaining question is what the application is made of and where it runs. That is the territory of the architectural diagrams (component for build-time structure, deployment for run-time topology), covered next.
The interactive below runs the BookCopy state machine. Fire events with the buttons and watch the current state change, with guards enforced.
Component and deployment diagrams sit higher up the abstraction ladder than the diagrams above. They are concerned with how the system is partitioned at build time and how it is distributed at run time.
A component diagram shows the structural relationships between the major components of a system. A component in UML 2 is a modular part of the system with well-defined interfaces. Components offer two kinds of interface:
A provided lollipop fits into a matching required socket; the connection is valid if the socket's required operations are a subset of the lollipop's provided operations and their signatures are compatible.
<<component>> stereotype and the small component icon (the two-rectangle glyph). Lollipop-and-socket notation makes the dependency between Order and the other two components explicit.<<infrastructure>> components shared across the system.A deployment diagram shows the runtime configuration of the system: which software runs on which hardware (or virtual) nodes, and how the nodes connect. It is the right diagram when the system is non-trivially distributed.
Notation:
<<server>>, <<client>>, <<database>>, <<mobile device>>.<<artifact>> stereotype and a small document icon. Executables, configuration files, databases.A small but useful distinction:
Component diagrams answer "what are the major moving parts and how do they connect?". Deployment diagrams answer "where does each part actually run and what does it talk to?". Both are architectural views that operations and infrastructure engineers, not application developers, are the primary consumers of.
Internal class structure of a component (use a class diagram), runtime behaviour of a component (use sequence diagrams), or workflow across components (use activity diagrams). Component diagrams stop at the interface boundary; what happens inside is a separate concern.
Lucidchart, draw.io, and the AWS / Azure / GCP architecture-icon libraries dominate cloud work. Structurizr (by Simon Brown, of Software Architecture for Developers) is a text-driven tool aligned with the C4 model, a modern simplification of UML's structural diagrams. ArchiMate tooling (Archi, BiZZdesign) for enterprise architecture.
The earlier sections cover each diagram in isolation. This section walks one user requirement from the elicitation interview to a first-cut design, showing the substance at each step. The example is intentionally small so the full trace fits on this page; on a real project, every requirement goes through this same chain.
In a structured interview with the head librarian of the Birzeit Main Library, the analyst captures the following extract (paraphrased to the level of detail an interview transcript would record):
| Source | Interview with M. Hamdan, Head Librarian, 14 March. |
| Question | "Walk me through what happens when a student borrows a book." |
| Answer (paraphrased) | "The student brings the copy to the desk. We scan the barcode and pull up their record. If they already have six items out, we refuse the loan, they have to return something first. If they're clear, we record the loan with a due date that depends on the book: short loans are two days, medium loans two weeks, long loans three months. The student keeps the copy and a small printed slip with the due date." |
| Follow-up question | "What if the barcode is damaged or unreadable?" |
| Answer | "We type it in manually and log an exception so the copy gets a replacement barcode next week." |
Notice what the interview transcript already contains, even before any modelling: an actor (BookBorrower, called "the student"), a sub-actor implied (Librarian, the speaker), a business rule (max six items), a domain rule (loan periods depend on book type), a normal flow, an exception (damaged barcode), and an alternative outcome (loan refused). The analyst's job in the next stage is to write that down in a form that survives months of execution.
The transcript converts into one UR with two SR refinements. The numbering follows the convention used in Ch.3 section 3.
| UR3 | A library member shall be able to borrow up to six copies of books at one time, with the loan period determined by the book type (short, medium, or long loan). |
| SR3.1 | The system shall enforce a maximum of six concurrent loans per LibraryMember. An attempt to record a seventh loan shall be refused, and the BookBorrower shall be informed of the reason at the point of refusal. |
| SR3.2 | The system shall compute the return date for each Loan as: start date + ShortLoan(2 days) | MediumLoan(2 weeks) | LongLoan(3 months), based on the BookCopy's parent Book's type field. |
| SR3.3 | If the BookCopy's barcode is unreadable, the system shall allow manual entry by an authorised Librarian and shall raise a damaged-barcode exception for review. |
Each SR is a developer-precise refinement of UR3 (note the shared prefix). Each is testable: SR3.1 corresponds to a test case for the seventh-loan refusal, SR3.2 to a parameterised test of the three loan periods, SR3.3 to a manual-entry test plus exception verification.
Using the per-UR method from Ch.3 section 11, the team estimates UR3 as follows. The estimate is in person-weeks (pw); the calculator in Ch.3 takes these numbers and rolls them up into the project total.
| Concurrent developers | 2 (one full-stack on the front end and persistence; one specialist on the barcode integration) |
| Effort per developer | 1.5 person-weeks (covers SR3.1 enforcement, SR3.2 date logic with three branches, SR3.3 manual-entry handler and exception logging, plus tests) |
| Total effort for UR3 | 3 person-weeks (rolled into the project total) |
This estimate is what the customer is asked to authorise. If the customer later asks for "also support overdue notifications", a new UR is added, re-estimated, and added to the project total before any work begins.
UR3 maps to one primary use case (Borrow copy of a book) plus its refinement use cases (Compute return date as <<include>>, Refuse loan as <<extend>>). The diagram form is in figure 3 above; the textual form, expanded into the eight-field template used throughout section 8, looks like this:
| Use Case: Borrow Copy of a Book (refines UR3) | |
|---|---|
| Description | A BookBorrower borrows a copy of a book from the library; the Librarian processes the loan. The copy's status moves from Available to OnLoan and a return date is computed. |
| Actors | BookBorrower (Principal), Librarian (Principal). |
| Pre-condition | (a) BookBorrower is a registered member. (b) BookBorrower has fewer than 6 items on loan. (c) The BookCopy is in state Available. |
| Trigger | BookBorrower presents the copy to the Librarian. |
| Workflow (normal) | 1. Librarian scans the copy's barcode. 2. System retrieves the BookCopy and its parent Book. 3. System counts BookBorrower's current loans. 4. System invokes Compute return date (using Book.type to choose ShortLoan, MediumLoan, or LongLoan). 5. System creates a Loan(start_date, return_date, copy, member). 6. BookCopy.status becomes OnLoan. 7. Librarian hands the copy and printed slip to BookBorrower. |
| Alternative workflow | At step 3, if currentLoans == 6, invoke Refuse loan (the <<extend>> at the maxItemsCheck extension point); inform BookBorrower; no Loan is created. |
| Error workflow | At step 1, if the barcode is unreadable, Librarian enters the barcode manually; a damaged-barcode exception is logged against the BookCopy (SR3.3). |
| Post-condition | (a) On success: a new Loan exists; BookBorrower's loan count is +1; BookCopy.status == OnLoan. (b) On refusal: no system state change. |
This textual description is the contract; the ellipse on the diagram is the index entry. The activity diagram (section 9) would draw steps 1 through 7 as actions in swimlanes for BookBorrower, Librarian, and System, with a decision diamond at step 3 splitting the normal and refusal branches. The sequence diagram (section 11) would draw the messages between Librarian, System, BookCopy, Loan, and PersistenceStore for the normal scenario.
From the noun-verb analysis of the UR / SR text (section 10): nouns LibraryMember, Book, BookCopy, Loan, Librarian; attributes loan count, status, barcode, start_date, return_date, type; verbs borrow, return, compute return date, refuse. The first-cut class diagram fragment for UR3 is:
borrows BookCopy with multiplicity 0..1 to 0..6 (a copy is on loan to at most one member; a member borrows at most six copies, directly encoding SR3.1). Loan is an association class (attached to the borrows line by a dashed link at the midpoint); its computeReturn() operation is the realisation of SR3.2. Book aggregates BookCopy (open diamond): one Book has many copies; if a Book is removed from the catalogue, copies still exist as physical objects, so aggregation (not composition) is correct.Three observations worth taking away from the fragment:
0..6 multiplicity on the borrows association. SR3.2 (compute return date) is the computeReturn() operation on Loan. SR3.3 (manual barcode entry, damaged-barcode exception) does not appear here because it is a workflow concern; it lives in the activity diagram for the use case, not in the class fragment.One requirement, five artefacts, each refining the previous and each surfacing questions the previous stage missed. The work of UML modelling is not drawing pretty ellipses; it is the disciplined re-asking, at progressively finer detail, of "what exactly does the system do?". A model that lets you skip the re-asking is not a useful model. A model that forces the re-asking, and lets the team write the answers down so they survive the project, is the artefact this chapter is teaching you to produce.
Drawn from Fowler's UML Distilled, recurring review findings on real UML models, and Brooks' general observations about modelling.
"Book borrowing" is not a use case label. Use cases are verb phrases: "Borrow a book". The label has to read as something an actor does.
Include is unconditional and the base points to it. Extend is conditional and the extension points to the base. The arrows go opposite ways. Get the direction wrong and the meaning inverts.
A class diagram is an abstraction of the domain; a schema is an artefact of the persistence layer. Drawing one for the other means the design decisions you should have made in the model were made for you by the database.
If every class has only attributes, you have drawn an entity-relationship diagram, not a class diagram. UML classes carry behaviour as well as data; if there is no behaviour, ask whether the class earns its place.
A sequence diagram should capture the interaction at a level of abstraction worth discussing. If the diagram has one message per line of code, it is a code listing in a clumsy notation.
Drawing a state machine for a data holder, value object, or pure function adds notation without adding insight. State machines pay back when the class genuinely has states; otherwise they are over-engineering.
A diagram with more than ten use cases stops being readable. Use composite use cases and split the diagram into a top-level overview with first-level expansions.
Diagrams produced once, never looked at, never revised, are decoration. The team that benefits is the team that draws diagrams to think, refers to them in design conversations, and updates them when the design changes.
The course textbook and Prof Adel's lecture notes anchor the chapter; the books below are the works directly referenced in the text and the standard practitioner references.