Service Architecture
Clean Architecture, Ports and Adapters, and internal service design.
Service Architecture
While System Architecture defines how WordLoop's components communicate, Service Architecture dictates how we build the software inside those components.
We embrace Ports and Adapters (often referred to as Hexagonal or Clean Architecture) as our foundational pattern.
The Core Strategy
We use Clean Architecture because protecting our core domain logic provides immense engineering agility. By isolating our business rules from external dependencies, we can test comprehensively and confidently swap infrastructure (like databases or third-party APIs) as our needs evolve.
Ports and Adapters
We construct a strict boundary around our core domain logic by breaking code into three layers:
- The Domain (The Center): This is pure language code representing what our application does. It defines the business rules natively without relying on external frameworks, database drivers, or HTTP libraries.
- Ports (The Boundaries): The domain defines interfaces (Ports) describing what it needs to drive (e.g., "save a domain entity") or what drives it (e.g., "create a user account"). The domain owns these definitions completely.
- Adapters (The Infrastructure): Adapters implement the Ports to connect the exact infrastructure. A REST Handler Adapter converts an HTTP payload into domain objects, while a PostgreSQL Adapter implements a storage Port to persist domain entities.
Principles of Clean Architecture at WordLoop
1. Inward Dependency
Code dependencies flow inward, pointing exclusively toward the domain. The domain focuses purely on business logic, while the adapters translate external concepts into domain concepts.
2. Built-In Testability
Isolating the domain from infrastructure allows us to test our logic instantly and deterministically. We execute massive suites of business rule tests locally using fast, in-memory mock implementations of our Ports, providing millisecond-level feedback loops.
3. Progressive Elaboration
This architecture empowers us to build and verify the entire behavior of a feature before making infrastructure commitments. The domain defines what infrastructure is necessary, allowing us to defer decisions on database technologies or cloud resources until the business logic is fully proven.
The Frontend Nuance
While our backend services (Go, Python) strictly structure their physical directories as core/, providers/, and entrypoints/, full-stack frontend frameworks require a pragmatic adaptation.
We build our web application using Next.js. Modern frontend frameworks derive immense performance, caching, and developer experience benefits from deeply opinionated file-system routing (e.g., the Next.js App Router). Forcing a literal core/ and providers/ folder structure over a Next.js app actively fights the framework and destroys its native capabilities.
Instead of fighting the framework, we map the concepts of Clean Architecture to the standard Next.js layout:
- Inbound Adapters: The Next.js
app/directory (React Server Components and Route Handlers) acts as the entrypoint. Sub-components (components/) handle presentation. - The Core: Custom hooks (
hooks/) and pure validation schemas (lib/) orchestrate local business logic. - Providers: Generated API clients (
lib/providers/) manage external side-effects, guaranteeing that React components never manually constructfetch()calls.
This ensures we maintain absolute architectural discipline—separating I/O and side-effects from pure UI representation—without sacrificing the native power of our chosen frontend tooling.