"Doğrulamanın katmanlı bir mimaride nereye ait olduğunu soran başka bir soru değil mi?" Evet, ama umarım bu konuya biraz farklı bir bakış getirecektir.
Doğrulamanın pek çok biçim aldığını, bağlam temelli olduğunu ve mimarinin her düzeyinde değiştiğini kesin olarak inanıyorum. Her katmanda ne tür bir doğrulama yapılması gerektiğini belirlemeye yardımcı olan post sonrası için temel budur. Ayrıca, sıkça ortaya çıkan bir soru, yetkilendirme kontrollerinin nereye ait olduğudur.
Örnek senaryo bir catering işletmesi için yapılan başvurudur. Gün boyunca periyodik olarak, bir sürücü kamyonu bir yerden bir yere götürürken birikmiş oldukları fazla parayı ofise teslim edebilir. Uygulama, kullanıcının sürücü kimliğini ve miktarını toplayarak 'nakit düşüşünü' kaydetmesini sağlar. İlgili katmanları gösteren bazı iskelet kodları:
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
...
}
}
Kodda yer alan doğrulama kontrollerini gördüğüm 10 konum belirtmiştim. Benim sorum, aşağıdaki iş kuralları (uzunluk, aralık, biçim, tür, vb. İçin standart denetimlerle birlikte) verildiğinde, her biri için ne tür kontroller yapacağınızdır:
- Nakit düşüş tutarı sıfırdan büyük olmalıdır.
- Nakit düşüşünün geçerli bir Sürücüsü olmalıdır.
- Geçerli kullanıcının nakit damlası ekleme yetkisi olmalıdır (geçerli kullanıcı sürücü değildir).
Lütfen düşüncelerinizi, bu senaryoya nasıl yaklaştığınız veya yaklaşacağınızı ve seçimlerinizin nedenlerini paylaşın.
CashDropAmount
değer yerine bir değer nesnesi alarak burada değer nesneleri kaldırabileceğini düşünüyorum Decimal
. Sürücünün var olup olmadığını kontrol etmek, komut işleyicide yapılacaktır ve aynısı yetkilendirme kuralları için de geçerlidir. Approver approver = approverService.findById(employeeId)
Çalışan onaylayan rolündeyse nereye atar gibi bir şey yaparak ücretsiz izin alabilirsiniz . Approver
bir varlık değil, sadece bir değer nesnesi olur. Ayrıca bunun yerine bir AR üzerinde fabrika veya kullanım fabrika yönteminin kurtulmak olabilir: cashDrop = driver.dropCash(...)
.