F5.03 · part 3 of 3
Iterating the slice
Once the skeleton walks, the system grows the same way it started: one thin vertical slice at a time. The next use case — deliver the first lesson — is another tracer bullet through the same layers: a route, a context function, a read from the store. Then record progress, then the next thing. Each slice is thin at every layer and reuses the frame, and crucially each one leaves the system running and demoable. This is the opposite of building horizontally — finishing the whole web layer, then the whole engine — where nothing works until the very end.
Three slices, each cutting through every layer. Select one to see what it adds.
Slice by slice
Each column below is one iteration, and each spans all four layers — web, context, struct, store. The first is the skeleton you already have; the next two are added on top, reusing it. Growth is always vertical, so the application is runnable at the end of every slice, not only at the end of the project. Select a slice.
Vertical slices · select one
iteration: Iteration 1 · enroll
adds: the skeleton
Grow vertically, never horizontally. A stack of thin, finished slices is a working product at every step; a stack of half-built layers is nothing that runs until the last one lands.
In code
The second slice has the same shape as the first: a new route, one new context function, a store read. Catalog gains a single function; Learning, the store, and the server are untouched. That is what reusing the frame looks like — each iteration is small because the skeleton already carries the weight.
# iteration 2 — deliver the first lesson: a new thin slice, same shape get "/lessons/:id" do case Portal.Catalog.lesson(id) do {:ok, lesson} -> send_resp(conn, 200, Jason.encode!(lesson)) :error -> send_resp(conn, 404, "not found") end end # Catalog grows one function; Learning, the store, and the server are untouched def lesson(lesson_id), do: Portal.Store.fetch(lesson_id)
one slice at a time
Each use case is a thin vertical cut through every layer, added on top of the last.
always running
The system works at the end of every slice — growth never takes it offline.
That closes F5.03: a tracer bullet became a walking skeleton, and the skeleton grows by slices. The next module, F5.04 — Design by contract, hardens the commands each slice runs with preconditions and invariants. Back to the module overview or the chapter.
References
Primary sources for this lesson, and where it connects in the course.
Sources
- Hunt and Thomas — The Pragmatic Programmer — tracer bullets: build end-to-end before exhaustive.
- Elixir — Introduction to Mix — scaffold the thin, running skeleton app.