Cómo no ahogarse en espaguetis: Arquitectura Hexagonal en C#

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Cuando el proyecto se convierte en un desastre

¿Alguna vez has abierto un proyecto de C# escrito hace un año y te has dado cuenta con horror de que nada se puede cambiar sin riesgo de romperlo todo? La lógica de negocio está estrechamente entrelazada con Entity Framework, los controladores ASP.NET guardan secretos de la base de datos, y las pruebas unitarias se convierten en una integración infernal con la BD real. ¿Te suena?

Este es el síntoma clásico de la falta de arquitectura. La buena noticia: existe una receta probada: la Arquitectura Hexagonal (también conocida como Ports & Adapters). Este patrón, ideado por Alistair Cockburn, no es solo un término de moda. Es un salvavidas para proyectos medianos y grandes en C#. Analicemos cómo funciona y escribamos código de inmediato.



La esencia de la Arquitectura Hexagonal: núcleo y periferia

Imagina un hexágono. En el centro está tu aplicación con lógica de negocio pura, escrita en C# puro sin dependencias externas. En los bordes están los puertos (interfaces) a través de los cuales el núcleo se comunica con el mundo exterior. Los adaptadores son las implementaciones concretas: controladores ASP.NET, repositorios EF Core, clientes RabbitMQ.

La regla principal: el núcleo no sabe nada del mundo exterior. Solo conoce sus puertos. Esto permite cambiar la base de datos, la UI o las colas de mensajes sin modificar la lógica de negocio.



¿Por qué es útil para un desarrollador C#?

  • Capacidad de prueba: La lógica de negocio se puede probar sin BD, HTTP ni sistema de archivos.
  • Flexibilidad: ¿Quieres reemplazar PostgreSQL por MongoDB? Solo cambias el adaptador.
  • Legibilidad: El código se vuelve similar a una especificación de requisitos, no a una maraña de dependencias.
  • Cumplimiento de SOLID: Especialmente el principio de inversión de dependencias (Dependency Inversion).


Estructura del proyecto en C#

En la Arquitectura Hexagonal normalmente se distinguen tres capas principales. Para C#, es conveniente organizarlas como proyectos separados en una misma solución:



MyApp.sln├── MyApp.Domain          // Núcleo: entidades, value objects, puertos (interfaces)├── MyApp.Application     // Casos de uso (servicios de aplicación)├── MyApp.Infrastructure  // Adaptadores: EF Core, APIs externas, logging└── MyApp.Api             // Adaptador de entrada: ASP.NET Controllers / Minimal API


Observa que Domain y Application son bibliotecas de clases puras sin referencias a Microsoft.AspNetCore o EntityFramework. Solo System y System.Threading.Tasks.



Escribimos código: ejemplo real

Supongamos que estamos creando un sistema de pedidos. Necesitamos crear un pedido y guardarlo.



Paso 1. Núcleo (Domain)

Aquí viven las entidades y los puertos — interfaces que definen cómo el núcleo se comunica con el mundo.



// MyApp.Domain/Entities/Order.cspublic class Order{    public Guid Id { get; private set; }    public string CustomerName { get; private set; }    public decimal TotalAmount { get; private set; }    public DateTime CreatedAt { get; private set; }

public Order(string customerName, decimal totalAmount) { Id = Guid.NewGuid(); CustomerName = customerName; TotalAmount = totalAmount; CreatedAt = DateTime.UtcNow; }}

// MyApp.Domain/Ports/IOrderRepository.cs (Puerto de salida)public interface IOrderRepository{ Task<Order> GetByIdAsync(Guid id); Task AddAsync(Order order);}

// MyApp.Domain/Ports/IOrderNotifier.cs (Puerto de salida — notificaciones)public interface IOrderNotifier{ Task NotifyOrderCreatedAsync(Order order);}


Observa: IOrderRepository e IOrderNotifier son los puertos. El núcleo define qué quiere, pero no cómo se implementa.



Paso 2. Casos de uso

Blogs

Book Recommendations