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.
Recorded session covering much of Chapter 4. Read this companion alongside the recording for notation references, hover-enabled diagrams, and the worked example tracing one user requirement through to a first-cut class fragment.
Focus on three sections: Use case diagrams (Section 7), Activity diagrams (Section 9), and the back-to-back case study (Section 9b), which draws both diagrams from one set of requirements. Sections 1 to 6 are background and 10 to 16 are wider breadth.
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, where it is used in practice, and how to choose which model to draw, before turning to how to draw each of the seven course diagrams correctly. A worked example near the end ties them together from elicitation to first-cut design, and a closing section 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.
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. The notation was frozen at UML 1.1, substantially revised at UML 2.0 (2005, which added the sequence-diagram interaction fragments and refined activity diagrams along business-process lines), and has been stable since UML 2.5.1 (2017), the version this course follows. The point of standardising was readability: after UML, a diagram drawn in one company is readable in another, in a research lab, and in a textbook.
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. |
One user requirement, and already five linked analysis artefacts. Most of the value is not in any single one; it is in the traceability from UR3 onward, which lets the team change the design and know which other artefacts to update. These five are the analysis views this chapter teaches first; section 14 carries the same thread on into the design diagrams (class, sequence, state, component, deployment).
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: what it is and when to draw it; actors and how to find them (users, external systems, time); use cases and how to find them (noun-verb analysis); the building blocks and the system boundary. Refining and detailing: <<include>>, <<extend>>, generalisation and extension points; composite (multi-level) use cases; the use case description; and scenarios (normal, alternative, error). The goal: read a narrative and draw a correct, fully-refined diagram, then write the contract behind it.
The diagram serves three decisions, and only three:
Beyond those three decisions, the use case model earns its keep across the whole project. The course notes list five further things a good use case set does: it specifies the context of the system (its boundary and the actors around it); it lets the team plan iterations of development (each use case is a unit of work to schedule); it validates the architecture (every architecturally significant use case must be realisable on the proposed design); it drives implementation (each use case becomes a thread of construction); and it generates test cases (each scenario through a use case is a system-test script). Use cases are built early in development, by analysts and domain experts during requirements analysis, and stay useful long after.
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 (Primary)." The description belongs in the requirements document next to the diagram; the diagram itself only carries the name.
Identifying actors is rarely a one-pass job: the first list is usually too coarse or too fine, then it is organised. Reading the Library requirements actor-first yields a fine-grained list of roles, several of which turn out to be the same person:
| Candidate actor | Role (semantics) |
|---|---|
BookBorrower | A member of the library who borrows books only. |
JournalBorrower | A member (staff) who borrows books and journals. |
BookBrowser | Searches for books or journals; may not be a member, and cannot borrow. |
BookClassifier | Classifies and catalogs new books and registers them in the system. |
BookReturnRegistrar | Receives returned books and registers them. |
BookLendRegistrar | Lends (or renews) books and registers them. |
BookShelver | Shelves books and records their shelving status. |
The last four are all the same human, the Librarian; listing them as separate fine-grained roles first and then grouping them is the normal route to a clean actor. Where one actor can do everything another can and more, the relationship is actor generalisation, drawn with the hollow-triangle inheritance arrow (as in a class diagram), pointing from the specialised actor to the general one. For the Library, the primary-actor hierarchy is:
LibraryUser, then Browser, then BookBorrower, then JournalBorrower. Each inherits the use cases of the one before it and adds its own: a Browser can search, a BookBorrower is a Browser who can also borrow books, a JournalBorrower is a BookBorrower who can also borrow journals.Browser is also specialised by Librarian. The staff actor inherits the ability to browse and adds the management use cases (add, update, catalog, remove).Generalisation keeps the diagram honest: rather than repeating every borrowing association on JournalBorrower, you draw it once on BookBorrower and let JournalBorrower inherit it. This is the actor-side counterpart of the use case generalisation covered below.
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:
How do you know a candidate is genuinely a use case, and at the right granularity? The course's tests: estimate the frequency of use (something done once at setup may not warrant its own use case); examine the differences between candidate use cases (if two are nearly identical, they may be one use case with alternative scenarios); and distinguish the normal from the alternative course of events (an alternative path is usually a scenario of an existing use case, not a new use case). A use case should be a complete, valuable task from the actor's point of view, not a single click ("enter password") nor a whole subsystem ("manage everything").
The course's standard technique for turning a written requirements document into a first-cut use case diagram is noun-verb analysis. Read the requirements text and mark it up in two colours:
Not every candidate survives. Discard: redundant or omnipotent nouns (a catch-all "system" that does everything), vague entities, meta-language (words about the document rather than the domain), entities outside the system scope, pure attributes, and constraints or events that are not tasks. What remains, read straight off the marked-up text, is the actor list down the side, the use case ellipses in the middle, and the association lines between them. The same noun-verb pass later seeds the class diagram, so it is worth doing carefully.
"The library contains books and journals; it may have several copies of a book. A library member may borrow for three weeks; members borrow up to six items, staff up to 12; only staff borrow journals. Members of the public can browse / search but cannot borrow. Late returns pay a fine, in cash or by credit card; an email reminder is sent automatically. Staff manage books: add, update, catalog, remove." Bold marks nouns (actors and entities); italic marks verbs (use cases). The credit card and the email pull in the Bank and Email secondary actors, and the verbs become the Borrow / Renew / Return / Browse / Pay fine / Send reminder / Manage use cases on the diagram.
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 online food-ordering app shows the same stereotypes paying back in a different domain.
<<include>>-d from Place order, and also from Modify order, because both always need the running total (items, delivery fee, tax). It is factored out so the pricing rules live in one place and both base use cases change together.<<extend>>-ed from Place order, at an extension point "before payment", with guard [has promo]. Most orders carry no promo; the extension keeps the Place order description clean.<<extend>>-ed from Place order, at the extension point "after stock check", with guard [item unavailable]. This is structurally identical to the Library's Refuse loan, and shows the same conditional-alternative pattern recurring across very different domains.The two stereotypes answer two different needs. <<include>> exists to avoid duplication when two or more base use cases share a sub-task (Calculate order total is shared by Place order and Modify order). <<extend>> exists to keep the base description clean when an optional or exceptional behaviour would otherwise crowd it (Apply promo code and Refuse order only run sometimes; each belongs on a separate ellipse, not as a footnote inside Place order).
When a use case depends on an external system to do its job, that system is a secondary actor: a payment provider, an SMS or email service, an identity or verification provider, a maps service. Draw it as an actor outside the boundary, with the association running from the use case to it (the use case reaches out to the service to finish its work). It also appears in the use case description's Actors row. The distinction to hold: the primary actor starts the use case for their own goal; the secondary actor is the one the system calls on to complete it.
The third refinement, generalisation (informally <<inherit>>), applies when one use case is a more specific version of another. A library borrower can Pay fine in two ways: Pay by cash and Pay by credit card each specialise Pay fine, inheriting its general workflow and adding their own steps. The notation is the class-diagram one: a solid line with a hollow triangle, pointing from the specialised case to the general Pay fine.
The three refinements compose, and a single realistic requirement usually needs all of them. Take the rule "for every successful credit-card payment, send an email confirmation; the bank must approve the payment and may refuse it":
<<inherit>> Pay fine: it is a kind of fine payment.<<include>> Send payment confirmation: every successful card payment sends one, so it is unconditional, and the confirmation reaches the Email System (a secondary actor).<<extend>>-ed by Validate payment against the Bank System: the bank may refuse, so this is the conditional, sometimes-failing path.Reuse cuts across this picture: Send message (by email) is factored out as an included sub-use-case shared by both "Send reminder to late loans" (triggered by the SystemTimer) and "Send payment confirmation". One ellipse, two base cases, one change-point. This single Pay-fine picture is the clearest demonstration that include, extend, and generalisation are not academic decorations: all three fall out of one ordinary business rule.
<<include>> arrows point from a base case to a sub-task it always uses: Borrow and Renew both include Compute return date, and both Send reminder to late loans and Send payment confirmation include Send message (by email), one shared ellipse with a single change-point. The rust dashed <<extend>> arrows point from a conditional case to its base: Refuse loan extends Borrow under [too many books], and Validate payment extends Pay by credit card (the bank may refuse). The solid hollow-triangle <<inherit>> arrows point from a specialised case to the general one: Pay by cash and Pay by credit card both specialise Pay fine. The three secondary actors (SystemTimer, Email System, Bank System) sit outside the boundary and are reached by plain association, not by a refinement.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, written in a compartment inside the base ellipse (or in the base's textual description). Borrow copy of a book declares two:
[too many books].Extension points keep the base's flow auditable: a reader of the base ellipse 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.Composite (multi-level) use case. Draw one when a single ellipse really stands for a bundle of related tasks that would crowd the top-level page if listed separately. Mark it with the small grid icon and expand it in a lower-level diagram: Manage room inventory becomes Add room, Update rate, Set availability, Remove room; Adel's Manage patient registration becomes Register and De-register patient. Use it to keep the top level readable, not to hide missing analysis: each sub-use-case must still be a real, verb-named task.
Generalised actor. Draw one when two actors share most of their use cases but one is a more capable kind of the other. The specific actor inherits every use case of the general one and adds (or specialises) a few: a Senior Agent is a kind of Support Agent who also handles escalations; a Duty Manager is a kind of Receptionist who can also issue refunds. If the two actors share no use cases, keep them separate; generalisation earns its place only when it removes duplicated associations.
The Mentcare mental-health patient-management system (MHC-PMS), Sommerville's running example, exercises the same machinery in a different domain. Its actors are the Medical receptionist, Nurse, Doctor, Manager, and the external Patient record system (a secondary actor). Typical use cases: Register patient, Unregister patient, View patient info, Contact patient, Transfer data, View / Edit patient medical record, Setup consultation, Export statistics report, Generate medical report.
One detail is worth singling out, because it is easy to draw wrongly: Transfer data is initiated by the medical receptionist, but its result flows out of the system to the Patient record system. The external records system is therefore a secondary actor: the association line leaves the boundary on the far side of the Transfer data ellipse, with the receptionist on the near side. The receptionist triggers the use case; the records system receives its output. Distinguishing the primary actor who starts a use case from the secondary actor on the receiving end is exactly the kind of thing the diagram exists to make explicit.
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.
A composite use case is marked with a small grid icon to signal that it decomposes further. For the MHC-PMS, the course uses three levels:
Each level keeps the same system boundary (MHC-PMS) and shows only the actors relevant to that region. Treat the top-level diagram as a map of the system, and each lower-level diagram as a magnified region of that map; decompose only as far as readability requires.
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. |
The same template applied in a different domain, the MHC-PMS "Transfer patient data" use case, shows it is not Library-specific. Note that the external Patient record system appears in the Actors row as a secondary actor, matching the boundary-leaving arrow on the MHC-PMS use case diagram:
| System Name: MHC-PMS · Use Case Title: Transfer Patient Data | |
|---|---|
| Description | A medical receptionist may transfer data from the MHC-PMS to a general patient-record database maintained by a health authority. The information transferred is either updated personal information (address, phone number, etc.) or a summary of the patient's diagnosis and treatment. |
| Actors | Medical receptionist, Patient record system (PRS). |
| Data | Patient's personal information; treatment summary. |
| Stimulus / Trigger | User command issued by the medical receptionist. |
| Pre-conditions | 1. The patient is a member of the clinic. 2. The patient information is accessible. |
| Workflow (sequence of events) |
1. The medical receptionist selects the patient records to transfer. 2. The receptionist transfers the selected records to the health authority. 3. If successful: the transfer completes and is acknowledged. 4. Else (alternative or error path): the system reports the failure and no transfer is recorded. |
| Post-conditions / Response | Confirmation that the PRS has been updated. |
| Comments | The receptionist must have appropriate security permissions to access the patient information and the PRS. |
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.
| In one line | |
|---|---|
| What | A workflow as a flow of actions: their order, the decisions that branch them, the work that runs in parallel, and which actor owns each step. It models behaviour and the coordination between activities, and a well-formed one never gets stuck: every path reaches a final node. |
| How | Unpack a use case description (or a whole business process): steps become actions, choices become a decision closed by a merge, simultaneous work becomes a fork closed by a join, and actions are dropped into swimlanes by actor. Guards in [brackets] on a decision must be mutually exclusive and exhaustive. |
| When | When a use case has real branching, parallel work, or hand-offs between actors, and as an elicitation tool to see how several use cases combine into one process. Over-engineering for a single linear path of three or four steps. |
The notation: initial and final nodes, actions; decision/merge and fork/join, and how each pair must close; swimlanes (hand-offs) and loops (repeat, retry, guarded exit). Putting it together: unpacking a use case description into a flow; the two granularities (one use case, or a whole business process); and a second worked domain end to end. The goal: take one use case and draw a well-formed flow, decisions closed by merges, forks by joins, every path reaching a final node.
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.
Beyond drawing a workflow that is already understood, activity diagrams are an elicitation tool. Drawn during requirements work, they help the team see how use cases interact to achieve a business process, and they frequently surface use cases and operations that the static use case diagram missed. They model the system's behaviour and the dependencies and coordination between activities, and a well-formed one has a property worth checking explicitly: the flow must not get "stuck", every path eventually reaches a final node. Although they are most often drawn for a use case or a business process, an activity diagram can be attached to any model element to describe its dynamic behaviour.
| 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. |
Two pairs of symbols are routinely confused, and the distinction is the most-marked correctness point on this material. A decision (diamond) chooses one of several guarded branches: its branches are alternatives, and exactly one fires. A fork (bar) starts all of its branches at once: its branches are concurrent. The test is simple. Are the branches a choice (one of them) or parallel work (all of them)? "New patient? create vs search record" is a decision; "place order, then send the confirmation email and update inventory" is a fork, because both happen.
Each opening symbol must be closed by its partner: a decision is closed by a matching merge (the diamond that brings the alternatives back to one path), and a fork is closed by a matching join (the bar that waits for every parallel branch to finish before continuing). An unmatched decision usually means a branch that silently never rejoins; an unmatched fork means concurrency that is never synchronised. Guards on a decision should be mutually exclusive and exhaustive, so exactly one branch is always taken.
A worked fork / join: in a "process order" workflow, the initial node leads to Receive order, then a fork runs two paths in parallel, Fill order (which itself contains a decision, priority vs regular delivery, closed by a merge) and Send invoice then Receive payment. A join waits for both the goods and the payment before Close order and the final node. The fork says both happen; the join says wait for both.
The same notation serves two levels. At the use case level, an activity diagram unpacks one use case ("Borrow copy of a book": locate the book, then fork to stamp the book and record the borrowing in parallel, then join). At the business-process level, it spans several use cases and actors ("book a journey": reserve flight, hotel and car in parallel, with a loop that repeats the car reservation until it succeeds, then confirm). Iteration like that loop, and parallelism like those reservations, are exactly what an activity diagram adds over a numbered list. Keep one granularity per diagram; mixing a single use case and a whole process on one page makes both hard to read.
The activity diagram for the Library's Borrow and Return use cases pulls together everything in this section: swimlanes for the two actors, a decision, a fork and join for the parallel stamping and record-keeping, and an explicit loop so a member can process several books in one visit. Iteration is the one piece of vocabulary the earlier figures did not need; here the [another book] edge feeds the flow back to the borrow-or-return decision until the member is done.
[another book] loops back to the start so the member can process the next item, and [no] ends the activity. The loop is how an activity diagram expresses "repeat until done"; without it the diagram would describe a single book only.Loops are how an activity diagram expresses "do this more than once", and they take a few shapes worth recognising, all built from an ordinary decision whose branch points back into the flow:
[another book] edge above.A retry loop and a guarded exit usually appear together: try, check, and on failure either loop back or, once the attempts run out, leave by a different edge. The case study in the next section draws a retry loop in full.
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. The next section first pulls these two behavioural views together on one small system, end to end; after that, the class diagram captures the static structure those activities run on.
The two behavioural views in this chapter, the use case diagram and the activity diagram, are usually drawn back to back from the same requirements. This case study takes one small system from a short requirements description through to both diagrams, so the bridge between them is concrete. The worked example in section 14 carries a single requirement all the way to a class fragment; here the focus is the two diagrams an analyst draws first.
A boutique hotel wants a small online booking system. From a stakeholder workshop, the analyst captures:
| Context | Guests book rooms online; the hotel manager maintains the room list and rates; payments are taken through an external payment provider. |
| Description | "A guest searches for rooms by date and the system shows what is available. The guest picks a room, enters their details and card, and we take the payment through our payment provider; if the card is declined the guest can try again. When payment succeeds we reserve the room and confirm the booking. Guests can cancel a booking, and the manager keeps the room list up to date." |
The description yields a short set of user requirements (UR), each a complete task from someone's point of view:
| UR1 | A Guest shall be able to search for available rooms by date. |
| UR2 | A Guest shall be able to book an available room, paying through the payment provider, and receive a confirmation. |
| UR3 | A Guest shall be able to cancel an existing booking. |
| UR4 | A Hotel Manager shall be able to maintain the room list and rates. |
Reading the nouns and verbs (section 7): the nouns Guest, Hotel Manager, and the external payment provider become actors; "search", "book", "cancel", "maintain", "pay", and "check availability" become candidate use cases; the guest-verb pairings become associations.
Two primary actors (Guest, Hotel Manager) and one secondary actor (Payment Provider) sit around the boundary. Every booking checks availability and takes payment, so both are <<include>> sub-tasks (Check availability is shared by Search rooms and Book room); a promo code is optional, so it <<extend>>s Book room. Manage room inventory is not one task but several (add a room, update a rate, set availability, remove a room), so it is drawn as a composite use case (the small grid marker) that expands into its own lower-level diagram rather than sitting as one vague catch-all ellipse.
<<include>>d by both Search rooms and Book room; Process payment is <<include>>d by Book room and reaches the Payment Provider; Apply promo code <<extend>>s Book room under [has promo]. The single arrowed association leaving the boundary marks the Payment Provider as the system the use case calls on to finish its work.The central use case, Book room, expands into the template from section 8:
| Use Case: Book room (refines UR2) | |
|---|---|
| Actors | Guest (Primary), Payment Provider (Secondary). |
| Pre-conditions | The Guest has chosen the dates they want. Availability is not assumed; it is checked inside the flow. |
| Trigger | The Guest asks to book for those dates. |
| Workflow (normal) | 1. Guest selects a room. 2. If the Guest has a promo code, they enter it and the system applies the discount (optional, the Apply promo code extension). 3. Guest enters their details and card. 4. System requests authorisation from the Payment Provider. 5. On approval, the system reserves the room. 6. The booking is confirmed and the authorised payment is captured. |
| Alternative / error | Before booking, if no room is available the flow ends without a booking (the early final node). At step 4, if the card is declined the Guest re-enters payment details and the request is retried; no booking is made until a payment is approved. |
| Post-conditions | (a) On success: a reserved booking exists and is confirmed. (b) On failure: no room is reserved. |
The same Book room flow, drawn as an activity diagram, makes the order of work, the decisions, the retry loop, and the hand-off to the external provider explicit. Swimlanes assign each step to the Guest, the Booking System, or the Payment Provider.
[rooms available?] decision either ends the flow (no rooms) or continues; the cross-lane arrow to Authorise payment is the hand-off to the external provider; the optional [has promo?] decision is the activity form of the Apply promo code extend, a guarded branch that merges straight back; the [declined] branch is the retry loop, returning to Enter payment details until a payment is approved; on the [approved] branch the room is reserved, then a fork runs Confirm booking and Capture payment in parallel before a join merges them. Two final nodes: one for "no rooms", one for a confirmed booking.Read it against the description and every action traces back to a workflow step or an alternative path. The use case description and the activity diagram describe the same behaviour at two levels: the description in words, the diagram in flow.
One short description produced four artefacts in sequence: user requirements, a use case diagram, a use case description, and an activity diagram. Each adds precision the previous one left implicit: the diagram names the actors and tasks, the description pins down the steps and conditions, and the activity diagram fixes the order, the decisions, and the loop. Drawing them in this order is the everyday rhythm of the analysis stage.
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.
Classes, not instances. A class diagram shows the types in the system, Book, LibraryMember, the kinds of thing that can exist, not the particular copy on the shelf or the member at the desk. To show specific instances at one moment (this member, that copy, with concrete values) you draw an object diagram, the section immediately after this one.
| In one line | |
|---|---|
| What | The classes the system knows about, their attributes (data) and operations (behaviour), and the associations, with multiplicity, that connect them. In early analysis a class is a real-world thing: a patient, a prescription, a book. |
| How | Mostly bottom-up from the requirements by noun-verb analysis: nouns and roles become classes and attributes, verbs become operations, and the noun-verb pairings become associations. Then add multiplicity, generalisation for is-a, aggregation or composition for part-of, and association classes for attributes that belong to a relationship. |
| When | Whenever an object-oriented model is built; it is the central structural deliverable and the one teams design against. Not for the order operations run in (sequence or activity), an object's lifecycle (state machine), concurrency, or deployment. |
Before any class is drawn you decide how to decompose the system. Adel's notes name three classic strategies; analysis-level work usually blends them, but it helps to know which one you are leaning on.
In analysis we work mostly bottom-up from the requirements, using the noun-verb method below, and sanity-check it against a top-down view of the whole. The goal is classes justified by the text, not by the developer's imagination.
A class box has three compartments, and each maps to something the behavioural views already produced. This is the bridge from behaviour to structure: the name compartment comes from an actor or entity, the attributes from the data the use cases touch, and the operations from the use cases that object performs. Every part of a class should be answerable to an earlier model.
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:
An analysis class abstracts one or more classes of the eventual design; it models the problem domain, not the solution. It focuses on functional requirements, defines responsibilities (cohesive subsets of behaviour), names attributes at a domain level, and shows the relationships it takes part in. A design class adds full method signatures and types, tightened visibility, infrastructure classes (persistence, controllers, factories), design patterns, and navigability. In this course, Phase 3 expects an analysis-level class diagram drawn from your requirements; reserve the design-level detail for later.
Adel's running example. Underline the nouns in the requirement, then sift them.
The library contains books and journals. It may have several copies of a given book. Some of the books are for short-term loans only. All other books may be borrowed by any library member for three weeks. Members of the library can normally borrow up to six items at a time, but members of staff may borrow up to 12 items at one time. Only members of staff may borrow journals. The system must keep track of when books and journals are borrowed and returned.
Candidate classes kept: Book, BookCopy, Journal, LibraryMember, StaffMember. Discarded or demoted: Library (the system itself), item (vague), three weeks / six / 12 (loan period and limits: attributes and multiplicities, not classes).
Noun-verb analysis gives candidates, not answers. For each one you argue keep, reject, or it depends, and the reasoning matters more than the verdict:
| Candidate | Decision | Why, and the alternative rejected |
|---|---|---|
| book | class | The work itself (ISBN, title). Not merged with its copies because one title has many physical copies and you lend a copy, not the title. |
| copy | class | The physical item (barcode, status). Keep only Book and you cannot say which of three copies is on loan; BookCopy is the fix. |
| journal | class (debatable) | Kept separate because journals follow staff-only loan rules. Alternative: Book and Journal both specialise an abstract LibraryItem, tidier if more item types arrive. |
| item | reject, but… | Too vague to be a class, yet it is the hint for that LibraryItem superclass. A rejected noun can still shape the model. |
| loan / borrowing | association class | Looks like a verb, but it carries its own data (start and return dates) belonging to the member-copy pairing, not to either alone: the Loan association class. |
| member, staff | class + generalisation | Staff is-a member, so generalisation. Alternative: if one person can be both at once, model a Role rather than a subclass. |
| library | reject | The system boundary, not a domain object, unless the requirements track several libraries. |
| three weeks, six, 12 | reject | Loan period and borrowing limits: attributes and constraints (multiplicities), not classes. |
The teaching point: a good class list is defended, not asserted. Be ready to say why BookCopy earns its place and library does not, to name the alternative you considered (the LibraryItem superclass, the Role class), and why you set it aside.
Five criteria, drawn from Cooper, Larman, and the broader OO design literature, that practitioner reviews look for:
Name an association with a verb phrase and read it in a direction. A plain line is bidirectional; an arrowhead makes it unidirectional (the tail class can reach the head class, but not the reverse). An association connects classes (the type level); a link is one instance of it between two specific objects (Adel: links instantiate associations).
Draw generalisation only for a genuine is-a. The test is substitutability: anywhere the code expects a LibraryMember you can hand it a StaffMember and nothing breaks. Wrong: "Car is-a Engine", a car is not a kind of engine, it has one, so that is an association (Car has Engine). Right: "ElectricCar is-a Car". If the substitution would be absurd (an Engine where a Car is expected), it is not generalisation.
Adel's other running example, from Sommerville's mental-health-care patient management system. It shows a different shape: one central, attribute-rich class, Consultation, that anchors the whole model.
A dependency (dashed line, open arrowhead) is a transient "uses" link, the weakest relationship: if an Order merely takes a Product as a method argument, that is a dependency, whereas an Order that holds Products over time is an association. Two stereotypes in guillemets flag boxes that are not ordinary domain classes: an «enumeration» is a type whose value must be one of a fixed, named list (a Category is Book, Music, Video or Software and nothing else); a «dataType» is a type with no identity of its own, defined purely by its value (two Money amounts of the same value are interchangeable, whereas two Order objects are distinct even with identical fields).
Most weak class models fail on cohesion or coupling. The test is simple: count the reasons to change. A low-cohesion Patient that also sends reminder emails, generates PDF reports, connects to the database and calculates insurance has four reasons to change; touch the email server and you risk breaking billing. A high-cohesion Patient does one job (be a patient) and moves the rest to a NotificationService, a ReportGenerator, a PatientRepository and an InsuranceCalculator, so it changes only when what it means to be a patient changes. Fewer reasons to change is higher cohesion.
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 class diagram shows the types; an object diagram shows specific instances of those types and the links between them at a single moment. Adel introduces it immediately after the class diagram, because the quickest way to test a class model is to populate it with real objects and see whether everything fits.
| In one line | |
|---|---|
| What | A snapshot: specific objects (instances of your classes) and the links (instances of associations) between them at one moment, with each attribute set to a concrete value. |
| How | Take a class diagram and instantiate it: draw a box per object with an underlined name : Class header and an attribute = value line for each attribute; join objects that are linked. Show no operations and no attribute types. |
| When | During analysis and design, to validate the class model against real data: a concrete snapshot quickly exposes a missing class, a wrong multiplicity, or an attribute with nowhere to live. |
Objects are instances of classes. An object diagram captures objects and the relationships between them, that is, instances of classes and the links (instances of associations) between them. It is built during analysis and design to illustrate data and object structures, to specify snapshots of the system at a point in time, and above all to validate the class model, asking whether the classes are sufficient to hold the data and support the methods the system needs. Analysts, designers and implementers all draw them.
An object box has a name compartment and an optional attribute compartment. The name is written objectName : ClassName and is underlined (this is what distinguishes an object from a class); each attribute is shown as attribute = value. Crucially, operations and attribute types are not shown on an object diagram: it is about concrete data at one instant, not behaviour.
Adel's running example pairs a class diagram with one object diagram that instantiates it. First the class model: a Company is composed of Departments and Offices; a Department is located at an Office and can contain sub-departments (a reflexive composition); a Person works at a Department and one Person manages it (a subset of works-at); a Headquarter is a kind of Office; and a Person depends on ContactInformation.
Now one snapshot of that model: the company "Smart Software", with its actual departments, office, an employee, and his contact record. Every box is an instance of a class above; every value is concrete; no operations appear.
SmartSoft : Company is composed of d1 : Department (R&D) and d2 : Department (Sales, itself composed of North and South Sales), and of BZUBranch : Office. d1 is located at the branch; p1 : Person (Sameer) works at and manages it; the branch is a Headquarter; and p1 uses a ContactInformation record. Building this snapshot is how you check the class model holds together: each value has a home, each link has a matching association.The same idea against the Library class diagram from the previous section: one member, one copy, one borrowing link.
adel : LibraryMember is linked to copy42 : BookCopy, one link of the member-borrows-copy association. A snapshot like this validates the class model: building it with real data exposes a missing class, a wrong multiplicity, or an attribute that has nowhere to live.An object diagram is the cheapest test of a class diagram. If you cannot draw a plausible snapshot, the class model is wrong somewhere: an attribute with no box to sit in, a link the associations do not allow, or a multiplicity the data violates. Draw one whenever a class model feels abstract or a multiplicity is in doubt.
A class diagram and its object snapshot are both static: a structure and one frozen instant of it. The next diagram, the sequence diagram, sets those same objects in motion, showing the messages they exchange over time.
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.
Instances, and one scenario at a time. The lifelines are instances (objects), written : Class (anonymous) or name : Class, never bare classes, because a sequence diagram shows real objects exchanging messages on one run. And one diagram tells one story: a single scenario of a single use case. Draw the normal (happy) path first as an instance diagram; fold the alternatives and errors in with combined fragments (alt, opt, loop), or draw them as separate diagrams (the generic diagram). Do not try to cram every path into one picture.
| In one line | |
|---|---|
| What | The interaction for one scenario of one use case: which participant sends which message to whom, in what order, with arguments, and when each participant is active (the activation bars). Time runs top to bottom; participants sit left to right. |
| How | Pick one scenario; place the initiating actor and then the collaborating objects (instances of your classes) across the top; drop a dashed lifeline from each; add messages in time order, naming the operation each calls; draw activation bars and dashed returns; wrap any choice or repetition in a fragment (alt, opt, loop). |
| When | For a scenario whose call order is not obvious, or a collaboration that needs pinning down: a checkout, an authorisation, a booking. Not for static structure (class diagram), an object's whole lifecycle (state machine), or every scenario at once (one diagram is one story). |
A sequence diagram invents nothing. It realises one scenario of a use case, using the classes from the class diagram and calling their operations:
| In the sequence diagram | Comes from |
|---|---|
| The scenario being drawn | one path through a use case (its normal flow, or one alternative) |
| The participants (lifelines) | actors and objects; the objects are instances of classes from the class diagram |
| The messages | the operations declared on those classes |
| The fragments (alt, loop) | the decisions and loops of the activity diagram for that use case |
Consistency check. If a lifeline receives a message fetchRecord(), the class it instantiates must declare fetchRecord(). The sequence diagram is therefore a live check on the class diagram: a message with no matching operation means the class model is incomplete.
: Class for an anonymous object, name : Class for a named one); the dashed lifeline drops from it; the thin activation bar marks the time it is busy. Message kinds: synchronous (filled head, the caller waits), reply/return (dashed, open head), and asynchronous (open head, solid line, fire and continue). A message back to the same lifeline is a self-message. Actors do not get an activation bar: an external participant (the Customer in the Deposit Cash example, the Librarian in the next one) sits outside the system, so we do not model its internal execution, it only sends and receives messages. Only the system objects that execute a message are barred.Adel draws the distinction clearly. An instance diagram is one concrete run, no branching, the happy path: quick to draw, ideal for explaining the normal flow. A generic diagram shows the family of runs using combined fragments (alt, opt, loop) to fold the alternatives and repetitions into one picture. Rule of thumb: draw the instance first to nail the normal flow, then promote it to a generic diagram only where real branching or looping matters. Do not cram every error path into one diagram; that is what fragments, or separate diagrams, are for.
alt fragmentFigure 7 promotes an instance to a generic diagram: the authorisation decision is folded into one picture with an alt fragment, exactly the notation the legend above introduces. Solid arrows are synchronous calls, dashed open-headed arrows are returns, and the guard after each branch label decides which one fires.
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. |
[ok] vs [else]); opt is a single branch that runs only if its guard holds; loop repeats while its guard holds; par runs its regions concurrently (order between them unspecified); ref stands in for a named sub-interaction drawn elsewhere. Use alt/opt for choice, loop for repetition, par for concurrency, ref for reuse.Adel's self-service-machine example, the normal scenario. Three internal objects do the work: the front (the customer interface), the register (where money is counted and the cash reserve kept), and the dispenser (which delivers the receipt).
The same Library modelled earlier with a use case, an activity diagram and a class diagram, now in motion for one scenario. The lifelines are objects of the classes LibraryMember, BookCopy and Loan; the messages are their operations; the alt is the activity's "limit reached?" decision.
Recipe. (1) Pick one scenario of one use case, starting with the normal flow. (2) Place the participants across the top: the actor that starts it, then the objects it collaborates with. (3) Drop a lifeline from each. (4) Add messages in time order, top to bottom, naming the operation and its arguments. (5) Draw activation bars for the time each participant is busy, and the dashed returns. (6) Wrap conditional or repeating parts in fragments.
Sanity checks. Every received message is an operation that exists on the receiver's class; every synchronous call has a matching return; time only goes down (no arrow points back up the page); one diagram is one scenario, branch with fragments rather than tangling two stories together.
fetchRecord() to a lifeline whose class has no such operation; fix the class diagram or the message.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.
Where it fits, and at what stage. A state machine describes the lifecycle of the instances of one class (a Loan, an Order, a BookCopy), so it is drawn at the design stage, after the class diagram has identified a class whose behaviour is state-dependent, the same call doing different things, or being illegal, in different states. Like the class diagram it is object-focused and long-lived; unlike a sequence diagram, which shows one scenario across many objects, a state machine shows one object across its whole life. Most classes never need one, reach for it only when an object's allowed operations change with its state.
| In one line | |
|---|---|
| What | The complete lifecycle of one object (or one system): the finite set of states it can occupy, the events that move it between them, and the actions those moves trigger. It answers "what can happen to this object, and when is each operation legal?". |
| How | Identify the distinct states (each a condition in which the object behaves differently); draw one initial pseudostate and the final state(s); for every state ask which events are legal and where each leads, labelling transitions event [guard] / action; attach entry/exit/do activities where behaviour belongs to the state itself; nest related states into a composite state when the picture grows. |
| When | When an object's behaviour depends on its current state (the same call does different things, or is illegal, depending on state), or it has a real, observable lifecycle (Loan, Order, Ticket, Account). Not for passive data carriers, value objects, or pure functions. |
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.A state machine is a finite-state automaton: a finite set of states, an alphabet of events, and a transition function mapping a (state, event) pair to a next state. It is the oldest and most rigorously understood model of behaviour in computing, which is why the same idea drives compilers, network protocols and control systems.
entry / do / exit activities are Moore-style (tied to the state), while the action on a transition is Mealy-style (tied to the event). Knowing which you mean keeps the diagram unambiguous.A transition label has the form event [guard] / action, and each part is precise:
borrow()); a signal event is an asynchronous message received; a change event fires when a condition becomes true, written when(balance < 0); a time event fires after a duration or at a moment, written after(30 days) or at(09:00). A transition with no event is a completion (triggerless) transition: it fires as soon as the source state's activity finishes.entry / exit of a state (run every time the state is entered or left, whichever transition was used).do / countDays()) and is interrupted if an event causes an exit. Unlike an action it takes time and can be cut short.entry/exit do not re-run; a self-transition exits and re-enters the state, so they do. Confusing the two is a frequent source of real bugs.These are the statechart extensions that keep a real diagram readable. A composite state contains a nested sub-machine; a transition out of it applies to all its sub-states at once, so you draw the shared cancel arrow once rather than from every sub-state. Orthogonal regions, separated by a dashed line inside a composite state, are active simultaneously: independent concerns modelled as two regions need 2 + 2 states, where flat modelling needs 2 × 2, and the gap widens fast. A history pseudostate (a circled H) remembers which sub-state was active when the composite was last left, so re-entry resumes there: it is how a "resume" feature is modelled.
cancel transition leaves the whole composite from any combination of sub-states, which is the economy a flat machine cannot offer.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.
| In one line | |
|---|---|
| What | Structure at two higher levels: a component diagram shows the build-time parts (modules or services) and the contracts (provided and required interfaces) between them; a deployment diagram shows the run-time topology, which artefact runs on which node and over which protocol. |
| How | For components: group cohesive classes into a component, expose what it offers as a provided interface (lollipop) and what it needs as a required interface (socket), and wire one component's socket to another's lollipop. For deployment: draw each execution node as a 3D box, place the artefacts that run on it inside, and join nodes with labelled communication paths. |
| When | Once the system is non-trivially partitioned (several modules or services) or distributed (more than one machine or tier). These are the views operations and infrastructure engineers read; for a single-process toy they are over-engineering. |
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.
A component is a modular, replaceable unit of the system that hides its implementation behind well-defined interfaces. Its defining property is substitutability: anything that offers the same provided interfaces can replace it without the rest of the system noticing. That single idea is what makes plug-ins, device drivers and microservices possible.
<<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.Deployment has a small vocabulary worth getting exactly right:
.jar, a .war, an executable, a config file, a database file. Artefacts are what actually get copied onto nodes, as opposed to the logical components they realise.A small but useful distinction:
A style is a reusable pattern for the system's overall layout, with a known shape and a known trade-off; an architecture is one style (or a blend) applied to a specific system. The common styles:
| Style | Core idea | Trade-off |
|---|---|---|
| Layered (n-tier) | Stacked layers, each using only the one below. | Predictable and testable; can be slow and rigid. 3-tier is the common instance. |
| Client-server | Clients request; a server holds data and logic. | Centralises control; the server is a bottleneck and a single point of failure. |
| Model-View-Controller | Separate data, presentation, and input handling. | Dominant in UI frameworks; logic can scatter if overused. |
| Pipe-and-filter | Data flows through a chain of independent transforms. | Excellent for batch and stream work (Unix pipes, compilers); poor for interactive use. |
| Event-driven / pub-sub | Components emit and react to events, decoupled in time. | Scales and decouples; harder to trace and debug. |
| Microkernel / plug-in | A minimal core plus plug-ins. | Highly extensible (IDEs, browsers); the core API is hard to get right. |
| Service-oriented / microservices | Independent services communicating over the network. | Independent deploy and scale; operational and distributed-failure complexity. |
No single diagram captures an architecture, so Kruchten's 4+1 view model (1995) describes it from several viewpoints at once, and each maps onto a UML diagram you now know:
| View | Question it answers | UML diagram |
|---|---|---|
| Logical | What functionality does the system provide? | class and object diagrams |
| Process | How does it behave and coordinate at run time? | activity and sequence diagrams |
| Development | How is the software organised for building? | component (and package) diagrams |
| Physical | How does the software map onto hardware? | deployment diagrams |
| + Scenarios | Do the four views actually work together? | use case diagrams |
This is the theoretical reason a chapter on system modelling needs all of these diagrams: each is a different projection of one system, and the use cases are the thread that checks the projections agree. It is the same point Sommerville makes with his four perspectives (context, interaction, structural, behavioural): you understand a system only by looking at it from more than one direction at once.
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 (Primary), Librarian (Primary). |
| 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 "maximum no. of items on loan" 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.