don't write the code
DESCRIPTION
Are you also drowning in the complex and unwieldy code. Can't you see the shoe for bare toes? 74% of all businesses are struggling with high IT budgets and low growth. So what is the solution to get out of trouble? The reasons for the poor code are many. Sometimes it is due to circumstances beyond our direct control, such as unrealistic deadlines, poor requirements or political struggles. In this lecture we will look at the part we have influence on namely the code we write and not least the code we DO NOT write. We will look at why many projects fail from day one, due bad decisions made on an uninformed basis, or based on stereotypical solutions. It is not enough to point the finger of the problems. We will also look at what we can do about it, in the form of concrete examples from the real world. Hints for the content: Testable code, Model Driven Development, Domain Driven Design, CQRS and Event Sourcing.TRANSCRIPT
![Page 1: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/1.jpg)
TIGERTEAM®
L E A N T H I N K I N G
Jeppe$Cramon$
$
Don’t&write&THAT&code&
Don’t&write&the&code&
![Page 2: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/2.jpg)
Corporate$growth$slowed$due$
to$lack$of$funding$Berlingske$Finans$
6$out$of$10$public$projects$are$$
going$over$?me$and$budget$Version2$
![Page 3: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/3.jpg)
HiCng$Point$of$No$Return$too$Early?$
Time&
Cost&of&Rework&
V&1.0&Freeze&
![Page 4: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/4.jpg)
Same$procedure$as$last$year?$
$
Same$procedure$as$every$year!!!$
![Page 5: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/5.jpg)
We$need$a$strong$founda?on$for$development$Alignm
ent&
Highly$aligned$
Less$aligned$
Effciency&Less$effec?ve$ Highly$effec?ve$
”Maintenance&Zone”$ ”WellEOiled&IT”$
”Alignment$Trap”$
11%$
74%$
7%$
8%$
%"of"the"504"
respondents"
+13$
Y14$
Y2$ Y15$
+11$
Y6$
+35$
”IT&enabled&Growth”$
%"difference"compared"to"the"overall"averages" IT&spending&Combined&yearly&growthE&rate&over&a&3&year&period&
Source:&B
ain&Ana
lysis&
+0$
![Page 6: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/6.jpg)
Open$for$new$ideas?$
Poul,$you$idiot,$what's$that!?$
You$should$only$bring$things$we$
can$eat!$
![Page 7: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/7.jpg)
What’s$for$dinner?$
![Page 8: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/8.jpg)
One$size$fits$all$
Client$
Remote$Facade$
Applica?on$Service$
Data$Access$Layer$
Data$Storage$
Domain$
Object$
Domain$
Object$
![Page 9: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/9.jpg)
Classic$Java$approach$
Hibernate/JPA$
Spring/EJB3/CDI$
Developer$meat$
![Page 10: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/10.jpg)
Classic$Ruby$on$Rails$approach$
Developer$meat$
Ruby$on$Rails$
![Page 11: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/11.jpg)
But$this$is$all$TECHNOLOGY$
When$did$we$get$so$
caught$up$in$technology,$
that$we$forgot$what$we$
were$trying$to$solve?$
![Page 12: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/12.jpg)
WE’RE&COMPLECTING&THINGS&Rick$Hickey,$2011$
![Page 13: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/13.jpg)
SOA
Web Services
Requirement Management tools
BPMN
Laye
red
Arch
itec
ture
We
bSph
ere
Work
flow
syst
em
Shar
ePoi
nt
Oracle Service bus
Team Foundation
Server
SubV
ersi
on
Documentum
Portal
Orac
le D
B MS
SQL
Ser
ver
NoSQ
L
Policy Manager
WebLogic
.NET
JAVA
Ruby on Rails
iOS
Android
XML
JavaScript
Flash
BlackBerry Git
Hg
Dart
Cloud
Spring
BizT
alk
Groo
vy
Scal
a
F#
C#
VB.N
ET
REST
![Page 14: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/14.jpg)
The$silverbullit$syndrome$
![Page 15: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/15.jpg)
Let’s$start$with$the$end$
OUR$HOLY$DATABASE$
![Page 16: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/16.jpg)
Not$all$data$is$created$equal$
• Data$survives$your$code,$so$treat$it$well$• But$treat$it$according$to$its$nature$$
• Who$said$a$rela?onal$database$was$the$best$
fit?$
• Why$do$we$create$so$big$models?$
• And$why$are$we$trying$to$solve$all$problems$
using$the$same$approach?$
![Page 17: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/17.jpg)
The$bigger$the$beher$–$right?$….$
…..$
…..$
$
….$
…..$
…..$
$
….$
…..$
…..$
$
….$
…..$
…..$
$
![Page 18: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/18.jpg)
A$big$unified$model$is$every$architects$
pibe$dream$
But$as$they$say$
![Page 19: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/19.jpg)
ONE MODEL TO RULE THEM ALL ONE MODEL TO FIND THEM
ONE MODEL TO BRING THEM ALL AND IN THE DARKNESS BIND THEM
![Page 20: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/20.jpg)
Result:$Our$queries$get$messy$
![Page 21: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/21.jpg)
Let’s$fix$the$complexity$of$SQL$code$
Let’s$use$a$big$hammer$–$ORM$
![Page 22: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/22.jpg)
Introducing$ORM$brings$other$fun$things$such$as$
• When$should$we$fetch$associa?ons$LAZY$and$when$EAGER$?$It$depends$on$the$use$case$
• Batch$processing$becomes$tricky$
• By$conven?on,$names$for$Tables,$Join$columns,$Join$Tables$Foreignkeys,$etc.$might$not$match$corporate$standard$or$be$too$long$for$Oracle$;)$
• General$OO$vs.$ER$impedance$mismatch$
• Tes?ng$ORM$code$is$tedious$
![Page 23: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/23.jpg)
LET’S&TAKE&A&STEP&BACK&AND&LOOK&AT&THE&NATURE&OF&DATA&
![Page 24: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/24.jpg)
Many$perspec?ves$on$data$
Customer&
Online$Ordering$System$
Pricing&
Inventory&
Sales&
Product$
Unit$Price$Promo?onal$Price$Promo?on$End$Date$
Stock$Keeping$Unit$(SKU)$Quan?ty$On$Hand$(QOH)$Loca?on$Code$
Price$Quan?ty$Ordered$Name$
![Page 25: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/25.jpg)
There’s$always$more$than$one$
model$at$play$in$any$big$project$
But$when$code$based$on$
mul?ple$models$is$combined$
![Page 26: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/26.jpg)
…$then$the$code$becomes$filled$with$
errors,$unreliable$and$difficult$to$
understand$
Communica?on$between$team$
members$becomes$confusing.$
$
It$is$ouen$unclear$in$what$context$a$
model$should$NOT$be$used!$
![Page 27: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/27.jpg)
Context$is$lacking$
![Page 28: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/28.jpg)
Smaller$models$&$clear$data$ownership$
Sales&Product$
SKU$Name$Descrip?on$Quan?ty$Ordered$…$
Sales&
Inventory&Product$
SKU$QOH$Loca?on$Code$…$
Inventory&
Pricing&Product$
SKU$Unit$Price$Promo?onal$Price$…$
Pricing&
DDD:$
Bounded$
Context$
SOA:$
Service$
Online$Ordering$System$
En?ty$iden?ty$
![Page 29: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/29.jpg)
Somethings$missing$
How$do$we$collaborate?$
![Page 30: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/30.jpg)
Status$Quo$
![Page 31: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/31.jpg)
Tradi?onal$Layered$(SOA)$Solu?on$
Data$
Storage$
Data$
Storage$
Data$
Storage$
Data$
Service$
Data$
Service$
Data$
Service$
Ac?vity$
Service$
Ac?vity$
Service$
Proces$Service$ Proces$Service$
Client$ Client$
Client$
Data$
Service$
![Page 32: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/32.jpg)
Composite$UI’s$
Online$Ordering$System$
Sales& Pricing& Inventory&
Web/Applica9on"
9er"
Background"server"
9er"
Storage"9er"
Composite$UI$
UI$ Layered$
Applica?on$Data$Access$Layer$
Read$m
odel$
Write$m
odel$
![Page 33: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/33.jpg)
Composite$UI$Y$example$
![Page 34: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/34.jpg)
That$covers$data$presenta?on$
What$about$transac?ons?$
![Page 35: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/35.jpg)
Next$Step$–$Event$Driven$Architecture$
Sales&Product$
SKU$Name$Price$Quan?ty$Ordered$…$
Inventory&Service&(SAP)&Product$
SKU$QOH$Loca?on$Code$…$
Pricing&Service&Product$
SKU$Unit$Price$Promo?onal$Price$…$
Inventory&
Pricing&
Sales&
Customers&
New$SKU$
Event$
New$SKU$
Event$
New$SKU$
Event$
Order$
Accepted
Event$
Message$Bus$
Who$
coordinates$the$
sales$process?$
Online$Ordering$System$
Web$Shop$
(Composite$UI)$
![Page 36: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/36.jpg)
Introducing$Sagas$
Sales&Service&Order$
Accepted$
Billing&Service&
Shipping&Saga&
Shipping&Service&
Online$Ordering$System$
Message$Bus$
Order$
Accepted$
Order$
Accepted$
Customer$
Billed$
Customer$
Billed$
Ship$
Order$
Ship$
Order$
![Page 37: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/37.jpg)
$
How$do$we$scale?$
$Both$in$terms$of:$$
developer$produc?vity$&$run?me$performance$
Let’s$first$check$the$premise$
![Page 38: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/38.jpg)
Collabora?ve$domains$
1.$Read$ 2.$Read$
4.$Update$3.$Coffee$?me$
5.$Stale$data$
![Page 39: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/39.jpg)
We’re$working$with$stale$data$
![Page 40: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/40.jpg)
Our$architectures$ouen$have$
problems$handling$this$type$of$
problem$
Let’s$look$at$how$we’ve$evolved$
![Page 41: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/41.jpg)
Thin$Layers$of$complexity$
UI$ Data$
Pro:$Easy$and$simple$
Con:$Scales$poorly$for$complex$domains$
![Page 42: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/42.jpg)
Next$step$–$more$layers$
UI$ Applica?on$ Domain$ Data$
Pro:$Handles$complex$domains$beher$by$$
Separa?ng$usecase$and$domain$logic$
Con:$Increasing$complexity.$Risk$of$Anemic$
Domain$model$combined$with$$
transac?onYscript.$
Time$
Real$domain$model$
Complexity$
![Page 43: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/43.jpg)
Queries$are$just$data$–$no$logic$$
• Give$me$the$customer$with$his$last$10$orders$
• Give$me$the$customer$with$total$sum$of$
orders$for$the$last$year$
• Give$me$the$complete$order$
• Give$me$the$shipping$status$for$the$order$
So$why$go$through$all$those$layers?$
![Page 44: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/44.jpg)
A"single"model"cannot"be"
appropriate"for"repor9ng,"searching"
and"transac9onal"behavior"Greg"Young,"2008$
![Page 45: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/45.jpg)
CQS$Separa?on$of$$
funcVons$that$write$$&$
funcVons$that$read&
UI$ Applica?on$ Domain$ Data$
Commands$–$Change$data$
UI$ Applica?on$ Data$
Queries$–$Ask$for$data$(no$side$effects)$
![Page 46: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/46.jpg)
CQS$from$a$code$perspec?ve$
public$class$CustomerService${$
$$$$//"Commands$
$$$$void$MakeCustomerPreferred(CustomerId)$$
$$$$void$ChangeCustomerLocale(CustomerId,$NewLocale)$$
$$$$void$CreateCustomer(Customer)$$
$$$$void$EditCustomerDetails(CustomerDetails)$
$
$$$$//"Queries$
$$$$Customer$GetCustomer(CustomerId)$$
$$$$CustomerSet$GetCustomersWithName(Name)$$
$$$$CustomerSet$GetPreferredCustomers()$}$
From:$hhps://gist.github.com/1964094$
![Page 47: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/47.jpg)
NEXT&STEP&E&CQRS&
CQRS"is"simply"the"crea9on"of"two"objects""
where"there"was"previously"only"one""Greg"Young$
![Page 48: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/48.jpg)
CQRS$
In$its$simplest$form$public$class$CustomerWriteService${$
$$$$//"Commands$
$$$$void$MakeCustomerPreferred(CustomerId)$$
$$$$void$ChangeCustomerLocale(CustomerId,$NewLocale)$$
$$$$void$CreateCustomer(Customer)$$
$$$$void$EditCustomerDetails(CustomerDetails)$
}$
$
public$class$CustomerReadService${$
$$$$//"Queries$
$$$$Customer$GetCustomer(CustomerId)$$
$$$$CustomerSet$GetCustomersWithName(Name)$$
$$$$CustomerSet$GetPreferredCustomers()$}$
From:$hhps://gist.github.com/1964094$
![Page 49: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/49.jpg)
Commands$&$Events$are$Messages$
Events$
UI$
Domain$model$Read$model$
”AcceptOrder”$
command"
”OrderAccepted”$
event"
”Find$all$$
Accepted$Orders”$
Query"
Commands$are$Impera?ve:$DoStuff$
Events$are$Past$tense:$StuffDone$
![Page 50: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/50.jpg)
CQRS$
As$its$ouen$prac?ced$
UI$ Domain$
Event$
Store$
Commands$–$Change$data$
Commands$ Events$
SQL$DB$ Document$DB$ Graph$DB$
UI$ Data$
Queries$–$Ask$for$data$
Events$
Query$ Build$
![Page 51: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/51.jpg)
CQRS$Building$blocks$
Client
Commands Command Bus
Sends
Command Handlers
Modify
Repositories
Read Write Data store
Publish Events
Event Bus
Command Services
Event Handlers Events
Read store Query Handlers Query Results
Queries
Query Services
Events
Domain
![Page 52: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/52.jpg)
New$UI$paradigme$
TaskYbased/Induc?ve$UI$
• A$depart$from$the$tradi?onal$WHAT$UI$(CRUD)$
• Task$based$UI’s$focuses$on$HOW$the$user$wants$to$use$the$applica?on$
• Guides$users$through$the$work$process$• The$UI$becomes$an$intrinsic$part$of$the$design$
• The$UI$design$directly$affects$our$commands$and$thereby$our$transac?onal$boundaries$
• Should$be$preferably$use$asynchronous$Commands$
![Page 53: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/53.jpg)
What$about$Valida?on$
• Happens$in$the$UI$before$Commands$are$sent$
• Typically$validated$using$Read$models$
• Helps$to$ensure$that$commands$don’t$ouen$
fail$$
• Validates$simple$things$(values$ranges,$unique$
keys/values)$
• Doesn’t$enforce$business$logic$rules$
![Page 54: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/54.jpg)
Circular$architecture$
Task$based$
UI$
Domain$
Model$Read$Model$ Event$ Event$ Event$
![Page 55: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/55.jpg)
Separa?on$of$Concerns$
• Different$developer$skills$and$roles$for$command$and$query$parts$
• New$Business$Requirements$ripples$
controllably$between$areas$
• No$need$for$Gehers$&$Sehers$in$your$domain$
model$
• Testability$–$Event$based$tes?ng$is$very$easy$
![Page 56: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/56.jpg)
public class CustomerCommandHandler { private Repository<Customer> customerRepository; public CustomerCommandHandler(Repository<Customer> customerRepository) { this.customerRepository = customerRepository; } @CommandHandler public void handle(UnsignCustomer cmd) { Customer customer = repository.load(cmd.getCustomerId()); customer.unsign(); } }
public class Customer { private boolean signedUp; public void unsign() { if (signedUp) { apply(new CustomerUnsignedEvent()); } } @EventHandler private void handle(CustomerUnsignedEvent event) { signedUp = false; } }
![Page 57: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/57.jpg)
Tes?ng$CQRS$@Test public void a_signedup_customer_can_unsign() { UUID customerId = UUID.randomUuid().toString(); FixtureConfiguration fixture = Fixtures.newGivenWhenThenFixture(); fixture.registerAnnotatedCommandHandler( new CustomerCommandHandler(fixture.createGenericRepository(Customer.class)) ); fixture.setAggregateIdentifier(customerId);
fixture .given( TestFactory.customerCreatedEvent(customerId), TestFactory.customerSignedUpEvent(customerId) ) .when( TestFactory.unsignCustomerCommand(customerId) ) .expectEvents( TestFactory.customerUnsignedEvent(customerId) ); }
![Page 58: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/58.jpg)
CQRS$is$not$top$level$architecture$Online$Ordering$System$
Sales& Pricing& Inventory&
Web/Applica9on"
9er"
Background"server"
9er"
Storage"9er"
Composite$UI$
UI$ Layered$
Applica?on$Data$Access$Layer$
Read$m
odel$
Write$m
odel$
![Page 59: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/59.jpg)
TIGERTEAM®
L E A N T H I N K I N G
Don’t&WRITE&the&code&
![Page 60: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/60.jpg)
Electronic$Landregistra?on$$
Case$study$
![Page 61: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/61.jpg)
ETL$Y$Automa?on$
• Extremely$complex$domain$area$
• The$rules$are$determined$by$Law$(not$logic)$
• Covering$registra?ons$there$are$several$hundred$years$old$
• Complex$logic$required$to$automate$law$
• Very$short$deadline$for$the$third$ahempt$to$
build$ETL$
Context&
![Page 62: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/62.jpg)
Electronic$Landregistra?on$
• Technical$choices$– Programming$language:$Java$
– Database:$Oracle$• First$challenge$
– How$do$we$integrate$Java$and$Oracle$database?$
![Page 63: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/63.jpg)
How$it’s$usually$done$
Java&code&
SQL&
![Page 64: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/64.jpg)
Means$we$go$from$this…$
![Page 65: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/65.jpg)
package dk.tigerteam.mdsd.demo.model.internal;@Entity@Table(name = "Customer")public class Customer extends AbstractEntity { private static final long serialVersionUID = 2098912667L; @Basic @Column(name = "name", nullable = false) private String name; @OneToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, fetch = FetchType.LAZY) @JoinColumn(name = "addressId") @NotNull private dk.tigerteam.mdsd.demo.model.internal.Address address; @OneToMany(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, targetEntity = Booking.class, mappedBy = "customer", fetch = FetchType.LAZY) private Set<Booking> bookingCollection = new java.util.HashSet<Booking>(); public String getName() { return name; } public void setName(String name) { this.name = name; } … … … … … … … … … …}
package dk.tigerteam.mdsd.demo.mode.internal; @Entity@Table(name = "Booking")public class Booking extends AbstractEntity { private static final long serialVersionUID = 170080605L; @Basic @Column(name = "comment", nullable = false) private String comment; @Basic @Temporal(TemporalType.TIMESTAMP) @Column(name = "time", nullable = false) private java.util.Date time; @Basic @Column(name = "timeslot", nullable = false) private int timeslot; @ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, fetch = FetchType.LAZY) @JoinColumn(nullable = false, name = "customerId") private Customer customer; public String getComment() { return comment; } public void setComment(String parameter) { this.comment = parameter; } public java.util.Date getTime() { return time; } … … … … … … …}
@Entity@Table(name = "Address")public class Address extends AbstractEntity { private static final long serialVersionUID = 1697028161L; @Basic @Column(name = "street", nullable = false) private String street; @Basic @Column(name = "zipCode", nullable = false) private String zipCode; @Basic @Column(name = "city", nullable = false) private String city; public String getStreet() { return street; } public void setStreet(String parameter) { this.street = parameter; } … … …}
To$this…$
![Page 66: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/66.jpg)
This$works$fairly$well,$un?l…$
• We$get$?red$of$wri?ng$the$same$tedious$code$by$hand$
• We$suddenly$realize$that:$$
• Our$assump?ons$didn’t$hold$up$and$we$need$to$change$many$of$
our$mappings$
• We$need$to$write$a$lot$of$test$code$to$ensure$that$our$mappings$
are$correct$
• We’re$wri?ng$a$lot$of$technical$code$and$very$lihle$business$
code$
![Page 67: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/67.jpg)
The$line$between$modeling$og$
muddling$in$hand$wrihen$code$is$
very$thin$
![Page 68: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/68.jpg)
Can’t$see$the$forest$for$the$trees?$package$dk.?gerteam.mddexample.model.customer;$
$
@javax.persistence.En?ty$
public$class$Customer$extends$dk.?gerteam.mddexample.model.user.User${$
$$$$private$sta?c$final$long$serialVersionUID"="1328488396L;"
$
[email protected](name$=$"comment")$
$$$$private$String$comment;$
$
[email protected]({@javax.persistence.AhributeOverride(name$=$"firstName",[email protected](name$=$"name_firstName")$
$$$$$$$$)$
$$$$$$$$,[email protected](name$=$"lastName",[email protected](name$=$"name_lastName")$
$$$$$$$$)$
$$$$})$
$$$$private$dk.?gerteam.mddexample.model.customer.Name$name;$
$
[email protected]({@javax.persistence.AhributeOverride(name$=$"street",[email protected](name$=$"address_street")$
$$$$$$$$)$
$$$$$$$$,[email protected](name$=$"state",[email protected](name$=$"address_state")$
$$$$$$$$)$
$$$$$$$$,[email protected](name$=$"zipCode",[email protected](name$=$"address_zipCode")$
$$$$$$$$)$
$$$$$$$$,[email protected](name$=$"city",[email protected](name$=$"address_city")$
$$$$$$$$)$
$$$$$$$$,[email protected](name$=$"country",[email protected](name$=$"address_country")$
$$$$$$$$)$
$$$$})$
$$$$private$dk.?gerteam.mddexample.model.customer.Address$address;$
$
[email protected](cascade$=$${$
$$$$$$$$javax.persistence.CascadeType.MERGE,"javax.persistence.CascadeType.PERSIST,"javax.persistence.CascadeType.REFRESH}"
$$$$,$targetEn?ty$=$dk.?gerteam.mddexample.model.customer.Pet.class,$mappedBy$=$"customer",$fetch$=$javax.persistence.FetchType.LAZY)"
$$$$private$java.u?l.Set<dk.?gerteam.mddexample.model.customer.Pet>$petCollec?on$=$
$$$$$$$$new$java.u?l.HashSet<dk.?gerteam.mddexample.model.customer.Pet>();$
$
[email protected](cascade$=$${$
$$$$$$$$javax.persistence.CascadeType.MERGE,"javax.persistence.CascadeType.PERSIST,"javax.persistence.CascadeType.REFRESH}"
$$$$,$fetch$=$javax.persistence.FetchType.LAZY)"
[email protected](name$=$"Customer_invoice",[email protected](name$=$"CustomerId")$
$$$$,[email protected](name$=$"invoiceId")$
$$$$)$
$$$$private$java.u?l.Set<dk.?gerteam.mddexample.model.invoice.Invoice>$invoiceCollec?on$=$
$$$$$$$$new$java.u?l.HashSet<dk.?gerteam.mddexample.model.invoice.Invoice>();$
$
[email protected](cascade$=$${$
$$$$$$$$javax.persistence.CascadeType.MERGE,"javax.persistence.CascadeType.PERSIST,"javax.persistence.CascadeType.REFRESH}"
$$$$,$fetch$=$javax.persistence.FetchType.LAZY)"
[email protected](name$=$"Customer_appointment",[email protected](name$=$"CustomerId")$
$$$$,[email protected](name$=$"appointmentId")$
$$$$)$
$$$$private$java.u?l.Set<dk.?gerteam.mddexample.model.customer.Appointment>$appointmentCollec?on$=$
$$$$$$$$new$java.u?l.HashSet<dk.?gerteam.mddexample.model.customer.Appointment>();$
$
$$$$public$String$getComment()${$
$$$$$$$$return$comment;$
$$$$}$
$
$$$$public$void$setComment(String$parameter)${$
$$$$$$$$this.comment$=$parameter;$
$$$$}$
$
$$$$public$dk.?gerteam.mddexample.model.customer.Name$getName()${$
$$$$$$$$return$name;$
$$$$}$
$
$$$$public$void$setName(dk.?gerteam.mddexample.model.customer.Name$parameter)${$
$$$$$$$$this.name$=$parameter;$
$$$$}$
$
$$$$public$dk.?gerteam.mddexample.model.customer.Address$getAddress()${$
$$$$$$$$return$address;$
$$$$}$
$
$$$$public$void$setAddress($
$$$$$$$$dk.?gerteam.mddexample.model.customer.Address$parameter)${$
$$$$$$$$this.address$=$parameter;$
$$$$}$
$
$$$$public$java.u?l.Set<dk.?gerteam.mddexample.model.customer.Pet>$getPetCollec?on()${$
$$$$$$$$return$petCollec?on;$
$$$$}$
$
$$$$public$java.u?l.Set<dk.?gerteam.mddexample.model.invoice.Invoice>$getInvoiceCollec?on()${$
$$$$$$$$return$invoiceCollec?on;$
$$$$}$
$
$$$$public$void$setInvoiceCollec?on($
$$$$$$$$java.u?l.Set<dk.?gerteam.mddexample.model.invoice.Invoice>$parameter)${$
$$$$$$$$this.invoiceCollec?on$=$parameter;$
$$$$}$
$
$$$$public$java.u?l.Set<dk.?gerteam.mddexample.model.customer.Appointment>$getAppointmentCollec?on()${$
$$$$$$$$return$appointmentCollec?on;$
$$$$}$
$
$$$$public$void$setAppointmentCollec?on($
$$$$$$$$java.u?l.Set<dk.?gerteam.mddexample.model.customer.Appointment>$parameter)${$
$$$$$$$$this.appointmentCollec?on$=$parameter;$
$$$$}$
}$
$
When$all$you$wanted$to$
convey$was$this$
![Page 69: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/69.jpg)
Hand$held$consistency…$
@En?ty$
public&class&Customer&{&$$@OneToMany($
$$$$$$targetEn9ty$=$Pet.class,&&&&&&&&mappedBy&=&"customer”&"")"$$private$Set<Pet>$petCollec?on$=$$new$HashSet<Pet>();$
$
$public&Set<Pet>&getPetCollecVon()&{&$$$$$$return&new&OneToManySetWrapper<Customer,&Pet>(this,&petCollecVon)&{&$$$$$$$$$$$$$$@Override$
$$$$$$$$$$$$$$protected&Customer&getOneSideObjectInManySideObject(Pet$manySideObject)${$
$$$$$$$$$$$$$$$$$$return&manySideObject.getCustomer();&$$$$$$$$$$$$$$}$
$
$$$$$$$$$$$$$$@Override$
$$$$$$$$$$$$$$protected&void&setOneSideObjectInManySideObject(Pet$manySideObject,$
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$Customer$oneSideObject)${$
$$$$$$$$$$$$$$$$$$manySideObject.setCustomer(oneSideObject);$
$$$$$$$$$$$$$$}$
$$$$$$$$};$
$$$$}$
}$
@En?ty$
public&class&Pet&{&$$$@ManyToOne$
$$$private$Customer$customer;$$
$$$$public&void&setCustomer(Customer$parameter)${$$$$$$$$$new&ManyToOneWrapper<Customer,&Pet>(this)&{&$$$$$$$$$$$$$$$$@Override$
$$$$$$$$$$$$$$$$protected&void&addManySideObjectToOneSideCollecVon(Customer$oneSide,$Pet$manySide)${$
$$$$$$$$$$$$$$$$$$$$((WrappedSet<Pet>)$oneSide.getPetCollec?on()).getWrappedCollec?on().add(manySide);$
$$$$$$$$$$$$$$$$}$
$$$$$$$$$$$$$$$$@Override$
$$$$$$$$$$$$$$$$protected&void&removeManySideObjectFromOneSideCollecVon(Customer$oneSide,$Pet$manySide)${$
$$$$$$$$$$$$$$$$$$$$((WrappedSet<Pet>)$oneSide.getPetCollec?on()).getWrappedCollec?on().remove(manySide);$
$$$$$$$$$$$$$$$$}$
$
$$$$$$$$$$$$$$$$@Override$
$$$$$$$$$$$$$$$$protected&Customer&getOneSideObjectInManySideObject(Pet$manySide)${$
$$$$$$$$$$$$$$$$$$$$return&manySide.customer;&$$$$$$$$$$$$$$$$}$
$
$$$$$$$$$$$$$$$$@Override$
$$$$$$$$$$$$$$$$protected&void&setOneSideObjectInManySideObject(Pet$manySide,Customer$oneSide)${$
$$$$$$$$$$$$$$$$$$$$manySide.customer$=$oneSide;$
$$$$$$$$$$$$$$$$}$
$$$$$$$$$$$$}.updateOneSideObject(parameter);$
$$$$}$
}$
![Page 70: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/70.jpg)
Automa?on$
From$sweatshops$to$automa?on$
!$
![Page 71: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/71.jpg)
The$end$of$wri?ng$tedious$code$by$hand$
Frameworks&$
(Hibernate/
JPA,$En?ty$
Framework)$
Libraries$(f.eks.$Java/.NET)$
Schema?c$code$
Interes?ng$code$$
(Wrihen$by$hand)$
WriYen&by&hand&
Model$ Generator$
![Page 72: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/72.jpg)
At$ETL$we$introduced$this$process$
UML&class&diagrams&
Java&code&Hibernate&
SQL&
Tests&
![Page 73: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/73.jpg)
Higher$abstrac?on$level$
BiYtemporal$history$
At"any"9me"
Over"a"long"period"
What"we"model"
<<History>>&
Gives$us$the$freedom$
to$chose$the$right$$
implementa?on$
without$revealing$it$in$the$
model$
1 *
Event Store
![Page 74: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/74.jpg)
Versioning$(Temporal$Object$Pahern)$
![Page 75: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/75.jpg)
The$Core$of$Flexible$Code$Generator$
XmiReader reader = new EAXmiReader(); XmiReader reader = new MagicDrawXmiReader();MetaModel metaModel = reader.read("model.xml");
![Page 76: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/76.jpg)
Model$Transforma?on$
JavaGenerator javaGenerator = new JavaGenerator();List<ClazzOrInterface> allGeneratedClazzes = javaGenerator.execute(metaModel);
Meta Type Java Model
MetaPackage JavaPackage
MetaClazz Clazz
MetaAssociationClazz Clazz
MetaEnumeration Enumeration
MetaInterface Interface
MetaProperty Property(Består af Field, GetterMethod og SetterMethod)
MetaOperation Method
![Page 77: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/77.jpg)
Code$DOM$
![Page 78: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/78.jpg)
An$Event$Based$Extension$Model$
![Page 79: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/79.jpg)
Extensions$
![Page 80: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/80.jpg)
Example$Extensions$
• $BuiltYin$Types$$
• $Bidirec?onal$associa?ons$
• $Property$Sugar$methods$
• $Get$Or$New$Property$methods$
• $Constructor$(immutable$proper?es)$
• $Class$Hierarchy$Java$doc$generator$
• $Serial$Version$UID$generator$
• $MetaType$Java$doc$generator$
• $Serializable$Pojo’s$
• $ToString/Equals/HashCode$
$
$
$
• $JPA$Field$based$persistence$
• $JPA$Named$Tables$and$Columns$
• $JPA$Op?mis?cLocking$excep?ons$
• $Hibernate$Foreignkey$Constraints$
• $Hibernate$Foreignkey$Index$
• $Hibernate$Fetch$Op?miza?on$
• $Hibernate$Associa?on$Unproxying$
• $Hibernate$Table$Comments$
• $Hibernate$HHY3544$bug$fix$
• $Temporal$logic$(Audit/History)$
• Groovy$
• GORM$
• Envers$
• Mixins$
![Page 81: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/81.jpg)
Example$Extension$
@OneToMany @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN) private Set<Tire> tires;public class HibernateDeleteOrphanListener extends BaseJpaGeneratorEventListener { @Override protected boolean handleOneToManyOwnerOfAssociation(OneToManyAssociationEvent event) { if (isDeleteOrphanCandidate(event)) { event.getProperty().getField().addAnnotations( new Annotation(Cascade.class).addAnnotationAttribute("value", CascadeType.DELETE_ORPHAN) ); event.getProperty().removeSetterMethod(); } return true; }
protected boolean isDeleteOrphanCandidate(OneToManyAssociationEvent event) { ... }}
![Page 82: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/82.jpg)
Example$Extension$Y$con?nued$protected boolean isDeleteOrphanCandidate(OneToManyAssociationEvent event) { if (event.getMetaProperty().isOwnerOfAssociation() && !event.getMetaProperty().getAssociation().isBidirectional() && !event.getMetaProperty().getAssociation().isSelfReferencing()) { // Check the clazz of the opposite property to see what kind of associations it has for (MetaProperty subMetaProperty : event.getMetaProperty().getType().getProperties()) { if (subMetaProperty.isPartInAnAssociation()) { if (subMetaProperty.isOwnerOfAssociation()) { if (subMetaProperty.getAssociationType() == AssociationType.ManyToMany || subMetaProperty.getAssociationType() == AssociationType.OneToMany) { return false; } } else if (subMetaProperty.getAssociation().isBidirectional()) { // The type of the our sub property is not an owning association and we have // a java association in both directions (bidirectional), which hibernate doesn't handle return false; } } } return true; } return false;}
![Page 83: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/83.jpg)
What$about$Domain$Logic?$
• It’s$important$to$separate$EnVty&Logic$and$Use&Case&Logic&
• Use&Case&Logic&doesn’t$belong$in$En??es$(violates$coherence)$
$
![Page 84: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/84.jpg)
Domain$Modeling$
James$Coplien$–$DCI$Talk$at$Öredev$2009$
![Page 85: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/85.jpg)
Domain$Logic$in$En??es$
We$have$several$op?ons$with$regards$to$En?ty$Logic$
What$we$model$
Par?al$classes$3$level$inheritance$
AlternaVves:&• Mixins$/$Traits$
• Extension$Methods$
• Priviledged$Aspects$
• Protected$Regions$
!$
![Page 86: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/86.jpg)
DCI$–$A$different$approach$to$handling$
logic$
• Allows$us$to$separate$Form&&– What$the$System$IS$–$AKA.$The$domain$mode$
• from$Structure&&– What$the$System$DOES$
• Iden?fying$that$Form$changes$much$slower$
than$the$Structure$
![Page 87: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/87.jpg)
Use$Case$Logic$
• This$type$of$logic$spans$Domain$Objects.$
• Data$Context$Interac?on$(DCI)$offers$a$very$flexible$way$of$handling$this$complexity,$by$
allowing$Domain$Objects$to$play$different$Roles$within$different$Contexts$(Use$cases)$
![Page 88: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/88.jpg)
DCI$
• Separa?ng$Structure$from$Form$is$done$using$
Roles,$which$are$(typically)$played$by$Domain$
Objects$
• Mixins/Traits/Par?al$Classes/Extension$
Methods$are$used$to$enhance$Domain$Objects$
with$extra$func?onality$(Role$Methods)$within$
a$Context$
![Page 89: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/89.jpg)
DCI$Marriage$Context$
Person$
ID:$3$
Person$
ID:$1$
Person$
ID:$2$
Role& Object&
Father$ Object$ID:$1$
Mother$ Object$ID:$2$
Son$ Object$ID:$3$Mother$
Son$Father$
Role$Map$
Interac?on$
![Page 90: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/90.jpg)
Create$your$own$UML$language$
![Page 91: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/91.jpg)
WebService$model$
![Page 92: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/92.jpg)
Another$possibility$
![Page 93: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/93.jpg)
Sounds$hard,$but$it’s$quite$easy$"$Rule$Language$M
eta$M
odel$
Rule$Grammar$(using$Xtext)$
+$
Data$Language$M
eta$M
odel$
+$
!$ Editor$&$IDE$
Text$Editor$
!$
![Page 94: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/94.jpg)
On$the$fly$code$genera?on$with$Xtend2$
![Page 95: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/95.jpg)
Point$of$No$Return,$tradi?onally$
Time&
Cost&of&Rework&
V&1.0&Freeze&
![Page 96: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/96.jpg)
Point$of$No$Return,$Model$Driven$
Time&
Cost&of&Rework&
V&1.0&
Hacks!&
Freeze&
![Page 97: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/97.jpg)
Posi?ve$SideYeffects$of$MDD$
• Beher$and$more$coherent$quality$
• Model$Documenta?on$is$always$upYtoYdate$
• Closer$to$the$customer$–$speak$the$same$language$
• Fewer$resources$–$beher$economy$
• Removes$focus$from$technical$mumboYjumbo$
• Automa?on$of$tests$
• Easier$to$follow$progress$
![Page 98: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/98.jpg)
Challenges$with$MDD$
• New$way$of$thinking$and$working$• This$is$NOT$Case$Tools$reYinvented!$• Parallel$development$(Branching$&$Merging$
requires$proper$tool$support)$
• Handling$new$produc?on$releases$requires$tool$support$for$upda?ng$databases,$etc.$
• The$Ketchup$effect$–$Don’t$forget$it’s$itera?ve$• Model$is$KING$
![Page 99: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/99.jpg)
References$
• BEC$Pension$• Letpension$• Elektronisk$Tinglysning$(CSC)$• Miracle$A/S$
• PFA$Pension$• DSB$• …$
![Page 100: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/100.jpg)
A$lihle$sta?s?cs$
Source:$hhp://modelseverywhere.wordpress.com/2010/12/20/moreYtechnologyYadop?onYcurves/$
![Page 101: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/101.jpg)
TIGERTEAM®
L E A N T H I N K I N G
Electronic$Land$registra?on$
QuesVons?&@TigerTeamDK$on$Twiher$hhp://?gerteam.dk$
![Page 102: Don't write the code](https://reader033.vdocuments.us/reader033/viewer/2022052522/54b75edc4a795945508b4577/html5/thumbnails/102.jpg)
Useful$links$
CQRS/DDD:&• Bounded$Contexts$and$Context$Maps:$hhp://www.infoq.com/ar?cles/dddYcontextmapping$
• Rinat$Abdullings$GeCng$Started$with$CQRS:$hhp://abdullin.com/cqrs/$
• CQRS$journey:$hhps://github.com/mspnp/cqrsYjourneyYdoc/$
• Greg$Youngs$old$blog:$hhp://codebeher.com/gregyoung/$
• Greg$Youngs$new$blog:$hhp://goodenoughsouware.net$
• Greg$Youngs$CQRS$info$site:$hhp://cqrs.wordpress.com$
• Sagas:$hhp://www.udidahan.com/2009/04/20/sagaYpersistenceYandYeventYdrivenYarchitectures/$
• Clarified$CQRS:$hhp://www.udidahan.com/2009/12/09/clarifiedYcqrs/$
• When$to$avoid$CQRS:$hhp://www.udidahan.com/2011/04/22/whenYtoYavoidYcqrs/$
• Why$you$should$be$using$CQRS$almost$everywhere:$hhp://www.udidahan.com/2011/10/02/whyYyouYshouldYbeYusingYcqrsYalmostYeverywhere…/$
• Videos$from$DDD$exchange$2011:$hhp://skillsmaher.com/event/designYarchitecture/dddYexchangeY2011$
• Fohjin$DDD$example:$hhps://github.com/MarkNijhof/Fohjin/tree/master/Fohjin.DDD.Example$
• Axon$Framework:$hhp://www.axonframework.org/$
$
MDD:&• TigerTeam$MDSD/Trimm$videos:$&$presenta?ons:$hhp://www.?gerteam.dk/resources/$
• xText:$hhp://www.eclipse.org/Xtext/$
• Xtend:$hhp://www.eclipse.org/xtend/$
• EMF/eCore:$hhp://www.eclipse.org/modeling/emf/$
• EMF$tutorial:$hhp://www.vogella.de/ar?cles/EclipseEMF/ar?cle.html$
$