El término "Arquitectura Limpia" se usa tan libremente que ha perdido algo de precisión. Quiero ser específico sobre lo que entiendo por ello, por qué importa para los sistemas .NET específicamente, y cómo se ve realmente en un directorio de proyecto real — no solo en un diagrama.

El Problema que Resuelve

La mayoría de las aplicaciones .NET que heredo tienen un defecto estructural crítico: la lógica de negocio depende de la infraestructura. Los controladores consultan directamente la base de datos a través de Entity Framework. Los objetos de dominio heredan de DbContext. Las reglas de negocio están mezcladas en el mismo archivo que el manejo de solicitudes HTTP.

Esto crea un sistema difícil de probar, difícil de cambiar y fuertemente acoplado a sus opciones tecnológicas actuales. Cambiar la base de datos, cambiar el ORM o pasar de REST a gRPC se convierte en un proyecto de varias semanas en lugar de un cambio de configuración.

La Arquitectura Limpia invierte estas dependencias.

Las Cuatro Capas

Dominio — La capa más interna. Contiene entidades de negocio, objetos de valor y lógica de dominio. No tiene dependencias en ningún framework, base de datos o librería externa. Clases C# puras. Aquí es donde viven las reglas de negocio reales.

Domain/
  Entities/
    Order.cs
    Payment.cs
  ValueObjects/
    Money.cs
    CustomerId.cs
  Exceptions/
    InsufficientInventoryException.cs

Aplicación — Orquesta el dominio. Contiene casos de uso (los llamo comandos y consultas, siguiendo la convención CQRS), interfaces para servicios externos y reglas de negocio específicas de la aplicación. Depende solo de la capa de Dominio.

Application/
  Orders/
    Commands/
      PlaceOrderCommand.cs
      PlaceOrderHandler.cs
    Queries/
      GetOrderByIdQuery.cs
      GetOrderByIdHandler.cs
  Interfaces/
    IOrderRepository.cs
    IPaymentGateway.cs
    IEmailService.cs

Las interfaces aquí — IOrderRepository, IPaymentGateway — se declaran en la capa de Aplicación pero se implementan en la capa de Infraestructura. Esta es la inversión de dependencias que hace funcionar toda la estructura.

Infraestructura — Implementa las interfaces declaradas en Aplicación. Contiene configuraciones de Entity Framework, migraciones de base de datos, clientes de API de terceros, servicios de correo y todo lo demás que toca el mundo exterior.

Infrastructure/
  Persistence/
    AppDbContext.cs
    Repositories/
      OrderRepository.cs
    Configurations/
      OrderConfiguration.cs
  ExternalServices/
    StripePaymentGateway.cs
    SendGridEmailService.cs

Presentación — El punto de entrada. Controladores, Razor Pages, endpoints gRPC, workers de fondo. Depende de Aplicación a través de MediatR (o invocación directa de handlers). No sabe nada sobre la base de datos.

Presentation/
  Controllers/
    OrdersController.cs
  Pages/
    Checkout/
      Index.cshtml

La Regla de Dependencia

Las dependencias fluyen solo hacia adentro. Dominio no sabe nada. Aplicación conoce Dominio. Infraestructura conoce Aplicación y Dominio. Presentación conoce Aplicación.

Esto se aplica a nivel de proyecto en .NET — creando archivos .csproj separados para cada capa y usando referencias de proyecto explícitas. Si alguien intenta referenciar Infrastructure desde Domain, es un error de compilación, no un hallazgo de revisión de código.

MediatR y CQRS en la Práctica

Uso MediatR para implementar el patrón comando/consulta en la capa de Aplicación. Cada caso de uso es un handler que recibe un objeto comando o consulta y devuelve un resultado. El controlador despacha a MediatR; MediatR enruta al handler apropiado.

Esto mantiene los controladores delgados (validan entradas, despachan y devuelven resultados) y mantiene la lógica de negocio en handlers donde es testeable de forma aislada — sin necesidad de mockear HttpContext ni la maquinaria del controlador.

Qué Te Aporta Esto

Testeabilidad. Los handlers de Aplicación pueden probarse unitariamente con repositorios mock. Sin necesidad de levantar una base de datos, sin contexto HTTP, sin overhead de test de integración para lógica de negocio pura.

Independencia del framework. Reemplazar Entity Framework con Dapper requiere cambiar solo el proyecto Infrastructure. Las capas de Dominio y Aplicación no se tocan. Hice esta migración en sistemas en vivo sin cambiar una sola regla de negocio.

Desarrollo en paralelo. Los desarrolladores frontend pueden trabajar con implementaciones mock de las interfaces mientras los desarrolladores backend construyen la infraestructura real. Los contratos (interfaces) se definen temprano; las implementaciones vienen después.

Claridad en el onboarding. Los nuevos desarrolladores saben inmediatamente dónde poner las cosas. Las reglas de negocio van en Dominio. La orquestación va en Aplicación. La plomería va en Infraestructura. No hay ambigüedad sobre dónde pertenece una nueva funcionalidad.

El Trade-Off Honesto

La Arquitectura Limpia introduce indirección. Para una aplicación CRUD simple con dos desarrolladores y una vida útil de seis meses, es sobre-ingeniería. La ceremonia de mapear entre capas, definir interfaces para todo y conectar MediatR agrega un overhead real que no siempre está justificado.

La aplico en sistemas que se espera que vivan por años, sean mantenidos por múltiples desarrolladores, o necesiten la capacidad de cambiar su capa de infraestructura sin reconstruir la lógica de negocio. Para los portales B2B y sistemas empresariales en los que típicamente trabajo, se paga sola dentro de la primera adición de funcionalidad importante.

Si estás evaluando la arquitectura de un sistema .NET existente o diseñando uno nuevo, contactáme. Me alegra recorrer qué estructura tiene sentido para tu contexto específico.