Building a lean architecture for Web
Applications using
Domain Driven Design &
Model Driven Software Development
Java Grup...
A little about me
A little about me

 15 years as a software developer
A little about me

 15 years as a software developer
 Partner in TigerTeam - focusing on our tool sets (TigerMDSD)
A little about me

 15 years as a software developer
 Partner in TigerTeam - focusing on our tool sets (TigerMDSD)
 Facili...
How do we create a Lean architecture
How do we create a Lean architecture
• We continuously think about how to improve our process, our
 architecture and our c...
How do we create a Lean architecture
• We continuously think about how to improve our process, our
 architecture and our c...
How do we create a Lean architecture
• We continuously think about how to improve our process, our
 architecture and our c...
How do we create a Lean architecture
• We continuously think about how to improve our process, our
  architecture and our ...
How do we create a Lean architecture
• We continuously think about how to improve our process, our
  architecture and our ...
How can Domain Driven
    Design help?
Challenge: It still takes too
long time to develop software
Why?
We often solve the wrong problems
We often solve the wrong problems

Because of poor communication
The developer needs to gain
knowledge about the application
domain to add value to a users
           activities
The amount of knowledge can be
great and the complexity can be
              high
Models to the rescue
Models to the rescue

A model is a selectively simplified
and deliberately structured form
         of knowledge
Models are not about realism
Models are not about realism


Even in a domain of real-world things,
   our domain model is artificial
    creation, like ...
Core principles of Domain Driven
Design
Core principles of Domain Driven
Design
1. The model and the heart of the design shape each other. It is the link/binding
...
Core principles of Domain Driven
Design
1. The model and the heart of the design shape each other. It is the link/binding
...
Core principles of Domain Driven
Design
1. The model and the heart of the design shape each other. It is the link/binding
...
So how do we go about
Developing the Model?
Write it by hand, draw it on
paper, use UML, DSLs or ...?
Use what works best for the project - but
     focus on enabling automation
What would you prefer?
This?
Or this?
@javax.persistence.Basic
                                                                                                 ...
Software development still
requires too many resources
Software development still
requires too many resources
  Too little abstraction
    and automation!
Too many developers reinvent the wheel time
                and time again
                       -
or keep writing the sa...
Things often get too technical
 and the domain experts are
  left out of the discussion
Let’s get the Model back into the driving
               seat using
              Model Driven
        Software Developmen...
Let’s get cranking with visual
           models
Design case
Web based desktop like veterinarian
       clinical application
But first - a word form our DDD
             sponsor
Core patterns in Domain Driven Design

 Layered Architecture   UI Layer      GWT +
 Modules
 Entities               Applic...
UI/Presentation Layer

Responsibilities:

    Show information to the user and
     interpret the users commands.
Application Layer

Responsibilities:
 A thin layer - which is responsible for
 coordinating user tasks and for
 delegating...
Domain/Model Layer

Responsibilities:
 Representing business concepts, state
 and rules.

 Delegates storing/fetching to t...
Domain/Model Layer

Responsibilities:
 Representing business concepts, state
 and rules.

 Delegates storing/fetching to t...
Infrastructure Layer

Responsibilities:
      Support for the higher layers

     Examples: Message sending,
     Persiste...
Core patterns in Domain Driven Design
 Layered Architecture
 Modules

 Entities
 Value Objects
 Aggregates
 Repositories
 ...
Core patterns in Domain Driven Design
 Layered Architecture
 Modules

 Entities                      Customer
 Value Objec...
Core patterns in Domain Driven Design
 Layered Architecture
 Modules
 Entities

 Value Objects
 Aggregates
 Repositories
 ...
Core patterns in Domain Driven Design
 Layered Architecture          Customer
 Modules
                        - name : St...
Core patterns in Domain Driven Design
 Layered Architecture          Customer
 Modules
                        - name : St...
Core patterns in Domain Driven Design
Layered Architecture
Modules
Entities
Value Objects

Aggregates
Repositories
Factori...
Core patterns in Domain Driven Design
Layered Architecture
                             Invoice
Modules
Entities
Value Obj...
Core patterns in Domain Driven Design
Layered Architecture
                       Account         Invoice
Modules         ...
From UML diagram to code
From UML diagram to code




UML modeling



  MagicDraw
From UML diagram to code




UML modeling   XMI Export


  MagicDraw
From UML diagram to code


                            +
                                 TigerMDSD
UML modeling   XMI Exp...
From UML diagram to code


                            +
                                 TigerMDSD     Java/C# code
UML m...
From UML diagram to code


                            +
                                 TigerMDSD     Java/C# code
UML m...
Requirement:
Persist the domain model in a Relational
     database using JPA/Hibernate
TigerMDSD
YAML configuration
# Setup


TigerMDSD
                    xmiModelPath: model.xml
                    umlTool: EA
                    basePa...
TigerMDSD - Java configuration
TigerMDSD - Java configuration
     JavaGenerator javaGenerator = new JavaGenerator();
     javaGenerator.addEventListeners...
Result:
package dk.tigerteam.vetapp.model;

@javax.persistence.Entity
@javax.persistence.Table(name = "Customer")
public c...
Automate the tedious details -
under full control!
Examples of configurable built in features:
Automate the tedious details -
under full control!
Examples of configurable built in features:
  Built-in Types            ...
TigerMDSD - Meta model level
TigerMDSD - Meta model level
   XmiReader reader = new EAXmiReader();
   XmiReader reader = new MagicDrawXmiReader();
   M...
TigerMDSD - Meta model level
   XmiReader reader = new EAXmiReader();
   XmiReader reader = new MagicDrawXmiReader();
   M...
TigerMDSD - Java Model
TigerMDSD - Java Model
TigerMDSD - Event based extension model
TigerMDSD - Event based extension model
TigerMDSD - Event Listeners
TigerMDSD - Event Listeners
TigerMDSD - Event Listeners


                         public interface GeneratorEventListener {
                         ...
TigerMDSD - Example extension
TigerMDSD - Example extension
@OneToMany
@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Set<Tire> t...
TigerMDSD - Example extension
@OneToMany
@Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Set<Tire> t...
TigerMDSD - Example extension
TigerMDSD - Example extension
protected boolean isDeleteOrphanCandidate(OneToManyAssociationEvent event) {
  if (event.get...
“I thought it was all about rich domain models!
What about my own domain code?”
“I thought it was all about rich domain models!
What about my own domain code?”

It is - but Usecase logic doesn’t belong ...
“I thought it was all about rich domain models!
What about my own domain code?”

It is - but Usecase logic doesn’t belong ...
For the logic that belongs in the domain
objects we have several choices...
What we model:
For the logic that belongs in the domain
objects we have several choices...
What we model:
For the logic that belongs in the domain
objects we have several choices...
What we model:


What we generate
using Extens...
For the logic that belongs in the domain
objects we have several choices...
What we model:


What we generate             ...
For the logic that belongs in the domain
objects we have several choices...
What we model:


What we generate             ...
Let’s get some UI running
UI framework considerations
               “Web 1.0”

      Client           5
                                           ...
UI framework considerations
                  “Client side RIA”

       Client                  4                     Serv...
UI framework considerations
    “Server driven Web 2.0 RIA”

      Client                              8
                 ...
Component Architecture
Component Architecture
“UI Component”
• Button, Table, Tree, ...
• Server-side data
• Full Java API
Component Architecture
                             HTTP(S)
“UI Component”                         “Widget”
• Button, Tabl...
Component Architecture
                             HTTP(S)
“UI Component”                         “Widget”
• Button, Tabl...
Component Architecture
                             HTTP(S)
“UI Component”                         “Widget”
• Button, Tabl...
Using TigerMDSD to create Vaadin
            Builders
Using TigerMDSD to create Vaadin
                             Builders
HorizontalLayout buttons = new HorizontalLayout();
...
Using TigerMDSD to create Vaadin
                             Builders
HorizontalLayout buttons = new HorizontalLayout();
...
Strong data binding
Exchange fragile strings such as “customer.name.firstName”
  with typesafe code property().getName().ge...
Strong data binding
Exchange fragile strings such as “customer.name.firstName”
  with typesafe code property().getName().ge...
Web UI design patterns
Web UI design patterns


M-V-C
Model View Controller
Web UI design patterns


M-V-C
Model View Controller
                         M-V-P
                         Model View Pr...
Web UI design patterns


M-V-C
Model View Controller
                                            M-V-P
                   ...
Web UI design patterns
1. Input/Event
                   <<stateless>>
    3 .Response   Controller


                    ...
Web UI design patterns
                                                        1. Execute Command                   2 .Upd...
Web UI design patterns
                                                        1. Execute Command                        2...
Web UI design patterns
                                                                                                 1....
Thank you for your attention!

     For more information
     jeppe@tigerteam.dk
       Twitter: @jeppec
Building a Lean Architecture for Web Applications using  Domain Driven Design &  Model Driven Software Development
Building a Lean Architecture for Web Applications using  Domain Driven Design &  Model Driven Software Development
Upcoming SlideShare
Loading in...5
×

Building a Lean Architecture for Web Applications using Domain Driven Design & Model Driven Software Development

2,955

Published on

How do we create a lean architecture and process for building Web Applications?

In this talk I will give my view on how I believe we can improve our track record - exemplified through a desktop style Web application developed using the Vaadin component based web framework.

I will draw upon best practices from Domain Driven Design and Model Driven Software Development, to show how we can get closer to the users mental model, while saving precious code lines through automation.

Finally we will look at how strong data-binding can give us less error prone code and finally we will dive into the differences between MVC (Model View Controller), Model View Presenter (MVP) and finally Model View - ModelView.

Published in: Technology, Business
1 Comment
10 Likes
Statistics
Notes
No Downloads
Views
Total Views
2,955
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
352
Comments
1
Likes
10
Embeds 0
No embeds

No notes for slide
  • How do we create a lean architecture and process for building Web Applications?

    In this talk I will give my view on how I believe we can improve our track record - exemplified through a desktop style Web application developed using the Vaadin component based web framework.

    I will draw upon best practices from Domain Driven Design and Model Driven Software Development, to show how we can get closer to the users mental model, while saving precious code lines through automation.

    Finally we will look at how strong data-binding can give us less error prone code and if time permits we will dive into the differences between MVC (Model View Controller), Model View Presenter (MVP) and finally Model View - ModelView.
  • For d&amp;#xE5;rlig kommunikation mellem forretningen og udvikling - manglende feedback loops og manglende forst&amp;#xE5;else i snitfladen mellem forretning og teknik
    Vi l&amp;#xF8;ser de forkerte problemer
  • An appropriate model makes sense of information and focuses it on a problem.
    A domain model is not a diagram -&gt; it is the idea that the diagram is intended to convey.
    It&apos;s not the knowledge in the domain experts head -&gt; It is a rigorously organized and selective abstraction of knowledge.
    A diagram can represent and communicate a model, as can carefully written code, as can an English sentence
  • 1. It is the link/binding between model and implementation that makes the model relevant and ensures that the analysis that &amp;#xA0;went into it applies to the final product, a running program Helps during maintenance and continuing development, because the code can be interpreted based on the understanding of the model.

    2. Because of model/implementation binding developers can talk in this language. They can talk to domain experts without translating.
  • 1. It is the link/binding between model and implementation that makes the model relevant and ensures that the analysis that &amp;#xA0;went into it applies to the final product, a running program Helps during maintenance and continuing development, because the code can be interpreted based on the understanding of the model.

    2. Because of model/implementation binding developers can talk in this language. They can talk to domain experts without translating.
  • 1. It is the link/binding between model and implementation that makes the model relevant and ensures that the analysis that &amp;#xA0;went into it applies to the final product, a running program Helps during maintenance and continuing development, because the code can be interpreted based on the understanding of the model.

    2. Because of model/implementation binding developers can talk in this language. They can talk to domain experts without translating.
  • Motivators: Separation of concern, cohesive layers which on depends on lower layers, makes testing easier and the design less fragile when changes occur
  • Motivators: Objects in the domain that are defined by identity (and thereby not by their attributes), which have life cycle, can change form and differ by time (e.g. a Person that becomes a father, which becomes a grand father, etc.) are called Entities. Focus is on who and not on what.
  • Motivators: Objects in the domain that are not defined by identify (and thereby by their attributes), which don&amp;#x2019;t have life cycle are called Value Objects (e.g. an Address). Focus is on what and not on who/which.
  • Motivators: Objects in the domain that are not defined by identify (and thereby by their attributes), which don&amp;#x2019;t have life cycle are called Value Objects (e.g. an Address). Focus is on what and not on who/which.
  • Motivators: To support consistency of changes to objects with complex associations, to support proper loading schemes and coarse grained locking, cluster Entities and Value Objects in to aggregates with well defined boundaries.
    Choose one entity to be root and control access to objects inside the boundary through the root. External objects hold references to the root only!
  • Motivators: To support consistency of changes to objects with complex associations, to support proper loading schemes and coarse grained locking, cluster Entities and Value Objects in to aggregates with well defined boundaries.
    Choose one entity to be root and control access to objects inside the boundary through the root. External objects hold references to the root only!
  • Motivators: To support consistency of changes to objects with complex associations, to support proper loading schemes and coarse grained locking, cluster Entities and Value Objects in to aggregates with well defined boundaries.
    Choose one entity to be root and control access to objects inside the boundary through the root. External objects hold references to the root only!
  • &amp;#x201C;Dumb&amp;#x201D;: We want to focus on what the system is - NOT what the system does
    What the System does is captured in use cases and implemented as &amp;#x201C;Contexts&amp;#x201D; where our domain objects play certain &amp;#x201C;Roles&amp;#x201D; (DCI - Data, Context, Interaction)
  • &amp;#x201C;Dumb&amp;#x201D;: We want to focus on what the system is - NOT what the system does
    What the System does is captured in use cases and implemented as &amp;#x201C;Contexts&amp;#x201D; where our domain objects play certain &amp;#x201C;Roles&amp;#x201D; (DCI - Data, Context, Interaction)
  • &amp;#x201C;Dumb&amp;#x201D;: We want to focus on what the system is - NOT what the system does
    What the System does is captured in use cases and implemented as &amp;#x201C;Contexts&amp;#x201D; where our domain objects play certain &amp;#x201C;Roles&amp;#x201D; (DCI - Data, Context, Interaction)
  • Pro: Simple model to comprehend - everything is controlled on the server and a new fresh page is sent out again
    Action based MVC (like Stripes, Struts, Struts 2) are not appropriate for this type of application since components are not naturally supported - poor encapsulation of tables, pagination, form validation (some frameworks support this better than others)
  • Pro: Everything is code in the native language of the browser (HTML + JavaScript).
    Needs a proper RIA framework with DataSource, Key/Value Observing like SproutCore, Qooxdoo, YUI, ExtJS, etc.
    Frameworks like jQuery lack proper support for DataSources, Key/Value Observing, etc.
    Con: Need to &amp;#x201C;replicate&amp;#x201D; server side model to the browser (REST, RPC, etc.) - Not all are familiar with JavaScript
  • Pro: Simple model to comprehend - everything is controlled on the server - framework handles page refreshs
    Needs a proper RIA framework with DataSource, Key/Value Observing (property change listener) like Vaadin
    Security is handled by the framework. Use GWT to program the Client side - no need to learn JavaScript
    Con: New (non-composite) components can be harder to comprehend (both GWT and Server side + XUL). Poor for &amp;#x201C;read-only&amp;#x201D; web-pages
  • It&amp;#x2019;s all about testability and ease of development
  • It&amp;#x2019;s all about testability and ease of development
  • It&amp;#x2019;s all about testability and ease of development
  • The controller is stateless with regards to domain state - it can contain Application state, such as progress in a Wizard/Flow
  • The controller is stateless with regards to domain state - it can contain Application state, such as progress in a Wizard/Flow
  • The controller is stateless with regards to domain state - it can contain Application state, such as progress in a Wizard/Flow
  • The controller is stateless with regards to domain state - it can contain Application state, such as progress in a Wizard/Flow
  • The controller is statefull both with regards to domain state and Application state, such as progress in a Wizard/Flow
  • Transcript of "Building a Lean Architecture for Web Applications using Domain Driven Design & Model Driven Software Development"

    1. 1. Building a lean architecture for Web Applications using Domain Driven Design & Model Driven Software Development Java Gruppen Conference - 2010 Jeppe Cramon - TigerTeam ApS TIGERTEAM ® LEAN THINKING
    2. 2. A little about me
    3. 3. A little about me 15 years as a software developer
    4. 4. A little about me 15 years as a software developer Partner in TigerTeam - focusing on our tool sets (TigerMDSD)
    5. 5. A little about me 15 years as a software developer Partner in TigerTeam - focusing on our tool sets (TigerMDSD) Facilitator for the Danish IT Societies Java competence network
    6. 6. How do we create a Lean architecture
    7. 7. How do we create a Lean architecture • We continuously think about how to improve our process, our architecture and our code
    8. 8. How do we create a Lean architecture • We continuously think about how to improve our process, our architecture and our code • We must eliminate waste - such as superfluous code
    9. 9. How do we create a Lean architecture • We continuously think about how to improve our process, our architecture and our code • We must eliminate waste - such as superfluous code • We must automate what can be automated
    10. 10. How do we create a Lean architecture • We continuously think about how to improve our process, our architecture and our code • We must eliminate waste - such as superfluous code • We must automate what can be automated • We must strive to be better at understand requirements and deliver then timely
    11. 11. How do we create a Lean architecture • We continuously think about how to improve our process, our architecture and our code • We must eliminate waste - such as superfluous code • We must automate what can be automated • We must strive to be better at understand requirements and deliver then timely • And we keep doing it - over and over again - iteratively refining our tools
    12. 12. How can Domain Driven Design help?
    13. 13. Challenge: It still takes too long time to develop software
    14. 14. Why?
    15. 15. We often solve the wrong problems
    16. 16. We often solve the wrong problems Because of poor communication
    17. 17. The developer needs to gain knowledge about the application domain to add value to a users activities
    18. 18. The amount of knowledge can be great and the complexity can be high
    19. 19. Models to the rescue
    20. 20. Models to the rescue A model is a selectively simplified and deliberately structured form of knowledge
    21. 21. Models are not about realism
    22. 22. Models are not about realism Even in a domain of real-world things, our domain model is artificial creation, like movie making...
    23. 23. Core principles of Domain Driven Design
    24. 24. Core principles of Domain Driven Design 1. The model and the heart of the design shape each other. It is the link/binding between model and implementation that makes the model relevant and ensures that the analysis that went into it applies to the final product, a running program.
    25. 25. Core principles of Domain Driven Design 1. The model and the heart of the design shape each other. It is the link/binding between model and implementation that makes the model relevant and ensures that the analysis that went into it applies to the final product, a running program. 2. The model is the backbone of a ubiquitous language used by all team members. Because of model/implementation binding developers can talk in this language. They can talk to domain experts without translating.
    26. 26. Core principles of Domain Driven Design 1. The model and the heart of the design shape each other. It is the link/binding between model and implementation that makes the model relevant and ensures that the analysis that went into it applies to the final product, a running program. 2. The model is the backbone of a ubiquitous language used by all team members. Because of model/implementation binding developers can talk in this language. They can talk to domain experts without translating. 3. The model is distilled knowledge. A model captures how we choose to think about the domain as we select terms, break down concepts and relate them
    27. 27. So how do we go about Developing the Model?
    28. 28. Write it by hand, draw it on paper, use UML, DSLs or ...?
    29. 29. Use what works best for the project - but focus on enabling automation
    30. 30. What would you prefer?
    31. 31. This?
    32. 32. Or this?
    33. 33. @javax.persistence.Basic @javax.persistence.Column(name = "comment", nullable = false) private String comment; package dk.tigerteam.mdsd.demo.model.internal; package dk.tigerteam.mdsd.demo.model.internal; @javax.persistence.Basic @javax.persistence.Entity @javax.persistence.Temporal(javax.persistence.TemporalType.TIMESTAMP) @javax.persistence.Table(name = "Customer") @javax.persistence.Entity @javax.persistence.Column(name = "time", nullable = false) public class Customer extends dk.tigerteam.mdsd.demo.model.AbstractEntity { private java.util.Date time; private static final long serialVersionUID = 2098912667L; @javax.persistence.Table(name = "Address") @javax.persistence.Basic @javax.persistence.Basic public class Address extends dk.tigerteam.mdsd.demo.model.AbstractEntity { @javax.persistence.Column(name = "timeslot", nullable = false) @javax.persistence.Column(name = "name", nullable = false) private static final long serialVersionUID = 1697028161L; private int timeslot; private String name; @javax.persistence.ManyToOne(cascade = { @javax.persistence.OneToOne(cascade = { javax.persistence.CascadeType.MERGE, javax.persistence.CascadeType.PERSIST, javax.persistence.CascadeType.REFRESH} javax.persistence.CascadeType.MERGE, javax.persistence.CascadeType.PERSIST, javax.persistence.CascadeType.REFRESH} @javax.persistence.Basic , fetch = javax.persistence.FetchType.LAZY) , fetch = javax.persistence.FetchType.LAZY) @javax.persistence.Column(name = "street", nullable = false) @javax.persistence.JoinColumn(nullable = false, name = "customerId") @javax.persistence.JoinColumn(name = "addressId") private dk.tigerteam.mdsd.demo.model.internal.Customer customer; @org.hibernate.validator.NotNull private String street; private dk.tigerteam.mdsd.demo.model.internal.Address address; public String getComment() { return comment; @javax.persistence.OneToMany(cascade = { @javax.persistence.Basic } javax.persistence.CascadeType.MERGE, javax.persistence.CascadeType.PERSIST, javax.persistence.CascadeType.REFRESH} , targetEntity = dk.tigerteam.mdsd.demo.model.internal.Booking.class, mappedBy = "customer", fetch = javax.persistence.FetchType.LAZY)public void setComment(String parameter) { @javax.persistence.Column(name = "zipCode", nullable = false) private java.util.Set<dk.tigerteam.mdsd.demo.model.internal.Booking> bookingCollection = new java.util.HashSet<dk.tigerteam.mdsd.demo.model.internal.Booking>(); this.comment = parameter; private String zipCode; } public String getName() { public java.util.Date getTime() { return name; return time; @javax.persistence.Basic } } @javax.persistence.Column(name = "city", nullable = false) public void setName(String parameter) { private String city; public void setTime(java.util.Date parameter) { this.name = parameter; this.time = parameter; } } public dk.tigerteam.mdsd.demo.model.internal.Address getAddress() { public String getStreet() { public int getTimeslot() { if (address instanceof org.hibernate.proxy.HibernateProxy) { return street; return timeslot; address = (dk.tigerteam.mdsd.demo.model.internal.Address) ((org.hibernate.impl.SessionImpl) ((org.hibernate.proxy.HibernateProxy) address) } .getHibernateLazyInitializer() } .getSession()).getPersistenceContext() public void setTimeslot(int parameter) { .unproxyAndReassociate(address); this.timeslot = parameter; } public void setStreet(String parameter) { } return address; public dk.tigerteam.mdsd.demo.model.internal.Customer getCustomer() { this.street = parameter; } if (customer instanceof org.hibernate.proxy.HibernateProxy) { } customer = (dk.tigerteam.mdsd.demo.model.internal.Customer) ((org.hibernate.impl.SessionImpl) ((org.hibernate.proxy.HibernateProxy) customer) public void setAddress( .getHibernateLazyInitializer() dk.tigerteam.mdsd.demo.model.internal.Address parameter) { .getSession()).getPersistenceContext() this.address = parameter; .unproxyAndReassociate(customer); public String getZipCode() { } } return zipCode; public java.util.Set<dk.tigerteam.mdsd.demo.model.internal.Booking> getBookingCollection() { } return customer; return new dk.tigerteam.foundation.bean.bidirectional.OneToManySetWrapper<dk.tigerteam.mdsd.demo.model.internal.Customer, } dk.tigerteam.mdsd.demo.model.internal.Booking>((dk.tigerteam.mdsd.demo.model.internal.Customer) this, bookingCollection) { @Override public void setCustomer( public void setZipCode(String parameter) { dk.tigerteam.mdsd.demo.model.internal.Customer parameter) { protected dk.tigerteam.mdsd.demo.model.internal.Customer getOneSideObjectInManySideObject( this.zipCode = parameter; new dk.tigerteam.foundation.bean.bidirectional.ManyToOneWrapper<dk.tigerteam.mdsd.demo.model.internal.Customer, dk.tigerteam.mdsd.demo.model.internal.Booking manySideObject) { dk.tigerteam.mdsd.demo.model.internal.Booking>((dk.tigerteam.mdsd.demo.model.internal.Booking) this) { return manySideObject.getCustomer(); @Override } } protected void addManySideObjectToOneSideCollection( dk.tigerteam.mdsd.demo.model.internal.Customer oneSide, @Override public String getCity() { dk.tigerteam.mdsd.demo.model.internal.Booking manySide) { protected void setOneSideObjectInManySideObject( ((dk.tigerteam.foundation.bean.WrappedSet<dk.tigerteam.mdsd.demo.model.internal.Booking>) oneSide dk.tigerteam.mdsd.demo.model.internal.Booking manySideObject, .getBookingCollection()).getWrappedCollection() return city; dk.tigerteam.mdsd.demo.model.internal.Customer oneSideObject) { manySideObject.setCustomer(oneSideObject); .add(manySide); } } } }; @Override } protected void removeManySideObjectFromOneSideCollection( public void setCity(String parameter) { public dk.tigerteam.mdsd.demo.model.internal.Customer withName(String name) { dk.tigerteam.mdsd.demo.model.internal.Customer oneSide, this.city = parameter; dk.tigerteam.mdsd.demo.model.internal.Booking manySide) { setName(name); } ((dk.tigerteam.foundation.bean.WrappedSet<dk.tigerteam.mdsd.demo.model.internal.Booking>) oneSide .getBookingCollection()).getWrappedCollection() return (dk.tigerteam.mdsd.demo.model.internal.Customer) this; .remove(manySide); } } public dk.tigerteam.mdsd.demo.model.internal.Address withStreet( public dk.tigerteam.mdsd.demo.model.internal.Customer withAddress( String street) { @Override dk.tigerteam.mdsd.demo.model.internal.Address address) { protected dk.tigerteam.mdsd.demo.model.internal.Customer getOneSideObjectInManySideObject( setAddress(address); dk.tigerteam.mdsd.demo.model.internal.Booking manySide) { setStreet(street); return ((dk.tigerteam.mdsd.demo.model.internal.Booking) manySide).customer; return (dk.tigerteam.mdsd.demo.model.internal.Customer) this; } } return (dk.tigerteam.mdsd.demo.model.internal.Address) this; @Override public dk.tigerteam.mdsd.demo.model.internal.Customer addToBookingCollection( protected void setOneSideObjectInManySideObject( } dk.tigerteam.mdsd.demo.model.internal.Booking... values) { dk.tigerteam.mdsd.demo.model.internal.Booking manySide, getBookingCollection().addAll(java.util.Arrays.asList(values)); dk.tigerteam.mdsd.demo.model.internal.Customer oneSide) { ((dk.tigerteam.mdsd.demo.model.internal.Booking) manySide).customer = oneSide; public dk.tigerteam.mdsd.demo.model.internal.Address withZipCode( return (dk.tigerteam.mdsd.demo.model.internal.Customer) this; } } }.updateOneSideObject(parameter); String zipCode) { public dk.tigerteam.foundation.bean.mdsd.runtime.RuntimeMetaClazz getMetaType() { } setZipCode(zipCode); return metaType; public dk.tigerteam.mdsd.demo.model.internal.Booking withComment( } String comment) { } setComment(comment); return (dk.tigerteam.mdsd.demo.model.internal.Address) this; } return (dk.tigerteam.mdsd.demo.model.internal.Booking) this; } public dk.tigerteam.mdsd.demo.model.internal.Booking withTime( public dk.tigerteam.mdsd.demo.model.internal.Address withCity(String city) { java.util.Date time) { setCity(city); setTime(time); Or this? return (dk.tigerteam.mdsd.demo.model.internal.Booking) this; } return (dk.tigerteam.mdsd.demo.model.internal.Address) this; } public dk.tigerteam.mdsd.demo.model.internal.Booking withTimeslot( int timeslot) { setTimeslot(timeslot); public dk.tigerteam.foundation.bean.mdsd.runtime.RuntimeMetaClazz getMetaType() { return (dk.tigerteam.mdsd.demo.model.internal.Booking) this; return metaType; } } public dk.tigerteam.mdsd.demo.model.internal.Booking withCustomer( } dk.tigerteam.mdsd.demo.model.internal.Customer customer) { setCustomer(customer); return (dk.tigerteam.mdsd.demo.model.internal.Booking) this; }
    34. 34. Software development still requires too many resources
    35. 35. Software development still requires too many resources Too little abstraction and automation!
    36. 36. Too many developers reinvent the wheel time and time again - or keep writing the same code over and over - when it could be handled by tools
    37. 37. Things often get too technical and the domain experts are left out of the discussion
    38. 38. Let’s get the Model back into the driving seat using Model Driven Software Development (MDSD)
    39. 39. Let’s get cranking with visual models
    40. 40. Design case Web based desktop like veterinarian clinical application
    41. 41. But first - a word form our DDD sponsor
    42. 42. Core patterns in Domain Driven Design Layered Architecture UI Layer GWT + Modules Entities Application Layer Value Objects Aggregates Domain Layer Repositories Factories Infrastructure Layer Services
    43. 43. UI/Presentation Layer Responsibilities: Show information to the user and interpret the users commands.
    44. 44. Application Layer Responsibilities: A thin layer - which is responsible for coordinating user tasks and for delegating to the domain layer. Contains no business state!
    45. 45. Domain/Model Layer Responsibilities: Representing business concepts, state and rules. Delegates storing/fetching to the Infrastructure layer!
    46. 46. Domain/Model Layer Responsibilities: Representing business concepts, state and rules. Delegates storing/fetching to the Infrastructure layer!
    47. 47. Infrastructure Layer Responsibilities: Support for the higher layers Examples: Message sending, Persistence, UI Widget, Layer interaction
    48. 48. Core patterns in Domain Driven Design Layered Architecture Modules Entities Value Objects Aggregates Repositories Factories Services
    49. 49. Core patterns in Domain Driven Design Layered Architecture Modules Entities Customer Value Objects - name : String Aggregates Repositories Factories Services
    50. 50. Core patterns in Domain Driven Design Layered Architecture Modules Entities Value Objects Aggregates Repositories Factories Services
    51. 51. Core patterns in Domain Driven Design Layered Architecture Customer Modules - name : String Entities Value Objects Aggregates Repositories Factories Services
    52. 52. Core patterns in Domain Driven Design Layered Architecture Customer Modules - name : String Entities Value Objects Aggregates 1 Repositories Address Factories - street : String Services - zipCode : String
    53. 53. Core patterns in Domain Driven Design Layered Architecture Modules Entities Value Objects Aggregates Repositories Factories Services
    54. 54. Core patterns in Domain Driven Design Layered Architecture Invoice Modules Entities Value Objects Aggregates * Repositories InvoiceLine Factories Services
    55. 55. Core patterns in Domain Driven Design Layered Architecture Account Invoice Modules * Entities Value Objects Aggregates * Repositories InvoiceLine Factories Services
    56. 56. From UML diagram to code
    57. 57. From UML diagram to code UML modeling MagicDraw
    58. 58. From UML diagram to code UML modeling XMI Export MagicDraw
    59. 59. From UML diagram to code + TigerMDSD UML modeling XMI Export configuration MagicDraw
    60. 60. From UML diagram to code + TigerMDSD Java/C# code UML modeling XMI Export configuration JPA configuration Database configuration Integration tests Test data generator WSDL XML Schema MagicDraw ...
    61. 61. From UML diagram to code + TigerMDSD Java/C# code UML modeling XMI Export configuration JPA configuration Database configuration Integration tests Test data generator WSDL MagicDraw MODEL is KING XML Schema ...
    62. 62. Requirement: Persist the domain model in a Relational database using JPA/Hibernate
    63. 63. TigerMDSD YAML configuration
    64. 64. # Setup TigerMDSD xmiModelPath: model.xml umlTool: EA basePackageName: dk.tigerteam.vetapp YAML configuration # Paths generateBaseClassesToPath: src/main/generated generateTestClassesToPath: src/test/generated generateResourcesToPath: src/main/generated-resources mapUmlPropertyTypes: - name: DateTime javaType: org.joda.time.DateTime hibernateCustomTypeMappingType: org.joda.time.contrib.hibernate.PersistentDateTime # JPA Setup jpaSetup: makeBaseClassesIntoMappedSuperClassesIfPossible: true generatePresentFieldInEmbeddables: true defaultToLazyFetchingForAllAssociations: true rootMappedSuperClass: dk.tigerteam.vetapp.model.AbstractEntity resolveTableNames: - defaultTableName: User resolvedTableName: _User # Extensions eventListeners: - dk.tigerteam.mdsd.java.generator.extension.BidirectionalGeneratorEventListener - dk.tigerteam.mdsd.jpa.hibernate.HibernateAssociationUnproxyListener - dk.tigerteam.mdsd.java.generator.extension.SerialVersionUIDGeneratorListener - dk.tigerteam.mdsd.java.generator.extension.PropertySugarMethodsEventListener - dk.tigerteam.mdsd.java.generator.extension.MetaTypeJavaDocListener - dk.tigerteam.mdsd.jpa.hibernate.HibernateDeleteOrphanListener - dk.tigerteam.mdsd.jpa.hibernate.HibernateValidatorNotNullListener - dk.tigerteam.mdsd.jpa.hibernate.HibernateFetchOptimizationListener
    65. 65. TigerMDSD - Java configuration
    66. 66. TigerMDSD - Java configuration JavaGenerator javaGenerator = new JavaGenerator(); javaGenerator.addEventListeners(new BuiltInTypesListener() { @Override protected void resolveBuiltInTypes(Type type) { if (type.getName().equalsIgnoreCase("DateTime")) { type.setWrappedJavaClass(DateTime.class); } else { super.resolveBuiltInTypes(type); } } }); javaGenerator.addEventListeners(new JPAGeneratorEventListener() .setShouldMakeBaseClazzesMappedSuperClassesIfPossible(true) .setShouldGeneratePresentFieldInEmbeddables(false) .setDefaultToLazyFetchingForAllAssociations(true) ); javaGenerator.addEventListeners(new JPANamedTablesAndColumnsListener()); javaGenerator.addEventListeners(new BidirectionalGeneratorEventListener()); javaGenerator.addEventListeners(new HibernateAssociationUnproxyListener()); javaGenerator.addEventListeners(new SerialVersionUIDGeneratorListener()); javaGenerator.addEventListeners(new PropertySugarMethodsEventListener()); javaGenerator.addEventListeners(new MetaTypeJavaDocListener()); javaGenerator.addEventListeners(new HibernateIndexingListener()); javaGenerator.addEventListeners(new HibernateDeleteOrphanListener()); javaGenerator.addEventListeners(new HibernateValidatorNotNullListener()); javaGenerator.setCreateExtensionClazzes(true);
    67. 67. Result: package dk.tigerteam.vetapp.model; @javax.persistence.Entity @javax.persistence.Table(name = "Customer") public class Customer extends dk.tigerteam.vetapp.model.AbstractEntity { private static final long serialVersionUID = 100497609L; @javax.persistence.Lob @javax.persistence.Basic @javax.persistence.Column(name = "comment") private String comment; @javax.persistence.OneToOne(cascade = { javax.persistence.CascadeType.MERGE, javax.persistence.CascadeType.PERSIST, javax.persistence.CascadeType.REFRESH }, fetch = javax.persistence.FetchType.LAZY) @javax.persistence.JoinColumn(name = "addressId") private dk.tigerteam.vetapp.model.Address address; @javax.persistence.Embedded @javax.persistence.AttributeOverrides( { @javax.persistence.AttributeOverride( name = "firstName", column = @javax.persistence.Column(nullable = false, name = "name_firstName")), @javax.persistence.AttributeOverride( name = "lastName", column = @javax.persistence.Column(nullable = false, name = "name_lastName")), @javax.persistence.AttributeOverride( name = "present", column = @javax.persistence.Column(nullable = false, name = "name_present")) }) private dk.tigerteam.vetapp.model.Name name; @javax.persistence.OneToMany(cascade = { javax.persistence.CascadeType.MERGE, javax.persistence.CascadeType.PERSIST, javax.persistence.CascadeType.REFRESH }, fetch = javax.persistence.FetchType.LAZY) @javax.persistence.JoinTable(name = "Customer_invoice", joinColumns = @javax.persistence.JoinColumn(name = "CustomerId"), inverseJoinColumns = @javax.persistence.JoinColumn(name = "invoiceId")) private java.util.Set<dk.tigerteam.vetapp.model.Invoice> invoiceCollection = new java.util.HashSet<dk.tigerteam.vetapp.model.Invoice>();
    68. 68. Automate the tedious details - under full control! Examples of configurable built in features:
    69. 69. Automate the tedious details - under full control! Examples of configurable built in features: Built-in Types JPA Field based persistence Bidirectional associations JPA Named Tables and Columns Property Sugar methods Hibernate Foreignkey Constraints Get Or New Property methods Hibernate Foreignkey Index Constructor (immuteable properties) Hibernate Fetch Optimization Class Hierarchy Java doc generator Hibernate Association Unproxying Serial Version UID generator Hibernate Table Comments MetaType Java doc generator Hibernate HH-3544 bug fix Serializable Pojo’s ToString/Equals/HashCode
    70. 70. TigerMDSD - Meta model level
    71. 71. TigerMDSD - Meta model level XmiReader reader = new EAXmiReader(); XmiReader reader = new MagicDrawXmiReader(); MetaModel metaModel = reader.read("model.xml");
    72. 72. TigerMDSD - Meta model level XmiReader reader = new EAXmiReader(); XmiReader reader = new MagicDrawXmiReader(); MetaModel metaModel = reader.read("model.xml");
    73. 73. TigerMDSD - Java Model
    74. 74. TigerMDSD - Java Model
    75. 75. TigerMDSD - Event based extension model
    76. 76. TigerMDSD - Event based extension model
    77. 77. TigerMDSD - Event Listeners
    78. 78. TigerMDSD - Event Listeners
    79. 79. TigerMDSD - Event Listeners public interface GeneratorEventListener { boolean handle(GeneratorEvent event); ... }
    80. 80. TigerMDSD - Example extension
    81. 81. TigerMDSD - Example extension @OneToMany @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN) private Set<Tire> tires;
    82. 82. TigerMDSD - 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) { ... } }
    83. 83. TigerMDSD - Example extension
    84. 84. TigerMDSD - Example extension 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; }
    85. 85. “I thought it was all about rich domain models! What about my own domain code?”
    86. 86. “I thought it was all about rich domain models! What about my own domain code?” It is - but Usecase logic doesn’t belong in domain objects - so in reality very little code should enter the domain objects!
    87. 87. “I thought it was all about rich domain models! What about my own domain code?” It is - but Usecase logic doesn’t belong in domain objects - so in reality very little code should enter the domain objects! “Domain object design should focus on what the system is - NOT on what the system does!” James Coplien - DCI Talk at Öredev 2009
    88. 88. For the logic that belongs in the domain objects we have several choices... What we model:
    89. 89. For the logic that belongs in the domain objects we have several choices... What we model:
    90. 90. For the logic that belongs in the domain objects we have several choices... What we model: What we generate using Extension classes: (aka. 3 level inheritance)
    91. 91. For the logic that belongs in the domain objects we have several choices... What we model: What we generate al tion using Extension Op classes: (aka. 3 level inheritance)
    92. 92. For the logic that belongs in the domain objects we have several choices... What we model: What we generate al Alternatives: tion Generator Extensions using Extension Op Partial Classes classes: Mixins / Traits (aka. 3 level inheritance) Priviledged Aspects Protected Regions
    93. 93. Let’s get some UI running
    94. 94. UI framework considerations “Web 1.0” Client 5 Server HTML Page DOM over HttpResponse View 4 3 Model Parameters over HttpRequest Controller 2 DB 1
    95. 95. UI framework considerations “Client side RIA” Client 4 Server Requested data View to view as XML / JSON 5 DOM Model 3 1 Changes to model Controller encoded as parameters DB 2
    96. 96. UI framework considerations “Server driven Web 2.0 RIA” Client 8 Server 9 7 TerminalAdapter TerminalAdapter HTML Page over HttpResponse View 6 Automated by 5 DOM the RIA framework Model Parameters over HttpRequest Controller 1 4 3 DB 2
    97. 97. Component Architecture
    98. 98. Component Architecture “UI Component” • Button, Table, Tree, ... • Server-side data • Full Java API
    99. 99. Component Architecture HTTP(S) “UI Component” “Widget” • Button, Table, Tree, ... • Client-side peer for • Server-side data the component • Full Java API • Runs on JavaScript
    100. 100. Component Architecture HTTP(S) “UI Component” “Widget” • Button, Table, Tree, ... • Client-side peer for • Server-side data the component • Full Java API • Runs on JavaScript Java • Compiled with JDK
    101. 101. Component Architecture HTTP(S) “UI Component” “Widget” • Button, Table, Tree, ... • Client-side peer for • Server-side data the component • Full Java API • Runs on JavaScript Java Java • Compiled with JDK • Google Web Toolkit
    102. 102. Using TigerMDSD to create Vaadin Builders
    103. 103. Using TigerMDSD to create Vaadin Builders HorizontalLayout buttons = new HorizontalLayout(); buttons.setSpacing(true); Button discardChanges = new Button(text("general.button.back"), new Button.ClickListener() { public void buttonClick(Button.ClickEvent event) { getForm().discard(); getViewManager().showView(HomeView.class); } }); discardChanges.setStyleName(Button.STYLE_LINK); buttons.addComponent(discardChanges); // The save button Button apply = new Button(text("general.button.save"), new Button.ClickListener() { public void buttonClick(Button.ClickEvent event) { try { getForm().commit(); getPersistenceManager().merge(getFormEntity()); getViewManager().showView(HomeView.class); } catch (Exception e) { // Ignored, we'll let the Form handle the errors } } }); buttons.addComponent(apply); // Add the buttons to the layout getForm().getLayout().addComponent(buttons);
    104. 104. Using TigerMDSD to create Vaadin Builders HorizontalLayout buttons = new HorizontalLayout(); buttons.setSpacing(true); Button discardChanges = new Button(text("general.button.back"), formBuilder = new new Button.ClickListener() { HbnFormBuilder<User>(Application.getInstance().getContextUser()); public void buttonClick(Button.ClickEvent event) { formBuilder.getForm().getLayout().addComponent( getForm().discard(); horizontalLayout() getViewManager().showView(HomeView.class); .spacing(true) } .addComponents( }); button(text("general.button.back"), new Button.ClickListener() { discardChanges.setStyleName(Button.STYLE_LINK); public void buttonClick(Button.ClickEvent event) { buttons.addComponent(discardChanges); formBuilder.getForm().discard(); getViewManager().showView(HomeView.class); // The save button } Button apply = new Button(text("general.button.save"), new Button.ClickListener() { }), public void buttonClick(Button.ClickEvent event) { button(text("general.button.save"), new Button.ClickListener() { try { public void buttonClick(Button.ClickEvent event) { getForm().commit(); formBuilder.getForm().commit(); getPersistenceManager().merge(getFormEntity()); User user = formBuilder.getEntity(); getViewManager().showView(HomeView.class); getPersistenceManager().merge(user); } catch (Exception e) { getViewManager().showView(HomeView.class); // Ignored, we'll let the Form handle the errors } } } } ) }); ) buttons.addComponent(apply); // Add the buttons to the layout getForm().getLayout().addComponent(buttons);
    105. 105. Strong data binding Exchange fragile strings such as “customer.name.firstName” with typesafe code property().getName().getFirstName()
    106. 106. Strong data binding Exchange fragile strings such as “customer.name.firstName” with typesafe code property().getName().getFirstName() new SmartFormBuilder<Customer>(Customer, true) { protected void defineForm(SmartFormBuilder<Customer> formBuilder) { withProperties( property().getName().getFirstName(), property().getName().getLastName(), property().getAddress().getStreet(), property().getAddress().getZipCode(), property().getAddress().getCity(), property().getAddress().getCountry() ); } );
    107. 107. Web UI design patterns
    108. 108. Web UI design patterns M-V-C Model View Controller
    109. 109. Web UI design patterns M-V-C Model View Controller M-V-P Model View Presenter
    110. 110. Web UI design patterns M-V-C Model View Controller M-V-P Model View Presenter M-V-MV Model View ModelView/Presentation model
    111. 111. Web UI design patterns 1. Input/Event <<stateless>> 3 .Response Controller M-V-P 2 .Updates 4 .Pulls data View 5 .Change notification Model Model View Presenter Model View Controller M-V-MV Model View ModelView/Presentation model
    112. 112. Web UI design patterns 1. Execute Command 2 .Updates 1. Input/Event <<stateless>> <<stateless>> 3 .Response Controller 2 .Updates 3 .Updates Presenter 4 .Change Notification 4 .Pulls data View 5 .Change notification Model View Model Model View Controller Model View Presenter M-V-MV Model View ModelView/Presentation model
    113. 113. Web UI design patterns 1. Execute Command 2 .Updates 1. Input/Event <<stateless>> <<stateless>> 3 .Response Controller 2 .Updates 3 .Updates Presenter 4 .Change Notification 4 .Pulls data Pulls data View 5 .Change notification Model View Change notification Model Supervising controller Model View Controller Model View Presenter M-V-MV Model View ModelView/Presentation model
    114. 114. Web UI design patterns 1. Execute Command 2 .Updates 1. Input/Event <<stateless>> <<stateless>> 3 .Response Controller 2 .Updates 3 .Updates Presenter 4 .Change Notification 4 .Pulls data Pulls data View 5 .Change notification Model View Change notification Model Supervising controller Model View Controller Strong binding/Execute Command Apply/Commit Model View Presenter <<statefull>> Change ViewModel Errors notification ViewModel allows Invalid states View Model Model View ModelView/Presentation model
    115. 115. Thank you for your attention! For more information jeppe@tigerteam.dk Twitter: @jeppec
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×