Lesson 02 — Reading a card
Goal: by the end of this lesson you can open any fn in the editor and read what the canvas shows — which cards it drew and why, what the rows on a card are, how to unfold and fold, and where to find what a namespace, a fn, or a slot is for.
Concepts introduced: card, ancestor rows, level,
closed card, unfold / fold, hover preview, description
(namespace / fn / slot), ↖ provenance.
The card is the fn's ancestry
Open a composed fn and its card is a stack of rows. The top row is
the fn itself; each row below is an ancestor — parent, grandparent,
… — down to the base function whose Clojure impl finally runs. For
app.routes/health (the fn behind GET /health on every graphden):
health ← the fn you opened
get-route ← its parent: pins the HTTP method
route ← the generic reitit route
list ← the base function: [path method-data]
The card is a chain visualizer: click a row's name and you have walked one hop up the inheritance. (Two names sharing one row is a fn with two parents — Lesson 03.)
What the canvas draws when you open a fn
Only what the fn itself binds, plus every slot still free:
- a literal becomes a small value node —
path→"/health"; - a reference to a named fn becomes a second card —
handler→health-handler; - a free slot becomes a
+placeholder (lesson 01's:nums).
The second card is closed. A named fn is a boundary: its own bindings — what it is built from — are not drawn until you ask. That is why opening a fn that wires ten named pieces together still fits on one screen: you see the composition, one hop deep.
What you do not see at first: bindings made by the fn's ancestors.
get-route pins method to "get", but health inherits that
already decided, so no method edge is drawn — it is not health's
input. Which brings us to the rows.
Unfolding: rows are levels
Each row is a level. Clicking a row draws what that ancestor bound
— and every ancestor above it. Click get-route on the health card
and a method → "get" edge appears; the value node carries a ↖
that names where it came from (Inherited from get-route ← route)
and jumps there.
Levels are set, not toggled:
- clicking a deeper row unfolds down to it (the rows in between come along);
- clicking a shallower row folds back up to it;
- clicking the top row — the fn's own name — folds everything.
Two rows that add nothing of their own (route and list here — the
route's items are path and a method-map whose inputs are the method
and handler you already see) unfold together as one block.
Hover before you click. Pointing at a row previews the unfold: the canvas draws what the click would add, and puts it away when the pointer leaves. It costs nothing, so use it to read a card — click only when you want the layout to stay.
A card with two parents on one row (multiple inheritance, lesson 03) treats each half as its own switch: click one parent's name to unfold just that parent's bindings, click it again to fold it; once both halves are unfolded the row is simply "expanded to this level" like any other.
Opening a closed card
A card that arrived as a value — the fn bound into some slot — is
drawn closed. Unfold it the same way: click the row under its
name (its first parent) and its own bindings appear. On health's
canvas, click json-ok-response on the health-handler card and
body → health-json-body appears — closed in turn. Each hop is one
click. Reopen health later and the closed cards are back: the
unfolding is your reading position, not part of the graph.
If you want to read a closed card without changing the canvas at all,
its ⋯ → 👁 Peek opens its bindings in a floating panel
(Lesson 20).
Descriptions live at three levels
Anything that can be named can be described, and one glyph — i —
marks the description everywhere:
| Level | Where to read it | Where to write it |
|---|---|---|
| Namespace | the i at the right end of its row in the Explorer |
same i — click to pin, then ✎ Edit |
| fn | the Inspector's head when the fn is selected; ⋯ → i on any card row; the i on its Explorer row |
⋯ → i → ✎ Edit |
| Slot | the i after the type chip on the edge label |
same i → ✎ Edit, signed in |
A slot description is written where the slot was declared
(route declares method: "HTTP method literal — e.g. "GET" /
"POST"…") and travels with the slot to every fn that inherits it.
A slot nobody described says so — (no description) — which is the
same i you would click to add one.
In fns.edn the three are :description on the namespace map, on
the fn-def, and inside an arg's spec:
{:name :route
:description "Generic reitit route — `[path method-data]`. …"
:parent :list
:args {:items [{:as :path} :method-map]
:method {:type :keyword-or-text
:description "HTTP method literal — e.g. `\"GET\"` / `\"POST\"`. …"}}}
Try it
Prefer to be shown? This lesson exists as a guided in-editor tour: open the demo with the tour running (no sign-up), or pick “Interactive tutorial” in the editor's account menu.
In the running editor (nothing is created in this lesson):
- Type
healthin the Explorer filter and click thehealthrow (inapp.routes). The Inspector's head shows its description: GET /health — current health status as JSON. - Read the card: four rows —
health,get-route,route,list. To its right,path→"/health"andhandler→ the closedhealth-handlercard. Nomethodedge. - Hover
get-routeon thehealthcard — themethod→"get"edge is previewed. Click the row to keep it. Hover the value's↖: Inherited from get-route ← route. - Hover the
iaftermethodon the edge label: the slot's description. Compare with theiafterpath: (no description). - Click the
healthrow (the top one): the card folds back. - Click
json-ok-responseon thehealth-handlercard — the row under its name. Its own binding appears:body→health-json-body, closed in turn. - In the Explorer, hover the
routesrow and itsiat the right end: the namespace's description.
What we glossed over
- Why
routeandlistadd nothing when unfolded — the list's items arepathand the method-map, already on the canvas aspathandhandler; how a slot travels up through references is Lesson 05. - What the rows mean at the data level —
parent-idsand slot inheritance, Lesson 03 and Lesson 04. - Reading the other panels — the Inspector's Bindings table, kind filters, Peek: Lesson 20.