Agrega Kökü ne zaman başka bir AR içermelidir (ve ne zaman içermemelidir)


15

Önce yazının uzunluğundan özür dileyerek başlayayım, ama gerçekten çok fazla ayrıntı iletmek istedim, bu yüzden yorumlarda ileri geri gitmiyorum.

Bir DDD yaklaşımı izleyen bir uygulama tasarlıyorum ve bir Agrega Kökü'nün başka bir AR içermesi veya ayrı, "bağımsız" AR'ler olarak bırakılması gerekip gerekmediğini belirlemek için hangi rehberliği takip edebileceğimi merak ediyorum.

Çalışanların kendilerini gün içinde veya dışında saatlerini izlemelerini sağlayan basit bir Zaman Saati uygulaması ele alın. Kullanıcı arabirimi, çalışan kimliğini ve PIN kodunu girmelerine izin verir, bu daha sonra doğrulanır ve çalışanın geçerli durumu. Çalışan saatte çalışıyorsa, kullanıcı arabirimi bir "Saat Dışı" düğmesi görüntüler; ve tersine, eğer saat ayarlı değillerse, düğme "Saat Girişi" yazar. Düğmenin yaptığı işlem, çalışanın durumuna da karşılık gelir.

Uygulama, bir RESTful hizmet arabirimi aracılığıyla maruz bir arka uç sunucusu çağıran bir web istemcisidir. Sezgisel, okunabilir URL'ler oluşturma konusundaki ilk geçişim şu iki uç noktayla sonuçlandı:

http://myhost/employees/{id}/clockin
http://myhost/employees/{id}/clockout

NOT: Bunlar, çalışan kimliği ve PIN doğrulandıktan ve "kullanıcıyı" temsil eden bir "jeton" başlıkta iletildikten sonra kullanılır. Bunun nedeni, bir yöneticinin veya amirlerin başka bir çalışanı saatlerine ayırmasına veya çıkarmasına izin veren bir "yönetici modu" olmasıdır. Ama bu tartışma uğruna bunu basit tutmaya çalışıyorum.

Sunucuda, API sağlayan bir ApplicationService var. ClockIn yöntemi için ilk fikrim şuna benzer:

public void ClockIn(String id)
{
    var employee = EmployeeRepository.FindById(id);

    if (employee == null) throw SomeException();

    employee.ClockIn();

    EmployeeRepository.Save();
}

Bu, Çalışanın zaman çizelgesi bilgilerinin aslında bir işlem listesi olarak tutulduğunu fark edene kadar oldukça basit görünüyor. Bu, ClockIn veya ClockOut'u her aradığımda, doğrudan Çalışanın durumunu değiştirmiyorum, ancak bunun yerine Çalışanın Zaman Çizelgesine yeni bir giriş ekliyorum. Çalışanın mevcut durumu (saatli veya değil), Zaman Çizelgesi'ndeki en son girişten türetilir.

Bu nedenle, yukarıda gösterilen kodla gidersem, depomun Çalışanın kalıcı özelliklerinin değişmediğini, ancak Çalışanın Zaman Çizelgesine yeni bir giriş eklendiğini ve veri deposuna bir ekleme gerçekleştirdiğini tanıması gerekir.

Öte yandan (ve işte yazının nihai sorusu), TimeSheet, bir Agrega Kökü olduğu gibi kimliğe (çalışan kimliği ve dönemi) sahip gibi görünüyor ve TimeSheet ile aynı mantığı kolayca uygulayabilirim. (Çalışan kimliği).

Kendimi iki yaklaşımın esasını tartışırken buluyorum ve açılış paragrafında belirtildiği gibi, hangi yaklaşımın soruna daha uygun olduğunu belirlemek için hangi kriterleri değerlendirmem gerektiğini merak ediyorum.


Gönderiyi düzenledim / güncelledim, böylece soru daha net ve daha iyi bir senaryo kullanıyor (umarım).
SonOfPirate

Yanıtlar:


4

Zaman izleme için bir hizmet uygulamaya meyilli olurum:

public interface ITimeSheetTrackingService
{
   void TrackClockIn(Employee employee, Timesheet timesheet);

   void TrackClockOut(Employee employee, Timesheet timesheet);

}

Zaman çizelgesinin içeri girip çıkma zamanının sorumluluğunda olduğunu düşünmüyorum, ne çalışanın sorumluluğu.


3

Toplam kökler birbirlerini içermemelidir (ancak başkalarına kimlikler içerebilir).

Birincisi, TimeSheet gerçekten toplu bir kök mü? Kimliğine sahip olması onu mutlaka bir AR değil, bir varlık haline getirir. Kurallardan birine göz atın:

Root Entities have global identity.  Entities inside the boundary have local 
identity, unique only within the Aggregate.

Zaman Çizelgesi'nin kimliğini çalışan kimliği ve zaman periyodu olarak tanımlarsınız, bu da Zaman Çizelgesinin Çalışanın bir parçası olduğunu ve zaman diliminin yerel kimlik olduğunu gösterir. Bu bir Zaman Saati uygulaması olduğundan, Çalışanın temel amacı Zaman Çizelgeleri için bir kap olmak mı?

AR'lerinizin olduğu varsayılırsa, ClockIn ve ClockOut, Çalışanlarınkinden daha fazla TimeSheet işlemlerine benziyor. Hizmet katmanı yönteminiz şöyle görünebilir:

public void ClockIn(String employeeId)
{
    var timeSheet = TimeSheetRepository.FindByEmployeeAndTime(employeeId, DateTime.Now);    
    timeSheet.ClockIn();    
    TimeSheetRepository.Save();
}

Hem Çalışan hem de Zaman Çizelgesi'nde gerçekten saatli durumu izlemeniz gerekiyorsa, Etki Alanı Olaylarına bir göz atın (Evans'ın kitabında olduklarına inanmıyorum, ancak çevrimiçi çok sayıda makale var). Şuna benzer bir şey olurdu: Employee.ClockIn (), bir olay işleyicisinin seçtiği ve karşılığında TimeSheet.LogEmployeeClockIn () öğesini çağırdığı EmployeeClockedIn olayını yükseltir.


Puanlarını görüyorum. Ancak, bir Çalışanın saatli olup olmadığını kısıtlayan belirli kurallar vardır. Bu kurallar çoğunlukla Çalışanın şu anki durumu tarafından yönlendirilir; geçerli vardiya, vs. Zaman Çizelgesi bu bilgiye sahip olmalı mı?
SonOfPirate

3

Bir DDD yaklaşımı izleyen bir uygulama tasarlıyorum ve bir Agrega Kökü'nün başka bir AR içermesi veya ayrı, "bağımsız" AR'ler olarak bırakılması gerekip gerekmediğini belirlemek için hangi rehberliği takip edebileceğimi merak ediyorum.

Birleştirilmiş kök asla başka bir toplam kök içermemelidir.

Açıklamanızda, bir Çalışan varlığınız ve aynı şekilde bir Zaman Çizelgesi varlığınız var. Bu iki varlık farklıdır, ancak birbirlerine referanslar içerebilir (ör: bu Bob'un zaman çizelgesidir).

Temel modelleme bu kadar.

Toplam kök sorusu biraz farklıdır. Bu iki varlık birbirlerinden işlemsel olarak farklıysa, doğru bir şekilde iki ayrı toplama olarak modellenebilirler. İşlemsel olarak farklı bir ifadeyle, çalışanın mevcut durumunu ve aynı zamanda TimeSheet'in mevcut durumunu bilmeyi gerektiren bir iş değişkeni olmadığını kastediyorum.

Açıkladığınız şeye dayanarak, Timesheet.clockIn ve Timesheet.clockOut komutlarına izin verilip verilmediğini belirlemek için hiçbir zaman Çalışan'daki verileri kontrol etmenize gerek yoktur. Yani sorunun büyük bir kısmı için iki farklı AR mantıklı görünüyor.

AR sınırlarını dikkate almanın bir başka yolu, aynı anda ne tür düzenlemelerin yapılmasına izin verildiğini sormak olacaktır. Yöneticinin aynı zamanda İK, çalışanın profiliyle uğraşırken çalışanın işini durdurmasına izin veriliyor mu?

Öte yandan (ve işte yazının nihai sorusu), Zaman Çizelgesi, bir Küme Kökünün yanı sıra kimliğine (çalışan kimliği ve dönemi) sahip gibi görünüyor

Kimlik sadece onun bir varlık olduğu anlamına gelir - ayrı bir toplam kök olarak görülüp görülmeyeceğini yönlendiren iş değişmezidir.

Ancak, bir Çalışanın saatli olup olmadığını kısıtlayan belirli kurallar vardır. Bu kurallar çoğunlukla Çalışanın şu anki durumu tarafından yönlendirilir, örneğin o gün sona erdirilmiş, zaten saat içinde çalışmış, hatta o gün çalışacak şekilde planlanmış geçerli vardiya, vs. Zaman Çizelgesi bu bilgiye sahip olmalı mı?

Belki - agrega gerekir. Bu mutlaka Zaman Çizelgesi'nin olması gerektiği anlamına gelmez.

Yani, bir Zaman Çizelgesini değiştirme kuralları Çalışan varlığın mevcut durumuna bağlıysa, Çalışan ve Zaman Çizelgesi kesinlikle aynı toplamın bir parçası olmalıdır ve bir bütün olarak toplam, kuralların takip etti.

Bir topluluğun bir kök varlığı vardır; onu tanımlamak bulmacanın bir parçasıdır. Bir Çalışanın birden fazla Zaman Çizelgesi varsa ve her ikisi de aynı toplamın parçasıysa, Zaman Çizelgesi kesinlikle kök değildir. Bu, uygulamanın zaman çizelgesine komutları doğrudan değiştiremeyeceği veya gönderemeyeceği anlamına gelir - sorumluluktan bazılarını devredebilen kök nesneye (muhtemelen Çalışan) gönderilmeleri gerekir.

Bir başka kontrol de Zaman Çizelgelerinin nasıl oluşturulduğunu düşünmek olacaktır. Bir çalışan saat içinde örtülü olarak yaratılırsa, bu, toplamda ikincil bir varlık olmalarının başka bir ipucudur.

Bir yana, agregalarınızın kendi zaman duyularına sahip olması pek olası değildir. Bunun yerine, onlara zaman geçirilmelidir

employee.clockIn(when);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.