Domain Driven Design - A place for everything and everything in its place

General Idea, Real model, Make explicit what is implicit, All Building Blocks, Events, Sagas, Bounded Context, Domain Distillation, CqRS »
Sławek Sobótka

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ł Kadr

Loading comments...

Please log in to add your comment.

Report abuse

More presentations by Sławek Sobótka