Introducción a la clase
Hemos aprendido cómo modelar Entidades, Agregados y Value Objects en Clean Architecture con DDD. Ahora veremos cómo desacoplar dependencias utilizando interfaces e inversión de dependencias, permitiendo que nuestra aplicación sea modular y flexible.
¿Qué obtendrás de esta clase?
- Comprenderás por qué el desacoplamiento es clave en Clean Architecture.
- Aprenderás a usar interfaces para evitar dependencias directas.
- Implementarás el principio de inversión de dependencias con inyección de dependencias.
- Verás ejemplos en C# con interfaces y contenedores de inyección de dependencias.
¿Por qué es importante desacoplar el código?
El desacoplamiento permite que cada módulo o capa de nuestra aplicación funcione independientemente, facilitando la mantenibilidad y testabilidad del código.
Problemas de un código acoplado
- Dificultad para realizar cambios → Si un módulo cambia, otros se ven afectados.
- Baja testabilidad → No se pueden escribir pruebas unitarias sin depender de la infraestructura.
- Dependencia de tecnologías específicas → Si usamos una base de datos SQL y queremos cambiar a NoSQL, el código necesitaría modificaciones en varias partes.
Cómo Clean Architecture desacopla dependencias
En Clean Architecture, el código depende de abstracciones (interfaces), no de implementaciones concretas.
Reglas clave:
- La capa de Aplicación solo usa interfaces, no implementaciones concretas.
- La Infraestructura implementa esas interfaces, permitiendo cambiar tecnologías sin afectar la lógica del negocio.
- Los Casos de Uso interactúan solo con interfaces, haciendo que el código sea más flexible y testeable.
Paso 1: Definir una Interfaz para el Repositorio en la Capa de Aplicación
public interface IPedidoRepository
{
void Guardar(Pedido pedido);
Pedido ObtenerPorId(int id);
}
Paso 2: Implementar la Interfaz en la Capa de Infraestructura
public class PedidoRepository : IPedidoRepository
{
private readonly List<Pedido> _pedidos = new List<Pedido>();
public void Guardar(Pedido pedido)
{
_pedidos.Add(pedido);
Console.WriteLine($"Pedido {pedido.Id} guardado en la base de datos.");
}
public Pedido ObtenerPorId(int id)
{
return _pedidos.FirstOrDefault(p => p.Id == id);
}
}
Aquí, PedidoRepository implementa IPedidoRepository, lo que permite cambiar la infraestructura sin afectar la lógica de la aplicación.
Paso 3: Usar Inyección de Dependencias en los Casos de Uso
public class CrearPedidoUseCase
{
private readonly IPedidoRepository _repository;
public CrearPedidoUseCase(IPedidoRepository repository)
{
_repository = repository;
}
public void Ejecutar(Pedido pedido)
{
_repository.Guardar(pedido);
}
}
Ventajas de este enfoque:
- El Caso de Uso no depende de una implementación concreta.
- Podemos cambiar la base de datos sin afectar la lógica de negocio.
- Facilita la escritura de pruebas unitarias.
Paso 4: Configurar la Inyección de Dependencias en .NET
Para que .NET sepa qué implementación usar al inyectar IPedidoRepository, debemos configurar el contenedor de dependencias en Program.cs.
var builder = WebApplication.CreateBuilder(args);
// Configurar inyección de dependencias
builder.Services.AddScoped<IPedidoRepository, PedidoRepository>();
builder.Services.AddScoped<CrearPedidoUseCase>();
var app = builder.Build();
Paso 5: Uso del Caso de Uso en el Controlador
[ApiController]
[Route("api/pedidos")]
public class PedidoController : ControllerBase
{
private readonly CrearPedidoUseCase _crearPedidoUseCase;
public PedidoController(CrearPedidoUseCase crearPedidoUseCase)
{
_crearPedidoUseCase = crearPedidoUseCase;
}
[HttpPost]
public IActionResult CrearPedido([FromBody] Pedido pedido)
{
_crearPedidoUseCase.Ejecutar(pedido);
return Ok("Pedido creado exitosamente");
}
}
Cómo la Inversión de Dependencias mejora Clean Architecture
El Principio de Inversión de Dependencias (D de SOLID) establece que:
- Los módulos de alto nivel no deben depender de módulos de bajo nivel, sino de abstracciones.
- Las abstracciones no deben depender de detalles, sino que los detalles dependen de abstracciones.
En nuestro ejemplo:
- El Caso de Uso (CrearPedidoUseCase) no depende de una implementación específica de IPedidoRepository.
- La implementación de PedidoRepository puede cambiar sin afectar la lógica de aplicación.
- Podemos hacer pruebas unitarias creando una versión «falsa» de IPedidoRepository.
Errores comunes al desacoplar código
- No definir interfaces en la Capa de Aplicación → La aplicación termina dependiendo de la infraestructura.
- Solución: Definir interfaces en la Capa de Aplicación y solo implementarlas en Infraestructura.
- Inyectar implementaciones concretas en los Casos de Uso → Hace que el código sea difícil de cambiar y probar.
- Solución: Siempre inyectar interfaces en lugar de clases concretas.
- No registrar las dependencias en el contenedor de inyección → Genera errores en tiempo de ejecución.
- Solución: Configurar las dependencias correctamente en
Program.cs
.
- Solución: Configurar las dependencias correctamente en
Cuestionario de Autoevaluación
- ¿Por qué es importante usar interfaces en Clean Architecture?
- ¿Qué beneficios tiene la inversión de dependencias en la mantenibilidad del código?
- ¿Cómo se implementa la inyección de dependencias en .NET?
- ¿Por qué el Caso de Uso no debe depender directamente de la Infraestructura?
- ¿Cómo se puede hacer una prueba unitaria de un Caso de Uso usando una interfaz?
Resumen de la Clase
- El desacoplamiento es clave en Clean Architecture para mejorar la flexibilidad y mantenibilidad.
- Los Casos de Uso deben depender de interfaces y no de implementaciones concretas.
- La Infraestructura implementa las interfaces de la Aplicación, permitiendo cambiar tecnologías sin afectar la lógica del negocio.
- Usar Inyección de Dependencias permite que .NET resuelva automáticamente las dependencias en tiempo de ejecución.
Próximo paso
En la siguiente clase veremos cómo implementar la persistencia y controladores en Clean Architecture con DDD, integrando todo lo aprendido hasta ahora.