2.1 Top-Down vs. Bottom-Up

When faced with designing a system's architecture, architects generally follow one of two broad strategies — or, most commonly, a blend of both.

Top-Down Design

Start from the overall system and decompose into smaller parts. You begin with the big picture — the system boundary, its major responsibilities, the external systems it interacts with — and progressively break it down into subsystems, components, and modules.

Top-down works well when you have a clear understanding of the domain and the requirements are reasonably well-known. It's the natural approach for greenfield projects where you're starting from scratch.

Bottom-Up Design

Start from known building blocks and compose them into a larger system. You begin with existing components, libraries, services, or legacy systems and figure out how to combine them into a coherent whole.

Bottom-up is common in brownfield projects — where you're modernizing an existing system, integrating legacy components, or building on top of established platforms. You're constrained by what already exists.

Mixed / Iterative Approach

In practice, most architects use both approaches simultaneously. You sketch the top-level structure (top-down), then validate it against known components and constraints (bottom-up), and iterate. This "meet in the middle" strategy is the most realistic approach for real-world projects.

ApproachStarting PointBest ForRisk
Top-DownSystem as a wholeGreenfield, well-understood domainsMay ignore technical realities
Bottom-UpExisting componentsBrownfield, legacy modernizationMay lack coherent overall structure
MixedBoth — iterateMost real-world projectsRequires discipline to converge
The exam may ask which approach is most common in practice — the answer is mixed/iterative.

2.2 Decomposition and Modularization

Decomposition is the act of breaking a complex system into smaller, manageable pieces. It's the most fundamental technique in software architecture — and arguably in all of engineering. The question is: how do you decide where to draw the boundaries?

Why Decompose?

  • Manage complexity — Humans can only hold so much in their heads at once. Smaller pieces are easier to understand.
  • Enable parallel development — Independent teams can work on different building blocks simultaneously.
  • Support independent deployment — Well-decomposed systems allow deploying parts independently (critical for microservices).
  • Improve maintainability — Changes in one area shouldn't require changes everywhere else.
  • Enable reuse — Well-defined building blocks with clean interfaces can be reused across projects.

Decomposition Criteria

There is no single "correct" way to decompose a system. The criteria you use depend on your context, priorities, and constraints:

📦 DECOMPOSITION CRITERIA Functional / Domain-based decomposition Technical layers (UI, Logic, Data) Use-case / Process-based decomposition Quality-driven (performance, security hotspots) Team-structure-aligned (Conway's Law)

Domain-based decomposition is generally preferred for business applications because it aligns the system structure with the business structure. When a business capability changes, only the corresponding building block needs to change. This is the central idea behind Domain-Driven Design.

Technical decomposition (layers) is simpler to understand but tends to cause problems at scale: a single business change may require modifications across all layers (UI, logic, data), leading to high coordination overhead.

The best decomposition maximizes cohesion (related things together) and minimizes coupling (dependencies between pieces). This principle applies at every level of granularity.

2.3 Conway's Law

"Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations."
Melvin Conway, 1967

This is not just an observation — it's a force of nature in software engineering. If your organization has a frontend team, a backend team, and a database team, your system will naturally end up with a frontend layer, a backend layer, and a database layer — regardless of whether that's the best architecture for the problem.

Conway's Law has profound implications for architects:

  • Your architecture is constrained by your org structure whether you plan for it or not
  • If you want to change your architecture, you may need to change your team structure first
  • Cross-team interfaces will become the most important (and most fragile) parts of your system

The Inverse Conway Maneuver

Instead of letting your org structure accidentally shape your architecture, deliberately design your team structure to produce the architecture you want. This is called the Inverse Conway Maneuver.

For example, if you want a microservices architecture with independent services for "Orders," "Payments," and "Inventory," create teams aligned to those domains — not teams aligned to technical layers.

Domain-Driven Design (DDD) — Going Deeper

The CPSA-F curriculum mentions DDD briefly, but it's become one of the most influential approaches to architecture design, especially for microservices. Key DDD concepts:

Bounded Contexts

A bounded context is a clear boundary within which a particular domain model is defined and applicable. Inside the boundary, terms have specific meanings. Different bounded contexts can use the same word to mean different things — and that's OK.

DDD Bounded Contexts — Same Word, Different Models Sales Context Customer name, email, purchaseHistory, preferences, loyaltyTier Order items, discount, total, status Ubiquitous Language: "Customer", "Order", "Discount", "Cart" Shipping Context Customer name, shippingAddress, phone, deliveryPreference Shipment trackingId, carrier, weight, ETA Ubiquitous Language: "Recipient", "Shipment", "Carrier", "Route" ACL / API ⚠️ "Customer" means DIFFERENT things in each context — and that's intentional

For example, "Customer" in the Sales context might include purchase history and preferences, while "Customer" in the Shipping context might only include name and address. These are two different models with the same name.

Ubiquitous Language

Within a bounded context, everyone — developers, domain experts, testers — uses the same language to describe concepts. This language is used in conversations, documentation, and code. If the code says Order, the business says "Order," not "Purchase Request."

Context Mapping

When bounded contexts need to interact, you define explicit relationships between them:

  • Partnership — Two teams cooperate closely, evolving their models together
  • Customer-Supplier — Upstream team provides what downstream team needs
  • Conformist — Downstream team adopts the upstream model as-is
  • Anti-Corruption Layer (ACL) — Downstream team translates the upstream model into its own model
  • Shared Kernel — Two contexts share a small, explicitly managed model subset

Context mapping is critical for microservices architectures because it determines how services communicate and evolve independently.


Summary

ConceptKey Takeaway
Top-downDecompose from the whole — good for greenfield
Bottom-upCompose from parts — good for brownfield/legacy
MixedMost common in practice — iterate between both
DecompositionGoal: high cohesion, low coupling — domain-based is generally preferred
Conway's LawSystem structure mirrors org structure — plan for it
DDDBounded contexts, ubiquitous language, context mapping