Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
413 changes: 413 additions & 0 deletions docs/11-application-development/11.3-system-thinking.md

Large diffs are not rendered by default.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
39 changes: 39 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions docs/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -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**

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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
Expand Down
133 changes: 67 additions & 66 deletions docs/specs/02-spec-system-thinking/02-tasks-system-thinking.md

Large diffs are not rendered by default.

35 changes: 35 additions & 0 deletions examples/ch11/integration-example/README.md
Original file line number Diff line number Diff line change
@@ -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.
37 changes: 37 additions & 0 deletions examples/ch11/integration-example/adr-example.md
Original file line number Diff line number Diff line change
@@ -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
26 changes: 26 additions & 0 deletions examples/ch11/integration-example/diagrams/component.puml
Original file line number Diff line number Diff line change
@@ -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
27 changes: 27 additions & 0 deletions examples/ch11/integration-example/diagrams/dataflow.puml
Original file line number Diff line number Diff line change
@@ -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
39 changes: 39 additions & 0 deletions examples/ch11/integration-example/diagrams/sequence.puml
Original file line number Diff line number Diff line change
@@ -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
29 changes: 29 additions & 0 deletions examples/ch11/integration-example/presentation-outline.md
Original file line number Diff line number Diff line change
@@ -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.
Loading