a place for everything, everything in its place - dworld.pl - everything on place and...define roles...
TRANSCRIPT
● I create software – holistic approach● Technology (Java, Java EE) and Craftsmanship● Design, architecture, usability● Exploration of methodologies and best practices
● I work as a trainer and consultant● Java technologies● Software engineering
● Community● Leader of Lublin Java Users Group● Blogger, speaker, publisher...
What do I do
● Challenges of software● Domain Driven Design
● introduction● advanced topics
● Technical and architecturalaspects of implementation
● When to use DDD● Beyond DDD
Agenda
Business software● No sophisticated stuff
● nothing like Fast Fourier Transform● Just simple operations...
● just multiplied by 1000:)● synergy of simple components● continuously changing
● We need a structure for dozens ofsimple elements
●You read code and understand nothing● You can't see any rules or process
●You don't know how to translatebusiness requirements to code
●You change code and nothing works●Now it's Your problem:)
Symptoms
Complexity● Essential
● inherent and unavoidable● depends on problem
● Accidental● caused by chosen approach ● depends on solution
What would You change...if You start everything from the beginning?
XML
Annotations
New server
New versionof the serverSOA Dynamic language
Another webframework;)
It's all about the model● Model needs care● Model is a heart of the system
● reason why creating it● main value● advantage factor
● Modelling is the toughest part● weak model leads to failure
*it's not truth for all system, it's just DDD perspective
Unstructured design
Just adding new features – with no care about model
● big ball of mud● chaos and anarchy● costs in long term
What model IS NOT
Database is not a model● just data structure – very technical● no behavior● static – we can't see whats going on● created to early – later we need to hack
What model IS FOR● continous knowledge gathering
● about rules● about dynamics
● common (client … developer) understanding of domain● vocabulary● jargon
What model IS
Real model● description and simplification for current needs● no unimportant stuff – avoid mental overload ● knowledge base - rules and behavior
●General concept● technology and platform independent
●Set of design and analysis techniques● focus on domain logic layer● complexity reduction● extension-ability and changeability
●Pragmatic approach to OOD and OOA
Domain Driven Design
„There is technically nothing new or revolutionary in DDD, there is only a guide to a better way of thinking.”
Casey Charlton
●Focus on behavioral model
●Common (Ubiquitous) Language
●Strategic modeling● Core Domain● Contexts
●Domain Layer – OOD● Data and rules● Roles that implicate responsibility
● Responsibility Driven Design● GRASP● SOLID
DDD – Mental shift
Problems with models
●No model● just add features (somewhere;)
●Model at the beginning, but no maintenance● useless, inadequate documents
●Distinct jargon leads to need of translation● translation leads to errors and misunderstandings
●Pure analytical model – fails fast● unimplementable models are useless● "I've done my job, I don't care how You will implement it"
Solution: Ubiquitous language
● Model must be bind to code● modeling in right paradigm – there is no pure
modeling support for procedural paradigm● OOD techniques used by annalists● building blocks...
● Modeler must code● coding is not low-skilled job● result: creating implementable models
● Coder must fell responsibility for the model
“Good picture is worth more than 1000 words”
●Not only UML●Use any form that supports common understanding
and communication● Client specific diagrams● Sketch● System metaphor...
System metaphor● Software design tend to be abstract
● hard to grasp● Organize design around metaphor
● absorb vocabulary● Find metaphor in real world that
describes your system● loose, easy do understand● large scale structure
How to bind model and code?● Responsibility Driven Design
● Define roles that objects can play● Roles determines responsibility
● Separate logic in layers
Layers
User interface
Infrastructure
Application logic
Domain logic
Thin layer - just coordinates and delegatesto domain
Heart of the system – model of the businessconcepts and rules
Technical capabilities - may exist as a few layers(persistence, messages, etc)
Presentation – can be very sophisticated;do not underestimate
Building Blocks of Domain Layer
●Entities (not anemic)●Value Objects●Aggregates●Services (business)●Policies and Specifications●Business events
●Factories●Repositories
Entities● Object that need to be distinguished
● even if attributes are the same● some ID
● Not only data● Also behavior (business responsibility)
● characteristic● essential
Value Objects● Just description of some characteristic● No distinction – no identity
● VOs are the same if their attributes are the same● Typical usage:
● attributes of call between objects● Usually immutable - because has no identity
● therefore can be reusable – we don't care which instance is being used
● Usually no need to persist● if You have search criteria => You can create an instance
Power of VOs● Expression of business concepts
● adds conceptual power● more meaningful than just String
● May contain useful methods (instead of utils)● validation● constructor may validate input
● Examples● color, point (source, destination)● address*, phone number● money
Candidates for VO● Strings with format limitations
● zip code● name
● Numbers with limitations● percentage● quantity
● Business object's arguments/returns● money – composed: amount + currency
– maybe can be exchanged?● address
– can be valid only for specific time period?
Services● Business Services
● Sometimes it just isn't a thing● OO is not always proper approach● OO is not always possible (human factor)
● When can not find natural "home" in Entity/VO● Operation without state
● Defined in terms of other Building Block● Should not strip Entity/VO of all their
responsibilities
Aggregate● Cluster of objects (Entity/VOs)
● inner objects can reference each other inside● boundary with one root
● Outer entity is Aggregate root● controls access - encapsulation
● Unit of data change
Encapsulation is virtue
human.getDigestionSystem().getPeritoneum().getStomach().
add(new Sausage(2));
human.getDigestionSystem().getPeritoneum().getStomach().
add(new Sausage(2));
human.eat(new Sausage(2));
public void eat(Food f){ if (! iLike(f))
thow new IDontLikeItException(f); this.digestionSystem.swallow(f);}
human.eat(new Sausage(2));
public void eat(Food f){ if (! iLike(f))
thow new IDontLikeItException(f); this.digestionSystem.swallow(f);}
@Entitypublic class Order{
@Id private OrderId id;@OneToMany private List<OrderItem> items = new ArrayList<OrderItem>();private BigDecimal sum = new BigDecimal(0);//.... status, createDate, rebatePolicy, productRepository,...
public void add(ProductId id, int quantity){Product p = productRepository.load(id);OrderItem oi = orderItemFactory.build(p, quantity, rebatePolicy);items.add(oi);sum = sum.add(oi.getCost());
}
public void submit(){if (status != Status.NEW)
throw new InvalidStateException();status = Status.IN_PROGRESS;createDate = new Date();eventsManager.handle(orderEventsFactory.orderSubmitted(this));
}
public Iterator<OrderItem> getOrderItems(){return items.iterator();
}}
@Entitypublic class Order{
@Id private OrderId id;@OneToMany private List<OrderItem> items = new ArrayList<OrderItem>();private BigDecimal sum = new BigDecimal(0);//.... status, createDate, rebatePolicy, productRepository,...
public void add(ProductId id, int quantity){Product p = productRepository.load(id);OrderItem oi = orderItemFactory.build(p, quantity, rebatePolicy);items.add(oi);sum = sum.add(oi.getCost());
}
public void submit(){if (status != Status.NEW)
throw new InvalidStateException();status = Status.IN_PROGRESS;createDate = new Date();eventsManager.handle(orderEventsFactory.orderSubmitted(this));
}
public Iterator<OrderItem> getOrderItems(){return items.iterator();
}}
●Use factory when creation of Entity/Aggregate is complicated●Factory prevents from invalid Domain Object
● if “raw material” is invalid than factory vetoes●Options
● add factory method to closely related objects● if creating VO consider Singleton
●Architectural aspects● when creating ORM Entities (out of IoC containter control)● than inject dependencies manually in factory method
Factory
Repository
●Storage abstraction of objects (Entity/Aggregate) of some type●Encapsulates DB access
● decoupling domain and technical stuff●Retrieves objects by
● identity● business criteria (in business Use Cases)● don't use it as a finder (use separate service)
AOP Transactions
Application Service
OrdersRepository InvoicesRepository
OrmOrdersRepositoryImpl OrmInvoicesRepositoryImpl
Persistence Unit + Transactions Manager
Application Service Transaction Proxy
Policy● Process as a Domain Object
● makes it explicit● extends Ubiquitous Language
● Simply: Strategy Design Pattern● Useful when there is more than one way to
carry out a process● if process variations can be covered
by common interface● to choose process is to choose strategy
public class Order{ //FIXME: change to BigDecimal private double totalCost;
private TaxPolicy taxPolicy; private RebatePolicy rebatePolicy;
public void submit(){ totalCost-=rebatePolicy.calculateRebate(this); totalCost-=taxPolicy.calculateTax(this);
... }}
<<interface>>TaxPolicy
calculateTax(order)
PolishTaxPolicy UKTaxPolicy
Policy example
IoC Container
Policy injection
getOrderFactory
return OrderFactory
OrderFactory
PolishTaxPolicy
setTaxPolicy
@Componentpublic class OrderFactory{ private TaxPolicy taxPolicy; private RebatePolicy rebatePolicy;
@Autowired public OrderFactory(TaxPolicy tp, RebatePolicy rp){ this.taxPolicy = tp; this.rebatePolicy=rp; } public Order createOrder(...){ Order o = new Order(...);
… o.setTaxPolicy(taxPolicy);
o.setRebatePolicy(rebatePolicy); }}
@Component(„taxPolicy”)public class PolishTaxPolicy implements TaxPolicy{ ...}
<bean id="taxPolicy" class="x.y.PolishTaxPolicy">
@Configurationpublic class PolicyFactories{
@Beanpublic TaxPolicy taxPolicy() {
return ... ;}
}
Policy – common patternChange classic thinking
● noun – class● verb - method
Activity is an object● method is just a signal to execute it
Unleash OO techniques● polymorphic execution● re-usability
Extension and Testability● Extension without modification● Strategy implies high cohesion
● Single policy can be tested● Aggregate can be tested using policy stub/mock
Aggregate
<<interface>>Strategy
ConcreteBusiness Impl
Stub/MockTest Impl
Test
Test
Events● Business Event is a signal from Aggregate● Aggregate is highly decoupled
● does not know about receiver type● does not know how many receivers are interested in
@Entitypublic class Order{
public void submit(){if (status != Status.NEW)
throw new InvalidStateException();status = Status.IN_PROGRESS;createDate = new Date();
eventsManager.handle(orderEventsFactory.orderSubmitted(this));}
}
@Entitypublic class Order{
public void submit(){if (status != Status.NEW)
throw new InvalidStateException();status = Status.IN_PROGRESS;createDate = new Date();
eventsManager.handle(orderEventsFactory.orderSubmitted(this));}
}
What are Events for?● Decouple additional behavior
● adding new behavior without domain modification● strong form of Inversion of Control
● Collect state change (if we need to keep track of entity changes history) – Events Sourcing● events can signalize change
● Asynchronous invocation● When fast response is needed● Distributed DDD...
Specification● Model of rules● Makes rules explicit● Can be used for Entity/Aggregate validation or
selection
public interface InvoiceSpecyfication{public Collection<InvoiceProblem> check(Invoice i)
}
public interface InvoiceSpecyfication{public Collection<InvoiceProblem> check(Invoice i)
}
public class CombinedInvoiceSpecyfication implements InvoiceSpecyfication{
private List<InvoiceCriterion> criteria;
public Iterable<InvoiceProblem> check(Invoice i){Collection<InvoiceProblem> result = new ...;for (InvoiceCriterion criterion : criteria){
String problem = criterion.validate(i);if (problem != null){
result.add(new InvoiceProblem(problem));if (criterion.isCritical())
break;return result;
}}}}
public class CombinedInvoiceSpecyfication implements InvoiceSpecyfication{
private List<InvoiceCriterion> criteria;
public Iterable<InvoiceProblem> check(Invoice i){Collection<InvoiceProblem> result = new ...;for (InvoiceCriterion criterion : criteria){
String problem = criterion.validate(i);if (problem != null){
result.add(new InvoiceProblem(problem));if (criterion.isCritical())
break;return result;
}}}}
public interface InvoiceCriterion{public String validate(Invoice i);public boolean isCritical();
}
public interface InvoiceCriterion{public String validate(Invoice i);public boolean isCritical();
}
Domain Layer (Business Logic)
Aggregate
Entity(Aggregate root)
Entity
ValueObject
business methods
Delegate
LoadSave
BusinessService
<<interface>>Policy
(Strategy Design Pattern)
Application Layer (Application Services, Use Case Agents)
PolicyImpl1 PolicyImpl2
Building Blocks - cooperation
<<interface>>Repository
Factory
Event
Generate
Create
Delegate
Delegate
Comparison to procedural approach
PROCEDURE orderService(o:TOrder); BEGIN...END;
TOrder = RECORD id: integer;
...END;
You can't do everything perfect● Not enough knowledge● Not enough skilled people● Not enough time● Not enough money● Not enough time● Not enough money● Not enough time● Not enough money● Not enough time
Welcome to the real world, Neo
Focus on core domainCore Domain● Reason why we create system● Main business features (give advantage to the client)● Focus intellectual effort – invest time and best people
Supporting Domain● Additional features – not critical● Lower quality is acceptable● Can be rewritten (someday - sure;)
Generic Domain● Very specific (invoicing, math calculations)● Buy/use working solution and integrate with it
Core Domain Strategies● Write Domain Vision Statement
● what brings value?● Keep it small● Invest the best people
● Fame for implementing "sexy" business features
Context
When distinct models are combined, we are introubles
● difficult to understand● unreliable● buggy
Grand Unified Theory
Common anti-pattern● one, big, corporate model● meaningless● one word in different contexts mean different thing
– responsibility– behavior– structure
Bounded Context● When system grow up – complexity is too high
● can't look at the level of individual objects● Define context where model applies● Context is encapsulated
● communicates with outer word via interface● inner business model is hermetic● therefore it can evolve -changes don't spread
through whole system
Contexts Strategies● Common Core Context can be defined
● Shared Kernel
● Decouple distinct Domain Contexts● Core (business)● Generic (Math stuff etc)
Anti-corruption Strategies
Our brand newshiny nice system
Ugly legacysystem
Anti-corruptionLayer
FacadeAdapterService
Useful techniques already discussed
● ORM - aggregates● Inversion of Control
● Dependency Injection - policies● Events● Aspect Oriented Programming – transactions (also
security) over application layer that impact Repositories
● Design Patterns● Policy, Specification, Anti-corruption Layer
Command-query Separation Paradigm
● Method should play one of the following roles● command – executes some logic● query – return data
● Multiple query should not affect the answer● Eliminates side effect
●Class level violation
●System level violation● Add an Order and return list of all orders
● it's GUI functionality● but server API should offer 2 methods
private int x;public int incrementAndReturn(){ x++; return x;}
private int x;public int incrementAndReturn(){ x++; return x;}
Sample violation of CqS
(G)UI
Business Logic
Application Logic
Command
Facade
ORM + JDBC
Query
DTO
Repository/DAO
Command-query Responsibility Segregation
Data provider/Finder viaService
CqRS Characteristic● Processing C and Q is often asymmetrical
● Should be scaled separately● Is it worth to apply in CRUD systems?
(G)UI
Business Logic
Application Logic
Command
Data provider/Finder
Query
DTO
Repository/DAO
DB 1DB 2
Event(asynch)
Events Bus+ Event handlersChange
CqRS – Distributed DDD and scalability
public class SearchDocumentsQuery implements Serializable{private Status status;private Date epiryDate;private String[] titleWords;private String[] contentWords;//Getters and setters/constructor
}
public class SearchDocumentsQuery implements Serializable{private Status status;private Date epiryDate;private String[] titleWords;private String[] contentWords;//Getters and setters/constructor
}
public class DocumentQueries /*implements SomeInterface*/{public List<Document> search(SearchDocumentsQuery query){
//ORM return entities – simple case }
public List<DocumentDTO> search(SearchDocumentsQuery query){//SQL return UseCase relevant Data Transfer Object
}}
public class DocumentQueries /*implements SomeInterface*/{public List<Document> search(SearchDocumentsQuery query){
//ORM return entities – simple case }
public List<DocumentDTO> search(SearchDocumentsQuery query){//SQL return UseCase relevant Data Transfer Object
}}
Query – sample impl.
public class SearchDocumentsQuery implements Serializable{private Status status;private Date epiryDate;private String[] titleWords;private String[] contentWords;//ONLY getters
public SearchDocumentsQuery expired(){
status = Status.ACTIVE;expiryDate = new Date();return this;
}
public SearchDocumentsQuery contains(String phrase){String[] words = phrase.split(" ");titleWords = words;contentWords = words;return this;
}}
public class SearchDocumentsQuery implements Serializable{private Status status;private Date epiryDate;private String[] titleWords;private String[] contentWords;//ONLY getters
public SearchDocumentsQuery expired(){
status = Status.ACTIVE;expiryDate = new Date();return this;
}
public SearchDocumentsQuery contains(String phrase){String[] words = phrase.split(" ");titleWords = words;contentWords = words;return this;
}}
Query a'la DSL
public class OrderProductCommand implelents Serializable{ private int productId; private int quantity; //getters and constructor}
public class OrderProductCommand implelents Serializable{ private int productId; private int quantity; //getters and constructor}
public class Basket /*implements SomeInterface*/{ private Order order; public void add(AddProductCommand cmd){ Product prod = productRepository.get(cmd.getProductId()); order.add(prod, cmd.getQuantity()); }
public void submit(SubmitOrderCommand cmd){ order.submit(cmd.getPayment(), cmd.getAddressInfo());
orderRepository.save(order);eventsManager.orderSubmitted(new OrderSubmittedEvent(order));
}}
public class Basket /*implements SomeInterface*/{ private Order order; public void add(AddProductCommand cmd){ Product prod = productRepository.get(cmd.getProductId()); order.add(prod, cmd.getQuantity()); }
public void submit(SubmitOrderCommand cmd){ order.submit(cmd.getPayment(), cmd.getAddressInfo());
orderRepository.save(order);eventsManager.orderSubmitted(new OrderSubmittedEvent(order));
}}
Command – classic impl.
public class OrderProductCommand extends Command{...}public class OrderProductCommand extends Command{...}
public interface Handler<T> { void handleMessage(T message) throws Exception; }
public interface Handler<T> { void handleMessage(T message) throws Exception; }
Command – handlers based impl.
public class AddProductHandler implements Handler<AddProductCommand>{
private ProductRepository repository; public void handleMessage(AddProductCommand message) { //... }}
public class AddProductHandler implements Handler<AddProductCommand>{
private ProductRepository repository; public void handleMessage(AddProductCommand message) { //... }}
public class CommandBus{public void handle(Command cmd)
Collection<Handler<?>> matchedHandlers = handlers.get(message.getClass());
for (Handler handler : matchedHandlers){//prepare environment (transactions, security,//inject current user, etc)handler.handleMessage(cmd);
}//may generate message
}}
public class CommandBus{public void handle(Command cmd)
Collection<Handler<?>> matchedHandlers = handlers.get(message.getClass());
for (Handler handler : matchedHandlers){//prepare environment (transactions, security,//inject current user, etc)handler.handleMessage(cmd);
}//may generate message
}}
Event Sourcing● If state of Aggregate at any given time is
needed to be rebuild● not the same as Logs
● "Inner" events● represents current state of Aggregate● events are stored in persistence layer● Aggregate can be recreated to given state (point in
time) by rebuilding information from relevant events.
Temporal Object PatternAlternative to Event Sourcing●whole state of Aggregate version persisted●newest version is always available – no computation
source: http://mbartyzel.blogspot.com/2008/10/wzorce-projektowe-temporal-object.html
Is DDD right for me?● Aspects of personality● Aspects of business domain itself● Aspects of project nature
DDD Prerequisites● Domain is not trivial● Team has experience and interest in OOP/OOD● You have access to domain experts● You have an iterative process
Advanced data models● Model Archetype – analytical “design pattern”
● standard● "model component" that can be taken off the shelf,
customized, and instantiated in your own models● adaptable – can be trimmed to fit actual
requirements● extensible – can be extended to fit new
requirements● Catalog of models:
● Company structure and relationships, customers, products, inventory, orders, scientific stuff (laboratory),...
How to model People and Organizations?
Person
Employee
User
Client
Inheritance is not a good idea to model roles:P
Company
Party
source: Enterprise Patterns and MDA: Building Better Software with Archetype Patterns and UML By Jim Arlow, Ila Neustadt
General Idea
source: Enterprise Patterns and MDA: Building Better Software with Archetype Patterns and UML By Jim Arlow, Ila Neustadt
Example
source: Enterprise Patterns and MDA: Building Better Software with Archetype Patterns and UML By Jim Arlow, Ila Neustadt
Model
source: Enterprise Patterns and MDA: Building Better Software with Archetype Patterns and UML By Jim Arlow, Ila Neustadt
Details of Party
source: Enterprise Patterns and MDA: Building Better Software with Archetype Patterns and UML By Jim Arlow, Ila Neustadt
Person is a Party
source: Enterprise Patterns and MDA: Building Better Software with Archetype Patterns and UML By Jim Arlow, Ila Neustadt
Organization is a Party
source: Enterprise Patterns and MDA: Building Better Software with Archetype Patterns and UML By Jim Arlow, Ila Neustadt
Customer is a Party
source: Enterprise Patterns and MDA: Building Better Software with Archetype Patterns and UML By Jim Arlow, Ila Neustadt
Customer is a different story...
source: Enterprise Patterns and MDA: Building Better Software with Archetype Patterns and UML By Jim Arlow, Ila Neustadt
Behavior Driven Development● Agile software development technique● Encourages collaboration between
● developers, QA● non-technical or business participants
● BDD focuses on exposing internal logic (typically business rules) to review by stakeholders.
● Native language in combination with the ubiquitous language of DDD● describe the purpose and benefit of the code
Data Context Interaction● New programming paradigm
● needs dynamic language syntax (mixins, traits)● Trygve Reenskaug
● co-inventor of Object Oriented● inventor of MVC
● Mainstream OO languages● are not Object Oriented● they are rather Class Oriented
Data● core● basically dumb● may contain basic
responsibility
Interactions● business
responsibility● operates on data
Context● Whole Use Case● or just few steps● adds meaning to
the data
Full working Objects● makes sense only in context● methods implies by current role
DDD summary● No rocket science● “Just” rational usage of OOA and OOD● Pragmatic approach to complexity of business
logic● Most important things:
● Ubiquitous Language● Strategic Design
● Building Block are not the most important thing:P
Photo credits● http://www.norcalblogs.com/commission/images/house-of-cards.jpg
● http://nirmukta.com/wp-content/uploads/2009/08/complexity.jpg
● http://www.basicbonsai.com/wp-content/uploads/2009/11/brazilian_rain_tree.jpg
● http://i659.photobucket.com/albums/uu312/mlee4elbow/prof_chaos02.jpg
● http://a.images.blip.tv/Unclephilms-puppetTest1168.jpg
● http://www.individual-i.org/images/logo-3sizes.jpg
● https://star-cosmos.com/starcomsos_blog/wp-content/uploads/2009/08/human-body.jpg
● http://media.photobucket.com/image/train%20wreck/wgman21/train_wreck.jpg
● http://englishrussia.com/images/mig_factory/1.jpg
● http://upload.wikimedia.org/wikipedia/commons/thumb/b/b7/2000_core-repository02_hg.jpg/600px-2000_core-repository02_hg.jpg
● http://www.alacera.com/images/model_city_3d.jpg
● http://www.faqs.org/photo-dict/photofiles/list/5558/7276chess_pawn.jpg
● http://www.shoemoney.com/images/nuke.jpg
● http://www.dzieci.legnica.pl/grafikacms/niejadek250.jpg
● http://fineartamerica.com/images-medium/conwy-castle-and-the-telford-suspension-bridge-north-wales-mal-bray.jpg
● http://fandomania.com/wp-content/uploads/2008/05/terminator.jpg
● http://www.directortom.com/storage/square%20peg.jpg?__SQUARESPACE_CACHEVERSION=1223602138853
● http://dontsqueezethejj.com/blog/wp-content/uploads/2008/07/macgyver.jpg
● http://www.wilsonsalmanac.com/images2/shakespeare9.jpg
● http://arnoldit.com/wordpress/wp-content/uploads/2008/10/mismatch.jpg
● http://images1.wikia.nocookie.net/matrix/images/thumb/3/32/Neo.jpg/300px-Neo.jpg
● http://i69.photobucket.com/albums/i71/nynja24me/guns/M-67handgrenade.jpg
● http://www.travelooce.com/pics/sunset_sailing.jpg