Key Architecture Concepts

Coupling, cohesion, separation of concerns, SOLID principles applied to architecture, and bounded contexts.

Building a shared language

Before diving into distributed architecture, it’s worth establishing a shared vocabulary. These terms will come up again and again throughout the entire platform.

Many technical decisions seem complex only because shared definitions are missing. In this section we’ll build that common language along with the principles that guide architectural decisions.

Domain

This is the area of the business that the software aims to address. For example: users, products, orders, payments, inventory.

The domain is not a technical concept but a business one. Understanding the domain is the first step toward designing a good architecture.

Subdomain

A specific part within the overall business domain. It helps break the problem down into more manageable areas.

Bounded Context

An explicit boundary within which certain terms, models, and rules carry a concrete meaning.

Why do they matter?

In a large system, the same word can mean different things depending on the context:

  • β€œUser” in authentication: email, password, roles.
  • β€œUser” in billing: legal name, address, payment method.
  • β€œUser” in support: ticket history, satisfaction level.

Each bounded context has its own model with the attributes it needs.

Mapping to architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   AutenticaciΓ³n  β”‚  β”‚   FacturaciΓ³n    β”‚  β”‚     Soporte      β”‚
β”‚                  β”‚  β”‚                  β”‚  β”‚                  β”‚
β”‚  Usuario:        β”‚  β”‚  Cliente:        β”‚  β”‚  ContactoSoporte:β”‚
β”‚  - email         β”‚  β”‚  - nombre_fiscal β”‚  β”‚  - historial     β”‚
β”‚  - password_hash β”‚  β”‚  - direcciΓ³n     β”‚  β”‚  - satisfacciΓ³n  β”‚
β”‚  - roles         β”‚  β”‚  - mΓ©todo_pago   β”‚  β”‚  - prioridad     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Communication between contexts

  • Well-defined APIs: Explicit contracts between contexts.
  • Domain events: One context publishes events that others consume.
  • Anti-Corruption Layer (ACL): A translation layer that protects one context from changes in another.

DTO (Data Transfer Object)

An object used to transfer data between layers or systems. It doesn’t necessarily represent the internal domain model.

Contract

An explicit definition of how two parties communicate. It can define:

  • Request and response structure
  • Required and optional fields
  • Data types
  • Possible errors
  • Versioning rules

A contract reduces ambiguity and helps systems evolve without breaking consumers.

Event

A relevant fact that has already occurred in the system. For example: OrderPlaced, UserCreated, PaymentConfirmed.

Events are immutable and fundamental in event-driven architectures.

Integration

A connection between distinct systems or components, whether internal or external.

Consistency

The degree to which the data correctly reflects the state of the system.

Strong consistency

Everyone sees the same state immediately.

Eventual consistency

There may be temporary lags until the system converges.

Idempotency

The ability to execute an operation multiple times and get the same result without unwanted duplicate effects.

Coupling

Coupling measures how much one component depends on another.

Types of coupling (from highest to lowest)

  • Content coupling: One module directly modifies another’s internal data. It’s the worst type.
  • Common coupling: Two modules share global variables or mutable state.
  • Control coupling: One module tells another how to do its job (by passing control flags).
  • Data coupling: Modules communicate only through well-defined parameters. It’s the desirable type.

Practical example

// Alto acoplamiento: el servicio de pedidos conoce
// la estructura interna del servicio de usuarios
function crearPedido(usuarioId) {
  const usuario = db.query('SELECT * FROM usuarios WHERE id = ?', usuarioId);
  if (usuario.saldo_cuenta > 0) {
    // Accede directamente a la tabla de otro dominio
  }
}

// Bajo acoplamiento: comunicaciΓ³n a travΓ©s de una interfaz
function crearPedido(usuarioId) {
  const puedeComprar = await servicioUsuarios.verificarCapacidadCompra(usuarioId);
  if (puedeComprar) {
    // No conoce los detalles internos del servicio de usuarios
  }
}

Aim for low coupling between modules. Each component should be able to evolve independently.

Cohesion

Cohesion measures how closely related the responsibilities within a single component are. High cohesion means that everything a module does is tightly related.

Types of cohesion (from lowest to highest)

  • Coincidental: The functions are grouped together by chance, with no logical relationship.
  • Temporal: The functions are grouped because they run at the same time.
  • Functional: All functions contribute to a single, well-defined responsibility. It’s the ideal type.

Practical example

// Baja cohesiΓ³n: este mΓ³dulo hace demasiadas cosas no relacionadas
const utils = {
  formatearFecha(fecha) { /* ... */ },
  calcularImpuesto(monto) { /* ... */ },
  enviarEmail(destinatario, asunto) { /* ... */ },
  validarRUT(rut) { /* ... */ },
};

// Alta cohesiΓ³n: cada mΓ³dulo tiene una responsabilidad clara
const formatoFechas = {
  formatear(fecha, formato) { /* ... */ },
  parsear(texto, formato) { /* ... */ },
  diferencia(fechaA, fechaB) { /* ... */ },
};

The coupling-cohesion relationship

These two concepts are inversely related: when you increase cohesion within a module, you naturally reduce coupling between modules.

Separation of Concerns

Each part of the system should handle a single concern. In architecture, this manifests as layers and modules with clear responsibilities.

Layered example

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   PresentaciΓ³n (UI)     β”‚  β†’ CΓ³mo se muestra la informaciΓ³n
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   LΓ³gica de negocio     β”‚  β†’ QuΓ© reglas aplican
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   Acceso a datos        β”‚  β†’ DΓ³nde y cΓ³mo se almacenan los datos
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

SOLID principles in architecture

The SOLID principles, originally formulated for object-oriented design, also apply at the architectural level:

S β€” Single Responsibility

Each service or module should have one reason to change. If a change in billing rules requires modifying the users service, there’s a design problem.

O β€” Open/Closed

The system should be extensible without modifying what already exists. Plugins, middleware, and event-driven architectures make this easier.

L β€” Liskov Substitution

If a service implements a contract (API), any alternative implementation must be interchangeable without breaking consumers.

I β€” Interface Segregation

Consumers shouldn’t depend on interfaces they don’t use. The BFF (Backend for Frontend) pattern is a direct example of this principle.

D β€” Dependency Inversion

High-level modules shouldn’t depend on low-level modules. Both should depend on abstractions.

// ViolaciΓ³n: la lΓ³gica de negocio depende de PostgreSQL
class ServicioPedidos {
  constructor() {
    this.db = new PostgresClient();
  }
}

// Correcto: depende de una abstracciΓ³n
class ServicioPedidos {
  constructor(repositorio) {
    this.repositorio = repositorio; // Puede ser Postgres, Mongo, en memoria...
  }
}

Practical summary

ConceptKey questionGoal
DomainWhat business problem are we solving?Understand the context
Bounded ContextWhere are the domain boundaries?Clear, autonomous models
ContractHow do the parties communicate?Explicit communication
CouplingHow much does A depend on B?Minimize dependencies
CohesionHow related is what A does?Maximize internal relatedness
ConsistencyDoes the data reflect the real state?Manage expectations
IdempotencyCan I repeat without duplicate effects?Safe operations
SOLIDIs the design extensible and maintainable?Long-term flexibility

These concepts aren’t absolute rules but guides for making better decisions. The clearer this vocabulary is, the easier it will be to understand more advanced design decisions.