The design class diagram: the blueprint you can hand to a programmer.
π Where this lives: a design class diagram is what a database schema, an API specification and a set of class files all agree on β or fail to. When those three drift apart, you get the bugs that make no sense: a field nullable in the database, required in the API, and assumed present in the code. The diagram's real job is to be the single place where those decisions are made once, before three people make them differently. Search "schema API model consistency single source of truth".
Design class diagram versus domain model
The DESIGN CLASS DIAGRAM (DCD) illustrates the SPECIFICATIONS
FOR SOFTWARE CLASSES AND INTERFACES in an application. It is
distinct from the conceptual/domain model of ACtE0804, and the
differences are the content of this topic.
DOMAIN MODEL DESIGN CLASS DIAGRAM
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
real-world concepts software classes
no operations (usually) METHOD SIGNATURES with
parameters and return types
attributes untyped TYPES on every attribute
no visibility VISIBILITY markers (+ β # ~)
associations undirected NAVIGABILITY arrows, from the
visibility decisions
no interfaces Β«interfaceΒ» types and
realisations
domain classes only + controllers, repositories,
factories, adapters
no dependencies shown DEPENDENCY arrows for parameter
and local visibility
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
WHEN IS THE DCD DRAWN? AFTER the interaction diagrams, not
before. This is worth repeating because it is the most common
process error: the methods on a class ARE the messages sent to
it in some interaction, so the interactions determine the class
diagram. Drawing the DCD first produces speculative methods
that no collaboration needs, and misses methods that
collaborations require.
THE MECHANICAL PROCEDURE for producing a DCD:
1. identify all classes participating in the software
solution β from the interaction diagrams
2. draw them in a class diagram
3. duplicate the attributes from the associated concepts in
the domain model
4. add METHOD NAMES by analysing the interaction diagrams
5. add TYPE INFORMATION to the attributes and methods
6. add the ASSOCIATIONS necessary to support the required
attribute visibility
7. add NAVIGABILITY ARROWS to indicate the direction of
attribute visibility
8. add DEPENDENCY RELATIONSHIP LINES to indicate
non-attribute visibility
STEPS 6, 7 AND 8 ARE THE VISIBILITY DECISIONS from the previous
topic, rendered as notation. Attribute visibility becomes an
association with an arrow; parameter and local visibility
become a dashed dependency arrow.
A complete design class diagram
THE LICENCE ISSUANCE SUBSYSTEM, as a DCD in text form. Every
element traces to a decision made in an earlier topic.
ββ PRESENTATION / APPLICATION LAYER βββββββββββββββββββββββββ
IssueLicenceHandler
βββββββββββββββββββββββββββββββββββββββββββββ
- repository : ApplicationRepository
- pool : LicenceNumberPool
- events : EventPublisher
βββββββββββββββββββββββββββββββββββββββββββββ
+ IssueLicenceHandler(r : ApplicationRepository,
p : LicenceNumberPool,
e : EventPublisher)
+ handle(no : String, officer : OfficerId) : Licence
throws ApplicationNotFound, NotIssuableException,
NumberPoolExhaustedException
βββββββββββββββββββββββββββββββββββββββββββββ
βββΆ ApplicationRepository (attribute visibility)
βββΆ LicenceNumberPool (attribute)
βββΆ EventPublisher (attribute)
- -βΆ Application (dependency: local visibility)
ββ DOMAIN LAYER βββββββββββββββββββββββββββββββββββββββββββββ
Application
βββββββββββββββββββββββββββββββββββββββββββββ
- applicationNo : ApplicationNo {immutable}
- appliedOn : LocalDate {immutable}
- status : Status
- reviewedBy : OfficerId {0..1}
- issuedBy : OfficerId {0..1}
- payment : Payment {0..1}
- history : List<StatusChange> {ordered}
- version : int
/ feeDue : Money
βββββββββββββββββββββββββββββββββββββββββββββ
+ recordPayment(amt : Money, m : PaymentMethod,
o : OfficerId) : Payment
throws NotPayableException
+ issue(no : LicenceNo, o : OfficerId) : Licence
throws NotIssuableException,
SeparationOfDutiesException
+ currentStatus() : Status
+ wasEverRejected() : boolean
- assertTransition(to : Status) : void
- recordChange(from : Status, to : Status,
by : OfficerId) : void
βββββββββββββββββββββββββββββββββββββββββββββ
ββββΆ StatusChange 1 .. * (composition)
βββΆ Payment 0..1
βββΆ Licence 0..1
βββΆ District 1
NOTE WHAT IS ABSENT: there is no setStatus, no setPayment and
no getHistory. `wasEverRejected()` exposes the QUESTION
rather than the collection, per the visibility topic's
collection-leak trap. THE ABSENCE OF SETTERS IS THE DESIGN
DECISION β it is what makes the invariants enforceable.
Payment (a value-like entity)
βββββββββββββββββββββββββββββββββββββββββββββ
- amount : Money {immutable, β₯ 0}
- method : PaymentMethod {immutable}
- receivedOn : Instant {immutable}
- recordedBy : OfficerId {immutable}
- gatewayRef : String {0..1}
βββββββββββββββββββββββββββββββββββββββββββββ
+ isReconciled() : boolean
~ attachGatewayRef(ref : String) : void
Money (a value object)
βββββββββββββββββββββββββββββββββββββββββββββ
- amount : BigDecimal {scale 2}
- currency : Currency
βββββββββββββββββββββββββββββββββββββββββββββ
+ plus(other : Money) : Money
throws CurrencyMismatchException
+ isNegative() : boolean
β the value object from the associations topic: currency
travels with the amount, so mixing currencies cannot
compile past the type
Β«enumerationΒ» Status
RECEIVED Β· UNDER_REVIEW Β· APPROVED Β· REJECTED Β· ISSUED
ββ INFRASTRUCTURE BOUNDARY ββββββββββββββββββββββββββββββββββ
Β«interfaceΒ» ApplicationRepository β declared in the
βββββββββββββββββββββββββββββββββββββ DOMAIN package
+ find(no : String) : Application
throws ApplicationNotFound
+ save(app : Application) : void
throws OptimisticLockException
β³
β (realisation)
PostgresApplicationRepository β in infrastructure
Β«interfaceΒ» LicenceNumberPool
+ allocate() : LicenceNo
throws NumberPoolExhaustedException
Β«interfaceΒ» EventPublisher
+ publish(e : DomainEvent) : void
ββ THE READING ββββββββββββββββββββββββββββββββββββββββββββββ
Every element above answers a question asked earlier:
`version` β use case extension 5d, the
simultaneity question
`{reviewedBy β issuedBy}` β the separation-of-duties
constraint from the
associations topic, enforced
inside issue()
composition to StatusChange β the audit requirement
`/ feeDue` derived β the effective-dated fee rate
Money as a type β the currency defect
interfaces in the domain β dependency inversion
no setters β the anaemia test
`~ attachGatewayRef` β package visibility, so only
the reconciliation job can
call it
THE DIAGRAM IS A RECORD OF DECISIONS. Nothing in it is
arbitrary, and each item is traceable to a requirement, a
contract, or an interaction.
Reading a DCD critically
THE REVIEW CHECKLIST β what to look for when handed a design
class diagram.
DOES EVERY METHOD CORRESPOND TO A MESSAGE IN SOME INTERACTION?
A method nobody calls is speculative. Delete it, or find the
collaboration that needs it.
ARE THERE SETTERS FOR FIELDS CARRYING BUSINESS RULES?
The anaemia test. `setStatus` on a class with a legal
transition set means the transitions are unenforceable.
IS EVERY ASSOCIATION'S DIRECTION JUSTIFIED?
Walk each arrow and name the interaction that traverses it. A
bidirectional association needs two such interactions.
ARE THE MULTIPLICITIES CONSISTENT WITH THE DOMAIN MODEL?
A domain model saying 1..* and a design showing a single
field is a defect that will surface as "the system won't let
us enter a joint application".
DO THE TYPES PREVENT DEFECTS OR MERELY DESCRIBE THEM?
`amount : double` describes
`amount : Money` prevents
`status : String` describes
`status : Status` (enum) prevents
Every place a primitive stands in for a domain concept is a
place an invalid value can enter.
WHICH EXCEPTIONS ARE DECLARED, AND ARE THEY THE RIGHT ONES?
From the interface specification topic: an operation that
documents its parameters but not its failure modes is
half-specified. `throws NotIssuableException` is part of the
contract.
IS THE LAYERING RESPECTED?
Does any domain class reference a controller, a UI class or a
concrete infrastructure class? Each is a violation, and the
diagram is where it is visible.
ARE THE INTERFACES ON THE RIGHT SIDE?
`ApplicationRepository` must be declared where the domain can
see it, with the implementation elsewhere. An interface
declared in the infrastructure package that the domain
imports is dependency inversion done backwards, and it is a
surprisingly common mistake.
DOES THE DIAGRAM SAY ANYTHING THE CODE DOES NOT?
If the DCD is a mechanical restatement of existing code, it
will drift and mislead β the stale-model failure from the
modelling topic. A DCD earns its keep either BEFORE the code
(as a design decision record) or as a curated high-level view
that deliberately omits detail.
HOW MUCH TO DRAW β the proportionality rule again:
draw the classes whose STRUCTURE OR COLLABORATION IS
NON-OBVIOUS, and the boundaries between layers. Do not
draw every getter, every enum member, or every DTO. A DCD
of 200 fully detailed classes communicates less than one of
15 well-chosen ones.
THE HANDOVER TEST: could a competent programmer who was not in
the design discussions implement these classes without asking
what a method is supposed to do? If yes, the DCD plus the
interaction diagrams plus the contracts are a sufficient
specification β which is precisely what ACtE0806 assumes as its
starting point.
The most informative feature of a good design class diagram is often what it lacks. No setStatus, no getHistory β those absences are deliberate decisions that make the invariants enforceable, and they carry more design information than most of the methods that are present.
π Go further: the question "do the types prevent defects or merely describe them?" opens onto type-driven design. Beyond value objects, you can encode state in the type itself: an UnvalidatedApplication and a ValidatedApplication as distinct types mean a function requiring validation cannot be handed unvalidated input β the compiler rejects it, so an entire class of ordering bug becomes unrepresentable rather than merely tested for. Languages with richer type systems push this a long way, but even enums and small wrapper classes in mainstream languages capture most of the benefit. Search "type driven design parse don't validate".
π‘ Exam angle: distinguish the design class diagram from the domain model point by point β software classes, types, visibility, navigability, method signatures, interfaces β since that comparison is the standard question. Reproduce the procedure for creating a DCD: identify classes from the interaction diagrams, copy attributes from the domain model, add method names from the interactions, add types, add associations for attribute visibility, add navigability arrows, add dependency lines for non-attribute visibility. Emphasise that the DCD is drawn after the interaction diagrams. Be ready to draw one from a given collaboration and to critique one for setters, unjustified bidirectional associations and layering violations.
Syllabus points
Design class diagram (drawing)
Create a free account to tick topics off, take notes as you read, watch the video lessons and get a day-by-day study plan built around your exam date.