Capstone: Designing the Architecture for a Real Application
Software Architecture Fundamentals
Chapter 10 · Capstone: Designing the Architecture for a Real Application
Every chapter in this course built one real, verified piece of the same underlying system. This capstone assembles all nine into a single, working whole — OrderRepository (Ch.1–2), PricingEngine behind ports (Ch.7), an EventBus (Ch.6), OrderService/UserService/EmailService (Ch.4–6), and a stateless quote API (Ch.8) — and runs one real order through the whole thing end to end.
Wiring the Full System
Note the one deliberate design choice this capstone adds on top of the individual chapters: OrderService and the quote API both hold a reference to the identical PricingEngine instance — not two separately-constructed ones.
Running One Real Order End to End
quote_price_via_api() before buying — 103.5. They then place the order through order_service.place_order() — the actual charge is 103.5. Identical, matching a manual calculation (100 × 1.15 scarcity, stock 5 < 10, × 0.9 loyalty) exactly. This is Chapter 8's own thick-client lesson, applied a second time on the server side: had the quote endpoint and the order-placement flow used two separately-written pricing implementations instead of one shared PricingEngine, they could have silently diverged the same way the mobile and web clients did.
notification_adapter.notifications_sent shows ['PROD-1', 'PROD-1'] — two low-stock notifications, one from the quote call and one from the actual order. Both calls independently triggered PricingEngine's own scarcity-pricing branch, confirming the quote and the real order didn't just happen to agree — they ran through the exact same decision logic, twice.
user_service.users correctly shows {'USER-1': {'points': 10}}; email_service.sent_emails correctly shows the confirmation message with the right total. OrderService's own source, re-checked here exactly as in Chapter 6, still contains False references to both UserService and EmailService by name. repository.get('ORD-1') correctly stored final_price: 103.5, matching the price actually charged.
A Real ADR for This Design
PricingEngine as a single box, connected to both the order-processing flow and (indirectly, via the Pricing API) the client layer. This capstone's own verified code confirms that diagram wasn't aspirational — it's an accurate picture of what actually got built.
What This Course Doesn't Cover
This course deliberately stopped at a single application's own internal shape. It did not cover how OrderService and UserService would actually be deployed as separate, independently-scalable processes (Chapter 4 measured the network cost of that decision, but didn't build a real deployed system); how the event bus would behave under real concurrent load; or any of the resilience patterns (circuit breakers, retries, rate limiting) a genuinely production system would need once EventBus becomes a real message queue instead of an in-process Python object.
Where This Connects
| This capstone's finding | What it connects to |
|---|---|
| Every component from Chapters 1–9 assembled into one verified, running system | Confirms this course's own chapter-to-chapter continuity wasn't just narrative — the pieces genuinely compose |
| The scope note above (deployment, real message queues, resilience patterns) | Distributed Systems & Scalability — this course's own direct sibling, picking up exactly where this scope note leaves off |
| A real ADR, tested against Chapter 9's own four-question standard | This capstone's own ADR intentionally follows Chapter 9's Context/Decision/Consequences shape, not a shortcut version |
Hands-On Exercises
Run this chapter's own capstone scenario a second time with stock_data = {'PROD-1': 50} (well-stocked, no scarcity pricing) for a non-loyalty customer. Verify the quoted price still matches the actual charged price, and that no low-stock notification fires this time.
Deliberately break this chapter's own guarantee: construct a second, separate PricingEngine instance for the quote API only, while OrderService keeps using the original. Using different stock data for each engine's own adapter, verify the quoted price and actual charged price now genuinely diverge — reproducing Chapter 8's own thick-client bug at the server level.
Using this chapter's own ADR and Chapter 9's own four-question test, verify how many of those four questions this chapter's ADR-007 can actually answer. Identify which section of ADR-007 answers each one.
📄 View solutionChapter 10 Quick Reference — and Course Quick Reference
- This capstone: every verified component from Chapters 1–9 assembled into one working system — a customer's quoted price (
103.5) verified matching the actual charged price exactly, because both paths share onePricingEnginecore - The one new design decision: sharing a single core instance between the quote API and the order-placement flow, documented in a real ADR that passes Chapter 9's own four-question test
- Course arc: Ch.1 (measuring architecture's cost) → Ch.2 (layers) → Ch.3 (MVC variants) → Ch.4 (monolith vs. microservices, measured) → Ch.5 (finding boundaries) → Ch.6 (event-driven decoupling) → Ch.7 (hexagonal architecture, measured) → Ch.8 (stateless APIs, thin clients) → Ch.9 (documenting it all) → Ch.10 (assembling it into one system)
- Where this leads: Distributed Systems & Scalability — this course's own sibling, covering what happens once this system needs to run across multiple machines under real load