← Back

Software Architecture

The main enemy is accidental complexity. Every architecture decision should reduce cognitive load, enable parallel work, minimize change amplification, make decisions explicit, and be understandable by new team members.

Start with a Modular Monolith

Default to a modular monolith. It gives monolith speed with the structure to scale later.

  • Monorepo is the intermediate step — reuse without microservices complexity.
  • Microservices only when teams require complete isolation. Even then, it depends on the team and situation. Microservices add real complexity. Do not reach for them early.

Decision path: monolith → monorepo → microservices. Each transition is driven by constraints (team independence, deployment isolation), not taste.

Vertical Slices per Module

Each module follows: domain / application / infrastructure / shared (public API).

  • Each module owns its domain and exposes a clear public API through a Facade.
  • No cross-module direct imports. Use the Facade.
  • Domain never depends on infrastructure.
  • Application orchestrates.
  • Infrastructure implements.
  • No circular dependencies.

Screaming Architecture

The codebase should scream what the system does, not what framework it uses. Preferred patterns: Clean Architecture, DDD, Screaming Architecture.

  • Folder structure reveals the business domain, not the framework.
  • Framework concepts (Express, Next.js) stay in infrastructure — never in business logic.
  • Names reflect business language. Domain terminology is sacred.

DDD Enforcement

  • Entities are behavioral, not data bags. They have methods and computed properties.
  • Entities are immutable. Always return new objects to avoid side effects.
  • Use object parameters when more than 2 arguments.
  • Domain DTOs expose computed methods. Avoid assignment-order dependency.
  • Facades are the only place where use cases can be combined.

Abstractions Grow Through Understanding

Good abstractions are not designed upfront. Build, learn the real boundaries, refine. You cannot skip this discovery with a prompt or upfront design.

  • PoCs: anything goes — speed wins.
  • Production: clear layers and boundaries are essential. Well-defined abstraction rules are how you trust AI-generated code.

Architecture Is a Team Exercise

Module ownership, clear boundaries, and reduced change amplification — these are architecture decisions that are also team decisions. The goal is systems that last 10+ years, enable independent teams, and reduce fear of change.

Architecture should change because constraints changed, not because engineers want something shinier.

Evolution

  • Feb 2026 — rewritten in rule-oriented format from architecture evolution article, IDENTITY.md positions, and code review patterns.