$30 off During Our Annual Pro Sale. View Details »

Technically DDD C

pelshoff
January 26, 2019

Technically DDD C

pelshoff

January 26, 2019
Tweet

More Decks by pelshoff

Other Decks in Programming

Transcript

  1. public class Name { public String LastName { get; }

    public String FirstName { get; } public Name (String lastName, String firstName) { LastName = lastName; FirstName = firstName; NamePartsMayNotBeNull(); LastNameIsRequired(); } private void NamePartsMayNotBeNull() { if (null == LastName || null == FirstName) { NameIsInvalid.becausePartsAreMissing(); } } private void LastNameIsRequired() { if (LastName.Length < 1) { NameIsInvalid.becauseLastNameIsTooShort(); } ...
  2. public class Email { public String EmailAsString { get; }

    public Email(String email) { EmailAsString = email; EmailMustBeAnActualEmailAddress(); } private void EmailMustBeAnActualEmailAddress() { if (String.IsNullOrWhiteSpace(EmailAsString)) { EmailIsInvalid.becauseEmailIsMissing(); } if (!EmailAsString.Contains('@')) { EmailIsInvalid.becauseAtIsMissing(); } } }
  3. public class Attendee { public Guid Id { get; }

    private Name _Name; public Name Name { get { return _Name; } set { _Name = value; ValuesMayNotBeNull(); } } private Email _Email; public Email Email { get { return _Email; } set { _Email = value; ValuesMayNotBeNull(); } } public Attendee(Guid id, Name name, Email email) { Id = id; _Name = name; _Email = email; ValuesMayNotBeNull(); } private void ValuesMayNotBeNull() { if (null == _Name || null == _Email) { AttendeeIsInvalid.BecauseValuesAreNull(); } } }
  4. Entities • Hebben identiteit • Zijn meer dan hun attributes

    • Evoluëren over tijd • Zijn lastiger om te testen
  5. public class Registration { private RegistrationRepository Repository; public Registration(RegistrationRepository repository)

    { Repository = repository; } public void RegisterNew(Attendee Attendee) { EmailAddressMustBeUnique(Attendee.Email); Repository.Add(Attendee); } private void EmailAddressMustBeUnique(Email Email) { try { Repository.FindByEmail(Email); } catch (AttendeeNotFound ex) { return; } throw RegistrationFailed.becauseEmailAddressIsNotUnique(); } }
  6. Services • Hebben geen identiteit of attributes (Zijn geen “ding”)

    • Zijn geschikt voor cross-concern operations • Zijn nog lastiger om te testen
  7. public class Meeting { public Meeting( Guid id, string title,

    string description, string code, string startDate, string startTime, string endDate, string endTime, bool isPublished, string subTitle, List<ProgramSlot> program ) { // ... } }
  8. new Meeting( Guid.NewGuid(), "DotNed Saturday 2019", "...", "#dotNedSaturday", "2019-01-26", "09:00",

    "2019-01-26", "18:00", true, "HÉT NEDERLANDSE .NET COMMUNITY EVENEMENT", new List<ProgramSlot>(){ new ProgramSlot("2019-01-26", "09:00", "09:30", "Ontvangst en koffie", ""), new ProgramSlot("2019-01-26", "13:30", "14:30", "Technisch Gezien DDD", "Seminarruimte 1"), } );
  9. public class Meeting { public Meeting(/* */) { // ...

    MeetingsCannotEndBeforeStart(); } private void MeetingsCannotEndBeforeStart() { if (StartDate.CompareTo(EndDate) == -1) { return; } if (StartDate.CompareTo(EndDate) == 1) { MeetingIsInvalid.becauseMeetingEndsBeforeStarting(); } if (StartTime.CompareTo(EndTime) == 1) { MeetingIsInvalid.becauseMeetingEndsBeforeStarting(); } } }
  10. public class Meeting { // ... private MeetingDuration Duration; //

    ... public Meeting( Guid id, string title, string description, string code, MeetingDuration duration, bool isPublished, string subTitle, List<ProgramSlot> program ) { // ... Duration = duration; // ... } }
  11. public class MeetingDuration { // ... public MeetingDuration(string startDate, string

    startTime, string endDate, string endTime) { // ... MeetingsCannotEndBeforeStart(); } private void MeetingsCannotEndBeforeStart() { if (StartDate.CompareTo(EndDate) == -1) { return; } if (StartDate.CompareTo(EndDate) == 1) { MeetingIsInvalid.becauseMeetingEndsBeforeStarting(); } if (StartTime.CompareTo(EndTime) == 1) { MeetingIsInvalid.becauseMeetingEndsBeforeStarting(); } } }
  12. public class MeetingDuration { private DateTime Start; private DateTime End;

    public MeetingDuration(DateTime start, DateTime end) { Start = start; End = end; MeetingsCannotEndBeforeStart(); } private void MeetingsCannotEndBeforeStart() { if (Start.CompareTo(End) == 1) { MeetingIsInvalid.becauseMeetingEndsBeforeStarting(); } } }
  13. new Meeting( Guid.NewGuid(), "DotNed Saturday 2019", "...", "#dotNedSaturday", new MeetingDuration(

    new DateTime(2019, 01, 26 , 9, 0, 0), new DateTime(2019, 01, 26 , 18, 0, 0) ), true, "HÉT NEDERLANDSE .NET COMMUNITY EVENEMENT", new List<ProgramSlot>(){ new ProgramSlot("2019-01-26", "09:00", "09:30", "Ontvangst en koffie", ""), new ProgramSlot("2019-01-26", "13:30", "14:30", "Technisch Gezien DDD", "Seminarruimte 1"), } );
  14. new Meeting( Guid.NewGuid(), "DotNed Saturday 2019", "...", "#dotNedSaturday", new MeetingDuration(

    new DateTime(2019, 01, 26 , 9, 0, 0), new DateTime(2019, 01, 26 , 18, 0, 0) ), true, "HÉT NEDERLANDSE .NET COMMUNITY EVENEMENT", new List<ProgramSlot>(){ new ProgramSlot("2019-01-26", "09:00", "09:30", "Ontvangst en koffie", ""), new ProgramSlot("2019-01-26", "13:30", "14:30", "Technisch Gezien DDD", "Seminarruimte 1"), } );
  15. private void ProgramSlotsCannotOccurInTheSameRoomAtTheSameTime() { foreach (var slotA in Program) {

    foreach (var slotB in Program) { if (slotA == slotB) { continue; } if (!slotA.Room.Equals(slotB.Room)) { continue; } if (!slotA.Date.Equals(slotB.Date)) { continue; } if (slotA.StartTime.CompareTo(slotB.EndTime) == 1) { continue; } if (slotA.EndTime.CompareTo(slotB.StartTime) == -1) { continue; } MeetingIsInvalid.becauseProgramSlotsOverlap(); } } // ...
  16. public class Meeting { // ... private Program Program; public

    Meeting( Guid id, string title, string description, string code, MeetingDuration duration, bool isPublished, string subTitle, Program program ) { // ... Program = program; } }
  17. public class Program { private List<ProgramSlot> Slots; public Program(List<ProgramSlot> program)

    { Slots = program; ProgramSlotsCannotOccurInTheSameRoomAtTheSameTime(); } private void ProgramSlotsCannotOccurInTheSameRoomAtTheSameTime() { foreach (var slotA in Slots) { foreach (var slotB in Slots) { if (slotA == slotB) { continue; } // ... } } }
  18. public class Program { private List<ProgramSlot> Slots; public Program(List<ProgramSlot> program)

    { Slots = program; ProgramSlotsCannotOccurInTheSameRoomAtTheSameTime(); } private void ProgramSlotsCannotOccurInTheSameRoomAtTheSameTime() { foreach (var slotA in Slots) { foreach (var slotB in Slots) { if (slotA == slotB) { continue; } if (slotA.OverlapsWith(slotB)) { MeetingIsInvalid.becauseProgramSlotsOverlap(); } } } } }
  19. public class ProgramSlot { public MeetingDuration Duration; public string Title;

    public string Room; public ProgramSlot(MeetingDuration duration, string title, string room) { Duration = duration; Title = title; Room = room; } public bool OverlapsWith(ProgramSlot that) { return this.Room == that.Room && this.Duration.OverlapsWith(that.Duration); } }
  20. public class MeetingDuration { private DateTime Start; private DateTime End;

    public MeetingDuration(DateTime start, DateTime end) { Start = start; End = end; MeetingsCannotEndBeforeStart(); } private void MeetingsCannotEndBeforeStart() { /*...*/ } public bool OverlapsWith(MeetingDuration that) { return this.Start.CompareTo(that.Start) >= 0 && this.Start.CompareTo(that.End) < 1 || this.End.CompareTo(that.Start) >= 0 && this.End.CompareTo(that.End) < 1; } }
  21. public class MeetingDuration { private DateTime Start; private DateTime End;

    public MeetingDuration(DateTime start, DateTime end) { Start = start; End = end; MeetingsCannotEndBeforeStart(); } private void MeetingsCannotEndBeforeStart() { /*...*/ } public bool OverlapsWith(MeetingDuration that) { return this.Contains(that.Start) || this.Contains(that.End); } private bool Contains(DateTime Date) { return this.Start.CompareTo(Date) < 1 && this.End.CompareTo(Date) >= 0; } }
  22. public class MeetingDuration { private DateTime Start; private DateTime End;

    public MeetingDuration(DateTime start, DateTime end) { Start = start; End = end; MeetingsCannotEndBeforeStart(); } private void MeetingsCannotEndBeforeStart() { /*...*/ } public bool OverlapsWith(MeetingDuration that) { return !(this.Start.CompareTo(that.End) == 1 || this.End.CompareTo(that.Start) == -1); } }
  23. public class MeetingDuration { private DateTime Start; private DateTime End;

    public MeetingDuration(DateTime start, DateTime end) { Start = start; End = end; MeetingsCannotEndBeforeStart(); } private void MeetingsCannotEndBeforeStart() { /*...*/ } public bool OverlapsWith(MeetingDuration that) { return !this.IsBefore(that) && !that.IsBefore(this); } private bool IsBefore(MeetingDuration that) { return this.Start.CompareTo(that.End) == 1; } }
  24. new ProgramSlot( "2019-01-26", "13:30", "14:30", "Technisch Gezien DDD", "Seminarruimte 1"

    ) private bool IsBefore(MeetingDuration that) { return this.Start.CompareTo(that.End) == 1; }
  25. public class SlotDuration { private DateTime Start; private DateTime End;

    public SlotDuration(DateTime start, DateTime end) { Start = start; End = end; MeetingsCannotEndBeforeStart(); SlotMustStartAndEndOnSameDay(); } /*...*/ public bool OverlapsWith(SlotDuration that) { return !this.IsBefore(that) && !that.IsBefore(this); } private bool IsBefore(SlotDuration that) { return this.Start.CompareTo(that.End) >= 0; } }
  26. new Meeting( Guid.NewGuid(), "DotNed Saturday 2019", "...", "#dotNedSaturday", "2019-01-26", "09:00",

    "2019-01-26", "18:00", true, "HÉT NEDERLANDSE .NET COMMUNITY EVENEMENT", new List<ProgramSlot>(){ new ProgramSlot("2019-01-26", "09:00", "09:30", "Ontvangst en koffie", ""), new ProgramSlot("2019-01-26", "13:30", "14:30", "Technisch Gezien DDD", "Seminarruimte 1"), } );
  27. new Meeting( Guid.NewGuid(), "DotNed Saturday 2019", "...", "#dotNedSaturday", new MeetingDuration(new

    DateTime(2019, 01, 26 , 9, 0, 0), new DateTime(2019, 01, 26 , 18, 0, 0)), True, "HÉT NEDERLANDSE .NET COMMUNITY EVENEMENT", new Program( new List<ProgramSlot>(){ new ProgramSlot( new SlotDuration(new DateTime(2019, 1, 26, 9, 0, 0), new DateTime(2019, 1, 26, 9, 30, 0)), "Ontvangst en koffie", "" ), new ProgramSlot( new SlotDuration(new DateTime(2019, 1, 26, 13, 30, 0), new DateTime(2019, 1, 26, 14, 30, 0)), "Technisch Gezien DDD", "Seminarruimte 1" ), } ) );
  28. Meer weten? “Domain-Driven Design: Tackling Complexity in the Heart of

    Software”, Eric Evans “Domain-Driven Design Distilled”, Vaughn Vernon https://github.com/procurios/diconverg ent