mut zur fachlichkeit
DESCRIPTION
Mut zur Fachlichkeit Speaker: Lars Röwekamp Leider sind in der "freien Wildbahn" nach wie vor viele Architekturen und APIs stark durch die verwendeten Technologien, Frameworks, Generatoren etc. getrieben. Die eigentliche Fachlichkeit der Anwendung bleibt dabei häufig auf der Strecke und ist im Quellcode kaum noch auffindbar. Das geht – nur – solange gut, bis der erste Fehler gefunden werden muss. Die Session zeigt einfache, aber sehr effektive Strategien, wie bestehende Anwendungen in ein fachlich getriebenes Architektur- und API-Design überführt werden können - Aha-Effekte garantiert.TRANSCRIPT
![Page 1: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/1.jpg)
@mobileLarson @_openKnowledge
Lars Röwekamp | CIO New Technologies
Mut zur Fachlichkeit
![Page 2: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/2.jpg)
Business vs. Technology Mut zur Fachlichkeit
JAX2014
„May I submit my billing info to your merchant account via your payment
gateway?“
![Page 3: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/3.jpg)
Mut zur FachlichkeitJAX2014
End User
Domain Expert
TechnicalExpert
Business vs. Technology
Translationist auf Dauer teuer - sogar sehr teuer!
![Page 4: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/4.jpg)
Mut zur FachlichkeitJAX2014
End User
Domain Expert
TechnicalExpert
Ubiquitous Language
Basis für ein konsistentes
Domain Model
Business vs. Technology
![Page 5: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/5.jpg)
„Produce Software that makes perfectly sense to business,
not only to coder“
Mut zur FachlichkeitJAX2014
End User
Domain Expert
TechnicalExpert
Rich Domain Model
Business vs. Technology
![Page 6: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/6.jpg)
„Produce Software that is always
in a correct state, not only partially“
Mut zur FachlichkeitJAX2014
Domain Expert
TechnicalExpert
Rich Domain Model
Business vs. Technology
Access Layer
Business Layer
DB Layer
![Page 7: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/7.jpg)
Mut zur FachlichkeitReality CheckJAX
2014
![Page 8: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/8.jpg)
Mut zur FachlichkeitReality CheckJAX
2014
The déjà-vuExperiment
![Page 9: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/9.jpg)
/** * 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 sureName; ! private Date birthDate; private Address address; ! public void setFirstName(String aFirstName) { ... } public String getFirstName() { return firstName; } ! public void setSureName(String aSureName) { ... } public String getSureName() { return sureName; } ! public void setBirthDate(Date birthDate) { ... } public Date getBirthDate() { return birthDate; } ! public void setAddress(Address address) { ... } public Address getAddress() { return address; } !}
Reality Check
Fachlichkeit?
JAX2014 Mut zur Fachlichkeit
![Page 10: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/10.jpg)
/** * 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 { ! public Customer(String firstName, String sureName, String zipCode, String city) { ... } ! public Customer(String firstName, String sureName, String zipCode, String city, String street) { ... } ... }
Reality Check
Parameter (Hölle)?
JAX2014 Mut zur Fachlichkeit
Konstruktor (Hölle)?
![Page 11: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/11.jpg)
/** * 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 { ! public Customer(String firstName, String sureName, String zipCode, String city) { Validate.isTrue(StringUtils.isNotEmpty(firstName)); Validate.isTrue(StringUtils.isNotEmpty(sureName)); ... } ! public void setFirstName(String firstName) { this.firstName = firstName; } !! ... }
Reality CheckJAX2014 Mut zur Fachlichkeit
Validierung?
![Page 12: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/12.jpg)
/** * 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 static final String ZCODE_PATTERN = ...; ! public Customer(String firstName, String sureName, String zipCode, String city) { setFirstName(firstName); setZipCode(zipCode); ... } ! public void setZipCode(String zipCode) { Validate.isTrue(Pattern.matches(ZCODE_PATTERN, zipCode)); } ! ... }
Reality CheckJAX2014 Mut zur Fachlichkeit
Richtig hier?
![Page 13: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/13.jpg)
/** * Represents a controller to handle * customer related changes */ public class CustomerController { !/** * save new date of birth retrieved from the web * in a customer entity */ public void alterBirthDate(Customer customer, String newDate) { ! SimpleDateFormat df = new SimpleDateFormat(); Date birthDate = null; try { birthDate = df.parse(newDate); } catch (ParseException e) { // do something } Date today = new Date(); ! if (birthDate.after(today)) { // do something } else { customer.setBirthDate(birthDate); } } ... }
Reality CheckJAX2014 Mut zur Fachlichkeit
Konvertierung?
![Page 14: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/14.jpg)
/** * Represents a controller to handle * customer related changes */ public class CustomerController { ! /** * check if a customer has birthday today */ public boolean hasBirthDay(Customer customer) { ! Calendar todayCal = Calendar.getInstance(); Calendar birthDateCal = Calendar.getInstance(); birthDate.setTime(customer.getBirthDate().getTime()); ! if (birthDateCal.get(Calendar.YEAR) > (todayCal.get(Calendar.YEAR))) { return false; } else if (birthDateCal.get(Calendar.MONTH) != (todayCal.get(Calendar.MONTH))) { return false; } else if (birthDateCal.get(Calendar.DAY_OF_MONTH) != (todayCal .get(Calendar.DAY_OF_MONTH))) { return false; } return true; } ... }
Reality CheckJAX2014 Mut zur Fachlichkeit
Auswertung?
![Page 15: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/15.jpg)
/** * Util to calculate current age for a given date * and to calculate if the date is a birthday today. */ public class BirthDayUtilAkaHelper { public static boolean hasBirthDay(Date date) { ... return ...; } public static int getAge(Date date) { return 0; } } !/** * usage of BirthdayUtil */ Customer customer = ...; if (BirthDayUtilAkaHelper.hasBirthDay(customer.getBirthDate())) { ...; }
Reality CheckJAX2014 Mut zur Fachlichkeit
Util & Helper (Hölle)?
Manager?
![Page 16: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/16.jpg)
/** * 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 Date birthDate; ! public void setBirthDate(Date newBirthDate) { if (isInFuture(newBirthDate)) { /*abort */ ... } birthDate = newBirthDate; } ! public Date getBirthDate() { return birthDate; } ... } !/** * usage of getBirthDate */ Customer customer = ...; customer.getBirthDate().setTime(someTimeInFuture);
Reality Check
Immutable?
JAX2014 Mut zur Fachlichkeit
![Page 17: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/17.jpg)
/** * Data Access Object for retrieving * customer objects from the DB. */ public class CustomerDao { ! public List<Customer> findByZipCodeOrCity(String zipCode, String city) { return ...; } ! public List<Customer> findByZipCodeOrCityWithLimit(String zipCode, String city, int limit) { return ...; } ! public List<Customer> findByZipCodeOrCityAndOrders(String zipCode, String city, int orderCount) { return ...; } } !/** * usage of getBirthDate */ String current= ...; String value = ...; List<Customer> searchResult = dao.findByZipCodeOrCity(current,value);
Reality Check
Meaningful API?
JAX2014 Mut zur Fachlichkeit
Correct Order?
![Page 18: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/18.jpg)
/** * Data Access Object for retrieving * customer objects from the DB. */ public class CustomerDao { // BEFORE refactoring public List<Customer> findByZipCodeOrCity(String zipCode, String city) { return ...; } ! // AFTER refactoring public List<Customer> findByZipCodeOrCity(String zipCode, String city, String street) { return ...; } ! ...; }
Reality Check
Refactoring?
JAX2014 Mut zur Fachlichkeit
![Page 19: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/19.jpg)
Mut zur FachlichkeitProblemfelderJAX
2014
![Page 20: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/20.jpg)
JAX2014
Anemic Domain Model !
„Pay most of the high cost of developing a Domain Model, but get little or none of the benefits.“
Mut zur FachlichkeitProblemfelder
(Vaugn Vernon, Implementing Domain-Driven Design)
![Page 21: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/21.jpg)
JAX2014 Mut zur Fachlichkeit
Problemfelder
Anemic Domain Model !
‣ „kraftloses“ fachliche Objekte mit getter/setter ‣ eigentliche Fachlichkeit ausserhalb des Modells !
‣ Konsistenzprüfung ausserhalb ‣ Konvertierung ausserhalb ‣ Validierung ausserhalb
![Page 22: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/22.jpg)
JAX2014 Mut zur Fachlichkeit
Problemfelder
Anemic Domain Model !
‣ forced by procedural programming mentality ‣ forced by oversimplified samples !
‣ forced by Tool-Support ‣ forced by generated Models ‣ forced by Specifications
![Page 23: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/23.jpg)
JAX2014 Mut zur Fachlichkeit
Problemfelder
Anemic Domain Model
1980s 1991 1992-1995 1996/1997 1998+
Objekte gewinnen an Bedeutung dank C++ und Smalltalk
Visuelle Tools und IDEs werden „produktiv“ und verbreiten sich
„Explosion“ von Reflexion-basierten Tools und Frameworks
Visual Basic Properties und Property Sheets erscheinen
Release von Java JDK 1.0 und der JavaBeans Spezifikation
![Page 24: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/24.jpg)
JAX2014 Mut zur Fachlichkeit
Problemfelder
Anemic Domain Model !
‣ Besitzt „Domain Model“ hauptsächlich getter/setter, kaum Business Logik undfungiert als Attribute-Holder? !
‣ Sitzt die Business Logik in den Nutzern des „Domain Models“ und ruft dort getter/setter auf?
![Page 25: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/25.jpg)
JAX2014 Mut zur Fachlichkeit
Problemfelder
Null Value Handling !
‣ wird validiert? ‣ wann wird validiert? ‣ wie oft wird validiert? !
‣… und vor allem wo wird validiert? ‣… bitte nicht in den Use Cases!
![Page 26: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/26.jpg)
JAX2014 Mut zur Fachlichkeit
Problemfelder
Duplicated Code !
‣ Konvertierung von Parametern ‣ Validierung von Parametern ‣ Validierung von Rückgabewerten
![Page 27: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/27.jpg)
JAX2014 Mut zur Fachlichkeit
Problemfelder
Utils & Helper (und Manager und …) !
‣ Verlagerung des Problems ‣ Trennung von Fachlichkeit & Domain !
‣ Util Hell a.k.a. „Ach wir haben dafür ein Util?“ ‣ Code Duplication als Konsequenz
![Page 28: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/28.jpg)
JAX2014 Mut zur Fachlichkeit
Problemfelder
Non-Meaningful APIs !
‣ String & Friends Parameter Hölle ‣ fehlende Typsicherheit !
‣Methodennamen als Parameter-Deskriptor ‣Methodennamen als Refactoring-Pitfall
![Page 29: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/29.jpg)
JAX2014 Mut zur Fachlichkeit
Problemfelder
Fehlende Robustheit !
‣ Refactoring erhöht das Risiko für … ‣… Programmierfehler ‣… fehlerhafte API Methoden ‣… fehlerhafte API Dokumentation
![Page 30: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/30.jpg)
JAX2014 Mut zur Fachlichkeit
Problemfelder
Fehlende Robustheit !
‣ Teamwachstum / -fluktuation als Risiko ‣Wo finde ich was? ‣Was macht das? ‣Wo gehört das hin? !
‣ Copy & Paste Design Pattern!
![Page 31: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/31.jpg)
Mut zur FachlichkeitLösungsansätzeJAX
2014
![Page 32: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/32.jpg)
JAX2014
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.“
Mut zur FachlichkeitLösungsansätze
![Page 33: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/33.jpg)
JAX2014 Mut zur Fachlichkeit
Lösungsansätze
Anforderungen !
‣ sprechendes Modell ‣ sprechendes API !
‣ konsistent erzeugen ‣ konsistent erhalten
![Page 34: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/34.jpg)
JAX2014 Mut zur Fachlichkeit
Lösungsansätze
Rich Domain Model !
‣ inkl. Fachlichkeit ‣ inkl. Validierung ‣ inkl. Konvertierung ‣ inkl. Normalisierung ‣ inkl. Konsistenzprüfung
![Page 35: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/35.jpg)
JAX2014 Mut zur Fachlichkeit
Lösungsansätze
Refactoring Step by Step !
‣ Schritt 1: Value Objects ‣ Schritt 2: Builder Pattern ‣ Schritt 3: Framework Support
![Page 36: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/36.jpg)
JAX2014 Mut zur Fachlichkeit
Schritt 1: Value Objects
![Page 37: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/37.jpg)
JAX2014 Mut zur Fachlichkeit
Schritt 1: Value Objects
Value Objects Definition !
‣ Ein Value Object repräsentiert eine fachlich relevante Eigenschaft des Domain Models.
Wo ist da die Grenze?
![Page 38: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/38.jpg)
JAX2014 Mut zur Fachlichkeit
Schritt 1: Value Objects
Value Objects Definition !
‣ Ein Value Object repräsentiert eine fachlich relevante Eigenschaft des Domain Models.
![Page 39: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/39.jpg)
JAX2014 Mut zur Fachlichkeit
Schritt 1: Value Objects
Value Objects … !
‣ #1: sind Objekte und keine primitive ‣ #2: sind unveränderbar ‣ #3: konvertieren fachlich ‣ #4: normalisieren fachlich ‣ #5: validieren fachlich ‣ #6: sind vollwertig und vergleichbar !
![Page 40: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/40.jpg)
/** * #1: Value Objects sind Objekte */ public class Customer { ! private Date birthDate; ! private DateOfBirth birthDate; ! ... !) !/** * Represents a date of birth */ public class DateOfBirth { ! private Date dateOfBirth; ! public boolean hasBirthDay() { return ...; } ! public int getCurrentAge() { return ...; } }
Schritt 1: Value Objects
Fachlichkeit!
JAX2014 Mut zur Fachlichkeit
![Page 41: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/41.jpg)
/** * #2: Value Objects sind unveränderbar */ public class DateOfBirth { ! private Date dateOfBirth; public DateOfBirth(Date date) { // do some validation here and // throw IllegalArgumentException if fail ...; this.dateOfBirth = date; } public Date getDate() { return new Date(dateOfBirth.getTime()); } ! public boolean hasBirthDay() { return ...; } ! public int getCurrentAge() { return ...; } !}
Schritt 1: Value Objects
Immutable!
JAX2014 Mut zur Fachlichkeit
![Page 42: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/42.jpg)
/** * #3: Value Objects konvertieren fachlich */ public class DateOfBirth { ! private Date dateOfBirth; public DateOfBirth(Date date) { // do some validation here and // throw IllegalArgumentException if fail ...; this.dateOfBirth = date; } public DateOfBirth(String date) { // create date of birth from "date" string with default pattern ...; ! } public DateOfBirth(String date, String pattern) { // create date of birth from "date" string with "pattern" ...; } ! ... !}
Schritt 1: Value Objects
Konvertieren!
JAX2014 Mut zur Fachlichkeit
![Page 43: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/43.jpg)
/** * #4: Value Objects normalisieren fachlich */ public class DateOfBirth { ! private Date dateOfBirth; public DateOfBirth(Date date) { // do some validation here and // throw IllegalArgumentException if fail ...; this.dateOfBirth = copyAndStripTimeStamp(date); } private Date copyAndStripTimeStamp(Date date) { // strip timestamp and copy result in a new Date object return ...; ! } ... !}
Schritt 1: Value Objects
Normalisieren!
JAX2014 Mut zur Fachlichkeit
![Page 44: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/44.jpg)
/** * #4: Value Objects validieren fachlich */ public class DateOfBirth { ! private Date dateOfBirth; public DateOfBirth(Date date) { Date today = new Date(); if (date.after(today)) { throw new IllegalArgumentException("Birthday " + date + " may not be after current time " + today); } this.dateOfBirth = copyAndStripTimeStamp(date); } private Date copyAndStripTimeStamp(Date date) { // strip timestamp and copy result in a new Date object return ...; ! } ... !}
Schritt 1: Value Objects
Validieren!
JAX2014 Mut zur Fachlichkeit
![Page 45: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/45.jpg)
/** * #4: Value Objects sind vollwertig */ public class DateOfBirth implements Serializable, Comparable{ ! private Date dateOfBirth; ... ! @Override public String toString() { return ...; } ! @Override public int hashCode() { return ...; } ! @Override public boolean equals(Object obj) { return ...; } ! public int compareTo(Object o) { return ...; }}
Schritt 1: Value Objects
Full blown Object!
JAX2014 Mut zur Fachlichkeit
![Page 46: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/46.jpg)
JAX2014 Mut zur Fachlichkeit
Schritt 1: Value Objects
Value Objects Beispiele !
‣ FirstName, LastName, DateOfBirth ‣ ZipCode, City, Country ‣ Email, PhoneNumber ‣ Note, Description ‣ Year, Month, … !
‣Money, …
![Page 47: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/47.jpg)
JAX2014 Mut zur Fachlichkeit
Schritt 1: Value Objects
Value Objects Benefits !
‣ Fachlichkeit befindet sich direkt in der Domain ‣ Kein/kaum duplizierter Code !
‣ sprechender & konsistenter Code ‣ verbesserter Lesbarkeit & Wartbarkeit !
‣ Keine Util, Helper, Manager & Friends
![Page 48: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/48.jpg)
// Entity with Value Objects public class Customer { private FirstName firstName; private LastName lastName; private FamilyStatus familyStatus; private Address postalAddress; private HashMap<PhoneNumber> phoneNumbers; private HashMap<EmailAddress> emailAddresses; ... public void changePersonalName(FirstName newFirstName, LastName newLastName) { ... } public void relocatePostalAddress(Address changedPostalAddress) { ... } public void changeHomePhoneNumber(PhoneNumber changedHomePhoneNumber) { ... } public void disconnectHomePhone() { ...} public void changeMobilePhoneNumber(PhoneNumber changedHomePhoneNumber) { ... } public void disconnectMobilePhone() { ... } public void changePrimaryEmailAddress(EmailAddress newPrimaryEmailAddress) { ... } public void changeSecondaryEmailAddress(EmailAddress newSecondaryEmailAddress) { ... } ! public List<Email> findEmailsOf(EmailDomain emailDomain) { ... } ! public void marry(LastName newLastName) { lastName = newLastName familyStatus = FamilyStatus.MARRIED; } public boolean isMarried() { return (familyStatus == FamilyStatus.MARRIED); } }
Schritt 1: Value Objects JAX2014 Mut zur Fachlichkeit
![Page 49: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/49.jpg)
JAX2014 Mut zur Fachlichkeit
Schritt 2: Builder Pattern
![Page 50: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/50.jpg)
JAX2014 Mut zur Fachlichkeit
Schritt 2: Builder Pattern
Das kleine 1x1 des Builder Pattern !
‣ Object Creation Design Pattern ‣ Antwort auf das Constructor-Hell Anti-Pattern !
‣ Step-by-Step Ansatz ‣ Kandidat für Fluent-API
![Page 51: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/51.jpg)
// Builder Pattern - Poor Mans Edition public class Address { ! public Address(String street, String streetNumber, String zipCode, String city, String state, String country) { Validate.isTrue(StringUtils.isNotEmpty(streetNumber)); Validate.isTrue(StringUtils.isNotEmpty(zipCode)); Validate.isTrue(StringUtils.isNotEmpty(city)); Validate.isTrue(StringUtils.isNotEmpty(state)); Validate.isTrue(StringUtils.isNotEmpty(country)); ... } ! // value object is immutable // - no setter // - but getter ...; }
Schritt 2: Builder PatternJAX2014 Mut zur Fachlichkeit
Schön? Nee!
![Page 52: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/52.jpg)
// Builder Pattern - Simple Edition public class AddressBuilder { private Street street; private StreetNumber streetNumber; private ZipCode zipCode; private City city; private State state; private Country country; public Address build() { // validate single parameter and cross parameter constraints // and throw exception if any problem occurs ... // create valid Address object else return new Address(...); } public void setStreet(Street street) { this.street = street; } ! public void setStreetNumber(StreetNumber streetNumber) { this.streetNumber = streetNumber; } ! ... }
Schritt 2: Builder PatternJAX2014 Mut zur Fachlichkeit
Schöner? Naja!
![Page 53: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/53.jpg)
// Builder Pattern - Simple Edition IN ACTION !// 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();
Schritt 2: Builder PatternJAX2014 Mut zur Fachlichkeit
![Page 54: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/54.jpg)
// Builder Pattern - Extended Edition public class AddressBuilder { private Street street; private StreetNumber streetNumber; ... private AddressBuilder() { /* empty constructor to prohibit use */ } public static AddressBuilder newAddress() { return new AddressBuilder(); } public AddressBuilder forStreetNumber(StreetNumber aStreetNumber) { streetNumber = aStreetNumber; } public AddressBuilder ofStreet(Street aStreet) { street = aStreet; } public Address build() { // validate single parameter and cross parameter constraints // and throw exception if any problem occurs ... // create valid Address object else return new Address(...); } }
Schritt 2: Builder PatternJAX2014 Mut zur Fachlichkeit
Schöner? Ja!
![Page 55: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/55.jpg)
// Builder Pattern - Extended Edition IN ACTION !// create AddressBuilder AddressBuilder builder = newAddress() ! // set values .forStreetNumber(...).ofStreet(...) .inCity(...).withZipCode(...) .lyingInState(...).ofCountry(...) ! // build Address object .build(...);
Schritt 2: Builder PatternJAX2014 Mut zur Fachlichkeit
![Page 56: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/56.jpg)
// Builder Pattern - Extended Edition with Inner Class Builder public class Address { ! public static Builder newAddress() { return new Address().new Builder(); } ! private String street; ! public class Builder { ! public Builder ofStreet(String initialStreet) { street = validateStreet(initialStreet); return this; } ! public Address build() { validate(); return Address.this; } } }
Schritt 2: Builder PatternJAX2014 Mut zur Fachlichkeit
![Page 57: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/57.jpg)
JAX2014 Mut zur Fachlichkeit
Schritt 3: Framework Support
![Page 58: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/58.jpg)
JAX2014 Mut zur Fachlichkeit
Schritt 3: Framework Support
JSF?Access Layer
Business Layer
DB Layer JPA?
jUnit?
![Page 59: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/59.jpg)
JAX2014 Mut zur Fachlichkeit
Value Objects & JPA !
‣ Value Objects und Mapping ‣ Binding via @Embeddable / @Embedded ‣ Spaltendef. via @Column / @AttributeOverride ‣ Value Objects und JPA-QL ‣ Navigation bis zu primitiven Eigenschaften ‣ Value Objects und ResultSet ‣ via ScalarQueries
Schritt 3: Framework Support
![Page 60: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/60.jpg)
/** * Embeddable date of birth for (re)use in value objects */ @Embeddable public class DateOfBirth { ! @Column(name=“BIRTHDATE“) // use this or … private Date dateOfBirth; ! ... } !!/** * Customer entity making use of date of birth embeddable */ @Entity public class Customer { ! @Embedded @AttributeOverride(name=„dateOfBirth", // … this column=@Column(name=“CUST_BIRTHDATE“)) // … or both private DateOfBirth dateOfBirth; ! ... }
JAX2014 Mut zur Fachlichkeit
Schritt 3: Framework Support
![Page 61: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/61.jpg)
JAX2014 Mut zur Fachlichkeit
Value Objects & JPA !
‣ Value Objects und JPA-QL ‣ Navigation bis zu Value Objects ‣ Navigation bis zu primitiven Eigenschaften
Schritt 3: Framework Support
![Page 62: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/62.jpg)
/** * 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; ! ... !}
JAX2014 Mut zur Fachlichkeit
Schritt 3: Framework Support
![Page 63: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/63.jpg)
JAX2014 Mut zur Fachlichkeit
Value Objects & JPA !
‣ Value Objects und ResultSet ‣ via ScalarQueries
Schritt 3: Framework Support
![Page 64: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/64.jpg)
/** * Examples for ResultSets and ValueObjects (via ScalarQueries) */ public FullNameWithAddress findFullNameWithAddress(Email uniqueEmail) { TypedQuery<Object[]> query = em.createQuery( "SELECT c.name, c.address from Customer c "‚ + "WHERE u.email.value = :emailString"‚ Object[].class); query.setParameter("emailString", uniqueEmail.getAddress()); ! Object[] result = query.getSingleResult(); FullName fullName = (FullName) result[0]; Address address = (Address) result[1]; return new FullNameWithAddress(fullName, address); } !public List<FullNameWithAddress> findFullNamesWithAddress() { ! TypedQuery<FullNameWithAddress> query = em.createQuery( "SELECT " + " new de.openknowlede.FullNameWithAddress(c.name, c.address) " + " from Customer c", FullNameWithAddress.class ); return query.getResultList(); }
JAX2014 Mut zur Fachlichkeit
Schritt 3: Framework Support
![Page 65: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/65.jpg)
JAX2014 Mut zur Fachlichkeit
Value Objects & JSF !
‣ Binding von Value Objects ‣ direkte Unterstützung durch U-EL ‣ Konvertierung von Value Objects ‣ via JSF Converter ‣ Validierung von Value Objects ‣ via JSF Validator
Schritt 3: Framework Support
![Page 66: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/66.jpg)
/** 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; } ... }
JAX2014 Mut zur Fachlichkeit
Schritt 3: Framework Support
![Page 67: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/67.jpg)
<!-- Value Object binding in JSF xhtml page via Unified Expression Language & JSF Faces Converter --> !<!-- using JSF converter for Value Object of type ZipCode --> <h:outputText value=“#{customerController.zipCode}“ /> !<h:outputText value=“#{customerController.zipCode}“ > <f:converter converterId=“de.openknowledge.jsf.converter.ZipCodeConverter“ </h:outputText> !!<!-- using JSF converter for Value Object of type DateOfBirth --> <h:outputText value=“#{customerController.dateOfBirth}“ /> !<h:outputText value=“#{customerController.dateOfBirth}“ > <f:converter converterId=“de.openknowledge.jsf.converter.DateOfBirthConverter“ </h:outputText> !<!-- using JSF default converter for Date & Time objects --> <h:outputText value=“customerController.dateOfBirth.date“ > <f:convertDateTime locale=“DE“ dateStyle=“short“/> </h:outputText>
JAX2014 Mut zur Fachlichkeit
Schritt 3: Framework Support
![Page 68: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/68.jpg)
@FacesConverter(forClass = DateOfBirth.class, value = "de.openknowledge.jsf.converter.DateOfBirthConverter") public class DateOfBirthConverter implements Converter { // convert String input into Value Object @Override public Object getAsObject(FacesContext context, UIComponent component, String value) { if (value == null) { return null; } return new DateOfBirth(value); } // convert Value Object into String @Override public String getAsString(FacesContext context, UIComponent component, Object value) { String string = null; // power point programming - not bullet proofed! if (value!=null) { string = value.toString(); } return string; } }
JAX2014 Mut zur Fachlichkeit
Schritt 3: Framework Support
![Page 69: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/69.jpg)
Mut zur FachlichkeitKritiker zu WortJAX
2014
![Page 70: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/70.jpg)
JAX2014 Mut zur Fachlichkeit
Kritiker zu Wort
Das soll funktionieren? Das … !
‣… ist doch viel zu langsam! ‣… sind doch viel zu viele Klassen! ‣… ist doch viel zu aufwendig!
![Page 71: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/71.jpg)
JAX2014 Mut zur Fachlichkeit
Kritiker zu Wort
Das ist doch viel zu langsam! !
‣ Java Objekterzeugung ist nicht mehr teuer ‣ Immutability unterstützt Garbage Collection ‣ Immutability unterstützt Inlining
![Page 72: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/72.jpg)
JAX2014 Mut zur Fachlichkeit
Kritiker zu Wort
Das sind doch viel zu viele Klassen! !
‣ Domain Model erfordert mehr Vorarbeit ‣ Speedup kommt später im Projekt !
‣ deutlich bessere Verständnis für die Domain ‣ deutlich bessere Entwicklungsperformance !
‣ Basisklassen helfen
![Page 73: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/73.jpg)
/** * Abstract value object as a common base for all single value * value objects. */ 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 ...; } }
Kritiker zu WortJAX2014 Mut zur Fachlichkeit
![Page 74: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/74.jpg)
/** * 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(); } !}
Kritiker zu WortJAX2014 Mut zur Fachlichkeit
![Page 75: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/75.jpg)
JAX2014 Mut zur Fachlichkeit
Kritiker zu Wort
Das ist doch in der Nutzung viel zu aufwendig! !
‣ komplexe Konstruktoren, da Typen statt „String“ ‣ komplexe API aufrufe, da Typen statt „String“!// Vorher Customer customer = new Customer(“Max“,“Mustermann“); !// Nacher Customer customer = new Customer(new FirstName(“Max“), new SureName(“Mustermann“);
![Page 76: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/76.jpg)
JAX2014 Mut zur Fachlichkeit
Kritiker zu Wort
Das ist doch viel zu aufwendig! !
‣ Problemfeld „Konstruktoren“ ‣ Builder Pattern ‣ Problemfeld „Systemgrenzen“ ‣ Frameworks entschärfen das Problem ‣ Problem „Unit Test“ ‣ zentralisierte Erzeugung von Testdaten
![Page 77: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/77.jpg)
Mut zur FachlichkeitFazitJAX
2014
![Page 78: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/78.jpg)
JAX2014
!!
„The Design is the Code, the Code is the Design.“
Mut zur FachlichkeitFazit
![Page 79: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/79.jpg)
JAX2014
„Muss ich denn jedes Mal den Code ändern, wenn
sich die Fachlichkeit ändert?“
Mut zur FachlichkeitFazit
![Page 80: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/80.jpg)
JAX2014
„Zur Hölle, ja! !
Wann denn bitte sonst?“
Mut zur FachlichkeitFazit
![Page 81: Mut zur Fachlichkeit](https://reader037.vdocuments.mx/reader037/viewer/2022100220/556120c5d8b42a98508b4bf2/html5/thumbnails/81.jpg)
@mobileLarson @_openKnowledge
Lars Röwekamp | CIO New Technologies
Mut zur Fachlichkeit
lohnt sich!