Level 4 - Code¶
A Code diagram zooms into one component and shows how it is implemented: classes, interfaces, and their relationships, usually as a UML class or sequence diagram. It is the optional level. Simon Brown's own advice is to draw it rarely, keep it out of version-controlled documentation, and generate it from an IDE when needed, because it is obsolete the moment someone refactors.
Draw one when the design is subtle and worth explaining: a state machine, a strategy hierarchy, a tricky concurrency protocol.
The example: inside the Security Component¶
Note the shape: the component exposes one interface to the rest of the container, and hides the rest. That is what makes it a component rather than a folder.
Behaviour, not just structure¶
Class diagrams show what exists; sequence diagrams show what happens. For most level-4 explanations, the sequence is the interesting part.
sequenceDiagram
autonumber
participant C as Sign In Controller
participant A as DatabaseAuthenticationService
participant R as JdbcUserRepository
participant H as BcryptPasswordHasher
participant DB as PostgreSQL
C->>A: authenticate("mani", "•••")
A->>R: findByUsername("mani")
R->>DB: SELECT ... WHERE username = ?
DB-->>R: row
R-->>A: User
alt user locked
A-->>C: AuthResult.locked()
else not locked
A->>H: matches(raw, user.passwordHash)
H-->>A: false
A->>R: recordFailedAttempt(user)
A-->>C: AuthResult.invalidCredentials()
end
The alt block carries the design decision worth documenting: lockout is checked before the hash comparison, so a locked account costs no bcrypt work. Structure alone would never have shown that.
State, when the logic is a machine¶
stateDiagram-v2
[*] --> Active
Active --> Active: failed attempt (n < 5)
Active --> Locked: 5th failed attempt
Locked --> Active: lockout expires (15 min)
Locked --> Active: admin unlock
Active --> Disabled: account closed
Disabled --> [*]
When to draw level 4, and when not to¶
| Situation | Draw it? |
|---|---|
| Explaining a non-obvious algorithm or protocol to reviewers | Yes, in the pull request or an ADR |
| Onboarding someone into a subtle component | Yes, generated on the spot |
| Documenting every component of the system | No. It will be wrong before the sprint ends |
| Whiteboarding a design before writing it | Yes, then erase it |
| Repository documentation intended to stay accurate | No. Generate on demand instead |
The rule of thumb: level 4 diagrams should be cheap enough to throw away. If keeping one accurate would cost real effort, the code should be readable enough not to need it.
Generate rather than maintain¶
flowchart LR
code["Source code"] --> tool["IDE / doc generator<br/><i>IntelliJ diagrams, pyreverse,<br/>PlantUML parsers, Doxygen</i>"]
tool --> diag["Class or sequence diagram<br/><i>correct by construction</i>"]
hand["Hand-drawn level 4"] -.->|"drifts from code"| stale["Confidently wrong diagram"]
A hand-maintained level-4 diagram is worse than none: readers trust it, and it lies. This is the same failure mode as stale comments, at larger scale.
How the four levels relate one last time¶
flowchart TB
A["Level 1, Context<br/><i>Internet Banking System</i><br/>stable for years"]
B["Level 2, Containers<br/><i>SPA, API, database</i><br/>stable for months"]
C["Level 3, Components<br/><i>Security, Mainframe Facade</i><br/>stable for weeks; generate or test"]
D["Level 4, Code<br/><i>DatabaseAuthenticationService</i><br/>stable for hours; generate on demand"]
A --> B --> C --> D
Effort should be spent in inverse proportion to volatility: invest in levels 1 and 2, enforce level 3 with tests, and let level 4 be disposable.
Check Your Understanding¶
What is the standard advice about level 4 code diagrams?
A sequence diagram of the sign-in flow shows the lockout check happening before the password hash comparison. Why is that worth documenting at level 4?