Archyno
UMLStructure diagrams

UML package diagrams

How a model or a codebase is grouped, and - the part that matters - which group is allowed to depend on which. The diagram that makes an architectural rule checkable instead of aspirational.

6 min readUML 2.5.110 of 15

uidomaininfrastructureshared«import»«import»
A layered architecture as a dependency graph. Every arrow points at something more stable than its source, and nothing points back up.

01What it shows

A package diagram is the table of contents for a model, plus a rule about who may reference whom. The tabbed-folder shape is a namespace: a group of classes, use cases, components, or other packages.

The grouping alone is mildly useful. The arrows are where the value is. A dependency from ui to domain says the UI layer may reference domain types. The absence of an arrow the other way says the domain must not know the UI exists - and that is an architectural rule you can test, lint, and fail a build on.

02The notation

ElementNotationWhat it means
Packagetabbed folderA namespace. Its name goes in the tab when the body holds contents, in the body when it does not.
DependencyThe source references something in the target. The general case, and usually enough.
«import»The target's public members become visible in the source and are re-exported from it.
«access»Visible in the source but not re-exported. The narrower, and usually more accurate, of the two.
«merge»The target's contents are combined into the source. Rare outside metamodels; you will read it more often than write it.
Nestingpackage inside a packageContainment, written outer::inner. Also drawable as a line with a circled cross at the parent.

In practice the plain dependency arrow carries most package diagrams, and the «import» versus «access» distinction only earns its keep when you are modelling a language or framework whose module system makes the difference real.

03Reading the direction

Everything interesting in a package diagram is in the direction of the arrows, and there are two things to look for.

Cycles. If you can start at a package, follow arrows, and get back where you started, those packages cannot be built, tested, understood, or deployed independently. They are one package pretending to be several. A package diagram makes a cycle visible in about two seconds, which is the fastest way to find one short of a tool.

Stability. Dependencies should point towards things that change less often. In the diagram above, ui and infrastructure both point at domain, and all three point at shared. That is the shape of a layered architecture: volatile things depend on stable things, never the reverse. An arrow from domain to ui would be the single most important thing on the page.

This is also how you spot a shared or common package going wrong. One that everything points at is fine, as long as it points at nothing itself. The moment it acquires an outgoing arrow, every package in the system transitively depends on that target.

04When to draw one

Reach for it when

  • Establishing or documenting a layering rule that should be enforced
  • Reviewing a codebase for dependency cycles between modules
  • Giving a new joiner the map of a repository before the detail
  • Planning how to split a monolith - the cut lines are where the arrows are thin

Reach for something else when

  • There are three packages and the structure is obvious from the folder tree
  • The interesting thing is the contracts between parts - use a component diagram
  • You would need to redraw it every time a file moves
  • The grouping exists but no rule about dependencies does; the arrows would be descriptive noise

Package diagrams work well at two altitudes and badly in between: the whole system at five to nine packages, or one subsystem at similar granularity. A diagram of forty packages is a dependency graph, and a dependency graph is better read by a tool than by a person.

In one line each

  1. 01Packages are namespaces; the arrows between them are the actual content.
  2. 02«import» re-exports, «access» does not; a plain dependency is usually enough.
  3. 03Follow the arrows to find cycles - packages in a cycle are one package.
  4. 04Dependencies should point towards what changes least.
  5. 05A shared package may be pointed at by everything; it must point at nothing.
  6. 06This is the UML diagram most likely to become an automated build check.
All articles