Introducción a la clase
Hemos explorado diferentes arquitecturas, sus ventajas y aplicaciones en la industria. Sin embargo, durante la implementación es común cometer errores que pueden afectar la escalabilidad, el mantenimiento y la eficiencia del software.
En esta clase aprenderás:
- Los errores más frecuentes al aplicar Clean Architecture, Hexagonal y Vertical Slice
- Cómo identificar y corregir problemas de diseño en la arquitectura
- Buenas prácticas para evitar estos errores en proyectos reales
Errores Comunes en Clean Architecture
1. Acoplar la lógica de negocio con la infraestructura
- Error: Acceder directamente a la base de datos desde los casos de uso
- Problema: Hace que la lógica de negocio dependa de tecnologías específicas
- Solución: Usar interfaces (puertos) y separar la infraestructura en adaptadores
Ejemplo incorrecto:
public class CrearPedidoUseCase
{
private readonly AppDbContext _context;
public CrearPedidoUseCase(AppDbContext context)
{
_context = context;
}
public void Ejecutar(Pedido pedido)
{
_context.Pedidos.Add(pedido);
_context.SaveChanges();
}
}
Ejemplo corregido usando un puerto:
public interface IPedidoRepository
{
void Guardar(Pedido pedido);
}
public class CrearPedidoUseCase
{
private readonly IPedidoRepository _repository;
public CrearPedidoUseCase(IPedidoRepository repository)
{
_repository = repository;
}
public void Ejecutar(Pedido pedido)
{
_repository.Guardar(pedido);
}
}
2. Exceso de abstracciones innecesarias
- Error: Crear interfaces para todo, incluso cuando no es necesario
- Problema: Hace que el código sea más difícil de leer y mantener
- Solución: Usar abstracciones solo cuando realmente ayudan al desacoplamiento
Ejemplo innecesario:
public interface IUsuarioService
{
void CrearUsuario(Usuario usuario);
}
public class UsuarioService : IUsuarioService
{
public void CrearUsuario(Usuario usuario)
{
// Lógica de creación
}
}
Mejor alternativa:
public class UsuarioService
{
public void CrearUsuario(Usuario usuario)
{
// Lógica de creación
}
}
Errores Comunes en Hexagonal Architecture
3. No definir correctamente los puertos (Interfaces mal diseñadas)
- Error: Crear puertos con métodos que dependen de la infraestructura
- Problema: No se logra el desacoplamiento total
- Solución: Los puertos deben contener solo la lógica necesaria para la aplicación
Ejemplo incorrecto:
public interface IPedidoRepository
{
void Guardar(Pedido pedido);
Pedido ObtenerPorId(int id);
string ObtenerCadenaDeConexion(); // Esto está mal, depende de la infraestructura
}
Ejemplo corregido:
public interface IPedidoRepository
{
void Guardar(Pedido pedido);
Pedido ObtenerPorId(int id);
}
4. Crear demasiados adaptadores innecesarios
- Error: Cada repositorio tiene su propio adaptador aunque sean similares
- Problema: Duplica código y hace difícil la mantención
- Solución: Usar una estructura común para adaptadores que puedan compartir lógica
Ejemplo de adaptación innecesaria:
public class PedidoSqlRepository : IPedidoRepository { ... }
public class PedidoMongoRepository : IPedidoRepository { ... }
Mejor alternativa:
public class PedidoRepository : IPedidoRepository
{
private readonly IDbContext _context;
public PedidoRepository(IDbContext context)
{
_context = context;
}
public void Guardar(Pedido pedido)
{
_context.Add(pedido);
_context.SaveChanges();
}
public Pedido ObtenerPorId(int id)
{
return _context.Pedidos.FirstOrDefault(p => p.Id == id);
}
}
Errores Comunes en Vertical Slice Architecture
5. No reutilizar código común entre Features
- Error: Cada Feature implementa su propia validación, lógica de autorización y acceso a datos
- Problema: Genera código duplicado y difícil de mantener
- Solución: Crear servicios compartidos o middleware para lógica repetitiva
Ejemplo incorrecto:
public class CrearPedidoHandler
{
public void Handle(CrearPedidoCommand command)
{
if (command.Cliente == "")
throw new Exception("Cliente requerido");
if (!command.Productos.Any())
throw new Exception("Debe incluir productos");
// Lógica de creación...
}
}
Ejemplo corregido con validación reutilizable:
public class CrearPedidoValidator : AbstractValidator<CrearPedidoCommand>
{
public CrearPedidoValidator()
{
RuleFor(x => x.Cliente).NotEmpty();
RuleFor(x => x.Productos).NotEmpty();
}
}
6. No definir una estructura clara de Features
- Error: Features mezcladas sin estructura clara
- Problema: A medida que crece el proyecto, es difícil encontrar código relacionado
- Solución: Mantener una estructura consistente de Features
Ejemplo incorrecto:
/Features
CrearPedidoCommand.cs
ObtenerPedidoQuery.cs
PedidoRepository.cs
Ejemplo corregido:
/Features
/CrearPedido
CrearPedidoCommand.cs
CrearPedidoHandler.cs
CrearPedidoValidator.cs
PedidoRepository.cs
/ObtenerPedido
ObtenerPedidoQuery.cs
ObtenerPedidoHandler.cs
PedidoRepository.cs
Errores Comunes Generales en Arquitectura de Software
7. No usar inyección de dependencias correctamente
- Error: Crear instancias manualmente en el código en lugar de usar un contenedor de IoC
- Problema: Hace que el código sea rígido y difícil de testear
- Solución: Usar inyección de dependencias
Ejemplo incorrecto:
public class PedidoService
{
private readonly PedidoRepository _repository = new PedidoRepository();
}
Ejemplo corregido con inyección de dependencias:
public class PedidoService
{
private readonly IPedidoRepository _repository;
public PedidoService(IPedidoRepository repository)
{
_repository = repository;
}
}
8. No realizar pruebas unitarias en la lógica de negocio
- Error: Probar solo controladores y no la lógica interna
- Problema: Si el código cambia, no hay garantías de que siga funcionando correctamente
- Solución: Implementar pruebas unitarias en la lógica del dominio
Ejemplo de prueba de un agregado:
[Fact]
public void PedidoDebeCalcularTotalCorrectamente()
{
var pedido = new Pedido(1, "Cliente1");
pedido.AgregarProducto(new Producto(1, "Producto1", 100));
pedido.AgregarProducto(new Producto(2, "Producto2", 200));
Assert.Equal(300, pedido.CalcularTotal());
}
Cuestionario de Autoevaluación
- ¿Por qué es importante separar la lógica de negocio de la infraestructura?
- ¿Cuándo una abstracción es innecesaria en Clean Architecture?
- ¿Cómo asegurarte de que un puerto en Hexagonal Architecture esté bien diseñado?
- ¿Qué estrategia puedes usar en Vertical Slice Architecture para evitar código duplicado?
- ¿Por qué es recomendable usar validaciones centralizadas en Vertical Slice Architecture?
Resumen de la Clase
- Evitar acoplar la lógica de negocio con la infraestructura
- No crear abstracciones innecesarias que complican el mantenimiento
- Diseñar correctamente los puertos y adaptadores en Hexagonal Architecture
- Mantener una estructura clara y evitar código duplicado en Vertical Slice Architecture
- Usar inyección de dependencias y pruebas unitarias para garantizar la calidad del código
Próximo paso
En la siguiente clase veremos Patrones avanzados y combinaciones entre arquitecturas para construir sistemas escalables y flexibles.