Arquitectura8 MINUTOS DE LECTURA

Diseño de Arquitecturas Hexagonales en Sistemas Distribuidos

Patrones prácticos para aislar la lógica de dominio central de la infraestructura, adapters externos y protocolos de transporte.

Equipo Klyntex
#Arquitectura Limpia#DDD#Hexagonal#TypeScript#Sistemas Distribuidos
Tecnologías:Node.jsTypeScriptDockerPostgreSQLRedis

La evolución de sistemas monolíticos hacia servicios distribuidos a menudo introduce acoplamientos accidentales si no se establecen fronteras arquitectónicas claras. En Klyntex Studio, el patrón de Puertos y Adaptadores (Arquitectura Hexagonal) constituye el estándar fundamental para desacoplar las reglas de negocio de los detalles de implementación tecnológica.

1. El Núcleo de Dominio Libre de Dependencias

El principio rector es la inversión de dependencias: el núcleo de dominio (Domain Entities, Value Objects, Domain Events) nunca debe importar librerías de persistencia (como Prisma, Drizzle o TypeORM), ni frameworks de transporte (Express, Fastify o gRPC).

// src/core/domain/entities/order.entity.ts
export interface OrderProps {
  id: string;
  customerId: string;
  totalAmount: number;
  status: 'PENDING' | 'SETTLED' | 'CANCELLED';
}

export class Order {
  private constructor(private readonly props: OrderProps) {}

  public static create(customerId: string, totalAmount: number): Order {
    if (totalAmount <= 0) {
      throw new Error('El importe total debe ser estrictamente positivo');
    }
    return new Order({
      id: crypto.randomUUID(),
      customerId,
      totalAmount,
      status: 'PENDING',
    });
  }

  public settle(): void {
    if (this.props.status !== 'PENDING') {
      throw new Error('Solo órdenes en estado pendiente pueden ser liquidadas');
    }
    this.props.status = 'SETTLED';
  }

  public get snapshot(): Readonly<OrderProps> {
    return Object.freeze({ ...this.props });
  }
}

2. Puertos (Inbound & Outbound)

Los puertos definen los contratos formales a través de interfaces TypeScript estrictas:

  • Primary / Driving Ports (Inbound): Casos de uso invocados por clientes HTTP, colas o tareas programadas.
  • Secondary / Driven Ports (Outbound): Interfaces que el dominio requiere para persistir datos o emitir notificaciones.
// src/core/ports/order-repository.port.ts
import type { Order } from '../domain/entities/order.entity';

export interface OrderRepositoryPort {
  findById(id: string): Promise<Order | null>;
  save(order: Order): Promise<void>;
}

3. Beneficios Observados en Producción

  1. Testabilidad pura: Las suites unitarias del dominio se ejecutan en microsegundos sin necesidad de levantar bases de datos ni contenedores Docker.
  2. Sustituibilidad de infraestructura: Es posible migrar de PostgreSQL a DynamoDB o introducir capas de caché Redis modificando únicamente adaptadores aislados.
  3. Mantenibilidad a largo plazo: La deuda técnica se mantiene controlada al evitar filtraciones de abstracción.
DEBATE TÉCNICO

¿Quieres comentar esta arquitectura o plantear un caso de uso?

Escríbenos directamente para intercambiar enfoques, discutir compensaciones técnicas o evaluar cómo aplicar estos patrones en tu organización.

Las marcas y nombres de productos mencionados pertenecen a sus respectivos propietarios y se citan únicamente con fines identificativos; su mención no implica patrocinio ni afiliación. El contenido es informativo y se ofrece tal cual, sin garantías.