Modularity and Domain Driven Design; a killer combination?
-
Upload
aca-it-solutions -
Category
Technology
-
view
1.403 -
download
2
description
Transcript of Modularity and Domain Driven Design; a killer combination?
![Page 1: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/1.jpg)
MODULARITY AND DOMAIN DRIVEN DESIGN
a killer combination?
Tom De Wolf Architect
[email protected] @tomdw
Stijn Van den Enden CTO
[email protected] @stieno
www.aca-it.be
![Page 2: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/2.jpg)
initial development maintenance phase
Software Design Customer SatisfactionSeparation 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 ChangeConstant change Business Driven
Aim for 1-on-1 mapping from business changes onto software constructs
Source of Change = Business
Functional Modularisation
![Page 3: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/3.jpg)
Vehicle
Option
Make
Warranty
Model
Transport
Location
Domain Driven Design Without modularity
BusinessPartner
AddressContact
consumer supplier
transports
owner
from to
![Page 4: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/4.jpg)
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
Locationfrom to
![Page 5: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/5.jpg)
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_IDdjdfjfdkjdk221 454 BE1234567
LOCATION_ID ADDRESS454 Sunstreet 23
foreign key
VAT_NUMBER NAME
BE1234567 Company A
![Page 6: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/6.jpg)
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!
![Page 7: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/7.jpg)
M modular database migration
cross domain transactionsTxS cross domain search and reporting
CHALLENGES
![Page 8: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/8.jpg)
Mmodular database migration
![Page 9: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/9.jpg)
MDev 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 3Version 1.0.0
Version 3.0.0
Version 2.0.2
Manually track which scripts have run on which environment for which module ?
![Page 10: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/10.jpg)
MLIQUIBASE
DATABASECHANGELOG table to track executed changesets for each environment
In versioned source codeXML based DSL for changeSets
www.liquibase.org
![Page 11: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/11.jpg)
MMODULAR 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
![Page 12: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/12.jpg)
MTHE 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 dependencyLiquibase
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
![Page 13: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/13.jpg)
Tcross domain transactionsx
![Page 14: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/14.jpg)
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 datasourceT1 transaction spanning multiple modular domains
JTA not needed
JTA required
x
![Page 15: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/15.jpg)
javax.transaction.TransactionManager
transaction provider e.g. atomikos
MODULAR PERSISTENCE
T osgi-datasource XA enabled
vehicle-domaintransport-domain
javax.sql.DataSource
persistence context
persistence context
commitx
![Page 16: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/16.jpg)
Scross domain search
![Page 17: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/17.jpg)
Scross domain search
SEARCH the tale of the evil joins
![Page 18: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/18.jpg)
NOcross
module search
![Page 19: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/19.jpg)
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
![Page 20: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/20.jpg)
domainA
B. Search is using a separate query model
search-module
domainB
SearchAPI EventProvider
Update Events
Update
![Page 21: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/21.jpg)
![Page 22: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/22.jpg)
$ curl -XPUT ‘localhost:9200/vehicle/external/1’ -d ‘{ “make”: “BMW”, “VIN”: “30203232012102”}’
index document_type
id
Index a document
![Page 23: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/23.jpg)
$ curl -XPOST ‘localhost:9200/vehicle/external/1/_update’ -d ‘{ “doc”: {“make”: “Alpina”}}’
Update a document
index document_type
id
![Page 24: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/24.jpg)
$ curl -XPOST localhost:9200/vehicle/_search?pretty -d ‘{"query":{"match":{"make":"BMW"}}}'
index
Querying an index
![Page 25: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/25.jpg)
$ curl -XPOST localhost:9200/vehicle/_search?pretty -d ‘{"query":{"match":{"make":"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" : {"make": "BMW", "VIN": "30203232012112"} } ]}}!
Querying an index
![Page 26: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/26.jpg)
• Distributed (shards/replicas)
• Advanced Quering (lucene/geo/aggregation)
• Facets (terms/ranges/histogram)
• API (HTTP/Java/Java Testing)
• …{
![Page 27: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/27.jpg)
1Populate the index
![Page 28: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/28.jpg)
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
![Page 29: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/29.jpg)
1Populate the index
search
SearchIndexService
update(entity)
Synchronise on Transaction
Track updated entities
A
Map entities to searchData
B
Bulk update search index
C
![Page 30: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/30.jpg)
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
![Page 31: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/31.jpg)
1Populate the index
Map entities to searchData
B
SearchDataProvider
domainB
Entity
SearchData
![Page 32: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/32.jpg)
1Populate the index
A
search
SearchIndexService
update(entity)
Synchronise on Transaction
Track updated entities
Bulk update search index
C
Map entities to searchData
B SearchDataProvider
domainB
A
![Page 33: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/33.jpg)
2Enhancing Search
![Page 34: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/34.jpg)
2Enhancing Search
![Page 35: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/35.jpg)
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); }
![Page 36: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/36.jpg)
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.NUMBERSearchCriterionQueryType.RANGE_NUMBER
"SERVICE_ITEM"
"km"
![Page 37: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/37.jpg)
2Enhancing Search
search
SearchService
domainB
SearchCriteriaProvider
domainB
![Page 38: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/38.jpg)
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 reportingEffort to integrate search is limited
• due to dynamic osgi service model
Advanced search functionality is possible
![Page 39: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/39.jpg)
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 reportingDomain Specific Query Language
!
Exploiting elastic search capabilities beyond search, e.g. reporting
![Page 40: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/40.jpg)
MModular migration
Liquibase extender @ DeployTCross domain transactions
Distributed JTA transactionsx SCross 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
![Page 41: Modularity and Domain Driven Design; a killer combination?](https://reader035.fdocuments.us/reader035/viewer/2022062704/5560b829d8b42af43b8b4bad/html5/thumbnails/41.jpg)
Tom De Wolf Architect
[email protected] @tomdw
Stijn Van den Enden CTO
[email protected] @stieno
www.aca-it.be