Learn

Architecture & pattern guides

Read the idea, build it on a Grid, prove it in a challenge. Short, practical guides — illustrated with RodGrid's own nodes — on system design, design patterns, flow modeling, and how to get the most out of the app.

All articles

Object diagrams: one moment of a running system

Instances instead of types: how an object diagram shows one concrete state with named objects, slots holding values and links between them, how that snapshot tests a class diagram's multiplicities and ownership, and why one snapshot can show a state is possible but never that every state is valid.

A draft and one request

A first class diagram for a file system usually comes out like the one below. Files and folders share an abstract Entry, so the code that walks the tree can ask any entry for its size() without caring which kind it holds. A Folder holds entries by composition, because deleting a folder deletes what is inside it. The label says a folder holds 0..* entries and each entry sits in exactly 1 folder. The shape is the Composite pattern, which has its own article; here it is only the diagram under test, and the diamond and the numbers are read as Association, aggregation, composition explains.

The draft

File and Folder are kinds of Entry. Folder's filled diamond says it owns its entries; the label gives the folder end 1 and the entry end zero or more.

It looks finished. Before approving it, a reviewer asks for one thing: draw a real tree, five entries, as it would sit in memory. That sounds like busywork, and it is the cheapest test this diagram will get. Every line on a class diagram is a rule about all possible trees at once, and a rule about everything is easy to get slightly wrong without noticing. One concrete tree either fits the rules or it does not.

Objects, slots and links

That drawing is an object diagram: the instances that exist at one moment, the values they hold, and the links between them. It reuses the class diagram's box, with different things inside.

  • The name is written name: Class. docs: Folder is an object called docs whose class is Folder. When the name does not matter, keep the colon and drop the name: : File is some file. Entry is abstract, so every real entry is a File or a Folder; UML also accepts : Entry when the kind does not matter, but this snapshot gives each entry its concrete class.
  • Slots take the place of attributes. Each one gives an attribute a value, bytes = 48200, where the class gave it a type. Inherited attributes get slots too, so a File can show the name declared on Entry; slots the question does not need can be left out.
  • No operations. Operations belong to the class and every instance shares them, so an object's box has nothing to add about them.
  • Links are instances of an association: one line between two objects, where the class diagram had one line between two classes. A link of a two-ended association like this one joins exactly two objects, so it carries no multiplicity. Counting links is how you check one.

On a Grid this is the Object stencil, the same three-compartment box as a Class (The class box: name, attributes, operations covers the compartments). docs: Folder is its name, the slots go in the middle compartment, and the bottom one stays empty. The Grid does not underline the name the way printed UML does; the colon and the class name mark the instance.

Five entries, one moment

root holds docs and todo; docs holds cv and the empty photos folder. Each line is one link of Folder's composition.

The picture already lets you do something the class diagram could not: run an operation by hand, given what it does: a File returns its bytes, a Folder adds up its children. docs.size() asks its two children, 48,200 bytes from cv and 0 from the empty photos folder. root.size() adds todo's 1,300 to that, 49,500. No folder has a size slot: the number is worked out from the children on every call.

Reading the draft against the snapshot

Now put the two diagrams side by side and ask two questions. First, does every link match an association? root to docs, root to todo, docs to cv and docs to photos all join a Folder to something that is an Entry, so each is an instance of the composition. A link with nothing to match, a File linked to another File, would mean the snapshot is wrong or the class diagram is missing a relationship.

Second, does every count respect the multiplicity? Count from each end; that is a fair test because this snapshot draws every link the tree has. On the entry end, root holds two entries, docs two, photos none: all inside 0..*, and photos shows that the zero is real. On the folder end, the draft says each entry sits in exactly 1 folder. docs, todo, cv and photos do. root does not, and it cannot, because it is the top of the tree. The draft forbids the one entry every tree has.

The fix is 0..1 on the folder end, which composition allows: a part has at most one owner, and here possibly none. That rule is looser than the truth, though. It would also accept a file floating with no folder at all. What the domain says is narrower, that exactly one entry, the root, has no parent, and a multiplicity cannot say it: it limits the links of each object, not how many objects in the whole tree are allowed to have none. A Note on the class diagram carries that rule.

The loop that passes every count

A second snapshot is worth drawing for what the first one could not contain. Take three folders, a, b and c: a holds b, b holds c, and c holds a. Each has exactly one parent and one child, so every count is legal, and every link joins a Folder to an Entry. The numbers accept this state, and it is not a tree. None of the three can be reached from root, and a.size() asks b, which asks c, which asks a again, until the stack runs out.

Multiplicities count links per object; a loop is invisible to them. UML composition rules it out: a part sits in at most one composite, and the whole–part links must not form a cycle, so the filled diamond already says this state is invalid. A reader who does not know that rule will not see it, so the same Note as the root rule spells it out, and add has to enforce it by refusing to put a folder inside itself or any of its own descendants.

A snapshot that fits shows only that its one state is allowed, not that every state the diagram allows makes sense: five clean snapshots are evidence, not proof. Pick them where rules break, at the root, an empty folder, the deepest nesting. They also hold no time: the order in which size() reaches each child is drawn in Sequence diagrams: who calls whom, in what order, whose lifeline heads use the same role: Type form as an object's name.

The same two questions on File System Tree

The File System Tree Challenge asks for this class diagram, with the containment labelled as composition and its multiplicity; it grades the class diagram, not an object diagram. Test the label against the root and an empty folder before you write it: if the root breaks 1, the label is composition 0..1 : 0..*, and a Note says what the numbers cannot, one root and no folder inside itself. On a Challenge Grid members go in the class name, as the brief shows with Folder (size()).

Whatever the diagram, the check you run on a snapshot stays the same: every link matches an association, and every object's links fit the multiplicity at that end.

Practice this