Sé que estás pensando (o tal vez gritando), "no es otra pregunta que pregunta ¿dónde está la validación en una arquitectura en capas?!?" Bueno, sí, pero espero que esto sea un poco diferente sobre el tema.
Creo firmemente que la validación toma muchas formas, se basa en el contexto y varía en cada nivel de la arquitectura. Esa es la base para el post - ayudar a identificar qué tipo de validación debe realizarse en cada capa. Además, una pregunta que surge a menudo es a dónde pertenecen las comprobaciones de autorización.
El escenario de ejemplo proviene de una aplicación para un negocio de catering. Periódicamente, durante el día, un conductor puede entregar a la oficina cualquier exceso de efectivo que haya acumulado al llevar el camión de un sitio a otro. La aplicación le permite a un usuario registrar la "caída de efectivo" al recopilar la identificación del conductor y la cantidad. Aquí hay un código esqueleto para ilustrar las capas involucradas:
public class CashDropApi // This is in the Service Facade Layer
{
[WebInvoke(Method = "POST")]
public void AddCashDrop(NewCashDropContract contract)
{
// 1
Service.AddCashDrop(contract.Amount, contract.DriverId);
}
}
public class CashDropService // This is the Application Service in the Domain Layer
{
public void AddCashDrop(Decimal amount, Int32 driverId)
{
// 2
CommandBus.Send(new AddCashDropCommand(amount, driverId));
}
}
internal class AddCashDropCommand // This is a command object in Domain Layer
{
public AddCashDropCommand(Decimal amount, Int32 driverId)
{
// 3
Amount = amount;
DriverId = driverId;
}
public Decimal Amount { get; private set; }
public Int32 DriverId { get; private set; }
}
internal class AddCashDropCommandHandler : IHandle<AddCashDropCommand>
{
internal ICashDropFactory Factory { get; set; } // Set by IoC container
internal ICashDropRepository CashDrops { get; set; } // Set by IoC container
internal IEmployeeRepository Employees { get; set; } // Set by IoC container
public void Handle(AddCashDropCommand command)
{
// 4
var driver = Employees.GetById(command.DriverId);
// 5
var authorizedBy = CurrentUser as Employee;
// 6
var cashDrop = Factory.CreateCashDrop(command.Amount, driver, authorizedBy);
// 7
CashDrops.Add(cashDrop);
}
}
public class CashDropFactory
{
public CashDrop CreateCashDrop(Decimal amount, Employee driver, Employee authorizedBy)
{
// 8
return new CashDrop(amount, driver, authorizedBy, DateTime.Now);
}
}
public class CashDrop // The domain object (entity)
{
public CashDrop(Decimal amount, Employee driver, Employee authorizedBy, DateTime at)
{
// 9
...
}
}
public class CashDropRepository // The implementation is in the Data Access Layer
{
public void Add(CashDrop item)
{
// 10
...
}
}
He indicado 10 ubicaciones donde he visto verificaciones de validación colocadas en el código. Mi pregunta es qué controles, si los hubiera, realizarían en cada una de las siguientes reglas comerciales (junto con los controles estándar de longitud, rango, formato, tipo, etc.):
- El monto de la caída de efectivo debe ser mayor que cero.
- La caída de efectivo debe tener un controlador válido.
- El usuario actual debe estar autorizado para agregar caídas de efectivo (el usuario actual no es el conductor).
Por favor, comparta sus ideas, cómo ha abordado este escenario y las razones de sus elecciones.