0

Arquitectura de Software con C# 11: Interfaces y Dependencias – Cómo Desacoplar Código en Clean Architecture

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:

  1. Los módulos de alto nivel no deben depender de módulos de bajo nivel, sino de abstracciones.
  2. 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.

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.

Fernando Sonego

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *