domain driven design 101
DESCRIPTION
Domain Driven Design (DDD) is a topic that's been gaining a lot of popularity in both the Java and .NET camps recently. Entities, value types, repositories, bounded contexts and anti-corruption layers -- find out what all the buzz is about, and how establishing a domain model can help you combat complexity in your code. Richard Dingwall is a .NET developer and blogger with a passion for architecture and maintainable code. He is currently working at Provoke Solutions as lead developer on a six-month project introducing test-driven development (TDD) and domain-driven design (DDD) to a large ASP.NET ERP system. An hour-long talk given at Wellington .NET user group, Sept 23 2009.TRANSCRIPT
![Page 1: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/1.jpg)
1
Domain Driven Design 101
![Page 2: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/2.jpg)
3
Agenda• Why• Building blocks
– Repositories, entities, specifications etc
• Putting it to practice– Dependency injection– Persistence– Validation– Architecture
• Challenges• When not to use DDD• Resources
![Page 3: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/3.jpg)
4
Software is complicated
![Page 4: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/4.jpg)
5
We solve complexity in software by distilling our problems
![Page 5: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/5.jpg)
6
public bool CanBook(Cargo cargo, Voyage voyage){ if (!overbookingPolicy.IsAllowed(cargo, voyage)) return false; ...}
public bool CanBook(Cargo cargo, Voyage voyage){ double maxBooking = voyage.Capacity * 1.1; if (voyage.BookedCargoSize + cargo.Size > maxBooking) return false; ...}
DDD is about making concepts explicit
![Page 6: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/6.jpg)
7
Domain Model
![Page 7: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/7.jpg)
8
Ubiquitous language
![Page 8: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/8.jpg)
9
public interface IPayrollService{ double GetHourlyRate(Employee employee);}
public interface ISapService{ double GetHourlyRate(int sapId);}
Intention-revealing interfaces
A poor abstractionû
ü
![Page 9: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/9.jpg)
10
public class Employee{ void ApplyForLeave(DateTime start, DateTime end, ILeaveService leaves) { ... }}
![Page 10: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/10.jpg)
11
Domain Expert
![Page 11: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/11.jpg)
12
Entities
![Page 12: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/12.jpg)
13
Value Types
![Page 13: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/13.jpg)
14
public class Employee : IEquatable<Employee>{ public bool Equals(Employee other) { return this.Id.Equals(other.Id); }}
public class PostalAddress : IEquatable<PostalAddress>{ public bool Equals(PostalAddress other) { return this.Number.Equals(other.Number) && this.Street.Equals(other.Street) && this.PostCode.Equals(other.PostCode) && this.Country.Equals(other.Country); }}
Entities are the same if they have the same identity
Value Types are the same if they have the same value
![Page 14: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/14.jpg)
15
public class Colour{ public int Red { get; private set; } public int Green { get; private set; } public int Blue { get; private set; } public Colour(int red, int green, int blue) { this.Red = red; this.Green = green; this.Blue = blue; } public Colour MixInTo(Colour other) { return new Colour( Math.Avg(this.Red, other.Red), Math.Avg(this.Green, other.Green), Math.Avg(this.Blue, other.Blue)); }}
Value Types are immutable
![Page 15: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/15.jpg)
16
Aggregates
![Page 16: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/16.jpg)
17
Aggregate root
*
![Page 17: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/17.jpg)
18
Repositories
![Page 18: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/18.jpg)
19
public interface IEmployeeRepository{ Employee GetById(int id); void Add(Employee employee); void Remove(Employee employee); IEnumerable<Employee> GetStaffWorkingInRegion(Region region);}
Repositories provide collection semantics and domain queries
![Page 19: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/19.jpg)
20
Domain Services
![Page 20: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/20.jpg)
21
public interface ITripService{ float GetDrivingDistanceBetween(Location a, Location b);}
![Page 21: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/21.jpg)
22
Specifications
![Page 22: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/22.jpg)
23
class GoldCustomerSpecification : ISpecification<Customer>{ public bool IsSatisfiedBy(Customer candidate) { return candidate.TotalPurchases > 1000.0m; }}
Specifications encapsulate a single rule
if (new GoldCustomerSpecification().IsSatisfiedBy(employee)) // apply special discount
![Page 23: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/23.jpg)
24
to construct objects
Specifications can be used…
![Page 24: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/24.jpg)
25
var spec = new PizzaSpecification() .BasedOn(new MargaritaPizzaSpecification()) .WithThickCrust() .WithSwirl(Sauces.Bbq) .WithExtraCheese(); var pizza = new PizzaFactory().CreatePizzaFrom(spec);
Constructing objects according to a specification
![Page 25: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/25.jpg)
26
for querying
Specifications can be used…
![Page 26: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/26.jpg)
27
public interface ICustomerRepository{ IEnumerable<Customer> GetCustomersSatisfying( ISpecification<Customer> spec);}
Querying for objects that match some specification
var goldCustomerSpec = new GoldCustomerSpecification(); var customers = this.customerRepository .GetCustomersSatisfying(goldCustomerSpec);
![Page 27: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/27.jpg)
28
Anticorruption Layer
![Page 28: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/28.jpg)
29
Other subsystemYour subsystem Anti-corruption layer
![Page 29: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/29.jpg)
30
“”
Any 3rd party system that I have to integrate with was
written by a drunken monkey typing with his feet.
Oren Eini aka Ayende
![Page 30: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/30.jpg)
31
Bounded Context
![Page 31: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/31.jpg)
32
public class Lead{ public IEnumerable<Opportunity> Opportunities { get; } public Person Contact { get; }}
public class Customer{ public IEnumerable<Ticket> Tickets { get; }}
public class Client{ public IEnumerable<Invoice> GetOutstandingInvoices(); public Address BillingAddress { get; } public IEnumerable<Order> PurchaseHistory { get; }}
![Page 32: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/32.jpg)
33
Dependency Injection
![Page 33: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/33.jpg)
34
public class EmailNotificationService : INotificationService{ void Notify(Employee employee, string message) { var message = new MailMessage(employee.Email, message); this.smtpClient.Send(message); }
}
public interface INotificationService{ void Notify(Employee employee, string message);}
Far away, a concrete class satisfies it
An interface defines the model
![Page 34: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/34.jpg)
35
public class LeaveService{ private readonly INotificationService notifications; public LeaveService(INotificationService notifications) { this.notifications = notifications; } public void TakeLeave(Employee employee, DateTime start, DateTime end) { // do stuff this.notifications.Notify(employee, "Leave approved."); }}
Dependencies are injected at runtime
![Page 35: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/35.jpg)
36
Persistence Ignorance
![Page 36: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/36.jpg)
37
“”
…ordinary classes where you focus on the business problem at hand without adding stuff
for infrastructure-related reasons… nothing else should
be in the Domain Model.
![Page 37: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/37.jpg)
38
public class Customer{ public int Id { get; private set; } public string FirstName { get; set; } public string LastName { get; set; } public IEnumerable<Address> Addresses { get; } public IEnumerable<Order> Orders { get; } public Order CreateOrder(ShoppingCart cart) { ... }}
Plain Old CLR Object (POCO)
![Page 38: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/38.jpg)
39
[global::System.Data.Objects.DataClasses.EdmEntityTypeAttribute(NamespaceName="AdventureWorksLTModel", Name="Customer")] [global::System.Runtime.Serialization.DataContractAttribute(IsReference=true)] [global::System.Serializable()] public partial class Customer : global::System.Data.Objects.DataClasses.EntityObject { [global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)] [global::System.Runtime.Serialization.DataMemberAttribute()] public int CustomerID { get { return this._CustomerID; } set { this.OnCustomerIDChanging(value); this.ReportPropertyChanging("CustomerID"); this._CustomerID = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value); this.ReportPropertyChanged("CustomerID"); this.OnCustomerIDChanged(); } } private int _CustomerID; partial void OnCustomerIDChanging(int value); partial void OnCustomerIDChanged();
This is not a POCO.
![Page 39: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/39.jpg)
40
Architecture
![Page 40: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/40.jpg)
41
Traditional Architecture
Presentation
Business Logic (BLL)
Data Access (DAL)
Infr
astr
uctu
re
![Page 41: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/41.jpg)
42
Onion Architecture
User Interface
G
Infrastr
ucture
Tests
Filesystem
Services
etc
Application Services
M
Domain Services
Domain Model
Database
![Page 42: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/42.jpg)
43
Onion Architecture
User Interface
G
Infrastr
ucture
Tests
Filesystem
Services
etc
Application Services
M
Domain Services
Domain Model
Database
Employee,IEmployeeRepository
NHibernateEmployeeRepository
EmployeeController
IEmailSender
SmtpEmailSender
![Page 43: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/43.jpg)
44
Validation
![Page 44: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/44.jpg)
45
Validation Examples
Is the first name filled in?Is the e-mail address format valid?Is the first name less than 255 characters long?Is the chosen username available?Is the password strong enough?Is the requested book available, or already out
on loan?Is the customer eligible for this policy?
Input validation
Business domain
![Page 45: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/45.jpg)
46
public class PersonRepository : IPersonRepository{ public void Save(Person customer) { if (!customer.IsValid()) throw new Exception(...) }}
validation and persistence anti-patterns
![Page 46: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/46.jpg)
47
The Domain Model is always in a valid state
The golden rule for validation:
![Page 47: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/47.jpg)
48
public class NewUserFormValidator : AbstractValidator<NewUserForm>{ IUsernameAvailabilityService usernameAvailabilityService; public NewUserFormValidator() { RuleFor(f => f.Email).EmailAddress(); RuleFor(f => f.Username).NotEmpty().Length(1, 32) .WithMessage("Username must be between 1 and 32 characters"); RuleFor(f => f.Url).Must(s => Uri.IsWellFormedUriString(s)) .Unless(f => String.IsNullOrEmpty(f.Url)) .WithMessage("This doesn't look like a valid URL"); RuleFor(f => f.Username) .Must(s => this.usernameAvailabilityService.IsAvailable(s)) .WithMessage("Username is already taken"); }}
separation of validation concerns with FluentValidation
![Page 48: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/48.jpg)
49
Where validation fits
User Interface
G
Infrastr
ucture
Tests
Filesystem
Services
etc
Application Services
M
Domain Services
Domain Model
DatabaseEmployee,
IEmployeeRepository
NHibernateEmployeeRepository
EmployeeController
IEmailSender
SmtpEmailSender
NewUserForm,NewUserFormValidator
IUsernameAvailabilityService
IOverdraftLimitPolicy
![Page 49: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/49.jpg)
51
Challenges
![Page 50: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/50.jpg)
52
When DDD isn’t appropriate
![Page 51: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/51.jpg)
53
Benefits
![Page 52: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/52.jpg)
54
Books
![Page 53: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/53.jpg)
55
LinksDomain Driven Design mailing list• http://tech.groups.yahoo.com/group/domaindrivendesign/
ALT.NET mailing list• http://tech.groups.yahoo.com/group/altdotnet/
DDD Step By Step• http://dddstepbystep.com/
Domain Driven Design Quickly (e-book)• http://www.infoq.com/minibooks/domain-driven-design-quickly
![Page 54: Domain Driven Design 101](https://reader033.vdocuments.site/reader033/viewer/2022061614/554f369bb4c90572088b4c64/html5/thumbnails/54.jpg)
56
“”
Any fool can write code that a computer can understand.
Good programmers write code that humans can
understand.Martin Fowler