Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.

Introduction to Domain Driven Design: Describing the problem, not the solution.

607 Aufrufe

Veröffentlicht am

DDD provides patterns to help us build software that actually represents the problem we're solving. By modelling entities, behaviour and interactions as first-class citizens it becomes easier to build the right thing and to accommodate changes as they emerge.

Veröffentlicht in: Technologie
  • Als Erste(r) kommentieren

Introduction to Domain Driven Design: Describing the problem, not the solution.

  1. 1. 1 ©ThoughtWorks 2019 Commercial in Confidence Introduction to Domain Driven Design Describing the problem, not the solution... Steve Morris
  2. 2. @SteveM_01 About me, about ThoughtWorks Steve MORRIS @SteveM_01 www.thoughtworks.com/careers
  3. 3. @SteveM_01 Format ● Slides ○ Code ○ Diagrams ○ Boxes ● Questions Target audience? Beginners
  4. 4. @SteveM_01 Domain Driven Design "Fundamentally, DDD is the principle that we should be focusing on the deep issues of the domain our users are engaged in..." - Eric Evans
  5. 5. @SteveM_01 Domain Driven Design Because the closer our business logic models the real world, the greater the chance we have of getting it right.
  6. 6. @SteveM_01 Problems What problem is DDD trying to solve? ● Complexity ● Centralised, unified models ● Low Cohesion, High Coupling ● People
  7. 7. @SteveM_01 Layers, the promise BUSINESS DATA PRESENTATION DB
  8. 8. @SteveM_01 presentationFoo.Save(foo); businessFoo.Save(foo); dataFoo.Save(foo); Layers, the reality PRESENTATION BUSINESS DATA
  9. 9. @SteveM_01 presentationFoo.Save(foo); businessFoo.Save(foo); dataFoo.Save(foo); Layers, the reality
  10. 10. @SteveM_01 Why Domain Driven Design? The closer our business logic models the real world, the greater the chance we have of getting it right. DDD naturally encourages separation of concerns… SRP. The architectural layers are more loosely coupled.
  11. 11. @SteveM_01 The bits you probably already care about... Entities Domain Events Aggregates Services Repositories
  12. 12. @SteveM_01 The bits you should also care about Entities Domain Events Aggregates Services Repositories Commands Queries Handlers
  13. 13. @SteveM_01 The bits you should care about the most Entities Domain Events Aggregates Services Repositories Commands Queries Handlers Ubiquitous Language Bounded Contexts
  14. 14. @SteveM_01 A contrived example...
  15. 15. Gruber @SteveM_01 Die Hard 20th Century Fox
  16. 16. @SteveM_01 The bits you probably already care about... Entities Domain Events Aggregates Services Repositories
  17. 17. @SteveM_01 Entities model intent person.Name = newName; person.ChangeNameTo(newName); person.PaymentMethod = preferredPaymentMethod; person.ChangePaymentMethodTo(preferredPaymentMethod);
  18. 18. @SteveM_01 Gruber Driver Rider Trip Address Entities
  19. 19. @SteveM_01 Entities are never in an invalid state... class Rider { public CancelTrip(Trip trip) { // assert if (!CanCancelTrip()) throw new CannotCancelTripException(); // act // do the thing // announce DomainEvents.Add(new TripCancelled(this.RiderId, trip.TripId); } }
  20. 20. @SteveM_01 Entities ● Model intent ● Are never in an invalid state ● Assert Act Announce
  21. 21. @SteveM_01 A Domain Event is a statement of fact ● UserRegistered ● EmailSent ● OrderCompleted ● OrderShipped
  22. 22. @SteveM_01 A Domain Event is a statement of fact public Register(string userName, string email, Address address, Date dateOfBirth) { if (accounts.exists(userName)) throw new UserNameAlreadyTakenException(); accounts.add(new Account(userName, email, address, dateOfBirth)); emailService.Send("WelcomeEmail", userName, email); promotionsService.Check(userName, email, dateOfBirth); printingService.Send("WelcomeLetter", userName, address); }
  23. 23. @SteveM_01 A Domain Event is a statement of fact public Register(string userName, string email, Address address, Date dateOfBirth) { if (accounts.exists(userName)) throw new UserNameAlreadyTakenException(); accounts.add(new Account(userName, email, address, dateOfBirth)); emailService.Send("WelcomeEmail", userName, email); promotionsService.Check(userName, email, dateOfBirth); printingService.Send("WelcomeLetter", userName, address); smsService.Send("WelcomeText", userName, phone); }
  24. 24. @SteveM_01 A Domain Event is a statement of fact public Register(string userName, string email, Address address, Date dateOfBirth) { // assert if (accounts.exists(userName)) throw new UserNameAlreadyTakenException(); // act accounts.Add(new Account(userName, email, address, dateOfBirth)); // announce DomainEvents.Add(new UserSignedUpEvent(userName)); }
  25. 25. @SteveM_01 Domain Events Gruber BookingCancelledEvent RiderCollectedEvent IHaveAMachineGunEvent Die Hard 20th Century Fox
  26. 26. @SteveM_01 The bits you probably already care about... Entities Domain Events Aggregates Services Repositories
  27. 27. @SteveM_01 Aggregates
  28. 28. @SteveM_01 Aggregate Roots
  29. 29. @SteveM_01 Aggregates Gruber Rider PaymentMethod Driver Cars
  30. 30. @SteveM_01 The bits you probably already care about... Entities Domain Events Aggregate Services Repositories
  31. 31. @SteveM_01 Services Gruber CancellationFeeService FareCalculationService NakatomiPlazaTransferService
  32. 32. @SteveM_01 The bits you probably already care about... Entities Domain Events Aggregates Services Repositories
  33. 33. @SteveM_01 Repositories Gruber RiderRepository DriverRepository BearerBondRepository
  34. 34. @SteveM_01 Repositories var user = userRepository.Get(driverId); var rider = riderRepository.Get(riderId); var driver = driverRepository.Get(driverId);
  35. 35. @SteveM_01 The bits you should also care about Entities Domain Events Aggregate Services Repositories Commands Queries Handlers
  36. 36. @SteveM_01 ● Encapsulate intent ● No behaviour; simple DTOs. Commands & Queries
  37. 37. @SteveM_01 Commands & Queries class ConfirmTripCommand { public Id RiderId { get; } public Address Destination { get; } } class GetEstimatedFareQuery { public Address From { get; } public Address To { get; } public CarType CarType { get; } }
  38. 38. @SteveM_01 Commands & Queries Gruber BookTripCommand GetCarLocationQuery RateDriverCommand GetPastTripsQuery GetVaultProgressQuery
  39. 39. @SteveM_01 Commands & Queries Gruber GiveMeMyDetonatorsCommand GiveMeMyDetonatorsQueryvs Die Hard 20th Century Fox
  40. 40. @SteveM_01 GiveMeMyDetonatorsQuery Commands & Queries Gruber GiveMeMyDetonatorsCommand
  41. 41. @SteveM_01 The bits you should also care about Entities Domain Events Aggregates Services Repositories Commands Queries Handlers
  42. 42. @SteveM_01 class CancelTripCommandHandler: ICommandHandler<CancelTripCommand> { private readonly IRepository<Rider> riderRepository; public CancelTripCommandHandler(IRepository<Rider> riderRepository) { this.riderRepository = riderRepository; } public void Handle(CancelTripCommand command) { var rider = riderRepository.Get(command.RiderId); rider.CancelTrip(); } } Handlers
  43. 43. @SteveM_01 class RateDriverCommandHandler : ICommandHandler<RateDriverCommand> { /* ... */ public void Handle(RateDriverCommand command) { var rider = riderRepository.Get(command.RiderId); var driver = driverRepository.Get(command.DriverId); rider.RateDriver(driver, command.DriverRating); } } Handlers
  44. 44. @SteveM_01 class GetTripQueryHandler : IQueryHandler<GetTripQuery, GetTripResponse> { /* ... */ public GetTripResponse Handle(GetTripQuery query) { var trip = tripRepository.Get(query.TripId); return new GetTripResponse(trip.TripId, trip.Date, trip.Cost); } } Handlers
  45. 45. @SteveM_01 class SendWelcomeEmailOnRegistration : IDomainEventHandler<UserSignedUpDomainEvent> { /* ... */ public void Handle(UserSignedUpDomainEvent domainEvent) { var email = domainEvent.Email; var userName = domainEvent.UserName; _emailService.Send("WelcomeEmail", email, userName); } } Handlers
  46. 46. @SteveM_01 Convention Tests UNIT INTEGRATION E2E CONVENTION
  47. 47. @SteveM_01 ● Every Command must have exactly one handler. ● Every Query must have exactly one handler. ● Every Domain Event must have at least one handler. Convention Tests & Handlers
  48. 48. @SteveM_01 The bits you should care about the most Entities Domain Events Aggregate Services Repositories Commands Queries Handlers Ubiquitous Language Bounded Contexts
  49. 49. @SteveM_01 It’s all about the naming Ubiquitous Language
  50. 50. @SteveM_01 It’s all about the naming “A rose by any other name would smell as sweet” - Romeo & Juliet, Shakespeare Ubiquitous Language
  51. 51. @SteveM_01 It’s all about the naming Ubiquitous Language “Tis but thy name that is my enemy” “A rose by any other name would smell as sweet” - Romeo & Juliet, Shakespeare
  52. 52. @SteveM_01 It’s all about the naming “If names be not correct…language is not in accordance with the truth of things.” - Confucius Ubiquitous Language
  53. 53. @SteveM_01 It’s all about the naming “Domain experts should object to terms or structures that are awkward or inadequate to convey domain understanding; developers should watch for ambiguity or inconsistency that will trip up design.” - Eric Evans Ubiquitous Language
  54. 54. @SteveM_01 Ubiquitous Language Gruber Car Driver Passenger Trip Cowboy Request a car Accept a trip Reject a trip Cancel a trip Pick up a rider End trip Pick up ammo Rate driver Rate passenger Yippee-kay-yay
  55. 55. @SteveM_01 The bits you should care about the most Entities Domain Events Aggregate Services Repositories Commands Queries Handlers Ubiquitous Language Bounded Contexts
  56. 56. @SteveM_01 It’s all about the scope Bounded Context
  57. 57. @SteveM_01 It’s all about the scope Thong? Bounded Context
  58. 58. @SteveM_01 It’s all about the scope ● Separation of concerns at a macro level ● Help ensure integrity across the entire the model Bounded Context
  59. 59. @SteveM_01 Gruber Gruber Eats Bounded Context Gruber Gruber Eats Customer (Rider) Customer (Diner) Die Hard 20th Century Fox
  60. 60. @SteveM_01 Bounded Context Aggregate Putting it all together Command Handler Repository Domain EventQuery Domain Event Aggregate Root Entity
  61. 61. @SteveM_01 Bounded Context Aggregate Putting it all together CancelTrip Command CancelTrip CommandHandler RiderRepository TripCancelled Event Rider Gruber Trip
  62. 62. @SteveM_01 ● Model the problem being solved ● Separate our business logic from other application concerns ● Reduce complexity ● Communicate better ● More effective software delivery High-level outcomes DDD is about ensuring we...
  63. 63. 63 Questions?
  64. 64. @SteveM_01 The books...
  65. 65. ©ThoughtWorks 2019 Commercial in Confidence Thank you 65 Steve Morris smorris@thoughtworks.com @SteveM_01

×