Top Banner
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
41

Modularity and Domain Driven Design; a killer combination?

May 24, 2015

Download

Technology

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.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Modularity and Domain Driven Design; a killer combination?

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?

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?

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?

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?

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?

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?

M modular database migration

cross domain transactionsTxS cross domain search and reporting

CHALLENGES

Page 8: Modularity and Domain Driven Design; a killer combination?

Mmodular database migration

Page 9: Modularity and Domain Driven Design; a killer combination?

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?

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?

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?

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?

Tcross domain transactionsx

Page 14: Modularity and Domain Driven Design; a killer combination?

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?

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?

Scross domain search

Page 17: Modularity and Domain Driven Design; a killer combination?

Scross domain search

SEARCH the tale of the evil joins

Page 18: Modularity and Domain Driven Design; a killer combination?

NOcross

module search

Page 19: Modularity and Domain Driven Design; a killer combination?

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?

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?
Page 22: Modularity and Domain Driven Design; a killer combination?

$ 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?

$ 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?

$ 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?

$ 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?

• 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?

1Populate the index

Page 28: Modularity and Domain Driven Design; a killer combination?

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?

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?

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?

1Populate the index

Map entities to searchData

B

SearchDataProvider

domainB

Entity

SearchData

Page 32: Modularity and Domain Driven Design; a killer combination?

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?

2Enhancing Search

Page 34: Modularity and Domain Driven Design; a killer combination?

2Enhancing Search

Page 35: Modularity and Domain Driven Design; a killer combination?

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?

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?

2Enhancing Search

search

SearchService

domainB

SearchCriteriaProvider

domainB

Page 38: Modularity and Domain Driven Design; a killer combination?

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?

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?

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?

Tom De Wolf Architect

[email protected] @tomdw

Stijn Van den Enden CTO

[email protected] @stieno

www.aca-it.be