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..ff86038e --- /dev/null +++ b/docs/11-application-development/11.3-system-thinking.md @@ -0,0 +1,413 @@ +--- +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 ~25-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`. + +## Transaction Tracing Methodology + +The simple-system app has three components and one interesting request. Real systems have dozens of services and hundreds of endpoints — you can't diagram all of it, and you shouldn't try. Instead, you trace **one transaction at a time**: pick a single user-facing action and follow it, hop by hop, until you've accounted for everything it touches. + +Use this systematic approach rather than randomly clicking through code: + +1. **Identify the entry point.** What's the first thing that receives the request — a browser action, an API call, a button click? Find the exact route/endpoint and HTTP method. +2. **Follow the calls.** From the entry point, find the first outbound call to another service. Is it HTTP (REST) or gRPC? Synchronous (caller waits) or async (message queue, event)? Repeat for each subsequent hop. +3. **Examine request/response payloads.** What does the request body actually contain? What comes back? This is usually more revealing than reading function signatures — the data tells you what the service actually needs and produces. +4. **Identify data transformations.** Does the data change shape or content at each hop? A cart item might be JSON at the edge, protobuf over gRPC internally, and a Redis hash at rest — each transformation is worth noting. +5. **Map service dependencies.** As you go, keep a running list of every service touched and what it depended on. This becomes your component diagram. +6. **Document findings** as you go, not after — use the [transaction tracing template](/examples/ch11/templates/transaction-tracing-template.md) to capture entry point, services involved, request flow, data transformations, and potential failure points while they're fresh. + +**Practical tools for tracing:** + +- **Code search** (`grep`/`ripgrep`) to find where an endpoint is defined, or where a service calls another service's client +- **`docker compose logs -f `** to watch a service's logs while you trigger the transaction, confirming which services actually get called (and in what order) rather than guessing from the code alone +- **Service READMEs** — most well-maintained microservice repos document each service's responsibilities and dependencies +- **Distributed tracing UIs** (like Jaeger, included in the OTel Demo) — if the system is instrumented, a trace waterfall shows you the real call graph and timing, no guesswork required + +## Worked Example: Tracing "Add to Cart" in OTel Demo + +This is a complete worked trace through the [OpenTelemetry Demo Application](https://github.com/open-telemetry/opentelemetry-demo) (setup instructions in [Exercise 2](#exercise-2-transaction-tracing-in-otel-demo) below), following the methodology above. Read it closely — Exercise 2 asks you to do the same thing for a different transaction. + +### Entry Point + +A shopper on the product page clicks **Add to Cart**. In the browser, this fires a request to the frontend's own API route: + +```text +POST /api/cart +Body: { productId: "OLJCESPC7Z", quantity: { units: 1 } } +``` + +### Following the Calls + +1. **Browser → Frontend Proxy (Envoy).** All external traffic enters through the frontend proxy, which routes `/api/*` to the frontend service. +2. **Frontend Proxy → Frontend (Next.js).** The frontend's `/api/cart` route handler receives the request. It doesn't touch a database itself — it's a thin layer that translates the browser's JSON request into a gRPC call. +3. **Frontend → Cart Service (gRPC `AddItem`).** The frontend calls the cart service's gRPC `AddItem` RPC, passing a `userId` (from a session cookie) and the `CartItem` (product ID + quantity). +4. **Cart Service → Valkey/Redis (cache write).** The cart service looks up the user's existing cart in its Redis-compatible store, merges in the new item, and writes the updated cart back as the value for that user's key. +5. **Cart Service → Frontend.** The cart service returns success (empty response) over gRPC. +6. **Frontend → Browser.** The frontend's API route resolves the browser's `fetch()` call; the UI updates to show the new cart count. + +### Data Transformations + +| Step | Shape | +|---|---| +| Browser form/click | In-memory JS object `{ productId, quantity }` | +| Browser → Frontend | JSON over HTTP (`POST /api/cart`) | +| Frontend → Cart Service | Protobuf-encoded gRPC message (`AddItemRequest`) | +| Cart Service → Valkey | Serialized cart object written under a `userId` key | +| Cart Service → Frontend | Empty protobuf gRPC response (success/failure only) | + +### Potential Failure Points + +- **Cart Service unreachable:** the frontend's gRPC call times out; the "add to cart" click fails and the UI should show an error (worth checking whether it does). +- **Valkey unreachable:** the cart service can accept the gRPC call but fail to persist it — a failure mode that's invisible to the frontend unless the cart service propagates the error correctly. +- **No session/user ID:** if the browser has no cart session cookie yet, the frontend must create one before the first `AddItem` call succeeds. + +This trace only touched 3-4 services. **Checkout** (used in Exercise 2) touches many more — cart, product catalog, currency, shipping, payment, email, and an async fraud-detection/accounting path over Kafka — which is exactly why it's a good exercise for practicing the methodology on a bigger transaction. + +![Sequence diagram tracing the "Add to Cart" transaction through the frontend proxy, frontend, cart service, and cart datastore in the OpenTelemetry Demo Application](./img11/otel-transaction-trace.png ':class=img-center :alt=Sequence diagram for the Add to Cart transaction in the OTel Demo :width=750') + +## Exercise 2: Transaction Tracing in OTel Demo + +**Goal:** Trace a transaction through 3-5 real microservices, using the methodology above, and document what you find. + +**Time estimate:** 120 minutes + +### Setup + +Follow the [OTel Demo setup guide](/examples/ch11/otel-demo-setup/README.md) to get the application running locally. Confirm the frontend loads and you can browse products before continuing. + +### Task + +**Starting point:** Trace the **checkout flow**, starting from clicking "Place Order" on the checkout page. + +1. **Find the entry point.** What request does the browser send when you click "Place Order"? (Hint: use your browser's network tab, or `docker compose logs -f frontend` while you click it.) +2. **Follow the calls, service by service.** The checkout service orchestrates several downstream calls — find them by reading the checkout service's code, and confirm what you find against the logs of each service you suspect is involved (`docker compose logs -f `). +3. **Identify at least one asynchronous hop.** Not everything in checkout is synchronous request/response — look for where an event gets published (hint: Kafka) and which service(s) consume it afterward. +4. **Create a sequence diagram** showing the complete transaction across every service you identified — model it on the worked example above. +5. **Document your findings** using the [transaction tracing template](/examples/ch11/templates/transaction-tracing-template.md): entry point, services involved, request flow, data transformations, and potential failure points. + +### Exploration Guidance + +If you're not sure where to start reading: + +- **`grep`/`ripgrep` for the entry point.** Search for the checkout endpoint/route name across the repo to find the frontend handler, then search for the client call it makes. +- **Check each service's README.** Most services in the OTel Demo have their own README describing their responsibilities and the RPCs/endpoints they expose. +- **Watch logs while you act.** Run `docker compose logs -f ` for a handful of suspected services in separate terminals, then click "Place Order" and see which ones light up, in what order. +- **Follow code from the top down.** Start at the checkout service's handler for "place order," and read downward: what clients does it construct, what does it call first, second, third? + +Don't just list every service in the OTel Demo — only include the ones you can actually confirm (via code or logs) are part of *this* transaction. + +## Architectural Decision Records (ADRs) + +An **Architectural Decision Record (ADR)** is a short document that captures one significant decision about a system's structure: what was decided, why, and what trade-offs came with it. ADRs exist because the *code* tells you what a system does, but not *why* it was built that way — and six months later, "why" is exactly what the next engineer needs and can no longer ask the person who decided it. + +**Why they matter:** + +- **Historical record.** Decisions made under real constraints (deadlines, team size, what libraries existed at the time) look bizarre in hindsight without that context. An ADR preserves it. +- **Knowledge transfer.** New team members can read a handful of ADRs and understand the reasoning behind a system faster than they could reconstruct it from code archaeology. +- **Decision rationale.** When someone proposes "let's just rewrite this," an ADR lets you check whether the original trade-offs still hold, instead of re-litigating from scratch. + +**When to write one:** for decisions that affect structure, not implementation details. "We chose gRPC over REST for internal service calls" is ADR-worthy. "We renamed a variable" is not. A reasonable test: if reversing this decision would require significant rework, it probably deserved an ADR when it was made. + +### ADR Structure + +- **Title** — a short, descriptive name for the decision (not "ADR 7", but "Use gRPC for Internal Service Communication") +- **Status** — proposed / accepted / deprecated / superseded +- **Context** — what situation required a decision? What constraints or forces were in play? +- **Decision** — what was decided, stated plainly +- **Consequences** — what are the resulting positive *and* negative outcomes? (a decision with no downsides usually means the analysis was incomplete) +- **Alternatives Considered** *(optional)* — what else was considered, and why wasn't it chosen? +- **References** *(optional)* — links to related ADRs, docs, or discussions + +Use the [ADR template](/examples/ch11/templates/adr-template.md) to write your own. Three worked examples analyzing real architectural decisions in the OTel Demo are provided as a model for the depth and structure expected: + +- [Why use gRPC between certain services?](/examples/ch11/templates/adr-example-grpc.md) +- [Why is the frontend server-side rendered?](/examples/ch11/templates/adr-example-frontend-ssr.md) +- [Why use multiple databases?](/examples/ch11/templates/adr-example-multiple-databases.md) + +## Documenting Architecture in README Files + +A component/sequence/data-flow diagram shows structure; a README ties that structure to *why* it exists and *how to work with it*. Good architecture documentation is: + +- **Clear** — written for someone who's never seen the system, not for the author's own memory +- **Concise** — a README that takes 20 minutes to read gets skipped; a scannable one gets used +- **Up-to-date** — stale documentation actively misleads, which is worse than no documentation at all +- **Audience-appropriate** — a README for engineers who'll modify the system needs more technical depth than one for a stakeholder who just wants the big picture + +Common sections worth including: system overview, architecture (components + diagram), communication patterns, data storage, technology stack, and key architectural decisions (linking out to ADRs rather than re-explaining them inline). Use the [README enhancement checklist](/examples/ch11/templates/readme-enhancement-checklist.md) as a concrete guide for what to include, and the [architecture README template](/examples/ch11/templates/architecture-readme-template.md) from Exercise 1 as your starting structure. + +## Presenting Technical Architecture + +Being able to explain a system out loud is a distinct skill from being able to diagram it — and it's one you'll use constantly: onboarding a new teammate, walking a reviewer through a design, or defending a decision in a design review. Diagrams and READMEs are read at the reader's own pace; a presentation has to build understanding in real time, which means structure matters even more. + +**Effective structure:** start with the overview (what and why), zoom into details (how), show your diagrams as you go rather than as an afterthought, and end by explicitly naming the trade-offs you made or observed. + +**Best practices:** + +- **Know your audience** — adjust depth for engineers vs. non-technical stakeholders +- **Tell a story** — "here's what happens when a user does X" is more engaging than a service-by-service inventory +- **Use visuals actively** — point at and narrate your diagrams rather than just displaying them +- **Practice** — run through it once against a clock before presenting live or recording, so you know your actual pacing + +Use the [presentation outline](/examples/ch11/templates/presentation-outline.md) as a starting structure, and the [presentation rubric](/examples/ch11/templates/presentation-rubric.md) to self-assess before you present or submit a recording. + +## Exercise 3: Architecture Documentation & Presentation + +**Goal:** Practice writing ADRs, documenting architecture, and communicating your understanding through a presentation. + +**Time estimate:** 150 minutes + +### Task + +1. **Write 2-3 ADRs** analyzing architectural decisions in the OTel Demo, using the [ADR template](/examples/ch11/templates/adr-template.md). Pick decisions you can actually investigate in the code — some starting prompts: + - Why use gRPC (or a message queue) between certain services, instead of plain REST? + - Why is the frontend built the way it is (SSR, a specific framework)? + - Why does the system use more than one kind of datastore? + - Why is there a separate service for a capability that could have lived inside an existing service (e.g. recommendations, fraud detection)? + + Read the three worked ADR examples linked above first — they show the expected depth. Don't just describe *what* the code does; explain the trade-offs a reasonable engineer would have weighed. + +2. **Create or enhance a README** documenting the OTel Demo's architecture, using the [README enhancement checklist](/examples/ch11/templates/readme-enhancement-checklist.md). Include at minimum: system overview, service responsibilities, communication patterns, data storage, and key architectural decisions (linking your ADRs from step 1). + +3. **Prepare and deliver (or record) a 10-15 minute walkthrough presentation** explaining the OTel Demo's architecture. Required content: + - System overview with your component diagram + - A transaction walkthrough with your sequence diagram (reuse your Exercise 2 trace, or create a new one) + - At least one architectural trade-off, referencing one of your ADRs + +4. **Self-assess** using the [presentation rubric](/examples/ch11/templates/presentation-rubric.md) before submitting or presenting live. + +> **Recording note:** if you record your walkthrough, check your screen for anything you wouldn't want shared — file paths containing your username, API keys in environment variables, browser tabs with unrelated personal information — before you save or submit it. Confirm with your instructor whether recordings are shared publicly, with the cohort, or kept private. + +## Exercise 4: Integration Exercise + +**Goal:** Synthesize everything from this chapter — diagramming, transaction tracing, ADRs, README documentation, and presenting — into a single, complete analysis of one OTel Demo feature you haven't already covered in Exercises 1-3. + +**Time estimate:** 180 minutes + +This is the capstone exercise for Chapter 11.3. Where Exercises 1-3 practiced each skill in isolation (diagramming a simple app, tracing one transaction, writing ADRs), this exercise asks you to apply all of them together to a feature of your choosing, the way you would when picking up an unfamiliar area of a real codebase. + +### Task + +1. **Pick a feature or workflow** in the OTel Demo that isn't the "Add to Cart" flow from the worked example or "Checkout" from Exercise 2. Some options: + - **Product recommendation flow** — the "you might also like" section on a product page + - **Payment processing** — what happens after checkout submits payment details + - **Email notification** — how an order confirmation email gets sent after checkout + - **Currency conversion** — how prices are converted when a shopper changes currency + - **Ad serving** — how contextual ads are selected and displayed on product pages + + An example analysis of the recommendation flow is provided in [`examples/ch11/integration-example/`](/examples/ch11/integration-example/) — read it as a model for depth and structure, but analyze a *different* feature yourself rather than reproducing it. + +2. **Perform a complete analysis**, producing all of the following deliverables: + - **Component diagram** showing every service involved in your chosen feature and its dependencies (see the [example](/examples/ch11/integration-example/diagrams/component.puml)) + - **Sequence diagram** showing the complete transaction flow, hop by hop, using the [transaction tracing methodology](#transaction-tracing-methodology) from Exercise 2 + - **Data flow diagram** showing how information changes shape as it moves through the services involved + - **README section** documenting the feature, following the [README enhancement checklist](/examples/ch11/templates/readme-enhancement-checklist.md) + - **One ADR** analyzing a genuine architectural decision related to your feature (see the [example ADR](/examples/ch11/integration-example/adr-example.md)) + - **A 10-15 minute presentation** (recorded or live) walking through your analysis, using the [presentation outline](/examples/ch11/templates/presentation-outline.md) as your structure + +3. **Self-assess** your complete submission against the [integration self-assessment checklist](/examples/ch11/templates/integration-self-assessment.md) before submitting. + +## Optional Advanced Extensions + +If you finish Exercise 4 with time to spare, these extensions go deeper into system-level thinking: + +- **Analyze failure scenarios and recovery.** Pick one service involved in your chosen feature and ask: what happens if it goes down mid-transaction? Does the caller retry, time out, or fail the whole request? Is there a fallback (cached data, a default response) or does the failure surface all the way to the shopper? Document what you find — and, if it isn't obvious from the code, what you'd expect to happen based on the communication pattern (sync HTTP/gRPC vs. async via Kafka). +- **Compare architectural approaches.** The OTel Demo is a microservices architecture with a mix of synchronous (gRPC) and asynchronous (Kafka) communication. Pick one service boundary and argue how it would look different as part of a monolith, or if a synchronous call were made asynchronous (or vice versa). What would you gain? What would you lose? +- **Propose an architectural improvement.** Identify one thing about your chosen feature's design you'd change, and write it up like an ADR: what's the current state, what would you change, why, and what trade-offs would that introduce? You don't need to implement it — the goal is practicing the reasoning. +- **Implement a simplified version.** Pick one service from your feature and reimplement a bare-bones version of its core logic (not production quality — just enough to demonstrate you understand what it actually does) in a language of your choice. + +## Summary and Next Steps + +This chapter built system-level thinking: the ability to look at a codebase spanning multiple services and languages and form an accurate mental model of how it works, without reading every line. You practiced: + +- **Diagramming** — sequence, component, and data flow diagrams, each answering a different question about a system +- **Transaction tracing** — a systematic method for following one request through a multi-service architecture, rather than guessing +- **Technical writing** — ADRs that capture *why* a decision was made, and README documentation that orients someone new to the codebase +- **Technical communication** — presenting an architecture clearly, with diagrams as the backbone of the narrative + +These are the skills you'll lean on directly in the chapters ahead: **11.7 (Debugging & Observability)** builds on transaction tracing to debug real failures using the same OTel Demo application, using traces, metrics, and logs instead of just reading code; **11.8 (Production Development)** assumes you can orient yourself in an unfamiliar service quickly enough to ship a change confidently. The mental models and templates from this chapter — diagram types, the tracing methodology, ADRs, README structure — aren't chapter-specific tools; they're the habits that make picking up any new codebase faster the next time. diff --git a/docs/11-application-development/img11/integration-example-component.png b/docs/11-application-development/img11/integration-example-component.png new file mode 100644 index 00000000..05dae62f Binary files /dev/null and b/docs/11-application-development/img11/integration-example-component.png differ diff --git a/docs/11-application-development/img11/integration-example-dataflow.png b/docs/11-application-development/img11/integration-example-dataflow.png new file mode 100644 index 00000000..06b7a93e Binary files /dev/null and b/docs/11-application-development/img11/integration-example-dataflow.png differ diff --git a/docs/11-application-development/img11/integration-example-sequence.png b/docs/11-application-development/img11/integration-example-sequence.png new file mode 100644 index 00000000..37d6d283 Binary files /dev/null and b/docs/11-application-development/img11/integration-example-sequence.png differ diff --git a/docs/11-application-development/img11/otel-transaction-trace.png b/docs/11-application-development/img11/otel-transaction-trace.png new file mode 100644 index 00000000..c18e457e Binary files /dev/null and b/docs/11-application-development/img11/otel-transaction-trace.png differ 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 00000000..f72f95a1 Binary files /dev/null and b/docs/11-application-development/img11/simple-system-component.png differ 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 00000000..f3f610fb Binary files /dev/null and b/docs/11-application-development/img11/simple-system-dataflow.png differ 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 00000000..aa25278c Binary files /dev/null and b/docs/11-application-development/img11/simple-system-sequence.png differ diff --git a/docs/README.md b/docs/README.md index 396f802c..ed48ee8a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -316,6 +316,45 @@ docs/11-application-development/11.2.2-data-layer-patterns.md: - SQLite - Design Patterns - AI Collaboration +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 docs/2-Github/2.2-Actions.md: category: CI/CD estReadingMinutes: 20 diff --git a/docs/_sidebar.md b/docs/_sidebar.md index a4872987..b89ad6bd 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -168,6 +168,7 @@ - [11.2 - Design Patterns](11-application-development/11.2-design-patterns.md) - [11.2.1 - SOLID Principles](11-application-development/11.2.1-solid-principles.md) - [11.2.2 - Data Layer Patterns](11-application-development/11.2.2-data-layer-patterns.md) +- [11.3 - System Thinking](11-application-development/11.3-system-thinking.md) - **Addendum** diff --git a/docs/specs/00-spec-chapter-11-appdev/00-spec-chapter-11-appdev.md b/docs/specs/00-spec-chapter-11-appdev/00-spec-chapter-11-appdev.md index 0473b2c0..dd2b1eb7 100644 --- a/docs/specs/00-spec-chapter-11-appdev/00-spec-chapter-11-appdev.md +++ b/docs/specs/00-spec-chapter-11-appdev/00-spec-chapter-11-appdev.md @@ -13,7 +13,7 @@ This parent spec coordinates seven child specifications that build the chapter s | Spec | Title | Status | Priority | |------|-------|--------|----------| | **01** | Design Patterns (11.2.2-11.2.5) | ✅ COMPLETE | P0 | -| **02** | System Thinking & Codebase Analysis (11.3) | ✅ COMPLETE | P1 | +| **02** | System Thinking & Codebase Analysis (11.3) | 🟡 CONTENT COMPLETE (OTel ARM validation pending) | P1 | | **03** | Databases & Data Persistence (11.4) | 📋 PLANNED | P1 | | **04** | REST API Design & OpenAPI (11.5) | 📋 PLANNED | P1 | | **05** | Authentication & Authorization (11.6) | 📋 PLANNED | P1 | @@ -118,12 +118,13 @@ By the end of Chapter 11, students should be able to: ### Phase 1: Foundation (Understanding Applications) -**Spec 02: System Thinking & Codebase Analysis (11.3)** 📋 PLANNED +**Spec 02: System Thinking & Codebase Analysis (11.3)** 🟡 CONTENT COMPLETE (OTel ARM validation pending) - Analyzing existing applications - Creating system diagrams (sequence, component, data flow) - Tracing transactions through services - Documentation and communication skills - Hands-on with realistic microservice architecture +- All content, templates, examples, and diagrams built and committed on `docs/11.3-system-thinking`; the OTel Demo setup guide's ARM (Apple Silicon) instructions are sourced from upstream docs but have not yet been exercised end-to-end on real ARM hardware in this environment **Why This Phase**: Students must learn to READ and UNDERSTAND code before effectively writing it. System thinking develops the mental models needed for production work. @@ -446,7 +447,7 @@ Students completing Chapter 11 should demonstrate: - ✅ Spec 01: Design Patterns (COMPLETE) **P1 (Foundation & Topics)**: -- 📋 Spec 02: System Thinking & Codebase Analysis +- 🟡 Spec 02: System Thinking & Codebase Analysis (content complete, OTel ARM validation pending) - 📋 Spec 03: Databases & Data Persistence - 📋 Spec 04: REST API Design & OpenAPI - 📋 Spec 05: Authentication & Authorization diff --git a/docs/specs/02-spec-system-thinking/02-tasks-system-thinking.md b/docs/specs/02-spec-system-thinking/02-tasks-system-thinking.md index c1c4bc81..7741a7aa 100644 --- a/docs/specs/02-spec-system-thinking/02-tasks-system-thinking.md +++ b/docs/specs/02-spec-system-thinking/02-tasks-system-thinking.md @@ -69,7 +69,7 @@ This task list breaks down the implementation of Chapter 11.3: System Thinking & ## Tasks -### [ ] 1.0 Create Introduction Section with Simple Application Example +### [x] 1.0 Create Introduction Section with Simple Application Example **Purpose:** Build the foundation by creating the main documentation page with system thinking concepts, and provide a simple 2-3 service example application that students can analyze to learn diagram types. @@ -83,30 +83,30 @@ This task list breaks down the implementation of Chapter 11.3: System Thinking & #### 1.0 Tasks -- [ ] 1.1 Create `docs/11-application-development/11.3-system-thinking.md` with front-matter (category: Software Development, estReadingMinutes: 30), H2 section "System Thinking & Codebase Analysis", introduction explaining the importance of understanding existing codebases, and learning objectives -- [ ] 1.2 Add H2 section "Understanding System Diagrams" to `11.3-system-thinking.md` explaining the three diagram types: sequence diagrams (request/response flows with time dimension), component diagrams (service boundaries and dependencies), and data flow diagrams (information movement through system) -- [ ] 1.3 Add H2 section "Diagramming Tools" to `11.3-system-thinking.md` introducing code-based tools (PlantUML, Mermaid) and visual tools (Draw.io, Lucidchart), with pros/cons of each approach and links to getting started guides -- [ ] 1.4 Create directory structure `examples/ch11/simple-system/` with subdirectories for `frontend/`, `backend/`, and `diagrams/` -- [ ] 1.5 Create `examples/ch11/simple-system/README.md` documenting what the application does (e.g., "Simple task list application with web UI, REST API, and SQLite database"), its architecture (3 components: frontend, backend, database), and how to run it with docker-compose -- [ ] 1.6 Create `examples/ch11/simple-system/frontend/app.py` with a simple Flask application serving HTML templates and making HTTP requests to the backend API (e.g., display task list, add new task) -- [ ] 1.7 Create `examples/ch11/simple-system/frontend/templates/index.html` with a simple UI showing the application functionality (form to add items, list display) -- [ ] 1.8 Create `examples/ch11/simple-system/frontend/requirements.txt` and `frontend/pyproject.toml` with Flask dependency and Python 3.11+ requirement -- [ ] 1.9 Create `examples/ch11/simple-system/backend/app.py` with a Flask REST API providing endpoints (e.g., GET /tasks, POST /tasks) and using SQLite for data persistence -- [ ] 1.10 Create `examples/ch11/simple-system/backend/requirements.txt` and `backend/pyproject.toml` with Flask dependency and Python 3.11+ requirement -- [ ] 1.11 Create `examples/ch11/simple-system/docker-compose.yml` orchestrating frontend and backend services with appropriate port mappings and health checks -- [ ] 1.12 Create `examples/ch11/simple-system/.gitignore` with common patterns (*.pyc, __pycache__, .venv/, *.db, .DS_Store) -- [ ] 1.13 Create `examples/ch11/simple-system/diagrams/sequence.puml` with PlantUML source showing a complete request flow (User → Frontend → Backend → Database → Backend → Frontend → User) -- [ ] 1.14 Create `examples/ch11/simple-system/diagrams/component.puml` with PlantUML source showing the three components (Frontend, Backend, Database) with their dependencies and interfaces -- [ ] 1.15 Create `examples/ch11/simple-system/diagrams/dataflow.puml` with PlantUML source showing how data flows through the system (user input → form data → API request → database write → query → API response → UI display) -- [ ] 1.16 Render all three PlantUML diagrams to PNG and save in `docs/11-application-development/img11/` as `simple-system-sequence.png`, `simple-system-component.png`, `simple-system-dataflow.png` -- [ ] 1.17 Add H2 section "Exercise 1: Simple Application Analysis" to `11.3-system-thinking.md` with instructions to run the simple-system application, examine its code, and create all three diagram types with reference to the example diagrams -- [ ] 1.18 Embed the three example diagram images in `11.3-system-thinking.md` using HTML img tags with proper alt text, showing students what quality diagrams look like -- [ ] 1.19 Create `examples/ch11/templates/architecture-readme-template.md` with sections: Overview (what does it do?), Architecture (components and their responsibilities), Communication Patterns (how components interact), Data Storage (what data is stored and where), Key Decisions (why was it built this way?) -- [ ] 1.20 Test that `docker-compose up` in `examples/ch11/simple-system/` successfully starts all services, and verify the application is accessible and functional (can add/view items) +- [x] 1.1 Create `docs/11-application-development/11.3-system-thinking.md` with front-matter (category: Software Development, estReadingMinutes: 30), H2 section "System Thinking & Codebase Analysis", introduction explaining the importance of understanding existing codebases, and learning objectives +- [x] 1.2 Add H2 section "Understanding System Diagrams" to `11.3-system-thinking.md` explaining the three diagram types: sequence diagrams (request/response flows with time dimension), component diagrams (service boundaries and dependencies), and data flow diagrams (information movement through system) +- [x] 1.3 Add H2 section "Diagramming Tools" to `11.3-system-thinking.md` introducing code-based tools (PlantUML, Mermaid) and visual tools (Draw.io, Lucidchart), with pros/cons of each approach and links to getting started guides +- [x] 1.4 Create directory structure `examples/ch11/simple-system/` with subdirectories for `frontend/`, `backend/`, and `diagrams/` +- [x] 1.5 Create `examples/ch11/simple-system/README.md` documenting what the application does (e.g., "Simple task list application with web UI, REST API, and SQLite database"), its architecture (3 components: frontend, backend, database), and how to run it with docker-compose +- [x] 1.6 Create `examples/ch11/simple-system/frontend/app.py` with a simple Flask application serving HTML templates and making HTTP requests to the backend API (e.g., display task list, add new task) +- [x] 1.7 Create `examples/ch11/simple-system/frontend/templates/index.html` with a simple UI showing the application functionality (form to add items, list display) +- [x] 1.8 Create `examples/ch11/simple-system/frontend/requirements.txt` and `frontend/pyproject.toml` with Flask dependency and Python 3.11+ requirement +- [x] 1.9 Create `examples/ch11/simple-system/backend/app.py` with a Flask REST API providing endpoints (e.g., GET /tasks, POST /tasks) and using SQLite for data persistence +- [x] 1.10 Create `examples/ch11/simple-system/backend/requirements.txt` and `backend/pyproject.toml` with Flask dependency and Python 3.11+ requirement +- [x] 1.11 Create `examples/ch11/simple-system/docker-compose.yml` orchestrating frontend and backend services with appropriate port mappings and health checks +- [x] 1.12 Create `examples/ch11/simple-system/.gitignore` with common patterns (*.pyc, __pycache__, .venv/, *.db, .DS_Store) +- [x] 1.13 Create `examples/ch11/simple-system/diagrams/sequence.puml` with PlantUML source showing a complete request flow (User → Frontend → Backend → Database → Backend → Frontend → User) +- [x] 1.14 Create `examples/ch11/simple-system/diagrams/component.puml` with PlantUML source showing the three components (Frontend, Backend, Database) with their dependencies and interfaces +- [x] 1.15 Create `examples/ch11/simple-system/diagrams/dataflow.puml` with PlantUML source showing how data flows through the system (user input → form data → API request → database write → query → API response → UI display) +- [x] 1.16 Render all three PlantUML diagrams to PNG and save in `docs/11-application-development/img11/` as `simple-system-sequence.png`, `simple-system-component.png`, `simple-system-dataflow.png` +- [x] 1.17 Add H2 section "Exercise 1: Simple Application Analysis" to `11.3-system-thinking.md` with instructions to run the simple-system application, examine its code, and create all three diagram types with reference to the example diagrams +- [x] 1.18 Embed the three example diagram images in `11.3-system-thinking.md` using HTML img tags with proper alt text, showing students what quality diagrams look like +- [x] 1.19 Create `examples/ch11/templates/architecture-readme-template.md` with sections: Overview (what does it do?), Architecture (components and their responsibilities), Communication Patterns (how components interact), Data Storage (what data is stored and where), Key Decisions (why was it built this way?) +- [x] 1.20 Test that `docker-compose up` in `examples/ch11/simple-system/` successfully starts all services, and verify the application is accessible and functional (can add/view items) --- -### [ ] 2.0 Create OTel Demo Integration Content and Transaction Tracing Materials +### [x] 2.0 Create OTel Demo Integration Content and Transaction Tracing Materials **Purpose:** Provide setup guidance and worked examples for analyzing the OpenTelemetry Demo Application, enabling students to trace multi-service transactions. @@ -120,23 +120,23 @@ This task list breaks down the implementation of Chapter 11.3: System Thinking & #### 2.0 Tasks -- [ ] 2.1 Create directory `examples/ch11/otel-demo-setup/` with subdirectory `diagrams/` -- [ ] 2.2 Create `examples/ch11/otel-demo-setup/README.md` with introduction to the OTel Demo Application (what it is, why we're using it), system requirements (Docker, RAM, CPU, disk), and links to official repository -- [ ] 2.3 Add setup instructions to `otel-demo-setup/README.md` covering: cloning the official OTel Demo repository, pinning to a specific stable release (research and specify version), running with docker-compose, and verifying all services are healthy -- [ ] 2.4 Add troubleshooting section to `otel-demo-setup/README.md` covering common issues: insufficient RAM (recommend 8GB+), port conflicts, ARM compatibility notes for M1/M2/M3 Macs, and container startup failures -- [ ] 2.5 Create optional `examples/ch11/otel-demo-setup/docker-compose-subset.yml` with a simplified configuration running only 4-5 core services to reduce system requirements (document which services and why in README) -- [ ] 2.6 Add H2 section "Transaction Tracing Methodology" to `docs/11-application-development/11.3-system-thinking.md` explaining the systematic approach: identify entry point, follow HTTP/gRPC calls, examine request/response payloads, identify data transformations, map service dependencies, and document findings -- [ ] 2.7 Add H2 section "Worked Example: Tracing 'Add to Cart' in OTel Demo" to `11.3-system-thinking.md` with step-by-step walkthrough of tracing a transaction through 3-5 services (e.g., Frontend → Cart Service → Product Catalog Service → Redis) -- [ ] 2.8 Create `examples/ch11/otel-demo-setup/diagrams/add-to-cart-trace.puml` with PlantUML source showing the complete sequence diagram for the worked example transaction -- [ ] 2.9 Render `add-to-cart-trace.puml` to PNG and save as `docs/11-application-development/img11/otel-transaction-trace.png` -- [ ] 2.10 Embed the worked example diagram in the "Worked Example" section of `11.3-system-thinking.md` using HTML img tag with alt text -- [ ] 2.11 Create `examples/ch11/templates/transaction-tracing-template.md` with structured sections: Transaction Name, Entry Point (URL/endpoint and HTTP method), Services Involved (list with brief role description), Request Flow (step-by-step with service → service arrows), Data Transformations (what data changes at each step), Potential Failure Points (where could this break?), and Notes -- [ ] 2.12 Add H2 section "Exercise 2: Transaction Tracing in OTel Demo" to `11.3-system-thinking.md` with progressive discovery exercise instructions: starting point (e.g., "Trace the checkout flow starting from the 'Place Order' button"), guidance on using code search and logs to discover the flow, and requirement to create a sequence diagram and document using the tracing template -- [ ] 2.13 Add guidance in the exercise section about how to explore the codebase: using grep/ripgrep to find API endpoints, examining service READMEs for architecture info, using docker logs to see service communication, and following code from controllers to service layers +- [x] 2.1 Create directory `examples/ch11/otel-demo-setup/` with subdirectory `diagrams/` +- [x] 2.2 Create `examples/ch11/otel-demo-setup/README.md` with introduction to the OTel Demo Application (what it is, why we're using it), system requirements (Docker, RAM, CPU, disk), and links to official repository +- [x] 2.3 Add setup instructions to `otel-demo-setup/README.md` covering: cloning the official OTel Demo repository, pinning to a specific stable release (research and specify version), running with docker-compose, and verifying all services are healthy +- [x] 2.4 Add troubleshooting section to `otel-demo-setup/README.md` covering common issues: insufficient RAM (recommend 8GB+), port conflicts, ARM compatibility notes for M1/M2/M3 Macs, and container startup failures +- [x] 2.5 Create optional `examples/ch11/otel-demo-setup/docker-compose-subset.yml` with a simplified configuration running only 4-5 core services to reduce system requirements (document which services and why in README) +- [x] 2.6 Add H2 section "Transaction Tracing Methodology" to `docs/11-application-development/11.3-system-thinking.md` explaining the systematic approach: identify entry point, follow HTTP/gRPC calls, examine request/response payloads, identify data transformations, map service dependencies, and document findings +- [x] 2.7 Add H2 section "Worked Example: Tracing 'Add to Cart' in OTel Demo" to `11.3-system-thinking.md` with step-by-step walkthrough of tracing a transaction through 3-5 services (e.g., Frontend → Cart Service → Product Catalog Service → Redis) +- [x] 2.8 Create `examples/ch11/otel-demo-setup/diagrams/add-to-cart-trace.puml` with PlantUML source showing the complete sequence diagram for the worked example transaction +- [x] 2.9 Render `add-to-cart-trace.puml` to PNG and save as `docs/11-application-development/img11/otel-transaction-trace.png` +- [x] 2.10 Embed the worked example diagram in the "Worked Example" section of `11.3-system-thinking.md` using HTML img tag with alt text +- [x] 2.11 Create `examples/ch11/templates/transaction-tracing-template.md` with structured sections: Transaction Name, Entry Point (URL/endpoint and HTTP method), Services Involved (list with brief role description), Request Flow (step-by-step with service → service arrows), Data Transformations (what data changes at each step), Potential Failure Points (where could this break?), and Notes +- [x] 2.12 Add H2 section "Exercise 2: Transaction Tracing in OTel Demo" to `11.3-system-thinking.md` with progressive discovery exercise instructions: starting point (e.g., "Trace the checkout flow starting from the 'Place Order' button"), guidance on using code search and logs to discover the flow, and requirement to create a sequence diagram and document using the tracing template +- [x] 2.13 Add guidance in the exercise section about how to explore the codebase: using grep/ripgrep to find API endpoints, examining service READMEs for architecture info, using docker logs to see service communication, and following code from controllers to service layers --- -### [ ] 3.0 Create Architecture Documentation and Communication Teaching Materials +### [x] 3.0 Create Architecture Documentation and Communication Teaching Materials **Purpose:** Develop content teaching ADRs, README documentation, and presentation skills, with templates and rubrics to guide student work. @@ -151,22 +151,22 @@ This task list breaks down the implementation of Chapter 11.3: System Thinking & #### 3.0 Tasks -- [ ] 3.1 Add H2 section "Architectural Decision Records (ADRs)" to `docs/11-application-development/11.3-system-thinking.md` explaining what ADRs are (documents capturing important architectural decisions), why they matter (historical record, knowledge transfer, decision rationale), and when to write them (significant decisions affecting structure, technology choices, design patterns) -- [ ] 3.2 Explain ADR structure in the ADR section: Title (short descriptive name), Status (proposed/accepted/deprecated), Context (what's the situation requiring a decision?), Decision (what did we decide?), Consequences (what are the positive and negative outcomes?), and optional sections (Alternatives Considered, References) -- [ ] 3.3 Create `examples/ch11/templates/adr-template.md` with the proper structure outlined in 3.2, including guidance comments for each section explaining what content to include -- [ ] 3.4 Create `examples/ch11/templates/adr-example-grpc.md` analyzing the decision "Why use gRPC between certain services in OTel Demo?" with realistic context (need for efficient inter-service communication), decision (use gRPC for internal service-to-service calls), and consequences (pros: type safety, performance; cons: complexity, debugging difficulty) -- [ ] 3.5 Create `examples/ch11/templates/adr-example-frontend-ssr.md` analyzing "Why is the frontend server-side rendered?" with context (need for good performance and SEO), decision (use server-side rendering with Next.js), and consequences -- [ ] 3.6 Create `examples/ch11/templates/adr-example-multiple-databases.md` analyzing "Why use multiple databases?" with context (different data access patterns for different services), decision (polyglot persistence approach), and consequences -- [ ] 3.7 Add H2 section "Documenting Architecture in README Files" to `11.3-system-thinking.md` explaining the purpose of architecture documentation, what makes good documentation (clear, concise, up-to-date, audience-appropriate), and common sections to include -- [ ] 3.8 Create `examples/ch11/templates/readme-enhancement-checklist.md` with checkboxes for: System Overview (1-2 paragraph description), Architecture Diagram (component or system diagram), Service Responsibilities (what does each service do?), Communication Patterns (how do services talk to each other?), Data Storage (databases, caches, message queues), Technology Stack (languages, frameworks, key libraries), Key Architectural Decisions (link to ADRs or brief explanations), Setup and Running (how to get it working locally) -- [ ] 3.9 Add H2 section "Presenting Technical Architecture" to `11.3-system-thinking.md` explaining why presentation skills matter (communicating with team, onboarding new members, design reviews), effective presentation structure (start with overview, zoom into details, show diagrams, explain trade-offs), and best practices (know your audience, tell a story, use visuals, practice) -- [ ] 3.10 Create `examples/ch11/templates/presentation-outline.md` with suggested structure: Introduction (1-2 min: what system/feature are you presenting?), System Overview (2-3 min: show component diagram, explain high-level architecture), Deep Dive (5-7 min: show sequence diagram, walk through a transaction, explain key decisions), Trade-offs and Alternatives (2-3 min: what are the pros/cons, what else was considered?), Q&A (2-3 min: be prepared for questions about decisions and details) -- [ ] 3.11 Create `examples/ch11/templates/presentation-rubric.md` with evaluation criteria and scoring (1-5 scale): Clarity (easy to follow, well-organized, clear speech), Accuracy (technically correct, no major misunderstandings), Completeness (covers all required topics, sufficient depth), Effective Use of Diagrams (diagrams are clear, properly explained, support the narrative), Time Management (within 10-15 minute target), Q&A Handling (answers questions confidently, acknowledges unknowns appropriately) -- [ ] 3.12 Add H2 section "Exercise 3: Architecture Documentation & Presentation" to `11.3-system-thinking.md` with instructions for students to: write 2-3 ADRs analyzing architectural decisions in OTel Demo (provide example prompts), create or enhance a README section documenting OTel Demo architecture (specify which sections to include), prepare and deliver/record a 10-15 minute walkthrough presentation (specify required content: overview, diagrams, transaction flow, trade-offs), and use the provided templates and rubric for self-assessment +- [x] 3.1 Add H2 section "Architectural Decision Records (ADRs)" to `docs/11-application-development/11.3-system-thinking.md` explaining what ADRs are (documents capturing important architectural decisions), why they matter (historical record, knowledge transfer, decision rationale), and when to write them (significant decisions affecting structure, technology choices, design patterns) +- [x] 3.2 Explain ADR structure in the ADR section: Title (short descriptive name), Status (proposed/accepted/deprecated), Context (what's the situation requiring a decision?), Decision (what did we decide?), Consequences (what are the positive and negative outcomes?), and optional sections (Alternatives Considered, References) +- [x] 3.3 Create `examples/ch11/templates/adr-template.md` with the proper structure outlined in 3.2, including guidance comments for each section explaining what content to include +- [x] 3.4 Create `examples/ch11/templates/adr-example-grpc.md` analyzing the decision "Why use gRPC between certain services in OTel Demo?" with realistic context (need for efficient inter-service communication), decision (use gRPC for internal service-to-service calls), and consequences (pros: type safety, performance; cons: complexity, debugging difficulty) +- [x] 3.5 Create `examples/ch11/templates/adr-example-frontend-ssr.md` analyzing "Why is the frontend server-side rendered?" with context (need for good performance and SEO), decision (use server-side rendering with Next.js), and consequences +- [x] 3.6 Create `examples/ch11/templates/adr-example-multiple-databases.md` analyzing "Why use multiple databases?" with context (different data access patterns for different services), decision (polyglot persistence approach), and consequences +- [x] 3.7 Add H2 section "Documenting Architecture in README Files" to `11.3-system-thinking.md` explaining the purpose of architecture documentation, what makes good documentation (clear, concise, up-to-date, audience-appropriate), and common sections to include +- [x] 3.8 Create `examples/ch11/templates/readme-enhancement-checklist.md` with checkboxes for: System Overview (1-2 paragraph description), Architecture Diagram (component or system diagram), Service Responsibilities (what does each service do?), Communication Patterns (how do services talk to each other?), Data Storage (databases, caches, message queues), Technology Stack (languages, frameworks, key libraries), Key Architectural Decisions (link to ADRs or brief explanations), Setup and Running (how to get it working locally) +- [x] 3.9 Add H2 section "Presenting Technical Architecture" to `11.3-system-thinking.md` explaining why presentation skills matter (communicating with team, onboarding new members, design reviews), effective presentation structure (start with overview, zoom into details, show diagrams, explain trade-offs), and best practices (know your audience, tell a story, use visuals, practice) +- [x] 3.10 Create `examples/ch11/templates/presentation-outline.md` with suggested structure: Introduction (1-2 min: what system/feature are you presenting?), System Overview (2-3 min: show component diagram, explain high-level architecture), Deep Dive (5-7 min: show sequence diagram, walk through a transaction, explain key decisions), Trade-offs and Alternatives (2-3 min: what are the pros/cons, what else was considered?), Q&A (2-3 min: be prepared for questions about decisions and details) +- [x] 3.11 Create `examples/ch11/templates/presentation-rubric.md` with evaluation criteria and scoring (1-5 scale): Clarity (easy to follow, well-organized, clear speech), Accuracy (technically correct, no major misunderstandings), Completeness (covers all required topics, sufficient depth), Effective Use of Diagrams (diagrams are clear, properly explained, support the narrative), Time Management (within 10-15 minute target), Q&A Handling (answers questions confidently, acknowledges unknowns appropriately) +- [x] 3.12 Add H2 section "Exercise 3: Architecture Documentation & Presentation" to `11.3-system-thinking.md` with instructions for students to: write 2-3 ADRs analyzing architectural decisions in OTel Demo (provide example prompts), create or enhance a README section documenting OTel Demo architecture (specify which sections to include), prepare and deliver/record a 10-15 minute walkthrough presentation (specify required content: overview, diagrams, transaction flow, trade-offs), and use the provided templates and rubric for self-assessment --- -### [ ] 4.0 Create Integration Exercise and Assessment Materials +### [x] 4.0 Create Integration Exercise and Assessment Materials (content complete; 4.18 live OTel Demo validation intentionally deferred, see status note) **Purpose:** Provide comprehensive integration exercise that synthesizes all skills, with self-assessment tools and optional extensions for advanced students. @@ -180,24 +180,25 @@ This task list breaks down the implementation of Chapter 11.3: System Thinking & #### 4.0 Tasks -- [ ] 4.1 Add H2 section "Exercise 4: Integration Exercise" to `docs/11-application-development/11.3-system-thinking.md` explaining this is a comprehensive exercise synthesizing all skills from the chapter -- [ ] 4.2 Add integration exercise instructions to `11.3-system-thinking.md`: students select a feature or workflow in OTel Demo not covered in previous exercises (provide examples: "product recommendation flow", "payment processing", "email notification system"), perform complete analysis, and produce all deliverables -- [ ] 4.3 Specify required deliverables in exercise instructions: component diagram showing all involved services and their dependencies, sequence diagram showing complete transaction flow with all service interactions, data flow diagram showing information movement and transformations, README section documenting the feature/workflow (following checklist), ADR analyzing one architectural decision related to the feature, and recorded or live presentation (10-15 minutes) walking through the analysis -- [ ] 4.4 Create directory `examples/ch11/integration-example/` with subdirectory `diagrams/` -- [ ] 4.5 Create `examples/ch11/integration-example/README.md` documenting an example feature analysis (e.g., "Product Recommendation System") with all required sections: overview, architecture, services involved, transaction flow, key decisions -- [ ] 4.6 Create `examples/ch11/integration-example/diagrams/component.puml` showing an example component diagram for the chosen feature with 3-5 services and their relationships -- [ ] 4.7 Create `examples/ch11/integration-example/diagrams/sequence.puml` showing an example sequence diagram for a complete transaction in the chosen feature -- [ ] 4.8 Create `examples/ch11/integration-example/diagrams/dataflow.puml` showing an example data flow diagram for the chosen feature -- [ ] 4.9 Render all three integration example diagrams to PNG and save in `docs/11-application-development/img11/` with appropriate names (e.g., `integration-example-component.png`) -- [ ] 4.10 Create `examples/ch11/integration-example/adr-example.md` analyzing one architectural decision from the example feature (e.g., "Why use a separate recommendation service?") -- [ ] 4.11 Create `examples/ch11/integration-example/presentation-outline.md` showing a complete presentation outline for the example feature analysis with all sections filled in -- [ ] 4.12 Create `examples/ch11/templates/integration-self-assessment.md` with checklist organized by deliverable type: Diagrams (all three types created? clear and accurate? follow conventions?), Documentation (README includes all sections? ADR follows template? writing is clear?), Presentation (within time limit? covers all topics? effective use of diagrams? prepared for questions?), and Overall (demonstrates understanding of architecture? identifies trade-offs? shows system-level thinking?) -- [ ] 4.13 Add H2 section "Optional Advanced Extensions" to `11.3-system-thinking.md` with enrichment activities: analyze failure scenarios and recovery mechanisms (what happens when a service goes down? how does the system recover?), compare OTel Demo architecture to alternative approaches (monolith vs microservices, synchronous vs event-driven), propose architectural improvements with justification (what would you change and why? what are the trade-offs?), and implement a simplified version of one service as a learning exercise -- [ ] 4.14 Add front-matter metadata to the top of `docs/11-application-development/11.3-system-thinking.md` following the spec requirements: category "Software Development", estReadingMinutes 30, and exercises array with all four exercises (Simple Application Analysis: 90 min, Transaction Tracing: 120 min, Documentation & Presentation: 150 min, Integration Exercise: 180 min) with proper technologies listed -- [ ] 4.15 Add H2 section "Summary and Next Steps" to `11.3-system-thinking.md` reviewing what students learned (system-level thinking, diagram types, transaction tracing, technical communication) and previewing how these skills will be used in later chapters (11.7 Debugging & Observability, 11.8 Production Development) -- [ ] 4.16 Review the complete `11.3-system-thinking.md` file for consistency, proper markdown formatting (H2 for navigation sections, H3 for content subsections), internal cross-references, and ensure all images are properly embedded with alt text -- [ ] 4.17 Verify all template files exist and are complete, all example diagrams are rendered, and all exercise instructions are clear and actionable +- [x] 4.1 Add H2 section "Exercise 4: Integration Exercise" to `docs/11-application-development/11.3-system-thinking.md` explaining this is a comprehensive exercise synthesizing all skills from the chapter +- [x] 4.2 Add integration exercise instructions to `11.3-system-thinking.md`: students select a feature or workflow in OTel Demo not covered in previous exercises (provide examples: "product recommendation flow", "payment processing", "email notification system"), perform complete analysis, and produce all deliverables +- [x] 4.3 Specify required deliverables in exercise instructions: component diagram showing all involved services and their dependencies, sequence diagram showing complete transaction flow with all service interactions, data flow diagram showing information movement and transformations, README section documenting the feature/workflow (following checklist), ADR analyzing one architectural decision related to the feature, and recorded or live presentation (10-15 minutes) walking through the analysis +- [x] 4.4 Create directory `examples/ch11/integration-example/` with subdirectory `diagrams/` +- [x] 4.5 Create `examples/ch11/integration-example/README.md` documenting an example feature analysis (e.g., "Product Recommendation System") with all required sections: overview, architecture, services involved, transaction flow, key decisions +- [x] 4.6 Create `examples/ch11/integration-example/diagrams/component.puml` showing an example component diagram for the chosen feature with 3-5 services and their relationships +- [x] 4.7 Create `examples/ch11/integration-example/diagrams/sequence.puml` showing an example sequence diagram for a complete transaction in the chosen feature +- [x] 4.8 Create `examples/ch11/integration-example/diagrams/dataflow.puml` showing an example data flow diagram for the chosen feature +- [x] 4.9 Render all three integration example diagrams to PNG and save in `docs/11-application-development/img11/` with appropriate names (e.g., `integration-example-component.png`) +- [x] 4.10 Create `examples/ch11/integration-example/adr-example.md` analyzing one architectural decision from the example feature (e.g., "Why use a separate recommendation service?") +- [x] 4.11 Create `examples/ch11/integration-example/presentation-outline.md` showing a complete presentation outline for the example feature analysis with all sections filled in +- [x] 4.12 Create `examples/ch11/templates/integration-self-assessment.md` with checklist organized by deliverable type: Diagrams (all three types created? clear and accurate? follow conventions?), Documentation (README includes all sections? ADR follows template? writing is clear?), Presentation (within time limit? covers all topics? effective use of diagrams? prepared for questions?), and Overall (demonstrates understanding of architecture? identifies trade-offs? shows system-level thinking?) +- [x] 4.13 Add H2 section "Optional Advanced Extensions" to `11.3-system-thinking.md` with enrichment activities: analyze failure scenarios and recovery mechanisms (what happens when a service goes down? how does the system recover?), compare OTel Demo architecture to alternative approaches (monolith vs microservices, synchronous vs event-driven), propose architectural improvements with justification (what would you change and why? what are the trade-offs?), and implement a simplified version of one service as a learning exercise +- [x] 4.14 Add front-matter metadata to the top of `docs/11-application-development/11.3-system-thinking.md` following the spec requirements: category "Software Development", estReadingMinutes 30, and exercises array with all four exercises (Simple Application Analysis: 90 min, Transaction Tracing: 120 min, Documentation & Presentation: 150 min, Integration Exercise: 180 min) with proper technologies listed +- [x] 4.15 Add H2 section "Summary and Next Steps" to `11.3-system-thinking.md` reviewing what students learned (system-level thinking, diagram types, transaction tracing, technical communication) and previewing how these skills will be used in later chapters (11.7 Debugging & Observability, 11.8 Production Development) +- [x] 4.16 Review the complete `11.3-system-thinking.md` file for consistency, proper markdown formatting (H2 for navigation sections, H3 for content subsections), internal cross-references, and ensure all images are properly embedded with alt text +- [x] 4.17 Verify all template files exist and are complete, all example diagrams are rendered, and all exercise instructions are clear and actionable - [ ] 4.18 Test the complete learning path by following the exercises in order: run simple-system, create diagrams, set up OTel Demo, trace a transaction, write documentation, review templates and examples - ensure everything works as documented + - **Status:** simple-system (Exercise 1) was verified running end-to-end (task 1.20). The OTel Demo portion (Exercises 2 & 4) was intentionally **not** run live in this environment — see "Local ARM validation: pending" in `examples/ch11/otel-demo-setup/README.md`. All written instructions, links, and templates were verified for consistency and completeness, but the full learning path has not been executed against a live OTel Demo instance. --- diff --git a/examples/ch11/integration-example/README.md b/examples/ch11/integration-example/README.md new file mode 100644 index 00000000..5c494f99 --- /dev/null +++ b/examples/ch11/integration-example/README.md @@ -0,0 +1,35 @@ +# Integration Exercise Example: Product Recommendation Flow + +> This is a worked example showing the expected depth and structure for Exercise 4 (Integration Exercise). It analyzes the "you might also like" product recommendation feature in the OpenTelemetry Demo Application — a feature not covered in the earlier worked examples in this chapter. + +## Overview + +When a shopper views a product page, the storefront shows a "you might also like" section with a handful of other products. This is powered by a dedicated recommendation service that looks at what's already in the shopper's view (or cart) and suggests other catalog items — a small but complete example of a service that exists purely to enrich another service's response, rather than to own its own core business data. + +## Architecture + +| Component | Responsibility | +|---|---| +| Frontend (Next.js) | Renders the product page; requests recommendations and their full details before rendering | +| Recommendation Service (Python, gRPC) | Given a list of product IDs already in view, returns a list of *other* product IDs to recommend | +| Product Catalog Service (Go, gRPC) | Source of truth for all product data; used both by the recommendation service (to know what exists) and the frontend (to get full details for the recommended IDs) | + +See [`diagrams/component.puml`](diagrams/component.puml) for the full component diagram. + +## Transaction Flow + +1. Frontend renders a product page and calls the Recommendation Service's `ListRecommendations` RPC, passing the product ID(s) currently in view. +2. The Recommendation Service calls the Product Catalog Service's `ListProducts` RPC to get the full catalog of product IDs. +3. The Recommendation Service filters out the product(s) already in view, randomly selects a handful of the remainder, and returns just their **IDs** (not full product details) to the frontend. +4. The frontend calls the Product Catalog Service's `GetProduct` RPC once per recommended ID to fetch full details (name, price, image) for rendering. +5. The frontend renders the "you might also like" section. + +See [`diagrams/sequence.puml`](diagrams/sequence.puml) for the complete sequence diagram, and [`diagrams/dataflow.puml`](diagrams/dataflow.puml) for how the data shape changes at each step. + +## Data Storage + +Neither the Recommendation Service nor this flow touch a database directly — the Product Catalog Service is the sole source of product data (served from an in-memory/static catalog in the demo). The recommendation logic itself is stateless and computed fresh on every request. + +## Key Decisions + +The recommendation service deliberately returns only product **IDs**, not full product objects, requiring the frontend to make follow-up calls to the Product Catalog Service. See [`adr-example.md`](adr-example.md) for the full analysis of why this boundary was drawn where it was, instead of having the recommendation service return complete product details directly. diff --git a/examples/ch11/integration-example/adr-example.md b/examples/ch11/integration-example/adr-example.md new file mode 100644 index 00000000..8599d2b9 --- /dev/null +++ b/examples/ch11/integration-example/adr-example.md @@ -0,0 +1,37 @@ +# ADR: Recommendation Service Returns Product IDs, Not Full Product Data + +> Example ADR for the integration exercise worked example (Product Recommendation Flow). + +## Status + +Accepted + +## Context + +The Recommendation Service needs to tell the frontend which products to show in a "you might also like" section. It has access to the full product catalog (it calls the Product Catalog Service's `ListProducts` to compute recommendations), so it technically *could* return complete product objects — name, price, description, image — directly to the frontend, saving the frontend from making follow-up calls. + +## Decision + +The Recommendation Service returns only a list of recommended product **IDs**. The frontend is responsible for calling the Product Catalog Service's `GetProduct` separately for each recommended ID to get full details. + +## Consequences + +**Positive:** + +- **Single source of truth for product data.** Only the Product Catalog Service ever returns full product details, so there's exactly one place product data can drift out of date or be formatted inconsistently. +- **Looser coupling.** The Recommendation Service's contract doesn't need to change if the Product Catalog Service adds new fields to its product schema — it never touches that data beyond IDs and whatever it needs internally to filter. +- **Simpler recommendation logic.** The service's only job is "which IDs," which keeps it small, easy to reason about, and easy to swap out (e.g. for a real ML-based recommender later) without touching how product details are served. + +**Negative:** + +- **Extra round trips.** The frontend now makes N additional gRPC calls (one per recommended product) instead of getting everything in one response from the Recommendation Service — more network hops, more places for partial failure (one `GetProduct` call failing shouldn't break the whole section, but that has to be handled explicitly). +- **Duplicated catalog lookups.** Both the Recommendation Service (to compute recommendations) and the frontend (to render them) end up calling into the Product Catalog Service for related data, within the same user-facing request. + +## Alternatives Considered + +- **Return full product objects from the Recommendation Service:** fewer round trips for the frontend, but couples the recommendation contract to the full product schema and duplicates "what does a product look like" logic across two services. +- **Have the frontend call `ListProducts` directly and do its own filtering client-side:** would remove the Recommendation Service's value entirely — the whole point of the service is to own the (eventually more sophisticated) recommendation logic in one place. + +## References + +- [`diagrams/sequence.puml`](diagrams/sequence.puml) — shows the extra `GetProduct` round trips this decision introduces diff --git a/examples/ch11/integration-example/diagrams/component.puml b/examples/ch11/integration-example/diagrams/component.puml new file mode 100644 index 00000000..464db784 --- /dev/null +++ b/examples/ch11/integration-example/diagrams/component.puml @@ -0,0 +1,26 @@ +@startuml integration-example-component +title Product Recommendation Flow - Component Diagram + +skinparam componentStyle rectangle + +actor "Shopper\n(Browser)" as Shopper + +package "OTel Demo (subset)" { + [Frontend\n(Next.js)] as Frontend + [Recommendation Service\n(Python, gRPC)] as Recs + [Product Catalog Service\n(Go, gRPC)] as Catalog +} + +Shopper --> Frontend : HTTP\n(view product page) +Frontend --> Recs : gRPC ListRecommendations\n(product IDs in view) +Frontend --> Catalog : gRPC GetProduct\n(per recommended ID) +Recs --> Catalog : gRPC ListProducts\n(full catalog) + +note right of Recs + Stateless: no database of its own. + Computes recommendations fresh + from the current catalog on + every request. +end note + +@enduml diff --git a/examples/ch11/integration-example/diagrams/dataflow.puml b/examples/ch11/integration-example/diagrams/dataflow.puml new file mode 100644 index 00000000..01e4eb9e --- /dev/null +++ b/examples/ch11/integration-example/diagrams/dataflow.puml @@ -0,0 +1,27 @@ +@startuml integration-example-dataflow +title Product Recommendation Flow - Data Flow Diagram + +skinparam defaultTextAlignment center + +rectangle "Viewed Product ID\n(from page URL)" as ViewedId +rectangle "gRPC Request\nListRecommendations(productIds=[id])" as RecReq +rectangle "Full Catalog\n(list of all Product objects)" as FullCatalog +rectangle "Filtered + Sampled IDs\n([id2, id3, id4, id5])" as SampledIds +rectangle "Per-ID GetProduct Calls\n(4x gRPC requests)" as GetCalls +rectangle "Full Product Objects\n(name, price, picture per ID)" as FullProducts +rectangle "Rendered HTML\n(\"You might also like\" cards)" as Html + +ViewedId -down-> RecReq : frontend builds\ngRPC request +RecReq -down-> FullCatalog : recommendation service\nfetches full catalog +FullCatalog -down-> SampledIds : recommendation service\nfilters + randomly samples,\nreturns IDs only +SampledIds -down-> GetCalls : frontend issues one\nGetProduct call per ID +GetCalls -down-> FullProducts : catalog service returns\nfull product details +FullProducts -down-> Html : frontend renders\nproduct cards + +note bottom of Html + Notice the recommendation service never sends full + product data -- only IDs. The frontend re-fetches full + details itself, an explicit boundary decision (see ADR). +end note + +@enduml diff --git a/examples/ch11/integration-example/diagrams/sequence.puml b/examples/ch11/integration-example/diagrams/sequence.puml new file mode 100644 index 00000000..dd96473e --- /dev/null +++ b/examples/ch11/integration-example/diagrams/sequence.puml @@ -0,0 +1,39 @@ +@startuml integration-example-sequence +title Product Recommendation Flow - Sequence Diagram + +actor Shopper +participant "Frontend\n(Next.js)" as Frontend +participant "Recommendation Service\n(Python, gRPC)" as Recs +participant "Product Catalog Service\n(Go, gRPC)" as Catalog + +Shopper -> Frontend: GET /product/[id] +activate Frontend + +Frontend -> Recs: gRPC ListRecommendations\n(productIds: [currentId]) +activate Recs + +Recs -> Catalog: gRPC ListProducts() +activate Catalog +Catalog --> Recs: all products +deactivate Catalog + +note right of Recs + Filters out currentId, + randomly selects up to 4 + remaining product IDs +end note + +Recs --> Frontend: RecommendationResponse\n(productIds: [id2, id3, id4, id5]) +deactivate Recs + +loop for each recommended productId + Frontend -> Catalog: gRPC GetProduct(productId) + activate Catalog + Catalog --> Frontend: full Product\n(name, price, picture) + deactivate Catalog +end + +Frontend --> Shopper: rendered page with\n"You might also like" section +deactivate Frontend + +@enduml diff --git a/examples/ch11/integration-example/presentation-outline.md b/examples/ch11/integration-example/presentation-outline.md new file mode 100644 index 00000000..a180e77e --- /dev/null +++ b/examples/ch11/integration-example/presentation-outline.md @@ -0,0 +1,29 @@ +# Presentation Outline Example: Product Recommendation Flow + +> A filled-in example of the [presentation outline template](../templates/presentation-outline.md), showing the expected level of specificity. + +## 1. Introduction (~1 min) + +"I analyzed the product recommendation feature in the OTel Demo — the 'you might also like' section on each product page. It's a small feature, but it's a clean example of a service that exists purely to enrich another service's data, which makes it a good case study for service boundaries." + +## 2. System Overview (~3 min) + +- Show `diagrams/component.puml` +- Three components involved: Frontend, Recommendation Service, Product Catalog Service +- Explain: the Recommendation Service has no database of its own — it's stateless, computing fresh recommendations from the catalog on every call + +## 3. Deep Dive (~6 min) + +- Show `diagrams/sequence.puml` +- Walk through: shopper loads a product page → frontend asks the Recommendation Service for IDs → Recommendation Service asks the Product Catalog Service for the full list, filters, samples → returns just IDs → frontend calls `GetProduct` once per ID → renders the section +- Point out the loop in the diagram (N `GetProduct` calls) as the most "surprising" part of the trace — it wasn't obvious from the UI, only from reading the code + +## 4. Trade-offs (~3 min) + +- Present the ADR: why return IDs instead of full product data? +- Trade-off: extra round trips and duplicated catalog lookups, in exchange for a single source of truth for product data and a Recommendation Service that stays simple and swappable +- "If this were a performance-critical path instead of a 'nice to have' UI section, I'd revisit this — but for this feature, the coupling reduction is worth the extra calls." + +## 5. Q&A (~2 min) + +- Anticipated question: "Why not cache the product details in the Recommendation Service?" — answer: it would reintroduce a second source of truth for product data, and this feature isn't performance-sensitive enough to justify that yet. diff --git a/examples/ch11/otel-demo-setup/README.md b/examples/ch11/otel-demo-setup/README.md new file mode 100644 index 00000000..78820a27 --- /dev/null +++ b/examples/ch11/otel-demo-setup/README.md @@ -0,0 +1,122 @@ +# OTel Demo Setup Guide + +This guide gets the [OpenTelemetry Demo Application](https://github.com/open-telemetry/opentelemetry-demo) ("Astronomy Shop") running locally so you can complete Exercise 2 (Transaction Tracing) and Exercise 4 (Integration Exercise) in [Chapter 11.3](/docs/11-application-development/11.3-system-thinking.md). + +## What It Is + +The OTel Demo is a realistic e-commerce microservices application — an online astronomy shop — built by the OpenTelemetry project specifically to demonstrate distributed tracing, metrics, and logs across services written in more than a dozen languages (Go, Java, .NET, Python, Node.js, Rust, PHP, and more). Unlike the [simple-system](/examples/ch11/simple-system) app from Exercise 1, it has real service-to-service communication (HTTP and gRPC), a message queue, multiple datastores, and a working Jaeger UI for viewing traces — making it a good target for practicing transaction tracing on something closer to a production system. + +We're using it here instead of building a custom multi-service app because reproducing this much realistic complexity from scratch wouldn't be a good use of bootcamp time, and because it's already fully instrumented with OpenTelemetry, which you'll build on again in Chapter 11.7 (Debugging & Observability). + +## Pinned Version + +This guide is written against **release `2.1.3`** (published 2025-09-26) of the [opentelemetry-demo repository](https://github.com/open-telemetry/opentelemetry-demo). Pinning avoids surprises from upstream changes — later releases (starting with `2.2.0`) add an optional Product Review service that calls the OpenAI API and can incur real cost, which we're intentionally avoiding here since no bootcamp exercise should require a paid API key. + +## System Requirements + +- **RAM:** 6 GB free for the full application, or ~3 GB in minimal mode (see [Reducing Resource Usage](#reducing-resource-usage) below) +- **Disk:** 14 GB free (container images plus build layers) +- **CPU:** no hard minimum documented upstream, but expect the full stack (~26 containers) to be noticeably heavier than the 2-container simple-system app from Exercise 1 +- **Docker Compose:** v2.0.0 or newer (check with `docker compose version`) +- **Docker/OrbStack:** must be running before any of the commands below + +## Setup Instructions + +1. **Clone the pinned release** (not `main`, so your setup matches this guide): + + ```bash + git clone --branch 2.1.3 --depth 1 https://github.com/open-telemetry/opentelemetry-demo.git + cd opentelemetry-demo + ``` + + Then pin the **runtime images** to the same release too — cloning the `2.1.3` tag only pins the source checkout. The shipped `.env` separately sets `DEMO_VERSION=latest`, which is what every service's `image:` tag is actually built from (`${IMAGE_NAME}:${DEMO_VERSION}-`), so `docker compose up` pulls the unpinned, continuously-moving `latest-*` tags regardless of which git tag you checked out. `latest` tracks upstream `main` and can be broken at any given moment — during validation of this guide, `latest-product-catalog` crashed on start (exited immediately, no log output) while `2.1.3-product-catalog` ran fine. Pin it before starting: + + ```bash + echo "DEMO_VERSION=2.1.3" >> .env + ``` + +2. **Start the full application:** + + ```bash + docker compose up --force-recreate --remove-orphans --detach + ``` + + This pulls prebuilt images from `ghcr.io/open-telemetry/demo` for all ~26 services on first run — expect it to take several minutes depending on your connection. + +3. **Verify the services are healthy:** + + ```bash + docker compose ps + ``` + + Look for all services in a `running` (or `healthy`, where a healthcheck is defined) state. A few restarts during the first 30-60 seconds while services wait on their dependencies (e.g., Kafka) are normal. + + If the very first `up` prints `Error dependency opensearch failed to start` and exits, opensearch just hadn't finished its health check the instant Compose checked it — it typically becomes healthy a few seconds later. Simply re-run the same `docker compose up --force-recreate --remove-orphans --detach` command; it resumes and starts the remaining containers rather than starting over. + +4. **Open the storefront** at . You should see the astronomy shop homepage with a product grid. From the same base URL, everything else is reachable behind the frontend proxy: + + | UI | Path | + |---|---| + | Web store | `/` | + | Jaeger (trace explorer) | `/jaeger/ui/` | + | Grafana (metrics dashboards) | `/grafana/` | + | Load generator | `/loadgen/` | + | Feature flag UI (flagd) | `/feature` | + + The base port is configurable — set `ENVOY_PORT=8081` (or any free port) before `docker compose up` if 8080 is already taken on your machine. + +5. **Generate some traffic** by clicking through the store yourself (add a product to cart, proceed toward checkout), or let the built-in load generator run in the background — it's started automatically and continuously exercises the storefront, which is useful for Exercise 2 since you'll have traces to inspect in Jaeger without manually reproducing every flow. + +6. **Tear down** when you're done: + + ```bash + docker compose down --volumes + ``` + +## Reducing Resource Usage + +If 6 GB of RAM for the full stack is more than your machine can spare, the repository ships a **minimal mode** that excludes the `accounting`, `fraud-detection`, `kafka`, and `postgresql` services (the async fraud-detection/accounting pipeline isn't needed for the exercises in this chapter): + +```bash +docker compose -f docker-compose.minimal.yml up --force-recreate --remove-orphans --detach +``` + +This drops resource usage to roughly 3 GB of RAM. Everything in the setup and verification steps above still applies — only the compose file changes. + +For an even smaller footprint scoped to exactly the "Add to Cart" worked example in this chapter, see the optional [`docker-compose-subset.yml`](docker-compose-subset.yml) in this directory. + +## Troubleshooting + +**Services stuck restarting / never become healthy.** Check logs for the specific service: `docker compose logs -f `. Most commonly this is Kafka (in full mode) taking longer than its dependents expect on first boot — give it another minute and re-check `docker compose ps`. + +**Port already in use.** The frontend proxy binds `${ENVOY_PORT}` (default `8080`) and `${ENVOY_ADMIN_PORT}` (default `8081`) on the host. If either is taken by something else on your machine, set `ENVOY_PORT=` (and/or `ENVOY_ADMIN_PORT`) as an environment variable before running `docker compose up`. + +**Insufficient RAM / Docker Desktop OOM-killing containers.** Increase Docker's memory allocation (Docker Desktop/OrbStack → Settings → Resources) to at least 6 GB (3 GB if using minimal mode), or switch to minimal mode above. + +**ARM compatibility (Apple Silicon: M1/M2/M3/M4).** All services in this release publish multi-arch images, so `docker compose up` works out of the box on ARM — but some JIT-heavy services have hit a known issue on Apple Silicon related to SVE (Scalable Vector Extension) support. The repository ships a workaround as `.env.arm64`, which disables the problematic JIT optimization. Pass it **in addition to** `.env`, not instead of it — `--env-file` replaces Compose's implicit `.env` load rather than merging with it, and `.env.arm64` alone is missing required variables (`HOST_FILESYSTEM`, `DOCKER_SOCK`, etc.), which fails immediately with `invalid spec: :/hostfs:ro: empty section between colons`: + +```bash +docker compose --env-file .env --env-file .env.arm64 up --force-recreate --remove-orphans --detach +``` + +Use this on Apple Silicon if you see Java services crash-looping in `docker compose ps`. + +**Slow first `docker compose up`.** This is expected — the first run pulls ~26 images from `ghcr.io`. Subsequent runs reuse cached layers and start in seconds. + +**Local ARM validation: done (2026-07-23, Apple M5 Max, macOS 26.6, OrbStack, Docker 29.4.0 / Compose v5.1.2, 64 GB host RAM, no fixed memory limit).** Following the setup steps above (including `DEMO_VERSION=2.1.3` and the merged `--env-file .env --env-file .env.arm64`), all 26 containers reached a stable `running`/`healthy` state with no further restarts, and the storefront, Jaeger, Grafana, load generator, and feature-flag UI all returned HTTP 200 through `http://localhost:8080`. Container creation/start itself took under a minute once images were cached; the ~3 GB of unique images is the dominant cost on a cold pull. Steady-state RAM across all 26 containers was **~3.5 GB** shortly after startup (heaviest: opensearch ~790 MB, load-generator ~610 MB, kafka ~505 MB) — comfortably under the documented 6 GB budget. Two ARM/OrbStack-specific issues turned up beyond the `.env.arm64` SVE workaround, both now folded into the steps above: + +- The `DEMO_VERSION=2.1.3` pin (see step 1) was the fix for `product-catalog` — without it, `latest-product-catalog` (upstream's moving `main` tag) crashed on start with no log output during this validation run. +- `otel-collector` crash-looped with `client version 1.25 is too old. Minimum supported API version is 1.40` from its `docker_stats` receiver. This is an OrbStack-specific Docker API version-negotiation issue, not a SVE/ARM CPU problem — OrbStack's daemon enforces `MinAPIVersion 1.40`, and the receiver's default client falls back to 1.25. Fix by adding `api_version: "1.41"` to the `docker_stats` receiver in the cloned repo's `src/otel-collector/otelcol-config.yml`: + + ```yaml + receivers: + docker_stats: + endpoint: unix:///var/run/docker.sock + api_version: "1.41" + ``` + + Then `docker compose up -d --force-recreate otel-collector` to pick it up. If you're on Docker Desktop rather than OrbStack, you likely won't hit this at all. + +## Next Steps + +Once the application is running and you can browse the storefront, continue to [Exercise 2: Transaction Tracing in OTel Demo](/docs/11-application-development/11.3-system-thinking.md#exercise-2-transaction-tracing-in-otel-demo). diff --git a/examples/ch11/otel-demo-setup/diagrams/add-to-cart-trace.puml b/examples/ch11/otel-demo-setup/diagrams/add-to-cart-trace.puml new file mode 100644 index 00000000..e764ae9f --- /dev/null +++ b/examples/ch11/otel-demo-setup/diagrams/add-to-cart-trace.puml @@ -0,0 +1,45 @@ +@startuml add-to-cart-trace +title OTel Demo - "Add to Cart" Sequence Diagram (Worked Example) + +actor Shopper + +participant "Frontend Proxy\n(Envoy)" as Proxy +participant "Frontend\n(Next.js)" as Frontend +participant "Cart Service\n(.NET, gRPC)" as Cart +database "Valkey / Redis\n(cart store)" as Store + +Shopper -> Proxy: POST /api/cart\n{productId, quantity} +activate Proxy + +Proxy -> Frontend: routes /api/* to frontend +activate Frontend + +Frontend -> Cart: gRPC AddItem(userId, CartItem) +activate Cart + +Cart -> Store: read existing cart for userId +activate Store +Store --> Cart: current cart (or empty) +deactivate Store + +Cart -> Store: write merged cart for userId +activate Store +Store --> Cart: OK +deactivate Store + +Cart --> Frontend: gRPC response (success) +deactivate Cart + +Frontend --> Proxy: 200 OK (JSON) +deactivate Frontend + +Proxy --> Shopper: 200 OK\n(UI updates cart count) +deactivate Proxy + +note over Cart, Store + Failure point: if Valkey is unreachable, the gRPC + call may still be accepted but the write can fail -- + the frontend only knows what the Cart Service tells it. +end note + +@enduml diff --git a/examples/ch11/otel-demo-setup/docker-compose-subset.yml b/examples/ch11/otel-demo-setup/docker-compose-subset.yml new file mode 100644 index 00000000..bab0dfe6 --- /dev/null +++ b/examples/ch11/otel-demo-setup/docker-compose-subset.yml @@ -0,0 +1,64 @@ +# Optional override: trims the OTel Demo (release 2.1.3) down to the ~5 core +# services touched by this chapter's "Add to Cart" worked example, instead of +# the full ~26-service stack or the ~21-service `docker-compose.minimal.yml`. +# +# Usage (from inside a checkout of the pinned opentelemetry-demo release): +# cp /path/to/this/file/docker-compose-subset.yml . +# docker compose -f docker-compose.yml -f docker-compose-subset.yml up frontend-proxy frontend cart product-catalog valkey-cart flagd jaeger otel-collector +# +# Why these services: `frontend` and `frontend-proxy` are the entry point, +# `cart` and `valkey-cart` handle the "Add to Cart" write, `product-catalog` +# serves the product data the frontend renders, and `flagd` / `jaeger` / +# `otel-collector` are supporting infrastructure the frontend depends on to +# start and that you need to view the resulting trace. +# +# What this trades away: the frontend's own `depends_on` list includes several +# services NOT started here (ad, checkout, currency, quote, recommendation, +# shipping, image-provider). Compose will still bring the storefront up, but +# product-page sections backed by those services (ads, recommendations, +# shipping estimates, checkout) will error or render empty — which is exactly +# what you'd expect to see if those services were actually down in production. +# That's a reasonable trade for this chapter's scope, since Exercise 2 only +# needs "Add to Cart" to work end-to-end. +# +# Not validated against a live run in this environment — see "Local ARM +# validation: pending" in README.md. If frontend fails to start because of an +# unmet dependency, fall back to `docker-compose.minimal.yml` or the full +# `docker-compose.yml` instead. +services: + ad: + profiles: ["disabled"] + checkout: + profiles: ["disabled"] + currency: + profiles: ["disabled"] + email: + profiles: ["disabled"] + payment: + profiles: ["disabled"] + quote: + profiles: ["disabled"] + recommendation: + profiles: ["disabled"] + shipping: + profiles: ["disabled"] + image-provider: + profiles: ["disabled"] + accounting: + profiles: ["disabled"] + fraud-detection: + profiles: ["disabled"] + kafka: + profiles: ["disabled"] + postgresql: + profiles: ["disabled"] + flagd-ui: + profiles: ["disabled"] + grafana: + profiles: ["disabled"] + prometheus: + profiles: ["disabled"] + opensearch: + profiles: ["disabled"] + load-generator: + profiles: ["disabled"] diff --git a/examples/ch11/simple-system/.gitignore b/examples/ch11/simple-system/.gitignore new file mode 100644 index 00000000..535b587e --- /dev/null +++ b/examples/ch11/simple-system/.gitignore @@ -0,0 +1,5 @@ +*.pyc +__pycache__/ +.venv/ +*.db +.DS_Store diff --git a/examples/ch11/simple-system/README.md b/examples/ch11/simple-system/README.md new file mode 100644 index 00000000..2c82be0b --- /dev/null +++ b/examples/ch11/simple-system/README.md @@ -0,0 +1,69 @@ +# Simple System: Task List Application + +A minimal 3-component application used in [Chapter 11.3 - System Thinking](../../../docs/11-application-development/11.3-system-thinking.md) as the first target for system analysis. It's intentionally small enough to read end-to-end in a few minutes, so you can focus on learning to *diagram* and *document* architecture rather than on understanding complex business logic. + +## What It Does + +A web-based task list: add a task, view the list, and toggle a task done/not-done. Nothing more. + +## Architecture + +Three components, each with a single clear responsibility: + +| Component | Responsibility | Technology | Port | +|---|---|---|---| +| **Frontend** | Renders HTML UI, handles form submissions, calls the backend over HTTP | Flask (Python) | 8080 (host) → 5000 (container) | +| **Backend** | Exposes a REST API, owns business logic and data access | Flask (Python) | 5001 | +| **Database** | Persists tasks | SQLite (file, owned by the backend) | n/a | + +```text +Browser --> 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
    of tasks)" as Html + +Input -down-> FormData : browser serializes form +FormData -down-> ApiRequest : frontend parses form,\nbuilds JSON payload +ApiRequest -down-> DbRow : backend validates,\ninserts row +DbRow -down-> ApiResponse : backend serializes\nnew row to JSON +ApiResponse -down-> Html : frontend re-fetches\ntask list, renders template + +note bottom of Html + Data is transformed at every hop: + raw text -> form encoding -> JSON -> SQL row -> JSON -> HTML. + Each transformation is a place a bug (or a diagram) can hide. +end note + +@enduml diff --git a/examples/ch11/simple-system/diagrams/sequence.puml b/examples/ch11/simple-system/diagrams/sequence.puml new file mode 100644 index 00000000..d626433b --- /dev/null +++ b/examples/ch11/simple-system/diagrams/sequence.puml @@ -0,0 +1,35 @@ +@startuml simple-system-sequence +title Simple System - "Add Task" Sequence Diagram + +actor User +participant "Frontend\n(Flask :5000)" as Frontend +participant "Backend API\n(Flask :5001)" as Backend +database "SQLite\n(tasks.db)" as DB + +User -> Frontend: Submit "Add Task" form\n(POST /tasks, title="Buy milk") +activate Frontend + +Frontend -> Backend: POST /tasks\n{"title": "Buy milk"} +activate Backend + +Backend -> DB: INSERT INTO tasks (title, done)\nVALUES ("Buy milk", 0) +activate DB +DB --> Backend: new row id +deactivate DB + +Backend --> Frontend: 201 Created\n{"id": 4, "title": "Buy milk", "done": false} +deactivate Backend + +Frontend -> Backend: GET /tasks\n(re-render list) +activate Backend +Backend -> DB: SELECT * FROM tasks +activate DB +DB --> Backend: rows +deactivate DB +Backend --> Frontend: 200 OK\n[{...}, {...}, {...}, {...}] +deactivate Backend + +Frontend --> User: 302 redirect -> rendered HTML\nwith updated task list +deactivate Frontend + +@enduml diff --git a/examples/ch11/simple-system/docker-compose.yml b/examples/ch11/simple-system/docker-compose.yml new file mode 100644 index 00000000..e7d5d553 --- /dev/null +++ b/examples/ch11/simple-system/docker-compose.yml @@ -0,0 +1,32 @@ +services: + backend: + build: ./backend + ports: + - "5001:5001" + volumes: + - backend-data:/data + environment: + DB_PATH: /data/tasks.db + healthcheck: + test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:5001/health')"] + interval: 5s + timeout: 3s + retries: 5 + + frontend: + build: ./frontend + ports: + - "8080:5000" + environment: + BACKEND_URL: http://backend:5001 + depends_on: + backend: + condition: service_healthy + healthcheck: + test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:5000/health')"] + interval: 5s + timeout: 3s + retries: 5 + +volumes: + backend-data: diff --git a/examples/ch11/simple-system/frontend/Dockerfile b/examples/ch11/simple-system/frontend/Dockerfile new file mode 100644 index 00000000..687285b6 --- /dev/null +++ b/examples/ch11/simple-system/frontend/Dockerfile @@ -0,0 +1,8 @@ +FROM python:3.11-slim +WORKDIR /app +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt +COPY app.py . +COPY templates/ templates/ +EXPOSE 5000 +CMD ["python3", "app.py"] diff --git a/examples/ch11/simple-system/frontend/app.py b/examples/ch11/simple-system/frontend/app.py new file mode 100644 index 00000000..7c3420f2 --- /dev/null +++ b/examples/ch11/simple-system/frontend/app.py @@ -0,0 +1,43 @@ +"""Frontend web service for the simple task list system. + +Renders an HTML UI and talks to the backend API over HTTP. This is the +"presentation" layer — it has no direct access to the database. +""" +import os + +import requests +from flask import Flask, redirect, render_template, request, url_for + +app = Flask(__name__) + +BACKEND_URL = os.environ.get("BACKEND_URL", "http://localhost:5001") + + +@app.get("/") +def index(): + response = requests.get(f"{BACKEND_URL}/tasks", timeout=5) + response.raise_for_status() + tasks = response.json() + return render_template("index.html", tasks=tasks) + + +@app.post("/tasks") +def add_task(): + title = request.form.get("title", "") + requests.post(f"{BACKEND_URL}/tasks", json={"title": title}, timeout=5) + return redirect(url_for("index")) + + +@app.post("/tasks//toggle") +def toggle_task(task_id): + requests.post(f"{BACKEND_URL}/tasks/{task_id}/toggle", timeout=5) + return redirect(url_for("index")) + + +@app.get("/health") +def health(): + return {"status": "ok"} + + +if __name__ == "__main__": + app.run(host="0.0.0.0", port=5000) diff --git a/examples/ch11/simple-system/frontend/pyproject.toml b/examples/ch11/simple-system/frontend/pyproject.toml new file mode 100644 index 00000000..0154b8b3 --- /dev/null +++ b/examples/ch11/simple-system/frontend/pyproject.toml @@ -0,0 +1,10 @@ +[project] +name = "simple-system-frontend" +version = "0.1.0" +description = "Frontend web UI for the simple task list system (Chapter 11.3 example)" +readme = "README.md" +requires-python = ">=3.11" +dependencies = [ + "Flask>=3.0,<4.0", + "requests>=2.31,<3.0", +] diff --git a/examples/ch11/simple-system/frontend/requirements.txt b/examples/ch11/simple-system/frontend/requirements.txt new file mode 100644 index 00000000..d9a7dc34 --- /dev/null +++ b/examples/ch11/simple-system/frontend/requirements.txt @@ -0,0 +1,2 @@ +Flask>=3.0,<4.0 +requests>=2.31,<3.0 diff --git a/examples/ch11/simple-system/frontend/templates/index.html b/examples/ch11/simple-system/frontend/templates/index.html new file mode 100644 index 00000000..0eb1ad20 --- /dev/null +++ b/examples/ch11/simple-system/frontend/templates/index.html @@ -0,0 +1,38 @@ + + + + + Simple Task List + + + +

    Task List

    + +
    + + +
    + +
      + {% for task in tasks %} +
    • +
      + +
      + {{ task.title }} +
    • + {% else %} +
    • No tasks yet.
    • + {% endfor %} +
    + + diff --git a/examples/ch11/templates/adr-example-frontend-ssr.md b/examples/ch11/templates/adr-example-frontend-ssr.md new file mode 100644 index 00000000..04fdf1b4 --- /dev/null +++ b/examples/ch11/templates/adr-example-frontend-ssr.md @@ -0,0 +1,38 @@ +# ADR 2: Server-Side Render the Storefront Frontend + +> Example ADR written by analyzing the OpenTelemetry Demo Application. This is a worked example showing the level of detail expected in Exercise 3 — not an official OTel Demo document. + +## Status + +Accepted + +## Context + +The frontend is the demo's storefront: a product catalog, product detail pages, and a checkout flow — the kind of application a real e-commerce team would want to load fast and be crawlable by search engines. It also needs to aggregate data from several backend gRPC services (product catalog, currency, recommendations, ads) before it can render a single page, and it needs to demonstrate distributed tracing across a "browser to backend" boundary, not just service-to-service. + +## Decision + +Build the frontend with Next.js, using server-side rendering (SSR): each page request is rendered on the frontend's own server (calling the necessary backend gRPC services during that render), and HTML is sent to the browser rather than shipping a client-side app shell that fetches data after load. + +## Consequences + +**Positive:** + +- First page load is fast and produces immediately-crawlable, fully-formed HTML — good for both real-world SEO and for the demo's own usability. +- Backend gRPC calls happen server-side, colocated with the other backend services, avoiding the need to expose every internal gRPC service directly to untrusted browser traffic. +- SSR naturally produces a clean "frontend server as an orchestrator" hop that's easy to instrument and trace — the frontend's server-side request handler is a single place where multiple backend calls fan out, which is pedagogically useful for a tracing demo. + +**Negative:** + +- The frontend server becomes a synchronous aggregation point: if one backend call it depends on is slow, the whole page render is slow (there's no independent client-side loading state per section unless explicitly built). +- Running a Node.js SSR server is an additional operational component compared to serving a static single-page app from a CDN — it needs its own scaling, health checks, and monitoring. +- Local development requires running the frontend's own server (not just a static file server), adding a small amount of setup overhead. + +## Alternatives Considered + +- **Client-side rendered SPA (e.g. plain React + client-side data fetching):** simpler infrastructure (static hosting), but loses SEO benefits and pushes multiple parallel API calls to the browser, which is less representative of how many real storefronts are built and less useful for demonstrating a clean server-side trace. +- **Static site generation (SSG):** would be fast, but product/cart data is inherently dynamic and per-user, so full static generation doesn't fit this use case. + +## References + +- [Next.js Server-Side Rendering documentation](https://nextjs.org/docs) diff --git a/examples/ch11/templates/adr-example-grpc.md b/examples/ch11/templates/adr-example-grpc.md new file mode 100644 index 00000000..61a6fd17 --- /dev/null +++ b/examples/ch11/templates/adr-example-grpc.md @@ -0,0 +1,39 @@ +# ADR 1: Use gRPC for Internal Service-to-Service Communication + +> Example ADR written by analyzing the OpenTelemetry Demo Application. This is a worked example showing the level of detail expected in Exercise 3 — not an official OTel Demo document. + +## Status + +Accepted + +## Context + +The OTel Demo is composed of ~15 backend services written in a deliberately wide mix of languages (Go, .NET, Java, Python, Node.js, Rust, C++, Ruby, Kotlin, PHP) to demonstrate OpenTelemetry instrumentation across ecosystems. These services need to call each other constantly and synchronously — the frontend calls the cart service, the checkout service calls product catalog, currency, shipping, payment, and email services, and so on. With that many polyglot services, two problems show up immediately: (1) without a shared contract, it's easy for services to drift on request/response shapes as they evolve independently, and (2) JSON-over-HTTP works but has real serialization overhead when a single user action can trigger a dozen internal calls. + +## Decision + +Use gRPC, with `.proto` files as the shared source of truth for service contracts, for all internal (service-to-service) communication. External-facing traffic (browser to frontend) remains plain HTTP/JSON, since browsers don't speak gRPC natively. + +## Consequences + +**Positive:** + +- A single `.proto` definition generates strongly-typed client/server code in every language used across the demo, so a Go service and a Ruby service can call each other without hand-written serialization code drifting apart. +- Protobuf's binary wire format is meaningfully smaller and faster to (de)serialize than JSON, which matters when a checkout can fan out to 6+ internal calls. +- Contract changes are visible in code review as diffs to `.proto` files, making breaking changes easier to catch before they ship. + +**Negative:** + +- gRPC is harder to poke at manually than REST — you can't just `curl` an endpoint and read the response; you need a gRPC-aware client (like `grpcurl`) or generated code. +- Debugging requires understanding both the gRPC framework and protobuf serialization, which is a steeper learning curve for engineers who've only worked with REST APIs. +- The frontend still needs an HTTP-to-gRPC translation layer for browser traffic, adding a component (and a place for bugs) that a pure-REST architecture wouldn't need. + +## Alternatives Considered + +- **REST/JSON everywhere:** simpler to debug and universally supported, but loses compile-time contract safety across 10 different languages and adds serialization overhead on the hot path. +- **A single shared language:** would simplify communication but defeats the demo's explicit goal of showing OpenTelemetry instrumentation across a realistic polyglot stack. + +## References + +- [gRPC documentation](https://grpc.io/docs/) +- OTel Demo `pb/` directory (shared `.proto` definitions) diff --git a/examples/ch11/templates/adr-example-multiple-databases.md b/examples/ch11/templates/adr-example-multiple-databases.md new file mode 100644 index 00000000..32ac9a96 --- /dev/null +++ b/examples/ch11/templates/adr-example-multiple-databases.md @@ -0,0 +1,38 @@ +# ADR 3: Use Multiple, Purpose-Specific Datastores (Polyglot Persistence) + +> Example ADR written by analyzing the OpenTelemetry Demo Application. This is a worked example showing the level of detail expected in Exercise 3 — not an official OTel Demo document. + +## Status + +Accepted + +## Context + +Different services in the OTel Demo have very different data access patterns. The cart service needs extremely fast key-value reads/writes keyed by user session, with data that's disposable (carts expire, get abandoned, get cleared on checkout). The feature flag service needs structured, queryable, durable configuration data that operators edit directly. Forcing every service to share one general-purpose relational database would mean either over-provisioning that database for cart-service-level traffic, or under-serving services that actually need relational querying. + +## Decision + +Give each service the datastore that fits its access pattern, rather than standardizing on one database for the whole system: a Redis-compatible in-memory store (Valkey) for the cart service's ephemeral, high-throughput key-value data, and a relational database (PostgreSQL) for the feature flag service's structured, durable configuration data. Most other services hold their data in-memory or as static seed data, since the demo prioritizes clarity over persistence for catalog-style data. + +## Consequences + +**Positive:** + +- Each datastore is a good fit for its owning service's actual access pattern — the cart service gets the low-latency key-value performance it needs without paying for relational query overhead it doesn't use. +- Services remain independently deployable and scalable — the cart's datastore can be scaled or reconfigured without touching the feature flag service's database, and vice versa. +- It's an honest, realistic demonstration: production microservice systems are almost always polyglot-persistence systems in practice, which makes the demo a more useful reference for students. + +**Negative:** + +- Operating multiple different kinds of datastores means more operational surface area — different backup strategies, different failure modes, different tools to monitor, compared to "just run backups on the one database." +- There's no single place to run a cross-service query or join — understanding "the whole picture" of system state requires knowing which service owns which piece of data and querying each independently. +- New engineers need to learn more than one datastore's operational quirks instead of specializing in a single technology. + +## Alternatives Considered + +- **Single shared relational database for everything:** simpler to operate and back up, but couples services through a shared schema (a classic distributed-monolith trap) and forces a one-size-fits-all performance profile onto services with very different needs. +- **Single shared NoSQL store for everything:** avoids the shared-schema coupling problem but still forces every service into one performance/consistency model, and doesn't fit the feature flag service's need for structured, queryable data. + +## References + +- [Polyglot Persistence (Martin Fowler)](https://martinfowler.com/bliki/PolyglotPersistence.html) diff --git a/examples/ch11/templates/adr-template.md b/examples/ch11/templates/adr-template.md new file mode 100644 index 00000000..17e4514a --- /dev/null +++ b/examples/ch11/templates/adr-template.md @@ -0,0 +1,35 @@ +# ADR [number]: [Short Descriptive Title] + +> Architectural Decision Records are short, and that's the point — this whole document should usually fit on one screen. Delete the guidance text (in blockquotes) as you go. + +## Status + +> One of: Proposed / Accepted / Deprecated / Superseded by ADR-[number] + +## Context + +> What is the situation that requires a decision? What forces are at play (technical constraints, team constraints, requirements)? Write this section so someone with no prior context understands *why a decision was even needed*. + +## Decision + +> What did we decide to do? State it plainly, in one or two sentences. Save the reasoning for Context and the trade-offs for Consequences — this section is just the decision itself. + +## Consequences + +> What happens as a result of this decision — both good and bad? A decision with no downsides is a sign you haven't looked hard enough. + +**Positive:** + +- + +**Negative:** + +- + +## Alternatives Considered (optional) + +> What else did you consider, and why wasn't it chosen? + +## References (optional) + +> Links to related ADRs, RFCs, documentation, or discussions. diff --git a/examples/ch11/templates/architecture-readme-template.md b/examples/ch11/templates/architecture-readme-template.md new file mode 100644 index 00000000..9bf9c8d6 --- /dev/null +++ b/examples/ch11/templates/architecture-readme-template.md @@ -0,0 +1,33 @@ +# Architecture: [System or Application Name] + +> Copy this template into your project's `README.md` (or a dedicated `ARCHITECTURE.md`) and fill in each section. Delete the guidance text (in blockquotes) as you go. + +## Overview + +> What does this application do, in 1-2 paragraphs? Write for someone who has never seen it before. + +## Architecture + +> What are the components (services, processes, databases) and what is each one responsible for? A table works well: + +| Component | Responsibility | Technology | +|---|---|---| +| | | | + +> Include or link to a component diagram here. + +## Communication Patterns + +> How do components talk to each other? HTTP/REST? gRPC? Message queue? Synchronous or asynchronous? Note any important conventions (auth headers, retry behavior, timeouts). + +## Data Storage + +> What data is stored, and where? List each datastore, what lives in it, and which component(s) own it. + +## Key Decisions + +> Why was it built this way? Call out 2-3 decisions that shaped the architecture and link to an ADR if one exists (see the [ADR template](adr-template.md)). + +## Setup and Running + +> How does someone get this running locally? Link to or restate the quickstart instructions. diff --git a/examples/ch11/templates/integration-self-assessment.md b/examples/ch11/templates/integration-self-assessment.md new file mode 100644 index 00000000..501cd2c7 --- /dev/null +++ b/examples/ch11/templates/integration-self-assessment.md @@ -0,0 +1,28 @@ +# Integration Exercise Self-Assessment + +Use this checklist to verify your integration exercise deliverables are complete before submitting or presenting. + +## Diagrams + +- [ ] All three diagram types created (sequence, component, data flow) +- [ ] Diagrams are clear and accurately reflect the code (not guessed from the UI) +- [ ] Diagrams follow the conventions used elsewhere in this chapter (labeled protocols, actors, clear direction of flow) + +## Documentation + +- [ ] README section includes all items from the [README enhancement checklist](readme-enhancement-checklist.md) +- [ ] ADR follows the [ADR template](adr-template.md) structure and states a real trade-off, not just a description +- [ ] Writing is clear enough that someone unfamiliar with the feature could follow it + +## Presentation + +- [ ] Within the 10-15 minute time limit +- [ ] Covers all required topics from the [presentation rubric](presentation-rubric.md) +- [ ] Diagrams are actively used and explained, not just displayed +- [ ] You could answer follow-up questions about the decisions and details, or knew how you'd find the answer + +## Overall + +- [ ] Demonstrates understanding of the feature's architecture, not just its UI behavior +- [ ] Identifies at least one real trade-off or design decision, with reasoning +- [ ] Shows system-level thinking — you can explain how the pieces fit together, not just what each piece does in isolation diff --git a/examples/ch11/templates/presentation-outline.md b/examples/ch11/templates/presentation-outline.md new file mode 100644 index 00000000..e880d462 --- /dev/null +++ b/examples/ch11/templates/presentation-outline.md @@ -0,0 +1,37 @@ +# Architecture Walkthrough Presentation Outline + +A suggested structure for a 10-15 minute technical walkthrough of a system you've analyzed. Adjust timing to fit your material, but keep the whole thing inside the 10-15 minute target — see the [presentation rubric](presentation-rubric.md) for how this gets evaluated. + +## 1. Introduction (1-2 min) + +- What system or feature are you presenting? +- Why does it matter / what problem does it solve for the user? + +## 2. System Overview (2-3 min) + +- Show your **component diagram** +- Explain the high-level architecture: what are the major pieces, and what does each one own? + +## 3. Deep Dive (5-7 min) + +- Show your **sequence diagram** +- Walk through one complete transaction, step by step, service by service +- Call out the interesting parts: an unexpected hop, an async boundary, a data transformation, a place where things could fail + +## 4. Trade-offs and Alternatives (2-3 min) + +- What are the pros and cons of how this was built? +- What else could have been done instead, and why wasn't it? +- Reference an ADR if you wrote one for this system + +## 5. Q&A (2-3 min) + +- Be ready for follow-up questions about decisions and details +- It's fine to say "I don't know, but here's how I'd find out" — that's often a stronger answer than a guess + +## Delivery Tips + +- **Know your audience.** Presenting to engineers who'll work in this codebase is different from presenting to a manager who wants the executive summary — adjust depth accordingly. +- **Tell a story, not a file listing.** "Here's what happens when a user clicks X" is more engaging (and more useful) than "here are all the services." +- **Use your diagrams as the spine of the talk.** Don't just show them — point at specific parts while you talk through them. +- **Practice against a clock once** before presenting or recording, so you know whether you're going to run long. diff --git a/examples/ch11/templates/presentation-rubric.md b/examples/ch11/templates/presentation-rubric.md new file mode 100644 index 00000000..ef29c2a9 --- /dev/null +++ b/examples/ch11/templates/presentation-rubric.md @@ -0,0 +1,21 @@ +# Presentation Rubric + +Use this rubric to self-assess (or have an instructor/peer assess) an architecture walkthrough presentation. Score each criterion 1-5; a strong presentation scores 4-5 across the board. + +| Criterion | 1 (Needs Work) | 3 (Solid) | 5 (Excellent) | +|---|---|---|---| +| **Clarity** | Hard to follow, disorganized, unclear speech | Understandable with some effort | Easy to follow, well-organized, clear delivery throughout | +| **Accuracy** | Contains clear misunderstandings of the system | Mostly correct, minor inaccuracies | Technically correct throughout, no misunderstandings | +| **Completeness** | Missing required topics (overview, transaction flow, or trade-offs) | Covers all required topics at a surface level | Covers all required topics with real depth and specific detail | +| **Effective Use of Diagrams** | Diagrams are absent, unclear, or not referenced during the talk | Diagrams are shown and roughly explained | Diagrams are clear, properly explained, and actively used to support the narrative | +| **Time Management** | Significantly under or over the 10-15 minute target | Close to the target, minor overrun/underrun | Within the 10-15 minute target | +| **Q&A Handling** | Unable to answer basic follow-up questions | Answers most questions, occasionally unsure | Answers confidently, and clearly acknowledges the limits of their own knowledge when appropriate | + +## Required Topics Checklist + +A complete presentation must cover: + +- [ ] System/feature overview and its purpose +- [ ] Component diagram and high-level architecture +- [ ] Sequence diagram walking through one complete transaction +- [ ] At least one architectural trade-off or decision, with reasoning diff --git a/examples/ch11/templates/readme-enhancement-checklist.md b/examples/ch11/templates/readme-enhancement-checklist.md new file mode 100644 index 00000000..573fbd62 --- /dev/null +++ b/examples/ch11/templates/readme-enhancement-checklist.md @@ -0,0 +1,18 @@ +# README Enhancement Checklist + +Use this checklist when documenting (or reviewing) an application's architecture in a README. Check off each section as you complete it — a good architecture README covers all of these, even briefly. + +- [ ] **System Overview** — a 1-2 paragraph description a new teammate could read in 30 seconds and understand what the system does +- [ ] **Architecture Diagram** — a component or system diagram showing the major pieces and how they connect +- [ ] **Service Responsibilities** — what does each service/component actually do? (one line each is fine) +- [ ] **Communication Patterns** — how do services talk to each other? (HTTP/REST, gRPC, message queue, sync vs. async) +- [ ] **Data Storage** — what databases, caches, or message queues exist, what lives in each, and who owns them +- [ ] **Technology Stack** — languages, frameworks, and key libraries per component +- [ ] **Key Architectural Decisions** — link to ADRs, or briefly explain the "why" behind non-obvious choices +- [ ] **Setup and Running** — how does someone get this running locally, from a clean checkout, with actual commands + +## What "Good" Looks Like + +- Each section is **accurate** — verified against the code, not guessed from the UI or remembered from a meeting +- Each section is **current** — a README describing a system as it was six months ago is worse than no README, because it actively misleads +- The **audience** is a competent engineer who has never seen this system before — not a co-author who already knows the context diff --git a/examples/ch11/templates/transaction-tracing-template.md b/examples/ch11/templates/transaction-tracing-template.md new file mode 100644 index 00000000..dc056a8a --- /dev/null +++ b/examples/ch11/templates/transaction-tracing-template.md @@ -0,0 +1,38 @@ +# Transaction Trace: [Transaction Name] + +> Copy this template and fill in each section as you trace a transaction through a multi-service system. Delete the guidance text (in blockquotes) as you go. + +## Transaction Name + +> A short, specific name for the user-facing action you're tracing, e.g. "Add item to cart" or "Place order." + +## Entry Point + +> The URL/endpoint and HTTP method a client first calls to kick off this transaction, e.g. `POST /api/cart` on the frontend. + +## Services Involved + +> List every service the transaction touches, in the order it touches them, with a one-line description of that service's role in this transaction. + +| Service | Role in this transaction | +|---|---| +| | | + +## Request Flow + +> Step-by-step, service → service, with the protocol and the operation called. Number each step. + +1. `Client` → `ServiceA`: ... +2. `ServiceA` → `ServiceB`: ... + +## Data Transformations + +> What does the data look like at each step? Where does its shape or content change (form data → JSON → protobuf → SQL row, etc.)? + +## Potential Failure Points + +> Where could this transaction break? What happens if a downstream service is slow, returns an error, or is unreachable? Does the caller retry, time out, or fail the whole request? + +## Notes + +> Anything else worth recording: surprising design choices, dead ends you investigated, questions you couldn't answer from the code alone. diff --git a/package.json b/package.json index 23740a94..75d8a9df 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,53 @@ "url": "https://github.com/liatrio/devops-bootcamp/issues" }, "homepage": "https://github.com/liatrio/devops-bootcamp#readme", + "cspell": { + "version": "0.2", + "ignorePaths": ["**/node_modules/**", "**/.venv/**", "docs/specs/**"], + "words": [ + "OLJCESPC", + "diffable", + "Lucidchart", + "Valkey", + "valkey", + "startuml", + "skinparam", + "enduml", + "bootcamp", + "hostfs", + "otelcol", + "bootcamper", + "healthcheck", + "loadgen", + "opensearch", + "crawlable", + "grpcurl", + "blockquotes", + "venv", + "chartjs", + "wordcloud", + "keypair", + "techdocs", + "llms", + "vmss", + "VMSS", + "pairprogramming", + "sonarqube", + "Qube", + "Taskfile", + "Dockerhub", + "Hashicups", + "hpas", + "productionalized", + "Gitea", + "kustomization", + "Logomark", + "quizdown", + "equivillant", + "leanred", + "pathes" + ] + }, "dependencies": { "chart.js": "^4.3.0", "chartjs-chart-wordcloud": "^4.2.0",