7 PlantUML anti-patterns

puml.online

This isn’t about how to use PlantUML. It’s about seven ways that “work, but suck” — pulled from real PR reviews and rewrites of my own old diagrams.

1. One diagram, 200 lines

The most common one. A sequence diagram wants to express 12 services and 40+ steps; reviewers can’t follow it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@startuml
title Complete order flow
participant User
participant App
participant Recommendation
participant H5
participant Cart
participant Order
participant Inventory
participant Payment
participant Ledger
participant RiskControl
participant Logistics
participant Push
User -> App: browse
App -> Recommendation: get recommendations
Recommendation --> App: list
App -> H5: navigate
H5 -> Cart: add to cart
Cart -> Order: place
Order -> Inventory: lock stock
Inventory --> Order: ok
Order -> Payment: request
Payment -> RiskControl: evaluate
RiskControl --> Payment: ok
Payment -> Ledger: charge
Ledger --> Payment: ok
Payment --> Order: success
Order --> H5: 200
... (another 30 lines)
@enduml

Slice by business step:

1
2
3
4
5
6
7
8
9
10
11
12
13
@startuml
title Order flow — browse to cart
participant User
participant App
participant Recommendation
participant H5
User -> App: browse
App -> Recommendation: get list
Recommendation --> App: items
App -> H5: navigate
H5 --> User: show product
User -> H5: add to cart
@enduml

A diagram should have 5–8 steps. 12 max. Past that, split.

2. Unnamed nodes

1
2
3
4
5
@startuml
A -> B: hello
B --> C
C -> A: ack
@enduml

A / B / C are implicit nodes; rendered as garbled text. At minimum:

1
2
3
4
5
6
7
8
9
@startuml
actor Alice
participant "Backend" as BE
database "User DB" as DB
Alice -> BE: hello
BE -> DB: query
DB --> BE: result
BE --> Alice: ack
@enduml

actor / participant / database / queue / boundary / control / entity cover the UML participant types; the diagram ends up both readable and UML-correct.

3. Sequence diagrams with no return arrows

Only A -> B: foo, never B --> A:

1
2
3
@startuml
API -> DB: SELECT
@enduml

The whole point of sequence diagrams is the two-way arrows. Without them reviewers can’t tell which way the flow goes.

1
2
3
4
@startuml
API -> DB: SELECT * FROM users
DB --> API: result
@enduml

Even failures get their own arrow:

1
2
3
4
5
@startuml
API -> DB: SELECT
DB --> API: timeout
API -> API: fallback to cache
@enduml

4. Using sequence for branches

People force if/else into sequence with note blocks:

1
2
3
4
5
6
7
@startuml
FE -> API: submit
note over API: if success then...
API --> FE: success
note over API: if failure then...
API --> FE: error
@enduml

That’s not what sequence is for. Use activity instead:

1
2
3
4
5
6
7
8
9
10
11
12
13
@startuml
start
:FE submit;
:API validate;
if (passed?) then (yes)
:write DB;
:return 200;
else (no)
:log;
:return 400;
endif
stop
@enduml

Or stay in sequence and use alt:

1
2
3
4
5
6
7
8
9
10
@startuml
FE -> API: submit
alt validation passed
API -> DB: write
API --> FE: 200
else validation failed
API -> DB: log
API --> FE: 400
end
@enduml

5. Class diagrams that abuse inheritance

1
2
3
4
5
6
7
8
9
10
11
12
@startuml
class Cat
class Dog
class Animal
Animal <|-- Cat
Animal <|-- Dog
class ServiceA
class ServiceB
class BaseService
BaseService <|-- ServiceA
BaseService <|-- ServiceB
@enduml

Not every Is-A deserves <|--. Composition, dependency, association are all valid relations:

1
2
3
4
5
6
7
@startuml
class Animal {
-food: Food
}
class Food
Animal --> Food : eats
@enduml

Default association is dashed; inheritance is the open-triangle arrow — keep them distinct.

6. Theme overload

The worst kind of diagram: someone brought CSS aesthetics into UML. None of it helps comprehension.

1
2
3
4
5
6
7
8
9
10
11
12
@startuml
skinparam class {
BackgroundColor gold
BorderColor red
FontColor white
FontSize 18
}
skinparam stereotypeCBackgroundColor yellow
class A
class B
A --> B
@enduml

Sane version:

1
2
3
4
5
@startuml
class A
class B
A --> B
@enduml

Fewer colors = more professionalism.

7. Diagram source detached from rendered artifact

The biggest organization-level anti-pattern: render to PNG, throw away the .puml.

1
2
3
docs/
architecture/
full.png # nobody remembers how to edit this

Six months later, a module changes. Nobody updates the diagram. Architecture diagram becomes “an archaeological artifact.”

Correct:

1
2
3
4
docs/
architecture/
full.puml
full.svg # rendered output

Source and artifact together in git. CI re-renders.

Anti-pattern → refactor table

Anti-pattern Impact Refactor
200-line diagram Impossible to read Split into 4–5 by step
Unnamed nodes Garbled render Use participant / actor / database
Sequence with no returns Flow direction unclear Add response arrows everywhere
Sequence for branching Hard to review Use activity or alt
Inheritance abuse Distorted design Use composition / association
Theme overload Diagram looks garish Default theme or minimal skinparam
Source detached from image Diagram rots Commit .puml + .svg together

Review checklist

When reviewing someone else’s PlantUML PR, ask:

  • Can this diagram be split into smaller pieces?
  • Are all nodes named?
  • Does every call in a sequence have a response?
  • Is the right diagram type being used (sequence / class / activity / use case)?
  • Is the theme minimal?
  • Will this stay in sync when the implementation changes?
  • Is the source file committed?
  • Title: 7 PlantUML anti-patterns
  • Author: puml.online
  • Created at : 2026-07-29 14:40:00
  • Updated at : 2026-08-14 21:34:29
  • Link: https://puml.online/blog/plantuml-anti-patterns-en/
  • License: This work is licensed under CC BY-NC-SA 4.0.