Modularity and Domain Driven Design - A killer combination - T De Wolf & S van Den Ende

1,729 views
1,429 views

Published on

Applying domain driven design in a modular fashion has implications on how your data is structured and retrieved. A modular domain consists out of multiple loosely coupled sub-domains, each having their own modular schema in the database. How can we migrate and evolve the database schema’s separately with each new sub-domain version? And how do we match this with reporting and cross-domain use cases, where aggregation of data from multiple sub-domains is essential?

A case study concerning an OSGi-based business platform for automotive services has driven us to solve these challenges without sacrificing the hard-worked-on modularity and loose coupling.

In this presentation you will learn how we used Modular Domain Driven Design with OSGi. 'Liquibase' is elevated to become a first class citizen in OSGi by extending multiple sub-domains with automatic database migration capabilities. On the other hand, 'Elasticsearch' is integrated in OSGi to become a separate search module coordinating cross-domain use cases.

This unique combination enabled us to satisfy two important customer requirements. Functionally, the software should not be limited by module boundaries to answer business questions. Non-functionally, a future-proof platform is required in which the impact of change is contained and encapsulated in loosely coupled modules.

Bios:
Tom De Wolf
Tom is currently technical lead of a Java software factory delivering multiple projects for multiple clients. His background skills include software architecture, designing & implementing enterprise systems using the Java eco-system. He has specialised in building OSGi based platforms using Agile methodologies and at the same time shaping a technological base platform for future ACA projects. His background as a PhD. in Computer Science at the Katholieke Universiteit Leuven enabled Tom to travel the world and present at multiple international conferences.

Stijn van Den Ende
Stijn is CTO at ACA IT-Solutions. His background skills include software architecture, designing & implementing enterprise class systems based on XML & WebServices, Enterprise Application Integration and B2B integration. He also has a strong background in agile methods. Instructing Java, Patterns, Architecture & XML courses is another way of his involvement with the JEE technology. He advises customers with regards to their enterprise system blueprints, and how to streamline their development process while defining and maintaining the technical roadmap for ACA IT-Solutions.

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,729
On SlideShare
0
From Embeds
0
Number of Embeds
7
Actions
Shares
0
Downloads
59
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Modularity and Domain Driven Design - A killer combination - T De Wolf & S van Den Ende

  1. 1. MODULARITY AND DOMAIN DRIVEN DESIGN a killer combination? Tom De Wolf Architect tom.dewolf@aca-it.be @tomdw Stijn Van den Enden CTO stijn.vandenenden@aca-it.be @stieno www.aca-it.be
  2. 2. initial development maintenance phase Software Design Customer Satisfaction Separation of Concerns Low coupling High Cohesion B AB A • Change A impacts all modules = costly • Change B requires split of module = costly • Change A only impacts other module if api change • Change B limited to module Encapsulate Source of Change Predictable Cost of Change Constant change Business Driven Aim for 1-on-1 mapping from business changes onto software constructs Source of Change = Business Functional Modularisation
  3. 3. Vehicle Option Make Warranty Model Transport Location Domain Driven Design Without modularity BusinessPartner Address Contact consumer supplier transports owner from to
  4. 4. Vehicle Option Make Warranty Owner Model Transported Item Transport Transport Supplier Transport Consumer Vehicle Context Transport Context Domain Driven Design Modularity with Bounded Contexts BusinessPartner AddressContact Business Partner Context Location from to
  5. 5. transport vehicle MODULAR DATABASE SCHEMA • cross domain database structures not allowed • queries cannot cross domain boundaries NO foreign key business partner UUID MAKE MODEL OWNER_ID djdfjfdkjdk221 Ford C-Max BE1234567 TRANSPORTED_ITEM_ID FROM CONSUMER_ID djdfjfdkjdk221 454 BE1234567 LOCATION_ID ADDRESS 454 Sunstreet 23 foreign key VAT_NUMBER NAME BE1234567 Company A
  6. 6. BENEFITS … • Domain modules can migrate independently to next version! • Database schema is internal to the domain bundle, i.e. NOT part of the API! • Persistence and/or database technology can differ between modules in one system!
  7. 7. Mmodular database migration cross domain transactions Tx Scross domain search and reporting C H A L L E N G E S
  8. 8. Mmodular database migration
  9. 9. M Dev Machine 1 MIGRATION CHALLENGE Dev Machine 2 Continuous Integration Test environment Acceptance environment Production environment Version 1.0.0 Version 1.0.1 Version 1.0.2 Version ? Version ? Version ? environment x Module 1 Module 2 Module 3 Version 1.0.0 Version 3.0.0 Version 2.0.2 Manually track which scripts have run on which environment for which module ?
  10. 10. M LIQUIBASE DATABASECHANGELOG table to track executed changesets for each environment In versioned source code XML based DSL for changeSets www.liquibase.org
  11. 11. M MODULAR LIQUIBASE transportvehicle business partner deployment 1 deployment 2 deployment 3 Migrate modules separately Migrate @deploy of module migrate to initial version migrate to initial version migrate to initial version no db changes, no migration migrate to version 2 migrate to version 2 migrate to version 3
  12. 12. M THE EXTENDER PATTERN bundle A bundle B bundle C bundle D extender bundle Extension Pattern ?! no match /OSGI-INF/liquibase/db.changelog-master.xml osgi-liquibase-extender framework dependency Liquibase change sets domain A change sets domain B change sets domain C • Only extender depends on Liquibase framework • Update of single bundle triggers Liquibase update • New Liquibase process 
 for each matching bundle
  13. 13. Tcross domain transactionsx
  14. 14. JTA OR NOT? • No persistence layer — direct jdbc/sql access — 1 datasource
 
 • Multiple datasources • Different types of persistence layers (JPA, NoSQL, …) • JPA persistence layer in each domain bundle • instead of one big persistence unit • even on 1 datasource T 1 transaction spanning multiple modular domains JTA not needed JTA required x
  15. 15. MODULAR PERSISTENCE T osgi-datasource XA enabled vehicle-domaintransport-domain javax.transaction.TransactionManager transaction provider e.g. atomikos javax.sql.DataSource persistence context persistence context commit x
  16. 16. Scross domain search
  17. 17. Scross domain search SEARCH the tale of the evil joins
  18. 18. NO cross module search
  19. 19. A. Search encapsulated in a separate module leveraging the functionality of other domain modules search- module domainA domainB x x Repository Repository Stop • requires specific implementation for every search • complexity increases with number of modules • inability to leverage power of the datastore SearchAPI
  20. 20. domainA B. Search is using a separate query model search- module domainB SearchAPI EventProvider Update Events Update
  21. 21. $ curl -XPUT ‘localhost:9200/vehicle/external/1’ -d ‘{ “make”: “BMW”, “VIN”: “30203232012102” }’ index document_type id Index a document
  22. 22. $ curl -XPOST ‘localhost:9200/vehicle/external/1/ _update’ -d ‘{ “doc”: {“make”: “Alpina”} }’ Update a document index document_type id
  23. 23. $ curl -XPOST localhost:9200/vehicle/_search?pretty -d ‘{"query":{"match":{"make":"BMW"}}}' index Querying an index
  24. 24. $ curl -XPOST localhost:9200/vehicle/_search?pretty -d ‘{"query":{"match":{"mark":"BMW"}}}' { "took" : 3, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "failed" : 0 }, "hits" : { "total" : 2, "max_score" : 0.30685282, "hits" : [ { "_index" : "vehicle", "_type" : "external", "_id" : "1", "_score" : 0.30685282, "_source" : {"make": "BMW", "VIN": "30203232012102"} }, { "_index" : "vehicle", "_type" : "external", "_id" : "2", "_score" : 0.30685282, "_source" : {"makes": "BMW", "VIN": "30203232012112"} } ]}} ! Querying an index
  25. 25. • Distributed (shards/replicas) • Advanced Quering (lucene/geo/ aggregation) • Facets (terms/ranges/histogram) • API (HTTP/Java/JavaTesting) • … {
  26. 26. 1Populate the index
  27. 27. 1Populate the index package be.vabfs.search.api; ! public interface SearchIndexService { void update(Object entityToUpdate); void delete(Object entityToRemove); ! void populate(); ! void clear(); ! } search SearchIndexService domainB Entity EntityListener @PrePersist @PostUpdate @PostRemove
  28. 28. 1Populate the index search SearchIndexService update(entity) Synchronise onTransaction Track updated entities A Map entities to searchData B Bulk update search index C
  29. 29. 1Populate the index Map entities to searchData B package be.vabfs.search.api.data; ! import java.util.List; ! public interface SearchDataProvider { ! Class<? extends Object> getEntityClass(); List<SearchData> index(Object entity); ! } domainB Entity SearchData
  30. 30. 1Populate the index Map entities to searchData B SearchDataProvider domainB Entity SearchData
  31. 31. 1Populate the index A search SearchIndexService update(entity) Synchronise onTransaction Track updated entities Bulk update search index C Map entities to searchData B SearchDataProvider domainB A
  32. 32. 2Enhancing Search
  33. 33. 2Enhancing Search
  34. 34. 2Enhancing Search search SearchService package be.vabfs.search.api; ! import … ! public interface SearchService { … ! SearchResults query(String query, int start, int rows, String sort, String sortOrder, String documentType); List<String> options(String field, String... documentTypes); List<SearchCriterion> availableCriteria( String... criteriaCategories); }
  35. 35. 2Enhancing Search package be.vabfs.search.api.criteria; ! import java.util.List; ! public interface SearchCriteriaProvider { String getProviderCategory(); List<SearchCriterion> getAvailableCriteria(); } package be.vabfs.search.api.criteria; ! public interface SearchCriterion { ! String getName(); String getKey(); String getUnitName(); SearchCriterionType getType(); SearchCriterionQueryType getQueryType(); String getDocumentType(); ! } "vehicle.mileage" "mileage" SearchCriterionType.NUMBER SearchCriterionQueryType.RANGE_NUMBER "SERVICE_ITEM" "km"
  36. 36. 2Enhancing Search search SearchService domainB SearchCriteriaProvider domainB
  37. 37. LESSONS LEARNED @deployment time migration = RISK • have CI build continuously migrate current production data Refactor wrong modularisation requires unwanted migration dependencies • reset/flatten migration change sets to restore modularisation Migration Cross domain search and reporting Effort to integrate search is limited • due to dynamic osgi service model Advanced search functionality is possible
  38. 38. WHAT IS NEXT? Multiple module versions active? Multiple schema versions active? • e.g. feature try-out to limited customer base Downgrade to older module version? • Previous schema with new data? Hot deploy while users are firing requests? • Migration still busy = failure Migration Cross domain search and reporting Domain Specific Query Language ! Exploiting elastic search capabilities beyond search, e.g. reporting
  39. 39. M Modular migration Liquibase extender @ DeployT Cross domain transactions Distributed JTA transactionsx S Cross domain search Elasticsearch view Functionally not limited by domain module boundaries to answer business questions Non-functionally future-proof platform with impact of change contained in loosely coupled domain modules
  40. 40. Tom De Wolf Architect tom.dewolf@aca-it.be @tomdw Stijn Van den Enden CTO stijn.vandenenden@aca-it.be @stieno www.aca-it.be

×