From 35a97c1dd324e2cd44989eefe2b1231daf7fe39f Mon Sep 17 00:00:00 2001 From: Jacob LeCoq Date: Wed, 22 Jul 2026 23:06:18 -0500 Subject: [PATCH 1/4] docs(11.3): add intro, diagram types, and simple-system example (Task 1.0) Adds Chapter 11.3 System Thinking main content page with intro, learning objectives, diagram type explanations (sequence/component/ data flow), and a diagramming tools comparison. Includes the simple-system example app (Flask frontend + Flask backend + SQLite), its PlantUML source diagrams and rendered PNGs, an architecture README template, and Exercise 1 instructions. Verified end-to-end via docker compose: add/list/toggle tasks all work. Frontend is published on host port 8080 instead of 5000 because macOS AirPlay Receiver silently intercepts port 5000. --- .../11.3-system-thinking.md | 190 ++++++++++++++++++ .../img11/simple-system-component.png | Bin 0 -> 20586 bytes .../img11/simple-system-dataflow.png | Bin 0 -> 27022 bytes .../img11/simple-system-sequence.png | Bin 0 -> 23745 bytes .../02-tasks-system-thinking.md | 42 ++-- examples/ch11/simple-system/.gitignore | 5 + examples/ch11/simple-system/README.md | 69 +++++++ .../ch11/simple-system/backend/Dockerfile | 7 + examples/ch11/simple-system/backend/app.py | 87 ++++++++ .../ch11/simple-system/backend/pyproject.toml | 9 + .../simple-system/backend/requirements.txt | 1 + .../simple-system/diagrams/component.puml | 37 ++++ .../ch11/simple-system/diagrams/dataflow.puml | 25 +++ .../ch11/simple-system/diagrams/sequence.puml | 35 ++++ .../ch11/simple-system/docker-compose.yml | 32 +++ .../ch11/simple-system/frontend/Dockerfile | 8 + examples/ch11/simple-system/frontend/app.py | 43 ++++ .../simple-system/frontend/pyproject.toml | 10 + .../simple-system/frontend/requirements.txt | 2 + .../frontend/templates/index.html | 38 ++++ .../templates/architecture-readme-template.md | 33 +++ 21 files changed, 652 insertions(+), 21 deletions(-) create mode 100644 docs/11-application-development/11.3-system-thinking.md create mode 100644 docs/11-application-development/img11/simple-system-component.png create mode 100644 docs/11-application-development/img11/simple-system-dataflow.png create mode 100644 docs/11-application-development/img11/simple-system-sequence.png create mode 100644 examples/ch11/simple-system/.gitignore create mode 100644 examples/ch11/simple-system/README.md create mode 100644 examples/ch11/simple-system/backend/Dockerfile create mode 100644 examples/ch11/simple-system/backend/app.py create mode 100644 examples/ch11/simple-system/backend/pyproject.toml create mode 100644 examples/ch11/simple-system/backend/requirements.txt create mode 100644 examples/ch11/simple-system/diagrams/component.puml create mode 100644 examples/ch11/simple-system/diagrams/dataflow.puml create mode 100644 examples/ch11/simple-system/diagrams/sequence.puml create mode 100644 examples/ch11/simple-system/docker-compose.yml create mode 100644 examples/ch11/simple-system/frontend/Dockerfile create mode 100644 examples/ch11/simple-system/frontend/app.py create mode 100644 examples/ch11/simple-system/frontend/pyproject.toml create mode 100644 examples/ch11/simple-system/frontend/requirements.txt create mode 100644 examples/ch11/simple-system/frontend/templates/index.html create mode 100644 examples/ch11/templates/architecture-readme-template.md diff --git a/docs/11-application-development/11.3-system-thinking.md b/docs/11-application-development/11.3-system-thinking.md new file mode 100644 index 00000000..81024c25 --- /dev/null +++ b/docs/11-application-development/11.3-system-thinking.md @@ -0,0 +1,190 @@ +--- +docs/11-application-development/11.3-system-thinking.md: + category: Software Development + estReadingMinutes: 30 + exercises: + - + name: Simple Application Analysis + description: Create sequence, component, and data flow diagrams for a simple multi-service application + estMinutes: 90 + technologies: + - System Design + - Diagramming + - Architecture Documentation + - + name: Transaction Tracing in OTel Demo + description: Trace a transaction through 3-5 services in the OpenTelemetry Demo Application + estMinutes: 120 + technologies: + - Microservices + - OpenTelemetry + - System Design + - + name: Architecture Documentation & Presentation + description: Write ADRs and README documentation, deliver walkthrough presentation + estMinutes: 150 + technologies: + - Technical Writing + - Architecture Documentation + - Communication + - + name: Integration Exercise + description: Complete analysis of a feature including all diagram types, documentation, and presentation + estMinutes: 180 + technologies: + - System Design + - Microservices + - OpenTelemetry + - Technical Writing +--- + +## System Thinking & Codebase Analysis + +Writing new code from scratch is a small fraction of what professional engineers actually do. Far more often, you're dropped into a codebase someone else built — sometimes years ago, sometimes last sprint by a teammate who's now on vacation — and asked to add a feature, fix a bug, or explain how something works. **System thinking** is the skill of building an accurate mental model of a codebase you didn't write: how its pieces are organized, how they talk to each other, and why they were built that way. + +New developers who skip this step tend to make local, function-level changes without understanding the system-level consequences — breaking a contract another service depends on, duplicating logic that already exists elsewhere, or fixing a symptom instead of a root cause. Developers who invest in system thinking first ship changes faster and with far fewer surprises, because they know where the edges of their change actually are. + +This section teaches you to: + +- Read an unfamiliar codebase systematically instead of clicking around at random +- Represent what you learn as **diagrams** — sequence, component, and data flow — so your understanding is checkable and shareable +- **Trace a transaction** across multiple services in a distributed system, from entry point to response +- **Communicate** your understanding through documentation (READMEs, Architectural Decision Records) and presentations + +You'll practice these skills on two applications of increasing complexity: a small 3-component task list app you can read end-to-end in a few minutes, and the [OpenTelemetry Demo Application](https://github.com/open-telemetry/opentelemetry-demo) — a realistic ~15-service e-commerce system that mirrors what you'll encounter in production. The understanding you build of the OTel Demo here is the foundation for the debugging (11.7) and production development (11.8) exercises later in this chapter, so take the OTel Demo exercises seriously — you'll be back in this codebase. + +### Learning Objectives + +By the end of this section, you should be able to: + +1. Explain the difference between sequence, component, and data flow diagrams, and choose the right one for a given question +2. Produce accurate diagrams of a system by reading its code, not just guessing from its UI +3. Trace a single request/transaction through multiple services, identifying every hop, API call, and data transformation +4. Write an Architectural Decision Record (ADR) that captures the *why* behind a design choice, not just the *what* +5. Document a system's architecture in a README that a new teammate could actually use +6. Deliver a clear, time-boxed technical walkthrough of a system you've analyzed + +### Prerequisites + +This section assumes you've completed [11.1 - Layers](11.1-layers.md) and [11.2 - Design Patterns](11.2-design-patterns.md), and that you're comfortable with: + +- Docker and `docker compose` (used throughout this chapter) +- Making HTTP requests with `curl` and reading JSON responses +- Basic REST API concepts (methods, endpoints, status codes) + +If any of these feel shaky, it's worth a quick refresher before continuing — the exercises below assume you can run containers and poke at HTTP APIs without hand-holding. + +## Understanding System Diagrams + +A diagram is a claim about how a system behaves, expressed visually instead of in prose. Different diagram types answer different questions — using the wrong one for the question you're actually asking wastes everyone's time. This section covers three diagram types you'll use throughout the chapter. + +
+ +### Sequence Diagrams + +**Question answered:** *In what order do things happen, and who talks to whom?* + +Sequence diagrams show a **specific interaction over time**: an actor or component sends a message, another component responds, and so on, top to bottom. They're the right tool when you're tracing a single transaction (like "what happens when a user clicks 'Add to Cart'") and need to capture ordering, request/response pairs, and timing. + +
+ +### Component Diagrams + +**Question answered:** *What are the pieces, and how are they wired together?* + +Component diagrams show the **static structure** of a system: services, their responsibilities, and the dependencies between them — but not the order operations happen in. They're the right tool for a "birds-eye view" you'd show someone on their first day, or when deciding what to touch for a given change. + +
+ +### Data Flow Diagrams + +**Question answered:** *How does information change shape as it moves through the system?* + +Data flow diagrams track a piece of data (a form submission, an event) as it's **transformed** at each step — form data becomes a JSON payload, becomes a SQL row, becomes a response body, becomes rendered HTML. They're the right tool when you're debugging "the data is wrong by the time it gets here" problems, or documenting a data pipeline. + +
+ +The three diagrams below all describe the *same* simple application (introduced in [Exercise 1](#exercise-1-simple-application-analysis)) — notice how each one answers a different question about the identical system. + +![Sequence diagram showing a user adding a task through the frontend, which calls the backend API, which writes to and reads from SQLite](./img11/simple-system-sequence.png ':class=img-center :alt=Sequence diagram for adding a task in the simple task list system :width=700') + +![Component diagram showing the frontend, backend API, and SQLite database as three boxes with HTTP and SQL connections between them](./img11/simple-system-component.png ':class=img-center :alt=Component diagram for the simple task list system :width=700') + +![Data flow diagram showing user input transformed step by step into form data, a JSON API request, a database row, a JSON API response, and finally rendered HTML](./img11/simple-system-dataflow.png ':class=img-center :alt=Data flow diagram for adding a task in the simple task list system :width=700') + +### Reading Diagrams Critically + +A diagram is only as good as the analysis behind it. When you look at (or draw) one, ask: + +- **Is every arrow backed by something you actually verified in the code?** A diagram based on guessing from the UI is fiction. +- **Does it show the right level of detail for its audience?** A component diagram cluttered with every internal function is really a sequence diagram in disguise. +- **What's missing?** Diagrams tend to show the happy path. Where do errors, retries, or timeouts happen, and should this diagram show them? + +## Diagramming Tools + +You don't need a specific tool to succeed in this chapter — you need a diagram that's accurate and easy to update. Two broad categories exist: + +### Code-Based Diagramming (Recommended) + +You write plain text describing the diagram, and a tool renders it as an image. This repository's examples all use this approach. + +- **[PlantUML](https://plantuml.com/)** — mature, supports sequence/component/data-flow-style diagrams well, renders via a local install, Docker, or the [online server](https://www.plantuml.com/plantuml/uml/). All example diagrams in this chapter are PlantUML `.puml` source files — open any file in `examples/ch11/*/diagrams/` to see the syntax. +- **[Mermaid](https://mermaid.js.org/)** — lighter-weight syntax, renders natively in GitHub markdown and many editors (including VS Code with an extension), good default if you want diagrams to preview inline as you write docs. + +**Pros:** diagrams are version-controlled text (diffable, reviewable in a PR), fast to update, no separate account or file format needed. +**Pros:** trivial to regenerate when the system changes — no re-dragging boxes. +**Cons:** initial syntax learning curve; layout is automatic and sometimes needs nudging for complex diagrams. + +### Visual Diagramming Tools + +You drag, drop, and connect shapes in a GUI. + +- **[draw.io / diagrams.net](https://app.diagrams.net/)** — free, no account required, exports to PNG/SVG, has UML shape libraries. +- **[Lucidchart](https://www.lucidchart.com/)** — polished collaborative editor, free tier is limited but workable for solo exercises. + +**Pros:** lower barrier to entry, precise manual control over layout, easier for quick freehand sketches. +**Cons:** harder to keep in sync with a changing codebase, diagrams are binary/proprietary files that don't diff well in git, more effort to redo after a refactor. + +### Which Should You Use? + +Either is fine for this chapter — pick whichever gets you to an accurate diagram fastest. If you're not sure, **start with Mermaid or PlantUML**: text-based diagrams are easier to keep accurate as you revise your understanding, which you will, repeatedly, while tracing the OTel Demo in Exercise 2. All rendered examples in this chapter were produced with PlantUML; source files are included so you can see exactly how each diagram was built. + +## Exercise 1: Simple Application Analysis + +**Goal:** Produce all three diagram types for a small application by reading its code — not by guessing from the UI. + +**Time estimate:** 90 minutes + +### Setup + +The target application lives in [`examples/ch11/simple-system/`](/examples/ch11/simple-system/) — a task list app with a Flask frontend, a Flask backend API, and a SQLite database. Its own README explains what it does; read that first. + +```bash +cd examples/ch11/simple-system +docker compose up --build +``` + +Once both services report healthy, open , add a few tasks, and toggle one done. Poke at the backend directly too: + +```bash +curl http://localhost:5001/tasks +curl -X POST http://localhost:5001/tasks -H "Content-Type: application/json" -d '{"title": "Trace this request"}' +``` + +### Task + +1. **Read the code** — `frontend/app.py`, `backend/app.py`, and the templates. Don't just skim; trace what happens when you submit the "add task" form, from the browser to SQLite and back. +2. **Create a sequence diagram** for "add a task" showing every hop: browser → frontend → backend → database → backend → frontend → browser. +3. **Create a component diagram** showing the three components, their responsibilities, and the protocol used between each pair (HTTP, SQL). +4. **Create a data flow diagram** for "add a task" showing how the data's *shape* changes at each step (form data → JSON → SQL row → JSON → HTML). +5. **Document the architecture** in a README using the [architecture README template](/examples/ch11/templates/architecture-readme-template.md). + +Use whichever tool you chose above. When you're done, compare your diagrams against the example diagrams shown earlier in this section (source: `examples/ch11/simple-system/diagrams/`) — not to copy them, but to check you didn't miss a hop or a component. + +### Self-Check + +- Does your sequence diagram show *every* service-to-service hop, including the "fetch updated list" call after a write? +- Does your component diagram label the protocol on each connection (not just draw a line)? +- Does your data flow diagram show the data's *shape* changing, not just its value? + +Tear the application down when you're finished: `docker compose down -v`. diff --git a/docs/11-application-development/img11/simple-system-component.png b/docs/11-application-development/img11/simple-system-component.png new file mode 100644 index 0000000000000000000000000000000000000000..f72f95a1ef09d4905e4a4e1f5e184e959c8f4e97 GIT binary patch literal 20586 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 literal 0 HcmV?d00001 diff --git a/docs/11-application-development/img11/simple-system-dataflow.png b/docs/11-application-development/img11/simple-system-dataflow.png new file mode 100644 index 0000000000000000000000000000000000000000..f3f610fb10da3e5c5e21c32f1b0189b16f9cc830 GIT binary patch literal 27022 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 literal 0 HcmV?d00001 diff --git a/docs/11-application-development/img11/simple-system-sequence.png b/docs/11-application-development/img11/simple-system-sequence.png new file mode 100644 index 0000000000000000000000000000000000000000..aa25278ce007cc15ba29828a445a7f6311ed3fc5 GIT binary patch literal 23745 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 Frontend (Flask) --> Backend API (Flask) --> SQLite +``` + +> **Note:** The frontend container listens on port 5000 internally (matching the diagrams below), but is published to host port **8080**. On macOS, port 5000 is often already bound by the built-in AirPlay Receiver (ControlCenter), which silently returns `403 Forbidden` instead of a connection error — see [Troubleshooting](#troubleshooting). + +The frontend never talks to the database directly — it only knows about the backend's HTTP API. This separation is what you'll be diagramming in Exercise 1. + +## Running It + +Requires Docker and Docker Compose. + +```bash +cd examples/ch11/simple-system +docker compose up --build +``` + +Once both services report healthy, open in a browser, or exercise the API directly: + +```bash +# View the UI +open http://localhost:8080 + +# Talk to the backend API directly +curl http://localhost:5001/tasks +curl -X POST http://localhost:5001/tasks -H "Content-Type: application/json" -d '{"title": "Learn system thinking"}' +curl -X POST http://localhost:5001/tasks/1/toggle +``` + +Stop and clean up: + +```bash +docker compose down -v +``` + +## Troubleshooting + +**`curl http://localhost:5000` returns `403 Forbidden` with `Server: AirTunes`**: macOS's built-in AirPlay Receiver (System Settings → General → AirDrop & Handoff) listens on port 5000 by default and will silently intercept the request before Docker ever sees it. This is why the frontend is published on host port **8080** instead of 5000 — use `http://localhost:8080`, or disable AirPlay Receiver if you'd rather free up port 5000. + +## Backend API Reference + +| Method | Path | Description | +|---|---|---| +| GET | `/health` | Liveness check | +| GET | `/tasks` | List all tasks | +| POST | `/tasks` | Create a task (`{"title": "..."}`) | +| POST | `/tasks//toggle` | Flip a task's done state | + +## Diagrams + +PlantUML source for this system's sequence, component, and data flow diagrams lives in [`diagrams/`](diagrams/). Rendered PNGs are embedded in the chapter content at `docs/11-application-development/img11/simple-system-*.png`. diff --git a/examples/ch11/simple-system/backend/Dockerfile b/examples/ch11/simple-system/backend/Dockerfile new file mode 100644 index 00000000..928128d9 --- /dev/null +++ b/examples/ch11/simple-system/backend/Dockerfile @@ -0,0 +1,7 @@ +FROM python:3.11-slim +WORKDIR /app +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt +COPY app.py . +EXPOSE 5001 +CMD ["python3", "app.py"] diff --git a/examples/ch11/simple-system/backend/app.py b/examples/ch11/simple-system/backend/app.py new file mode 100644 index 00000000..a16cec3b --- /dev/null +++ b/examples/ch11/simple-system/backend/app.py @@ -0,0 +1,87 @@ +"""Backend API service for the simple task list system. + +Provides a REST API backed by SQLite. This is the "business logic and +data access" layer that the frontend service calls over HTTP. +""" +import os +import sqlite3 +from pathlib import Path + +from flask import Flask, g, jsonify, request + +app = Flask(__name__) + +DB_PATH = os.environ.get("DB_PATH", str(Path(__file__).parent / "tasks.db")) + + +def get_db(): + if "db" not in g: + g.db = sqlite3.connect(DB_PATH) + g.db.row_factory = sqlite3.Row + return g.db + + +@app.teardown_appcontext +def close_db(_exception=None): + db = g.pop("db", None) + if db is not None: + db.close() + + +def init_db(): + db = sqlite3.connect(DB_PATH) + db.execute( + """ + CREATE TABLE IF NOT EXISTS tasks ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + title TEXT NOT NULL, + done INTEGER NOT NULL DEFAULT 0 + ) + """ + ) + db.commit() + db.close() + + +@app.get("/health") +def health(): + return jsonify({"status": "ok"}) + + +@app.get("/tasks") +def list_tasks(): + db = get_db() + rows = db.execute("SELECT id, title, done FROM tasks ORDER BY id").fetchall() + tasks = [{"id": r["id"], "title": r["title"], "done": bool(r["done"])} for r in rows] + return jsonify(tasks) + + +@app.post("/tasks") +def create_task(): + data = request.get_json(silent=True) or {} + title = (data.get("title") or "").strip() + if not title: + return jsonify({"error": "title is required"}), 400 + + db = get_db() + cursor = db.execute("INSERT INTO tasks (title, done) VALUES (?, 0)", (title,)) + db.commit() + return jsonify({"id": cursor.lastrowid, "title": title, "done": False}), 201 + + +@app.post("/tasks//toggle") +def toggle_task(task_id): + db = get_db() + row = db.execute("SELECT id, done FROM tasks WHERE id = ?", (task_id,)).fetchone() + if row is None: + return jsonify({"error": "task not found"}), 404 + + new_done = 0 if row["done"] else 1 + db.execute("UPDATE tasks SET done = ? WHERE id = ?", (new_done, task_id)) + db.commit() + return jsonify({"id": task_id, "done": bool(new_done)}) + + +if __name__ == "__main__": + init_db() + app.run(host="0.0.0.0", port=5001) diff --git a/examples/ch11/simple-system/backend/pyproject.toml b/examples/ch11/simple-system/backend/pyproject.toml new file mode 100644 index 00000000..c3e72c7b --- /dev/null +++ b/examples/ch11/simple-system/backend/pyproject.toml @@ -0,0 +1,9 @@ +[project] +name = "simple-system-backend" +version = "0.1.0" +description = "Backend API for the simple task list system (Chapter 11.3 example)" +readme = "README.md" +requires-python = ">=3.11" +dependencies = [ + "Flask>=3.0,<4.0", +] diff --git a/examples/ch11/simple-system/backend/requirements.txt b/examples/ch11/simple-system/backend/requirements.txt new file mode 100644 index 00000000..840d434b --- /dev/null +++ b/examples/ch11/simple-system/backend/requirements.txt @@ -0,0 +1 @@ +Flask>=3.0,<4.0 diff --git a/examples/ch11/simple-system/diagrams/component.puml b/examples/ch11/simple-system/diagrams/component.puml new file mode 100644 index 00000000..fc2341e7 --- /dev/null +++ b/examples/ch11/simple-system/diagrams/component.puml @@ -0,0 +1,37 @@ +@startuml simple-system-component +title Simple System - Component Diagram + +skinparam componentStyle rectangle + +actor "User\n(Browser)" as User + +package "simple-system" { + [Frontend\n(Flask, :5000)] as Frontend + [Backend API\n(Flask, :5001)] as Backend + database "SQLite\n(tasks.db)" as DB +} + +User --> Frontend : HTTP\n(HTML forms) +Frontend --> Backend : HTTP/JSON\n(REST API) +Backend --> DB : SQL + +note right of Frontend + Responsibility: presentation + Owns no data. Renders HTML, + translates form submissions + into backend API calls. +end note + +note right of Backend + Responsibility: business logic + + data access. Sole owner of + the database. Exposes a + REST API (GET/POST /tasks). +end note + +note right of DB + Responsibility: persistence. + Single table: tasks(id, title, done) +end note + +@enduml diff --git a/examples/ch11/simple-system/diagrams/dataflow.puml b/examples/ch11/simple-system/diagrams/dataflow.puml new file mode 100644 index 00000000..47c744f5 --- /dev/null +++ b/examples/ch11/simple-system/diagrams/dataflow.puml @@ -0,0 +1,25 @@ +@startuml simple-system-dataflow +title Simple System - Data Flow Diagram ("Add Task") + +skinparam defaultTextAlignment center + +rectangle "User Input\n(text typed into form field)" as Input +rectangle "Form Data\n(application/x-www-form-urlencoded\ntitle=\"Buy milk\")" as FormData +rectangle "API Request\n(JSON body\n{\"title\": \"Buy milk\"})" as ApiRequest +database "Database Row\n(id, title, done=0)" as DbRow +rectangle "API Response\n(JSON\n{\"id\":4,\"title\":\"Buy milk\",\"done\":false})" as ApiResponse +rectangle "Rendered HTML\n(updated