Free preview lesson ยท From the full paid path
Class Diagrams Without the UML Police
16 min read
The Diagram Three Engineers Read Three Different Ways
A team in Pune sent me a design doc to review before they built a returns-and-refunds flow for an e-commerce app. The centre of the doc was a class diagram: seven boxes, a dozen arrows between them, no labels on the arrows. It looked professional. It was also useless, and we found out the expensive way.
In the review meeting I asked what the arrow from Order to Refund meant. One engineer said "an order has a list of refunds." Another said "a refund points back to its order, the arrow shows the reference direction." The third said "it just means they are related, we will figure out the direction in code." Three people, one arrow, three readings. They had each built their part of the code against their own reading. The Order team stored refunds inside the order. The Refund team stored an order id inside the refund. Nobody stored the link the payments team assumed existed. The flow half-worked in three incompatible ways and took a sprint to untangle.
The arrows were the problem. Not the boxes, the arrows. A box is easy: it is a class, with a name and maybe some fields. The arrows are where the meaning lives, and this team was drawing arrows that meant "vaguely connected" while each reader filled in a different specific meaning. A class diagram is only worth drawing if the arrows say something precise, and precise is exactly what a small, shared vocabulary of arrow types gives you.
A class diagram shows the classes in a design and, more importantly, the relationships between them: which class holds which, which owns which, which depends on which, and how many. When you finish this page you can read any class diagram in this course, including the parking lot and elevator ones, and you can sketch one on a whiteboard fast enough to keep up with an interviewer, without turning into the UML police about it.
Why Should You Care?
First, every LLD lesson after this one leans on a class diagram, and every LLD interview expects you to draw one. If the arrows are noise to you, you are reading and drawing at half strength.
Second, the diagram is how you communicate a design to another human in seconds. A good class diagram settles the "who holds whom" argument before it becomes three incompatible code branches, which is exactly what it failed to do for the Pune team.
Third, drawing one forces you to make the relationship decisions early, on cheap whiteboard ink, instead of late, in expensive merge conflicts. The act of choosing "is this aggregation or composition" surfaces a real design question you would otherwise discover in production.
๐ข The Simple Version: A Box and Five Kinds of Line
In plain words: a class is a box with three floors, its name on top, its fields in the middle, its methods at the bottom. The lines between boxes are the whole point, and there are only five kinds you need. Learn the five lines and you can read any class diagram.
The box first. Cart on the top floor. items: List<CartItem> and couponCode: String in the middle. add(), totalPaise() at the bottom. In a fast whiteboard sketch you skip floors you do not need, often just the name and a method or two. That is fine. The box is the easy part.
The lines are where the Pune team drowned. Here are the five, weakest link first.
Scroll sideways to read, or tap to zoom
Course diagrams cannot draw a filled diamond on the line, so they put the glyph in the label next to the owner. On a whiteboard you draw the diamond yourself. If you forget the glyph, write "owns" or "has" on the line. A labelled plain arrow beats a beautiful arrowhead whose meaning the reader has to guess.
- Dependency (a dashed arrow, โข). "This class uses that one briefly, usually as a method parameter or a local, and does not hold it as a field." A
ReceiptPrinter.print(order)depends onOrderfor one call. That is the weakest link. - Association (a plain solid arrow, โ). "This class keeps a reference to that one, usually as a field." A
Driverholds theTripthey are on. Directed arrow means navigability one way, not "they both know each other." - Aggregation (a solid line with a hollow diamond โ at the owner's end). "This class holds that one, but the held thing can live on its own and be shared." A
PlaylistaggregatesSongs. Delete the playlist and the songs still exist; the same song sits in other playlists. The diamond sits on the container side. - Composition (a solid line with a filled diamond โ at the owner's end). "This class owns that one, and the owned thing does not outlive it." An
Orderis composed ofOrderItems. Delete the order and its order items are meaningless; they belong to that one order and no other. The filled diamond is the strong "owns and controls the lifetime" claim. - Inheritance / realization (a solid line with a hollow triangle โณ pointing at the parent, or dashed for implementing an interface). "This class is a kind of that one."
SavingsAccountinherits fromAccount. The triangle always points at the more general parent.
The single most useful distinction in that list is aggregation versus composition, the hollow diamond versus the filled one, because it answers "when this container dies, does the thing inside die with it?" An order's order items die with the order (composition, filled). A playlist's songs outlive the playlist (aggregation, hollow). Getting that arrow right is often the difference between a design that deletes cleanly and one that leaves orphaned rows.
One honesty note. This lesson teaches you to read and draw these relationships. The deeper design question, when you should actually choose composition over inheritance, is its own topic and lives in the later OOP composition lesson. Here we are learning the notation, not relitigating the decision.
๐ก Multiplicity, and Reading a Real Diagram
The arrows carry one more piece of information: multiplicity, the little numbers near each end that say how many. This is what the Pune diagram was missing, and it is what would have settled their argument in one glance.
The notation is small:
1exactly one0..1zero or one (optional)*many (zero or more)1..*at least one
So an Order to OrderItem link labelled 1 on the order end and 1..* on the item end reads as "one order has one or more order items, and each order item belongs to exactly one order." That single label, 1 to 1..*, tells every reader that order items live inside one order and there is no such thing as a shared order item. Had the Pune diagram carried 1 to * on that refund arrow with a filled diamond on the order side, all three engineers would have read it the same way: the order owns its refunds, one order, many refunds, and a refund does not float free.
Now read a real one. Here is a small order model, the kind you would sketch in the first ten minutes of an interview.
Scroll sideways to read, or tap to zoom
Walk it the way you would read it aloud to an interviewer:
Orderis composed ofOrderItem(filled diamond on the order side,1to1..*). One order owns one or more order items, and they die with it. That is the "delete the order, the order items are meaningless" claim.OrderItemis associated withMenuItem(plain arrow,*to1). Many order items can point at the same menu item, and the menu item lives on its own in the catalogue. Notice this is not composition: deleting an order must not delete the "Masala Dosa" from the menu. The arrow type is carrying a real rule.Orderis composed of at most onePayment(filled diamond,1to0..1). Zero or one, because an order can exist before it is paid. The payment row belongs to that order. The0..1says "unpaid order" is a legal state, so payment is not part of creating an order.Orderis associated withPricingStrategy(plain solid arrow). It holds the strategy as a field, the way the parking lot later holds one. A dashed arrow would mean it was only passed into a method and not stored. The later parking-lot code isprivate final PricingStrategy pricing, so this arrow is solid on purpose.
Read like that, the diagram is a paragraph of precise claims, not a decoration. Every arrow type and every multiplicity number removed one possible misreading. That is the entire value of the notation.
When you draw one under interview time, do it in this order: boxes with names first, then the strong ownership lines (the filled diamonds, because those are the load-bearing "who owns whose lifetime" decisions), then the associations and dependencies, then the multiplicity numbers last. If you run out of time, a diagram with the right boxes and the right ownership diamonds is far more useful than one with every arrow but no diamonds.
A trick that keeps a whiteboard sketch honest: read every arrow out loud as an English sentence as you draw it, using the arrow type as the verb. "One order owns one-or-more order items." "Many order items refer to one menu item." "One order optionally has one payment." If a sentence sounds wrong when spoken, the arrow is wrong. "One order owns one restaurant" sounds absurd the moment you say it, and that is the diamond catching the mistake before the code does. The reason the Pune diagram failed is that nobody read it aloud; on paper an undefined arrow looks fine, but the instant you try to speak it, the missing verb becomes obvious. This is also the fastest way to review someone else's diagram: point at each arrow and ask them to say it as a sentence. The arrows they stumble on are the ones that have not been thought through.
One more practical note on tooling. You do not need a UML tool to draw these, and reaching for one in an interview wastes minutes. A marker and the five arrow types are enough. The diamonds and triangles are worth memorising as glyphs, because a reviewer who knows them reads your intent instantly, but if you forget which diamond is filled, just write the word "owns" or "has" on the line. A labelled plain arrow beats a beautifully drawn arrowhead whose meaning the reader has to guess. Communication is the whole job, and words are a legal part of the notation.
๐ด Architect's Corner: The Diagram Is Communication, Not a Contract
The trap for people who take UML seriously is treating the diagram as a specification the code must match forever. It is not. A whiteboard class diagram is a communication tool with a lifespan of one conversation. Its job is to get four people in a room to agree on the shape of the design before anyone writes code. Once the code exists, the code is the truth, and the diagram is a sketch that helped you get there. I have watched teams waste an afternoon arguing whether an arrowhead was drawn at exactly the right angle. That afternoon bought nothing. The refund arrow being labelled bought everything.
So calibrate the formality to the audience. On a whiteboard with an interviewer, loose is correct: boxes, a few labelled arrows, the ownership diamonds where they matter, and spoken words filling the gaps. In a design doc that ten people will read asynchronously and cannot ask you to clarify, tighter is worth it, because the diagram has to answer the questions you are not there to answer. The Pune doc failed precisely because it was async, ten-reader formality with whiteboard-level looseness. The mismatch, not the tool, was the problem.
The second senior point is that diagrams rot. A class diagram checked into a repo drifts from the code within weeks, because code changes and nobody updates the picture. A stale diagram is worse than no diagram, because it lies with authority. My rule: diagrams live in the design phase and in lesson-style explanations where the shape is stable, and they do not get treated as living documentation of code that changes daily. If you want a picture that stays true, generate it from the code, do not hand-maintain it.
The third thing seniors do is resist over-modelling the diagram the same way they resist over-modelling the classes. You do not need every getter and setter on the box, you do not need a class for every noun, and you do not need an arrow for every reference. The diagram should show the load-bearing relationships, the ones a reader would otherwise get wrong. A String customerName field does not need to be drawn as a box-and-arrow to a String class. Draw what carries a decision, hide what is obvious.
How This Shows Up in India
Swiggy order model. In a design review, the arrow you fight about is Order to Restaurant: association, not composition. Deleting an order must never delete the restaurant. Drawing it as composition (filled diamond) would be a claim that a restaurant lives and dies with a single order, which is absurd, and the diamond is where a careful reviewer catches that.
IRCTC booking and passengers. A Booking is composed of Passenger entries for that journey (filled diamond, 1 to 1..*): those passenger rows belong to that PNR and no other. But the Booking is only associated with the Train (plain arrow): the train exists independently of any one booking. Same diagram, two different arrow types, two different lifetime rules.
Hotstar subscription and profiles. Hollow versus filled here is a product decision about lifetime, not about whether you can add or remove a profile (composition allows that too). If deleting the account deletes the profiles, it is composition (filled). If a profile can outlive the account, or sit on more than one account at once, it is aggregation (hollow). Draw the diamond that matches the rule you actually want.
The Decision Matrix
| The relationship in words | Arrow to draw | Multiplicity example |
|---|---|---|
| A uses B briefly, does not hold it | Dashed arrow (dependency) | ReceiptPrinter โข Order |
| A holds a reference to B | Plain solid arrow (association) | Driver 1 โ Trip 0..1 |
| A holds B, B can live alone and be shared | Solid line, hollow diamond โ on A | Playlist 1 โโ Song * |
| A owns B, B dies with A | Solid line, filled diamond โ on A | Order 1 โโ OrderItem 1..* |
| A is a kind of B | Solid line, hollow triangle โณ at B | SavingsAccount โณโ Account |
| A implements interface B | Dashed line, hollow triangle โณ at B | GupshupNotifier โขโณ Notifier |
Common Mistakes
- "An arrow just means the classes are related." That is exactly the undefined arrow that made three engineers build three different things. An arrow with no type is a question, not an answer. Give it a type, or do not draw it.
- "Aggregation and composition are basically the same." One is a hollow diamond, one is filled, and the difference is whether the held thing dies with its owner. An order's order items die with it (composition); a playlist's songs do not (aggregation). That difference decides whether your delete leaves orphans.
- "I skipped multiplicity, the arrow is enough." The
1to1..*versus1to*versus1to0..1is often the whole meaning. "An order with zero order items" and "an unpaid order" are legal-state questions the multiplicity answers at a glance. - "The diagram is the spec and the code must match it forever." A whiteboard diagram is a one-conversation communication tool. Once code exists, code is the truth. A hand-maintained diagram checked into the repo rots and then lies with authority.
- "More boxes and arrows means a more complete diagram." Draw the load-bearing relationships a reader would otherwise misread. A box for
Stringand an arrow for every getter is noise that hides the two arrows that actually matter.
๐ง Key Takeaways
- A box is easy; the arrows carry the meaning. An untyped arrow is where readers diverge, so every arrow gets a type or does not get drawn.
- Five relationships cover almost everything, weakest first: dependency, association, aggregation, composition, inheritance. The load-bearing pair is aggregation (hollow โ) versus composition (filled โ): does the held thing die with its owner?
- Multiplicity (
1,0..1,*,1..*) often is the meaning. It answers "can this be empty, can this be shared, is this optional" before code makes it expensive. - Draw in order of importance: boxes, then ownership diamonds, then other arrows, then multiplicity. If time runs out, right boxes plus right diamonds beats every arrow with no diamonds.
- A class diagram is communication with a short lifespan, not a contract. Match its formality to its audience, and never treat a hand-maintained diagram as the source of truth once code exists.
Think About It
"You are drawing Cart and MenuItem. Which relationship, and what happens to the menu item when a cart is deleted?" Association (a plain arrow), not composition, with a * to 1 multiplicity through the CartItem. Many cart items across many carts point at the same menu item, and the menu item lives in the catalogue independently. Deleting a cart must not delete "Masala Dosa" from the menu. If you drew a filled diamond here, you would be claiming the dosa belongs to one cart and dies with it, which is the bug the arrow type exists to prevent.
"An interviewer glances at your diagram and asks why one arrow is dashed and another solid. What is the honest answer?" The dashed arrow is a dependency: the class is handed that collaborator to use, usually as a method parameter, and does not hold it as a field. The solid arrow means the class keeps a reference as part of its own state. The distinction tells a reader whether swapping that collaborator is a constructor change (held) or just a different argument at a call site (passed in).
"A teammate wants to check the class diagram into the repo as living documentation. What do you advise?" I would push back gently. Hand-maintained diagrams drift from code within weeks and then mislead with authority. If we want a picture that stays true, we generate it from the code so it cannot lie. The hand-drawn diagram belongs in the design doc and the review conversation, where its job is to align people before the code exists, not to describe code that changes daily afterward.
Further Reading
- Martin Fowler, UML Distilled (class diagrams chapter). The pragmatic, non-dogmatic guide to exactly the subset of UML worth knowing, from the person who argued hardest against UML pedantry.
- Refactoring Guru: Relations Between Objects. A clear, diagram-heavy walk through association, aggregation, composition, and dependency with the lifetime rules spelled out.
- PlantUML class diagram syntax. If you want a text-to-diagram tool that generates from a description, so the picture can be regenerated instead of hand-maintained and left to rot.
Full quizzes, answers, progress, case studies and interview problems available in the paid path.