Not your Fathers @ mobile Larson @ _open Knowledge Java EE Lars - - PowerPoint PPT Presentation

not your father s
SMART_READER_LITE
LIVE PREVIEW

Not your Fathers @ mobile Larson @ _open Knowledge Java EE Lars - - PowerPoint PPT Presentation

Not your Fathers @ mobile Larson @ _open Knowledge Java EE Lars Rwekamp | CIO New Technologies May I submit my billing info to your merchant account via your payment gateway ? Wo liegt das Problem ... Too many times


slide-1
SLIDE 1

Not your Father’s
 Java EE

@mobileLarson 
 @_openKnowledge

Lars Röwekamp | CIO New Technologies

slide-2
SLIDE 2

„May I submit my billing info to your merchant account via your payment gateway?“

slide-3
SLIDE 3
slide-4
SLIDE 4

Wo liegt das Problem ... „Too many times application architects focus on the technical problems instead of designing for the problem domain.“

slide-5
SLIDE 5

Wo liegt das Problem ... App Service Data

User Interface CDI Managed Bean Session EJB Session EJB EntityManager Entity

TX UI

slide-6
SLIDE 6

Es wäre doch viel schöner, wenn ... App

User Interface UseCase Controller

TX UI

Business Object Business Object Business Object

Domain

slide-7
SLIDE 7

App

User Interface UseCase Controller

TX UI

Business Object Business Object Business Object

Domain Es wäre doch viel schöner, wenn ... Business

slide-8
SLIDE 8

Es wäre doch viel schöner, wenn ...

Domain Model Application

Adapter Adapter

slide-9
SLIDE 9

Es wäre doch viel schöner, wenn ...

Domain Model Application

Adapter Adapter

App Core mit Business TX

slide-10
SLIDE 10

Es könnte alles so einfach sein ...

slide-11
SLIDE 11

Das kleine 1x1 des DDD …

Eric Evans says „For most software projects, the primary focus should be on the domain and domain logic.“ „Complex domain design should be based on a model.“

slide-12
SLIDE 12

End User Domain Expert Technical Expert fachliche Domäne Die gemeinsame fachliche Welt in der wir „leben“.

Das kleine 1x1 des DDD …

slide-13
SLIDE 13

Das kleine 1x1 des DDD …

End User Domain Expert Technical Expert Ubiquitous Language Fachsprache als Basis
 für ein gemeinsames Domain Model

slide-14
SLIDE 14

Das kleine 1x1 des DDD …

„Produce Software 
 that makes perfectly 
 sense to business, 
 not only to coder“ End User Domain Expert Technical Expert Rich Domain Model

slide-15
SLIDE 15

Das kleine 1x1 des DDD …

„Produce Software 
 that is always 
 in a correct state, 
 not only partially“ Domain Expert Technical Expert Rich Domain Model Access Layer Business Layer DB Layer

slide-16
SLIDE 16

Das kleine 1x1 des DDD …

Factories

encapsulate with encapsulate with encapsulate with

Model-Driven Design Services

express model with

Entities

express model with

Value Objects

express model with

Smart UI

mutually exclusive choices

X

Aggregates

maintain integrity with act as root of encapsulate with

Repositories

access with access with

Layered Architecture

isolate domain with

slide-17
SLIDE 17

Das kleine 1x1 des DDD …

Bounded Context Ubiquitous Language

names enter

Continous Integration

keep model unified by

Context Map

assess/overview relationships with

Shared Kernel

Overlap allied contexts through

Customer Supplier Teams

relate allied contexts as

Conformist

  • verlap unilaterally as

Open Host Service

support multiple clients through

Published Language

formalize as

Separate Ways

free teams to go

Anticorruption Layer

translate and insulate unilaterally with

slide-18
SLIDE 18

Passt das zu Java EE?

slide-19
SLIDE 19

Passt das zu Java EE? Klar …

Java EE Next Generation BluePrint a.k.a. Java EE meets DDD

slide-20
SLIDE 20

Passt das zu Java EE? Klar …

slide-21
SLIDE 21

You must follow the „Chuck-Norris“ Rules!

Passt das zu Java EE? Klar, aber …

slide-22
SLIDE 22

RULE #1 Design a Rich not an Anemic Domain Model

Always follow the Rules …

slide-23
SLIDE 23

Rule #1: Rich not Anemic Domain Model

/** * Represents a business customer with a * full qualified name, a date of birth indicating * if the customer is „sui juris“ and a valid address * that may change after a relocation. */ public class Customer { private String firstName; private String lastName; private Date birthDate; private Address address; public void setFirstName(String aFirstName) { ... } public String getFirstName() { return firstName; } public void setLastName(String aLastName) { ... } public String getLastName() { return lastName; } public void setBirthDate(Date birthDate) { ... } public Date getBirthDate() { return birthDate; } public void setAddress(Address address) { ... } public Address getAddress() { return address; } }

Fachlichkeit?

slide-24
SLIDE 24

Rule #1: Rich not Anemic Domain Model

/** * Represents a customer data access object to * encapsulate all db relevant activities */ public class CustomerDao { ... public List<Customer> findByZipCodeOrCity( String zipCode, String city) { return ...; } public List<Customer> findByZipCodeOrCityOrCityLimit( String zipCode, String city, int order) { return ...; } }

sprechend?

slide-25
SLIDE 25

Rule #1: Rich not Anemic Domain Model

Zur Erinnerung „Wir möchten ein sprechendes Domain Model, mit einem sprechenden API, welches wir in sich konsistent erzeugen und im weiteren Verlauf konsequent konsistent erhalten.“

slide-26
SLIDE 26

Anforderungen

  • sprechendes Modell
  • sprechendes API
  • konsistent erzeugen
  • konsistent erhalten
  • Fachlichkeit, Validierung, Konvertierung,

Normalisierung und Konsistenzprüfung!

Rule #1: Rich not Anemic Domain Model

slide-27
SLIDE 27

Mut zur Fachlichkeit

slide-28
SLIDE 28

Anforderungen

  • sprechendes Modell
  • sprechendes API
  • konsistent erzeugen
  • konsistent erhalten

Rule #1: Rich not Anemic Domain Model

slide-29
SLIDE 29

Rule #1: Rich not Anemic Domain Model

// (JPA) Entity with Value Objects public class Customer extends HumanBeing { private FirstName firstName; private LastName lastName; private FamilyStatus familyStatus; private Customer partner; private Address postalAddress; private Map<PhoneNumberType, PhoneNumber> phoneNumbers; ... public void marry(Partner partner,LastName newLastName) { lastName = notNull(newLastName) familyStatus = FamilyStatus.MARRIED; // Ensure bidirectional integrity for partner entity! ... } public boolean isMarried() { return (familyStatus == FamilyStatus.MARRIED); } }

sprechend

slide-30
SLIDE 30

Rule #1: Rich not Anemic Domain Model

// (JPA) Entity with Value Objects public class Customer extends HumanBeing { ... private Map<PhoneNumberType, PhoneNumber> phoneNumbers; ... public void changeHomePhoneNumber( PhoneNumber changedHomePhoneNumber) { ... } public void disconnectHomePhone() { ...} public void changeMobilePhoneNumber( PhoneNumber changedHomePhoneNumber) { ... } public void disconnectMobilePhone() { ... } ... }

sprechend

slide-31
SLIDE 31

Rule #1: Rich not Anemic Domain Model

/** * Represents a customer data access object to * encapsulate all db relevant activities */ public class CustomerDao { ... public List<Customer> findByZipCodeOrCityOrStreet( String street, String city, String zipCode) { return ...; } public List<Customer> findByAnyOf( ZipCode zipCode, City city, Street order) { return ...; } }

sprechend

slide-32
SLIDE 32

Hmm, passt das wirklich zu Java EE?

slide-33
SLIDE 33

Rule #1: Rich not Anemic Domain Model

/** * Simple value object for first name using the * common base <code>SimpleValueObject</code> */ public class FirstName extends SimpleValueObject<String> { public FirstName(String aValue) { super(aValue); } public String getText() { return super.getValue(); } }

Common Base

  • Passt das wirklich: Value Objects?
slide-34
SLIDE 34

Rule #1: Rich not Anemic Domain Model

/** Abstract value object as a common base */ public abstract class SimpleValueObject<T extends Comparable> 
 implements Serializable, Comparable<SimpleValueObject<T>> { private T value; public SimpleValueObject(T aValue) { value = aValue; } protected T getValue() { return value; } public boolean equals(Object o) { return ...; } public int hashCode() { return ...; } public String toString() { return ...; } public int compareTo(SimpleValueObject<T> o) { return ...; } }

Common Base

slide-35
SLIDE 35

Rule #1: Rich not Anemic Domain Model

/** * Embeddable date of birth for (re)use in value objects */ @Embeddable public class DateOfBirth { private Date dateOfBirth; ... } /** * Customer entity making use of date of birth embeddable */ @Entity public class Customer { @Embedded @AttributeOverride(name=„dateOfBirth", column=@Column(name=“CUST_BIRTHDATE“)) private DateOfBirth dateOfBirth; ... }

VO, Entities & JPA

slide-36
SLIDE 36

Rule #1: Rich not Anemic Domain Model

/** * Using JPA-QL and ValueObjects */ @Entity @Table(name = "TAB_USER", ...) @NamedQueries({ @NamedQuery(name = "User.findByEmail", query = "select u from User u where u.email = :email"), @NamedQuery(name = "User.findByEmailString", query = "select u from User u " + " where u.email.value = :emailString“) }) public class User extends AbstractEntity { protected static final String EMAIL_COLUMN = "EMAIL"; @AttributeOverride(name = "value", column = @Column(name = EMAIL_COLUMN, unique = true, nullable = false)) private Email email; ... }

VO & JPA Queries

slide-37
SLIDE 37

Rule #1: Rich not Anemic Domain Model

/** CDI based JSF Controller managing user related input */ @Named("customerController") @RequestScoped public class CustomerController { private DateOfBirth dateOfBirth; private ZipCode zipCode; ...; public DateOfBirth getDateOfBirth() { return dateOfBirth; } public void setDateOfBirth(DateOfBirth newDateOfBirth) { dateOfBirth = newDateOfBirth; } public ZipCode getZipCode() { return zipCode; } public void setZipCode(ZipCode newZipCode) { zipCode = newZipCode; } ... }

VO & JSF

slide-38
SLIDE 38

Rule #1: Rich not Anemic Domain Model

<!-- Value Object binding in JSF xhtml page via Unified Expression Language & JSF Faces Converter

  • ->

<!-- using JSF converter for Value Object of type ZipCode (read) —> <h:outputText value=“#{customerController.zipCode}“ /> <!-- using JSF converter for Value Object of type ZipCode (write) —> <h:inputText value=“#{customerController.zipCode}“ ... />

VO & JSF

@FacesConverter(forClass = ZipCode.class) public class ZipCodeConverter extends SimpleValueObjectConverter <ZipCode> { }

slide-39
SLIDE 39

Anforderungen

  • sprechendes Modell
  • sprechendes API
  • konsistent erzeugen
  • konsistent erhalten

Rule #1: Rich not Anemic Domain Model

slide-40
SLIDE 40

Rule #1: Rich not Anemic Domain Model

// JPA entity @ValidPaymentMethod // cross-field constraint @Entity public class Customer { @Name // common constraint for type Name private FirstName firstName; @Name // common constraint for type Name private LastName lastName; @Valid // delegate validation to Class private CreditCard creditCard; @Valid // delegate validation to Class private BankAccount bankAccount; @Address(area = AddressArea.GERMANY) // special constraint private Address postalAddress; ... }

konsistent?

slide-41
SLIDE 41

Rule #1: Rich not Anemic Domain Model

// Builder Pattern - IN ACTION (easy version) // create AddressBuilder AddressBuilder builder = new AddressBuilder(); // set all known values // BTW: could be also used in JSF and other frameworks builder.setStreet(...); builder.setStreetNumber(...); builder.setZipCode(...); builder.setCity(...); builder.setState(...); builder.setCountry(...); // build valid and immutable Address object Address address = builder.build();

konsistent

slide-42
SLIDE 42

Rule #1: Rich not Anemic Domain Model

// Builder Pattern - IN ACTION (extended version) // create AddressBuilder Address address = newAddress() // set values // BTW: could be also used in JSF with own EL Resolver .forStreetNumber(...).ofStreet(...) .inCity(...).withZipCode(...) .lyingInState(...).ofCountry(...) // build Address object .build(...);

konsistent

slide-43
SLIDE 43

Rule #1: Rich not Anemic Domain Model

// Class with Builder - extended version public class Address { public static Builder newAddress() { return new Builder(); } ... public static class Builder { private Address address = new Address(); public Builder ofStreet(String initialStreet) { address.street = validateStreet(initialStreet); return this; } public Address build() { validate(); Address validAddress = address; address = new Address(); return validAddress; } } }

konsistent

slide-44
SLIDE 44

RULE #2 Inject Business not Infrastructure

Always follow the Rules …

slide-45
SLIDE 45

Rule #2: Inject Business not Infrastructure

// JSF UI Controller @javax.enterprise.context.RequestScoped @javax.inject.Named(“createCustomerController“) public class CreateCustomerController { // inject CustomerService and MailService via @Inject @Inject // CDI managed controller layer bean (SessionScoped) private AuthenticationController authController; private Customer customer; public String createCustomer() { currentCallCenterAgent = authController.getLoggedInCca(); customer.setAuditInformation(currentCallCenterAgent); customerService.create(customer); mailService.sendWelcomeMail(customer); return CUSTOMER_CREATED; } // getter / setter for customer ... }

slide-46
SLIDE 46

Rule #2: Inject Business not Infrastructure

// JSF UI Controller @javax.enterprise.context.RequestScoped @javax.inject.Named(“createCustomerController“) public class CreateCustomerController { // inject CustomerService and MailService via @Inject @Inject @Current private CallCenterAgent currentCallCenterAgent; private Customer customer; public String createCustomer() { customer.setAuditInformation(currentCallCenterAgent); customerService.create(customer); mailService.sendWelcomeMail(customer); return CUSTOMER_CREATED; } // getter / setter for customer ... }

slide-47
SLIDE 47

Rule #2: Inject Business not Infrastructure

// Authentication Controller @SessionScoped @Named(“authenticationController“) public class AuthenticationController implements Serializable { private CallCenterAgent loggedInCca; public String authenticate() {...} @Produces @Current public CallCenterAgent getLoggedInCca() { return loggedInCca; } ... } @RequestScoped

@Inject @Current CallCenterAgent

slide-48
SLIDE 48

Rule #2: Inject Business not Infrastructure

package de.openknowldege.qualifier import ... // self-made qualifier to indicate current instance of something @Qualifier @Target({TYPE, METHOD, PARAMETER, FIELD}) @Retention(RUNTIME) public @interface Current{ }

slide-49
SLIDE 49

Rule #2: Inject Business not Infrastructure

// JSF UI Controller @javax.enterprise.context.RequestScoped @javax.inject.Named(“createCustomerController“) public class CreateCustomerController { // inject CustomerService and MailService via @Inject @Inject @Current private CallCenterAgent currentCallCenterAgent; private Customer customer; public String createCustomer() { customer.setAuditInformation(currentCallCenterAgent); customerService.create(customer); mailService.sendWelcomeMail(customer); return CUSTOMER_CREATED; } // getter / setter for customer ... }

slide-50
SLIDE 50

Rule #2: Inject Business not Infrastructure

// JSF UI Controller @javax.enterprise.context.RequestScoped @javax.inject.Named(“createCustomerController“) public class CreateCustomerController { // inject CustomerService and MailService via @Inject @Inject @Current // still „bounded“ to controller layer? private CallCenterAgent currentCallCenterAgent; private Customer customer; public String createCustomer() { customer.setAuditInformation(currentCallCenterAgent); customerService.create(customer); mailService.sendWelcomeMail(customer); return CUSTOMER_CREATED; } // getter / setter for customer ... }

slide-51
SLIDE 51

Rule #2: Inject Business not Infrastructure

// JSF UI Controller @javax.enterprise.context.RequestScoped @javax.inject.Named(“createCustomerController“) public class CreateCustomerController { // inject CustomerService and MailService via @Inject @Inject @Current // still „bounded“ to controller layer? NO! private CallCenterAgent currentCallCenterAgent; private Customer customer; public String createCustomer() { customer.setAuditInformation(currentCallCenterAgent); customerService.create(customer); mailService.sendWelcomeMail(customer); return CUSTOMER_CREATED; } // getter / setter for customer ... }

slide-52
SLIDE 52

Rule #2: Inject Business not Infrastructure

// Customer Service EJB @Stateless public class CustomerService { @Inject @Current private CallCenterAgent currentCallCenterAgent; @PersistenceContext private EntityManager em; // transactional by default public void createCustomer(Customer customer) { customer.setAuditInformation(currentCallCenterAgent); em.persist(customer); } ... }

slide-53
SLIDE 53

Rule #2: Inject Business not Infrastructure

<html ...> <h:body> <h:form> Vorname: <h:inputText value=“#{createCustomerController.customer.firstname}"/> Name: <h:inputText value=“#{createCustomerController.customer.lastname}"/> </h:form> </h:body> </html>

Aber was ist mit der View?

slide-54
SLIDE 54

Rule #2: Inject Business not Infrastructure

<html ...> <h:body> <h:form> Vorname: <h:inputText value=“#{customerToCreate.firstname}"/> Name: <h:inputText value=“#{customerToCreate.lastname}"/> </h:form> </h:body> </html>

Fachlichkeit auch in der View?

slide-55
SLIDE 55

Rule #2: Inject Business not Infrastructure

// JSF UI Controller @javax.enterprise.context.RequestScoped @javax.inject.Named(“createCustomerController“) public class CreateCustomerController { @Inject private CustomerService customerService; private Customer customer; // getter for customer @javax.inject.Produces @javax.inject.Named(“customerToCreate“) public Customer getCustomer { return customer; } ... }

#{customerToCreate … }

slide-56
SLIDE 56

Rule #2: Inject Business not Infrastructure

// EJB based Service @Named(“shoppingCartService“) @ApplicationScoped public class ShoppingCartService { ... // call from JSF via #{shoppingCartService.add(...)} public void add( ShoppingCart shoppingCart, Article article) { ... } ... }

BTW: Service Access via EL

slide-57
SLIDE 57

Rule #2: Inject Business not Infrastructure

// JPA Repository public class CustomerRepository { @Inject EntityManager em; // CDI producer method for „current“ Customer @Produces @Current @Named(“currentCustomer“) public Customer findCustomer ( @Parameter(“customerId“) Integer customerId) { return em.find(Customer.class, customerId) } ... }

BTW: Repository als Producer

slide-58
SLIDE 58

RULE #3 Business drives TX not Technology

Always follow the Rules …

slide-59
SLIDE 59

Rule #3: Business drives TX not Technology

// Customer Service EJB @Stateless public class CustomerService { @Inject @Current private CallCenterAgent currentCallCenterAgent; @PersistenceContext private EntityManager em; // transactional by default public void createCustomer(Customer customer) { customer.setAuditInformation(currentCallCenterAgent); em.persist(customer); } ... }

slide-60
SLIDE 60

Rule #3: Business drives TX not Technology

// Customer Service EJB - no EJB annotation required! @ApplicationScoped @Stateless public class CustomerService implements Serializable { @Inject @Current private CallCenterAgent currentCallCenterAgent; @PersistenceContext private EntityManager em; // transactional by default public void createCustomer(Customer customer) { customer.setAuditInformation(currentCallCenterAgent); em.persist(customer); } ... }

slide-61
SLIDE 61

Rule #3: Business drives TX not Technology

// Customer Service @ApplicationScoped public class CustomerService implements Serializable { @Inject @Current private CallCenterAgent currentCallCenterAgent; @PersistenceContext private EntityManager em; @Transactional public void createCustomer(Customer customer) { customer.setAuditInformation(currentCallCenterAgent); em.persist(customer); } ... }

Java EE 7, DeltaSpike or „home brewn“

slide-62
SLIDE 62

Rule #3: Business drives TX not Technology

@Transactional @Interceptor public class TransactionAdvice { @Inject private UserTransaction utx; @AroundInvoke public Object applyTransaction( InvocationContext ic) throws Throwable { ... // 1. implement utx.begin() ic.proceed(); // 2. call original method ... // 3. implement utx.commit() } *XML registration omitted

slide-63
SLIDE 63

Rule #3: Business drives TX not Technology

// Customer Service - no annotation required! @ApplicationScoped public class CustomerService implements Serializable { @Inject @Current private CallCenterAgent currentCallCenterAgent; @PersistenceContext private EntityManager em; @Transactional public void createCustomer(Customer customer) { customer.setAuditInformation(currentCallCenterAgent); em.persist(customer); } ... }

slide-64
SLIDE 64

App

User Interface UseCase Controller

TX UI

Business Object Business Object Business Object

Domain Rule #3: Business drives TX not Technology

slide-65
SLIDE 65

App

User Interface UseCase Controller

TX UI

Business Object Business Object Business Object

Domain Business Rule #3: Business drives TX not Technology

slide-66
SLIDE 66

Rule #3: Business drives TX not Technology

// JSF UI Controller @javax.enterprise.context.RequestScoped @javax.inject.Named(“createCustomerController“) public class CreateCustomerController { @Inject private CustomerService customerService; private Customer customer; @Transactional public String createCustomer() { customerService.create(customer); ... // some additional use case “tx“ related work return CUSTOMER_CREATED; } // getter / setter for customer ... }

slide-67
SLIDE 67

App

User Interface UseCase Controller

TX

Business Object Business Object Business Object

Domain Business Rule #3: Business drives TX not Technology

Danger: LIE!

slide-68
SLIDE 68

Lazy Initialization Problem besteht nach wie vor!

  • EntityManager ist an Transaktion gebunden
  • Probleme bei lesenden Zugriffen ohne TX
  • Varianten
  • EXTENDED EM (@Stateful CM)
  • EXTENDED EM (@RequestScoped AM)
  • Fachliche Queries via EntityGraph (seit JPA 2.1)

Rule #3: Business drives TX not Technology

slide-69
SLIDE 69

… and You are my (wo)man!

Always follow the Rules …

slide-70
SLIDE 70

App

User Interface UseCase Controller

TX UI

Business Object Business Object Business Object

Domain Business Always follow the Rules …

slide-71
SLIDE 71

Es wäre doch viel schöner, wenn ...

Domain Model Application

Adapter Adapter

App Core mit Business TX

slide-72
SLIDE 72

Erkenntnis des Tages - bitte mitnehmen!

„The Design is the Code, the Code is the Design.“

slide-73
SLIDE 73

Erkenntnis des Tages - bitte mitnehmen!

„Muss ich denn jedes Mal den Code ändern, wenn sich die Fachlichkeit ändert?“

slide-74
SLIDE 74

Erkenntnis des Tages - bitte mitnehmen!

„Zur Hölle, ja! Wann denn 
 bitte sonst?“

slide-75
SLIDE 75

Not your Father’s
 Java EE

@mobileLarson 
 @_openKnowledge

Lars Röwekamp | CIO New Technologies