Skip to main content

ADR-004: Architecture Style — Modular Monolith First

Status: Accepted Date: 2026-03-16

Context

The PowerBuilder desktop app is a monolith — all business logic runs in a single process. For the SaaS rebuild, the team considered whether to jump directly to microservices or start with a modular approach.

Options considered:

  • Microservices from day one: Each bounded context is a separate service with its own database
  • Modular monolith: Bounded contexts as separate .NET projects sharing a single process, extracted to services only when needed
  • Traditional monolith: Everything in one project, refactor later

Decision

Modular monolith with separate .NET projects per bounded context sharing a single process and database. Extract services only when scale, team autonomy, or deployment velocity demands it.

Key design rules:

  • Each bounded context is a separate .NET class library project
  • Contexts communicate through well-defined interfaces (not direct class references)
  • No circular dependencies between contexts
  • The API host project references all contexts and wires them up via dependency injection
  • Database access is scoped per context (each context owns its tables)

Consequences

Positive:

  • Simpler operations — one deployment, one process, easier debugging
  • Cheaper hosting initially — no service mesh, no inter-service networking
  • Easier refactoring — rename and move within a single solution
  • Natural extraction path — when a context needs independence, its interface is already defined

Negative:

  • All contexts share the same deployment cycle (a change in Pricing requires redeploying everything)
  • Performance-intensive contexts (Pricing, Risk) cannot scale independently without extraction
  • Discipline required to maintain module boundaries — easy to take shortcuts in a monolith

Candidates for future extraction: Pricing and Risk modules are the most likely candidates due to computational intensity and potential need for independent scaling.