A place for everything, everything in its place Benjamin Franklin
What do I do 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...
Agenda Challenges of software Domain Driven Design introduction advanced topics Technical and architectural aspects of implementation When to use DDD Beyond DDD
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 of simple elements
Symptoms You read code and understand nothing You can't see any rules or process You don't know how to translate business requirements to code You change code and nothing works Now it's Your problem:)
Complexity Essential inherent and unavoidable depends on problem Accidental caused by chosen approach depends on solution
The Second Law of Thermodynamics Entropy does not diminish
Cowards solution Cowards solution;)
What would You change... if You start everything from the beginning? XML Annotations SOA Another web framework;) Dynamic language New server New version of the server
Insanity: doing the same thing over and over again and expecting different results
Where is the problem? Presentation layer Logic layer Data access layer
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
Domain Driven Design 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
DDD IS NOT A SILVER BULLET
EVANS IS NOT A SAVIOR
There is technically nothing new or revolutionary in DDD, there is only a guide to a better way of thinking. Casey Charlton
DDD Mental shift 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
Language of the model If domain expert don't understand model than something is really wrong
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 Organize design around metaphor hard to grasp absorb vocabulary Find metaphor in real world that describes your system loose, easy do understand large scale structure
Effort reduction + Domain Model Analysis == Domain Model Design Domain Logic Layer
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 Application logic Domain logic Infrastructure Presentation can be very sophisticated; do not underestimate Thin layer - just coordinates and delegates to domain Heart of the system model of the business concepts and rules Technical capabilities - may exist as a few layers (persistence, messages, etc)
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: Usually immutable - because has no identity attributes of call between objects 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(). human.getdigestionsystem(). getperitoneum().getstomach(). getperitoneum().getstomach(). add(new add(new Sausage(2)); Sausage(2)); human.eat(new human.eat(new Sausage(2)); Sausage(2)); public public void void eat(food eat(food f){ f){ if if (! (! ilike(f)) ilike(f)) thow thow new new IDontLikeItException(f); IDontLikeItException(f); this.digestionsystem.swallow(f); this.digestionsystem.swallow(f); }}
@Entity @Entity public public class class Order{ Order{ @Id private @Id private OrderId OrderId id; id; @OneToMany private List<OrderItem> @OneToMany private List<OrderItem> items items == new new ArrayList<OrderItem>(); ArrayList<OrderItem>(); private private BigDecimal BigDecimal sum sum == new new BigDecimal(0); BigDecimal(0); //... status, createdate, rebatepolicy, //... status, createdate, rebatepolicy, productrepository,... productrepository,... public public void void add(productid add(productid id, id, int int quantity){ quantity){ Product p = productrepository.load(id); Product p = productrepository.load(id); OrderItem OrderItem oi oi == orderitemfactory.build(p, orderitemfactory.build(p, quantity, quantity, rebatepolicy); rebatepolicy); items.add(oi); items.add(oi); sum sum == sum.add(oi.getcost()); sum.add(oi.getcost()); }} public public void void submit(){ submit(){ if if (status (status!=!= Status.NEW) Status.NEW) throw new InvalidStateException(); throw new InvalidStateException(); status status == Status.IN_PROGRESS; Status.IN_PROGRESS; createdate createdate == new new Date(); Date(); eventsmanager.handle(ordereventsfactory.ordersubmitted(this)); eventsmanager.handle(ordereventsfactory.ordersubmitted(this)); }} }} public public Iterator<OrderItem> Iterator<OrderItem> getorderitems(){ getorderitems(){ return items.iterator(); return items.iterator(); }}
Builder Design Pattern Director Builder
Factory 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
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 Transaction Proxy Application Service OrdersRepository InvoicesRepository OrmOrdersRepositoryImpl OrmInvoicesRepositoryImpl Persistence Unit + Transactions Manager
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
Policy example public class Order{ //FIXME: change to BigDecimal private double totalcost; <<interface>> TaxPolicy calculatetax(order) private TaxPolicy taxpolicy; private RebatePolicy rebatepolicy; PolishTaxPolicy } public void submit(){ totalcost-=rebatepolicy.calculaterebate(this); totalcost-=taxpolicy.calculatetax(this);... } UKTaxPolicy
Policy injection getorderfactory IoC Container OrderFactory settaxpolicy return OrderFactory PolishTaxPolicy
@Component public 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"> @Configuration public class PolicyFactories{ @Bean public TaxPolicy taxpolicy() { return... ; } }
Policy common pattern Change 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 Test Stub/Mock Test Impl Concrete Business Impl 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
@Entity @Entity public public class class Order{ Order{ public public void void submit(){ submit(){ if (status if (status!=!= Status.NEW) Status.NEW) throw new InvalidStateException(); throw new InvalidStateException(); status status == Status.IN_PROGRESS; Status.IN_PROGRESS; createdate createdate == new new Date(); Date(); }} }} eventsmanager.handle(ordereventsfactory.ordersubmitted(this)); 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 public interface interface InvoiceSpecyfication{ InvoiceSpecyfication{ public public Collection<InvoiceProblem> Collection<InvoiceProblem> check(invoice check(invoice i) i) }}
public public interface interface InvoiceCriterion{ InvoiceCriterion{ public public String String validate(invoice validate(invoice i); i); public public boolean boolean iscritical(); iscritical(); }} public public class class CombinedInvoiceSpecyfication CombinedInvoiceSpecyfication implements implements InvoiceSpecyfication{ InvoiceSpecyfication{ private private List<InvoiceCriterion> List<InvoiceCriterion> criteria; criteria; public public Iterable<InvoiceProblem> Iterable<InvoiceProblem> check(invoice check(invoice i){ i){ Collection<InvoiceProblem> Collection<InvoiceProblem> result result == new new...;...; for for (InvoiceCriterion (InvoiceCriterion criterion criterion :: criteria){ criteria){ String String problem problem == criterion.validate(i); criterion.validate(i); if if (problem (problem!=!= null){ null){ result.add(new result.add(new InvoiceProblem(problem)); InvoiceProblem(problem)); if if (criterion.iscritical()) (criterion.iscritical()) break; break; return return result; result; }}}} }}}}
Building Blocks - cooperation Application Layer (Application Services, Use Case Agents) Domain Layer (Business Logic) Entity (Aggregate root) Delegate business methods Factory Business Service Delegate Create Entity Delegate <<interface>> Policy (Strategy Design Pattern) <<interface>> Repository Load Save Value Object Aggregate Generate Event PolicyImpl1 PolicyImpl2
Comparison to procedural approach PROCEDURE orderservice(o:torder); BEGIN... END; TOrder = RECORD id: integer;... END;
memory.reset();
Strategic design Distillation of Domains Defining Bounded Contexts Introduce Anti-corruption Layer
You can't do everything perfect Welcome to the real world, Neo 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
Focus on core domain Core 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 in troubles 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 Layer
Anti-corruption Strategies Our brand new shiny nice system Anti-corruption Layer Facade Adapter Service Ugly legacy system
Technical aspects of DDD impl.
Main rule Platform, framework or technical architecture should not influence arena of domain model
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
Sample violation of CqS Class level violation private private int int x; x; public int incrementandreturn(){ public int incrementandreturn(){ x++; x++; return return x; x; }} System level violation Add an Order and return list of all orders it's GUI functionality but server API should offer 2 methods
Command-query Responsibility Segregation (G)UI Query Command DTO Application Logic Facade Data provider/finder via Service Business Logic Repository/DAO ORM + JDBC
CqRS Characteristic Processing C and Q is often asymmetrical Should be scaled separately Is it worth to apply in CRUD systems?
CqRS Distributed DDD and scalability (G)UI Query Command DTO Application Logic Business Logic Data provider/finder Event (asynch) DB 2 Change Events Bus + Event handlers Repository/DAO DB 1
Query sample impl. public public class class SearchDocumentsQuery SearchDocumentsQuery implements implements Serializable{ Serializable{ private Status status; private Status status; private private Date Date epirydate; epirydate; private String[] private String[] titlewords; titlewords; private String[] contentwords; private String[] contentwords; //Getters //Getters and and setters/constructor setters/constructor }} public public class class DocumentQueries DocumentQueries /*implements /*implements SomeInterface*/{ SomeInterface*/{ public List<Document> search(searchdocumentsquery public List<Document> search(searchdocumentsquery query){ query){ //ORM return entities simple case //ORM return entities simple case }} }} public public List<DocumentDTO> List<DocumentDTO> search(searchdocumentsquery search(searchdocumentsquery query){ query){ //SQL return UseCase relevant Data Transfer Object //SQL return UseCase relevant Data Transfer Object }}
Query a'la DSL public public class class SearchDocumentsQuery SearchDocumentsQuery implements implements Serializable{ Serializable{ private Status status; private Status status; private private Date Date epirydate; epirydate; private String[] private String[] titlewords; titlewords; private String[] contentwords; private String[] contentwords; //ONLY //ONLY getters getters public public SearchDocumentsQuery SearchDocumentsQuery expired(){ expired(){ status = Status.ACTIVE; status = Status.ACTIVE; expirydate expirydate == new new Date(); Date(); return this; return this; }} }} public public SearchDocumentsQuery SearchDocumentsQuery contains(string contains(string phrase){ phrase){ String[] words = phrase.split(" "); String[] words = phrase.split(" "); titlewords titlewords == words; words; contentwords = contentwords = words; words; return this; return this; }}
Command classic impl. public public class class OrderProductCommand OrderProductCommand implelents implelents Serializable{ Serializable{ private int productid; private int productid; private private int int quantity; quantity; //getters and //getters and constructor constructor }} public public class class Basket Basket /*implements /*implements SomeInterface*/{ SomeInterface*/{ private Order order; private Order order; public public void void add(addproductcommand add(addproductcommand cmd){ cmd){ Product prod = productrepository.get(cmd.getproductid()); Product prod = productrepository.get(cmd.getproductid()); order.add(prod, order.add(prod, cmd.getquantity()); cmd.getquantity()); }} }} public public void void submit(submitordercommand submit(submitordercommand cmd){ cmd){ order.submit(cmd.getpayment(), cmd.getaddressinfo()); order.submit(cmd.getpayment(), cmd.getaddressinfo()); orderrepository.save(order); orderrepository.save(order); eventsmanager.ordersubmitted(new eventsmanager.ordersubmitted(new OrderSubmittedEvent(order)); OrderSubmittedEvent(order)); }}
Command handlers based impl. public public class class OrderProductCommand OrderProductCommand extends extends Command{...} Command{...} public public interface interface Handler<T> Handler<T> {{ void void handlemessage(t handlemessage(t message) message) throws throws Exception; Exception; }}
public public class class AddProductHandler AddProductHandler implements implements Handler<AddProductCommand>{ Handler<AddProductCommand>{ private private ProductRepository ProductRepository repository; repository; }} public public void void handlemessage(addproductcommand handlemessage(addproductcommand message) message) {{ //... //... }} public public class class CommandBus{ CommandBus{ public void public void handle(command handle(command cmd) cmd) Collection<Handler<?>> matchedhandlers Collection<Handler<?>> matchedhandlers == handlers.get(message.getclass()); handlers.get(message.getclass()); for (Handler for (Handler handler handler :: matchedhandlers){ matchedhandlers){ //prepare environment //prepare environment (transactions, (transactions, security, security, //inject current user, etc) //inject current user, etc) handler.handlemessage(cmd); handler.handlemessage(cmd); }} }} }} //may //may generate generate message 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 Pattern Alternative 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
Constructor Writer
Sometimes it's all about just collecting data (with nice GUI)
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
Beyond DDD
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 User Employee Client Company Inheritance is not a good idea to model roles:p
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
Use Case flow and global algorithm Classes Classes Classes Classes Classes
Context Whole Use Case or just few steps adds meaning to the data Data core basically dumb may contain basic responsibility Interactions business responsibility operates on 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
Code should mean something Dan Bergh Johnsson
Dziękuję za uwagę więcej... http://art-of-software.blogspot.com slawomir.sobotka@bottega.com.pl Sławomir Sobótka
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