Domain Driven Design - A place for everything and everything in its place
Trener i doradca
Community
Twórca oprogramowania – całościowe podejście
O sobie
Java EE
Inżynieria oprogramowania
prezes Stowarzyszenia Software Engineering Professionals Polska
blogger, autor
członek rady programowej JDD i 4Developers
Technologie
Architektury
Najlepsze praktyki
Wzorce
Metodyki
Software
Craftsmanship
Ewolucja Modelu
?
Procesy ewolucyjne są ślepe. Czasem osiągają lokalne maksimum, z którego nie mogą się już wydostać.
Richard Dawkins
Architektura aplikacji DDD
Jeżeli ktoś rozróżnia naukę (poznanie) i zabawę, to nie zrozumiał żadnego z tych pojęć.
Infrastruktura
(dostęp do danych, servisy techniczne)
Logika Aplikacji
Prezentacja
Serwis aplikacyjny
@Transactional
@Service
//...
public class OrderService{
..@Autowired
..private OrdersRepository ordersRepository;
..@Autowired
..private PreductsRepository productssRepository;
..public void addProductToOrder(Long orderId, Long productId, int quantity){
....Order order = ordersRepository.load(orderId);
....Product product = productssRepository.load(productId);
....order.addProduct(product, quantity);
....ordersRepository.save(order);
..}
}
Jeżeli robisz coś i zaczyna być to skomplikowane, to robisz to źle.
Sławomir Sobótka
slawomir.sobotka@bottega.com.pl
http://art-of-software.blogspot.com/
http://ssepp.pl
Naruszenie Bounded Context
public class Client extends AggregateRoot {
....public void changeStatus(ClientStatus status){
........this.status = status;
........//wiecej logiki biznesowej
........if (status == VIP){
............//rabat na niezrealizowane zamówienia
........}
....}
}
Problemy z modelem domeny
Standardy projektowe
Tendencja do wzrostu entropii
(czyżby drugie prawo termodynamiki?)
Wszechobecny Spaghetti-monster
Mała podatność na zmiany
Krucha struktura
XML
Kolejny framework webowy
SOA
Nowa
specyfiakcja
platformy,
servera
Nowy
język
Złożoność
Esencjonalna
Przypadkowa
zależy od problemu
wynika z jego natury i jest nieunikniona
zależy od rozwiązania
wynika z wybranego podejścia i może być nieograniczona:)
Brak Modelu lub Model jedynie na początku
po prostu dodajemy (gdzieś) ficzery
myląca, nieadekwatna dokumentacja
Niespójny żargon
wymaga translacji
translacja prowadzi do błędów i niezrozumienia
"głuchy telefon"
Model czysto analityczny
nieimplementowalny
upada najszybciej
Model w ujęciu DDD
Serce systemu - największa wartość
Daje przewagę (nad konkurencją)
Powód tworzenia projektu
Modelowanie jest największym wyzwaniem w projekcie
Do czego służy model?
Model wymaga opieki...
nieustanne zbieranie wiedzy
o regułach
zachowaniu
wspólne rozumienie
żargon
słownictwo
Ubiquitous Language
Jak zacząć z DDD?
Certified Procedural Programmer?
Czy DDD aplikuje się w moim kontekście?
"Welcome to the Real World Neo"
W projekcie brakuje czasu/pieniędzy na rzetelne modelowanie...
Core
Domain
Supporting Domain
Generic
Domain
Warunki konieczne
Opłacalność przy złożonych, nietrywialnych domenach
Iteracyjny proces - "kruszenie" wiedzy
Dostęp do eksperta domenowego
Skillset teamu: OOD, raczej inteligencja werbalna niż
algorytmiczna
Wspólny model
Wspólny język
Logika Biznesowa
(model domeny)
Serwisy aplikacyjne
cienka warstwa
orkiestracja obiektów biznesowych
technikalia: transakcje, bezpieczeństwo,...
Domain Model
Building Blocks
Entity
Aggregate
Value Object
Serwis (biznesowy)
Policy
rich, not anemic
odpowiedzialność charakterystyczna dla danego bytu
technicznie: graf encji
enkapsulacja
jednostka logiki biznesowej (jednostka spójności)
wrapper dla typów prostych
zwiększenie ekspresji modelu biznesowego
uwypuklenie koncepcji biz.
koniec z utilsami:)
w odróżnieniu od aplikacyjnego
czynność, która nie jest charakterystyczna dla żadnego Agregatu/Encji/VO
uwypuklenie koncepcji biznesowej
technicznie: Strategy Design Pattern
uwypuklenie wariacji procesu biznesowego
IoC na poziomie logiki biz.
komunikacja pomiędzy Bounded Context
Zdarzenie (wydarzenie) biznesowe
Factory
tworzy złożone agregaty - również część logiki biz.
dba o poprawność - nie istnieją obiekty w niepoprawnym stanie
technicznie: drastycznie zwiększa testability
zarządza trwałością Agregatu/Encji
nie zawiera 150 wyszukiwarek (tak jak DAO)
ew. wyszukiwanie biznesowe
Repository
Alternatywa: Command+CommandHandler w architekturze Command query Responsibility Segregation
Specification
modelowanie logiki wyboru Encji/Agregatów spełniających kryteria biznesowe
technicznie: drzewo warunków połączonych operatorami logicznymi
Listener kilku zdarzeń
Modeluje proces wymagający zajścia kilku wydarzeń
Persystentny stan
Saga
if (p1 == null) ...
if (p1 > 1) ...
//chwileczę... 80% to 0.8 czy 80?
Double probability = p1 * p2;
Probability p1 = Probability.fromPercent(80.0);
...
Probability probability = p1.and(p2);
"Make explicit what is implicit"
Aggregate
@Entity
public class Order extends AggregateRoot{
..@OneToMany
..private List<OrderItem> items;
..@Embeded
..private Money sum;
..private RebatePolicy rebatePolicy;
..//status, createDate, rebatePolicy
..public Order(RebatePolicy rebatePolicy){
....this.rebatePolicy = rebatePolicy;
....sum = new Money(0.0);
....//...
}
..public void add(Product p, int quantity){
....OrderItem oi = orderItemFactory.build(p, quantity, rebatePolicy);
....items.add(oi);
....sum = sum.add(oi.getCost());
}
..//zwracamy niemodyfikowalną listę Value Objects aby ukryć impl
..public List<OrderedProduct> getOrderItems(){
....return repack(items);
..}
}
Factory
Ukrywa złożoność tworzenia Agregatu
Zapewnia poprawny stan
Enkapsuluje logikę biznesową związaną z wyborem Polityki
Polityka
public interface RebatePolicy{
..public Money calculateRebate(...);
}
Serwis aplikacyjny - C.D.
Servis Biznesowy (Building Block)
@Service
@Transactional
//..
public class OrderService{
..@Autowired
..private OrdersRepository ordersRepository;
..@Autowired
..private InvoicesRepository invoicesRepository;
..public void submitOrder(Long orderId, Payment payment){
....Order order = ordersRepository.get(orderId);
....order.confirm(payment);
....BookKeeperService bookKeeper = new BookKeeperService();//testability!!!
....Invoice invoice = bookKeeper.generateInvoice(order);
....ordersRepository.save(order);
....invoicesRepository.save(invoice)
..}
}
"Make explicit what is implicit"
Serwis Biznesowy
@Entity
public class Order extends AggregateRoot{
..public void confirm(Payment payment){
....if (status == CONFIRMED)
......throw new InvalidStateException();
....status = CONFIRMED;
....createDate = new Date();
....fireEvent(orderEventsFactory.orderSubmitted(getId()));
..}
}
Aggregate - C.D.
Supple Design
public class BookKeeperService{
..private TaxCalulatorPolicy taxCalculator;
..public BookKeeperService(...){
....//ew. wstrzyknięcie
..}
..public Invoice generateInvoice(Order order){
....//metoda, która nie pasuje do żadnego Agregatu
....//nie jest esencją istnienia Zamówienia
..}
}
"Make explicit what is implicit"
Listener
Integracja z innymi Bounded Context
"Make explicit what is implicit"
Wydarzenie biznesowe
(fakt, który nieodwracalnie miał miejscje)
Queue
Można zastanowić się nad tym, które z DODATKOWYCH obliczeń muszą być wykonane natychmiast...
Saga
"Make explicit what is implicit"
public class OrderTrackingSaga extends Saga<OrderTrackingSagaData>{
..@SagaAction
..public void handle(CustomerBilledForOrder event)
....memento.setCustomerHasBeenBilled(true);
....memento.setCustomerId(event.getCustomerId());
....memento.setOrderId(event.getOrderId());
....completeIfPossible();
..}
..@SagaAction
..public void handle(OrderSubmitted event){
....memento.setProductIdsInOrder = event.ProductIdsInOrder;
....memento.setCustomerId(event.getCustomerId());
....memento.setOrderId(event.getOrderId());
....completeIfPossible();
}
..private void completeIfPossible(){
....//if (...)
....//fire event, call cervice/send command
....markAsCompleted();
..}
VipRebate
WinterRebate
Moduł CRM i Moduł Sprzedaży to dwa różne Bounded Context!
różne modele
zwykle inny Ekspert Domenowy
public class OrderItem{
..RebatePolicy rebatePolicy;
..public Money calculateCost(){
//logika biznesowa
Money rebate = rebatePolicy.calculateRebate(...);
//nieco więcej logiki
..}
}
Bardziej odpowiedni poziom abstrakcji
Baza danych nie jest modelem!!!
"What Drives our Design?"
Projektowanie, modelowanie
ukierunkowane, skupione na pewnych aspektach (wybory priorytetów)
Sfery wiedzy i aktywności,
obszarach tematycznych, w których użytkownik aplikuje oprogramowanie
Value Object
BigDecimal/int value;
Currency curency;
Timestamp currencyRateDate;
http://code.google.com/p/ddd-cqrs-sample/
Easy != Simple
<<Aggregate>>
Order
<<Aggregate>>
Invoice
<<Service>>
BookKeeper
<<Policy>>
TaxCalculator
<<Factory>>
InvoiceFactory
<<Specification>>
OrderCriteria
Architektura
Command-query
Responsibility Segregation
Rozwiązanie problemów persystencji
Wydajność
Skalowanie
Moduł Sprzedaży
Moduł CRM
Moduł KadrMore presentations by
Domain Driven Design - A place for everything and everything in its place (en)
Sławek Sobótka on
General Idea, Real model, Make explicit what is implicit, All Building Blocks, Events, Sagas, Bounded Context, Domain Distillation, CqRS
Command-query Responsibility Segregation - nowe, bardziej racjonalne podejście do warstw
Sławek Sobótka on
CqRS, Domain Driven Design, Event Sourcing, etc
DDD & CqRS Sample
Sławek Sobótka on
Visualisation for http://code.google.com/p/ddd-cqrs-sample [Architecture and design visual map]
Popular presentations
30 Things About Me
Brooke Ahrens on
All About Brooke Ahrens- I used this presentation as an icebreaker to introduce myself to my classes this year.
More popular prezis in Explore>