102
TIGERTEAM ® LEAN THINKING Jeppe Cramon Don’t write THAT code Don’t write the code

Don't write the code

Embed Size (px)

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.

Citation preview

Page 1: Don't write the code

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

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

HiCng$Point$of$No$Return$too$Early?$

Time&

Cost&of&Rework&

V&1.0&Freeze&

Page 4: Don't write the code

Same$procedure$as$last$year?$

$

Same$procedure$as$every$year!!!$

Page 5: Don't write the code

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

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

What’s$for$dinner?$

Page 8: Don't write the code

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

Classic$Java$approach$

Hibernate/JPA$

Spring/EJB3/CDI$

Developer$meat$

Page 10: Don't write the code

Classic$Ruby$on$Rails$approach$

Developer$meat$

Ruby$on$Rails$

Page 11: Don't write the code

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

WE’RE&COMPLECTING&THINGS&Rick$Hickey,$2011$

Page 13: Don't write the code

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

The$silverbullit$syndrome$

Page 15: Don't write the code

Let’s$start$with$the$end$

OUR$HOLY$DATABASE$

Page 16: Don't write the code

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

The$bigger$the$beher$–$right?$….$

…..$

…..$

$

….$

…..$

…..$

$

….$

…..$

…..$

$

….$

…..$

…..$

$

Page 18: Don't write the code

A$big$unified$model$is$every$architects$

pibe$dream$

But$as$they$say$

Page 19: Don't write the code

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

Result:$Our$queries$get$messy$

Page 21: Don't write the code

Let’s$fix$the$complexity$of$SQL$code$

Let’s$use$a$big$hammer$–$ORM$

Page 22: Don't write the code

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

LET’S&TAKE&A&STEP&BACK&AND&LOOK&AT&THE&NATURE&OF&DATA&

Page 24: Don't write the code

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

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

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

Context$is$lacking$

Page 28: Don't write the code

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

Somethings$missing$

How$do$we$collaborate?$

Page 30: Don't write the code

Status$Quo$

Page 31: Don't write the code

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

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

Composite$UI$Y$example$

Page 34: Don't write the code

That$covers$data$presenta?on$

What$about$transac?ons?$

Page 35: Don't write the code

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

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

$

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

Collabora?ve$domains$

1.$Read$ 2.$Read$

4.$Update$3.$Coffee$?me$

5.$Stale$data$

Page 39: Don't write the code

We’re$working$with$stale$data$

Page 40: Don't write the code

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

Thin$Layers$of$complexity$

UI$ Data$

Pro:$Easy$and$simple$

Con:$Scales$poorly$for$complex$domains$

Page 42: Don't write the code

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

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

A"single"model"cannot"be"

appropriate"for"repor9ng,"searching"

and"transac9onal"behavior"Greg"Young,"2008$

Page 45: Don't write the code

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

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

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

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

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

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

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

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

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

Circular$architecture$

Task$based$

UI$

Domain$

Model$Read$Model$ Event$ Event$ Event$

Page 55: Don't write the code

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

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

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

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

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

Electronic$Landregistra?on$$

Case$study$

Page 61: Don't write the code

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

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

How$it’s$usually$done$

Java&code&

SQL&

Page 64: Don't write the code

Means$we$go$from$this…$

Page 65: Don't write the code

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

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

The$line$between$modeling$og$

muddling$in$hand$wrihen$code$is$

very$thin$

Page 68: Don't write the code

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

[email protected]$

[email protected](name$=$"comment")$

$$$$private$String$comment;$

$

[email protected]$

[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]$

[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

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

Automa?on$

From$sweatshops$to$automa?on$

!$

Page 71: Don't write the code

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

At$ETL$we$introduced$this$process$

UML&class&diagrams&

Java&code&Hibernate&

SQL&

Tests&

Page 73: Don't write the code

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

Versioning$(Temporal$Object$Pahern)$

Page 75: Don't write the code

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

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

Code$DOM$

Page 78: Don't write the code

An$Event$Based$Extension$Model$

Page 79: Don't write the code

Extensions$

Page 80: Don't write the code

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

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

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

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

Domain$Modeling$

James$Coplien$–$DCI$Talk$at$Öredev$2009$

Page 85: Don't write the code

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

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

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

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

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

Create$your$own$UML$language$

Page 91: Don't write the code

WebService$model$

Page 92: Don't write the code

Another$possibility$

Page 93: Don't write the code

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

On$the$fly$code$genera?on$with$Xtend2$

Page 95: Don't write the code

Point$of$No$Return,$tradi?onally$

Time&

Cost&of&Rework&

V&1.0&Freeze&

Page 96: Don't write the code

Point$of$No$Return,$Model$Driven$

Time&

Cost&of&Rework&

V&1.0&

Hacks!&

Freeze&

Page 97: Don't write the code

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

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

References$

•  BEC$Pension$•  Letpension$•  Elektronisk$Tinglysning$(CSC)$•  Miracle$A/S$

•  PFA$Pension$•  DSB$•  …$

Page 100: Don't write the code

A$lihle$sta?s?cs$

Source:$hhp://modelseverywhere.wordpress.com/2010/12/20/moreYtechnologyYadop?onYcurves/$

Page 101: Don't write the code

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

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$

$