Slide 1

Slide 1 text

Work harder not smarter

Slide 2

Slide 2 text

me Gerrit Meier Staff Software Engineer @ Neo4j

Slide 3

Slide 3 text

Why? How am I supposed to work even harder?

Slide 4

Slide 4 text

Why? How am I supposed to work even harder? !Most examples are over-simplified!

Slide 5

Slide 5 text

User Movie Actor Rating

Slide 6

Slide 6 text

User Rating Movie Actor uuid createdAt / updatedAt / etc. name dob …. uuid createdAt / updatedAt / etc. title stars …. uuid createdAt / updatedAt / etc. title plot …. uuid createdAt / updatedAt / etc. name dob ….

Slide 7

Slide 7 text

User Rating Movie Actor uuid createdAt / updatedAt / etc. name dob …. uuid createdAt / updatedAt / etc. title stars …. uuid createdAt / updatedAt / etc. title plot …. uuid createdAt / updatedAt / etc. name dob ….

Slide 8

Slide 8 text

Inheritance

Slide 9

Slide 9 text

Inheritance User Rating Movie Actor name dob …. title stars …. title plot …. name dob …. Entity uuid createdAt / updatedAt / etc.

Slide 10

Slide 10 text

Inheritance User Rating Movie Actor name dob …. title stars …. title plot …. name dob …. Entity uuid createdAt / updatedAt / etc.

Slide 11

Slide 11 text

Inheritance User Rating Movie Actor name dob …. title stars …. title plot …. …. Entity …. Person uuid

Slide 12

Slide 12 text

Inheritance User Rating Movie Actor name dob …. title stars …. title plot …. …. Entity …. Person uuid

Slide 13

Slide 13 text

Inheritance Entity User Movie Rating Person Actor

Slide 14

Slide 14 text

Inheritance Entity User Movie Rating Person Actor

Slide 15

Slide 15 text

Inheritance Entity User Movie Rating Person Actor

Slide 16

Slide 16 text

Inheritance Entity User Movie Rating Person Actor

Slide 17

Slide 17 text

Inheritance Entity User Movie Rating Person Actor

Slide 18

Slide 18 text

Inheritance Entity User Movie Rating Person Actor

Slide 19

Slide 19 text

Actor Entity uuid createdAt title actors Movie

Slide 20

Slide 20 text

Lombok Actor @ToString class Movie Entity uuid createdAt title actors Movie

Slide 21

Slide 21 text

Lombok Actor @ToString class Movie Entity uuid createdAt title actors Movie Movie(title=The Matrix, actors=[Actor(internationalActive=true)])

Slide 22

Slide 22 text

Lombok Actor @ToString(callSuper = true) class Movie Entity uuid createdAt title actors Movie Movie(super= Entity(uuid=c1e3c57e-...-b73147a13bfa, createdAt=2023-09-05T10:26:31.305), title=The Matrix, actors=[Actor(dob=1982-03-14,name=Your next Superstar,internationalActive=true,...)])

Slide 23

Slide 23 text

User Movie Actor Rating

Slide 24

Slide 24 text

User Movie Actor Rating

Slide 25

Slide 25 text

Lombok Actor @ToString(callSuper = true) class Movie Entity uuid createdAt title actors Movie Exception in thread "main" java.lang.StackOverflowError at java.lang.AbstractStringBuilder.append(AbstractStringBuilde r.java:449) at java.lang.StringBuilder.append(StringBuilder.java:141) at com.example.domain.Entity.toString(Entity.java:11) at com.example.domain.Movie.toString(Movie.java:11) at java.lang.String.valueOf(String.java:2994) at java.lang.StringBuilder.append(StringBuilder.java:136) at java.util.AbstractCollection.toString(AbstractCollection.ja va:462) at java.lang.String.valueOf(String.java:2994) at

Slide 26

Slide 26 text

Entity User Movie Rating Person Actor

Slide 27

Slide 27 text

Lombok Jackson Mapping

Slide 28

Slide 28 text

Jackson Actor new ObjectMapper() .writeValueAsString(movie) Entity uuid createdAt title actors Movie Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: java.util.ArrayList[0]->com.example.domain.Movie["actors"]- >java.util.ArrayList[0]->com.example.domain.Actor["movies"] ->java.util.ArrayList[0]->com.example.domain.Movie["actors" ]->java.util.ArrayList[0]->com.example.domain.Actor["movies "]->java.util.ArrayList[0]->com.example.domain.Movie["actor s"]->java.util.ArrayList[0]->com.example.domain.Actor["movi es"]->java.util.ArrayList[0]->com.example.domain.Movie["act ors"]->java.util.ArrayList[0]->com.example.domain.Actor["mo vies"]->java.util.ArrayList[0]->com.example.domain.Movie["a ctors"]->java.util.ArrayList[0]->com.example.domain.Actor[" movies"]->java.util.ArrayList[0]->com.example.domain.Movie[ "actors"]->java.util.ArrayList[0]->com.example.domain.Actor

Slide 29

Slide 29 text

Jackson Actor class Actor { @JsonIgnore public List movies; } Entity uuid createdAt title actors Movie {"uuid":"xxxx", "createdAt":[2023,9,5,11,0,58,264000000], "title":"The Matrix", "actors":[{"uuid":"yyyy", "createdAt":[2023,9,5,11,0,58,265000000], "name":"Your next Superstar", "dob":"1982-03-14", "internationalActive":true} ] }

Slide 30

Slide 30 text

Jackson Actor class Actor { @JsonIgnoreProperties("actors") public List movies; } Entity uuid createdAt title actors Movie {"uuid":"xxxx", "createdAt":[2023,9,5,11,2,8,999000000], "title":"The Matrix", "actors":[{"uuid":"yyyy", "createdAt":[2023,9,5,11,2,9,1000000], "name":"Your next Superstar", "dob":"1982-03-14", "internationalActive":true, "movies":[{"uuid":"xxxx", "createdAt":[2023,9,5,11,2,8,999000000], "title":"The Matrix"} ] } ] }

Slide 31

Slide 31 text

User Movie Actor Rating

Slide 32

Slide 32 text

Data loading (e.g. JPA) User data

Slide 33

Slide 33 text

Data loading (e.g. JPA) User data Rating data and Movie data OneToMany Ratings

Slide 34

Slide 34 text

Data loading (e.g. JPA) User data Rating data Movie data OneToMany(fetch = FetchType.EAGER) Ratings

Slide 35

Slide 35 text

Data loading (e.g. JPA) User data Rating data Movie data OneToMany Ratings @Entity @NamedEntityGraph(name = "User.ratings", attributeNodes = @NamedAttributeNode("ratings") ) public class User { //... }

Slide 36

Slide 36 text

Data loading (e.g. JPA) User data Rating data Movie data OneToMany Ratings @Entity @NamedEntityGraph(name = "User.ratings", attributeNodes = @NamedAttributeNode("ratings") ) public class User { //... } @Repository public interface UserRepository extends JpaRepository { @EntityGraph(value = "User.ratings") User findEagerById(String id); }

Slide 37

Slide 37 text

Data loading (e.g. JPA) User data Rating data Movie data OneToMany Ratings @Repository public interface UserRepository extends JpaRepository { @EntityGraph(attributePaths = {"ratings"}) User findEagerById(String id); }

Slide 38

Slide 38 text

Data loading ● Model your domain to cover all data needed ● Read and understand the specifications of your persistence mapper ● Use built-in mechanisms to load the data for your use-case ● Don’t try to work against the mapper library ○ Use lower abstractions or drivers

Slide 39

Slide 39 text

Writing readable code public List getValue(Movie m) { String x = "|"; return m.getRelated().stream() .map(a -> { String v1 = a.getValue1(); String v2 = a.getValue2(); return v1 + x + v2; }) .collect(Collectors.toList()); }

Slide 40

Slide 40 text

Writing readable code public List getValue(Movie movie) { String fieldSeparator = "|"; return movie.getActors().stream() .map(actor -> { String actorName = actor.getName(); String actorDob = actor.getDob(); return actorName + fieldSeparator + actorDob; }) .collect(Collectors.toList()); }

Slide 41

Slide 41 text

Writing readable code: Be explicit public void setTimeout(int timeout);

Slide 42

Slide 42 text

Writing readable code: Be explicit public void setTimeout(int timeout[In]Seconds);

Slide 43

Slide 43 text

Writing readable code: Avoid Utils-classes public class DomainUtils { public static Movie createMovieWithDefaults() { return new Movie( UUID.randomUUID().toString(), "", LocalDateTime.now()); } public static List top5Movies(List movies) { return movies.stream() .sorted((movie1, movie2) -> movie2.getAverageRating().compareTo(movie1.getAverageRating())) .limit(5) .collect(Collectors.toList()); } }

Slide 44

Slide 44 text

Writing readable code: Avoid Utils-classes public class Movie { public static Movie createDefault() { return new Movie( UUID.randomUUID().toString(), "", LocalDateTime.now()); } }

Slide 45

Slide 45 text

Writing readable code: Avoid Utils-classes public class Movies { public static List top5Movies(List movies) { return movies.stream() .sorted((movie1, movie2) -> movie2.getAverageRating().compareTo(movie1.getAverageRating())) .limit(5) .collect(Collectors.toList()); } }

Slide 46

Slide 46 text

Writing readable code: Nesting / Extraction public void update(Movie movie) throws Exception { if (!movie.hasMetadata()) { HttpResponse httpResponse = HttpClientBuilder.create().build().execute(new HttpGet("METADATA_URL")); switch (httpResponse.getStatusLine().getStatusCode()) { case 200: BufferedReader responseReader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent())); String response = responseReader.lines().collect(Collectors.joining()); // movie.set... // default } } if (!movie.hasImage()) { HttpResponse httpResponse = HttpClientBuilder.create().build().execute(new HttpGet("IMAGE_URL")); switch (httpResponse.getStatusLine().getStatusCode()) { case 200: BufferedReader responseReader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent())); String response = responseReader.lines().collect(Collectors.joining()); // movie.setImage(...) // default } }

Slide 47

Slide 47 text

public void update(Movie movie) throws Exception { if (!movie.hasMetadata()) { updateMetadata(); } if (!movie.hasImage()) { updateImage(); } } Writing readable code: Nesting / Extraction

Slide 48

Slide 48 text

Writing readable code: Inversion public String getOldestActor(Movie movie) { String oldestActorName; List actors = movie.getActors(); if (actors != null) { Actor oldestActor = actors.stream() .sorted(Comparator.comparing(Person::getDob)) .findFirst().get(); oldestActorName = oldestActor.getName(); } else { oldestActorName = ""; } return oldestActorName; }

Slide 49

Slide 49 text

Writing readable code: Inversion public String getOldestActor(Movie movie) { List actors = movie.getActors(); if (actors == null) { return ""; } Actor oldestActor = actors.stream() .sorted(Comparator.comparing(Person::getDob)) .findFirst().get(); return oldestActor.getName(); }

Slide 50

Slide 50 text

Meta

Slide 51

Slide 51 text

Have friendly exception messages ● Answer some questions ○ How did “we” get here? ○ How can “we” mitigate the situation? ■ Documentation/GH-Issues ● Be empathetic ● You can still be technical ○ What information is needed to support the customer ● Don’t be too verbose ● NEVER throw “expected” exceptions

Slide 52

Slide 52 text

Create a good documentation ● Have a dedicated technical writer ○ Implicit testing of your application and the documentation state ● Give the documentation to new team members ○ Helps with onboarding and also shows lacks in the documentation ● (if possible) share link to the open source repository ○ Problems/misunderstandings can be filed as issues ○ Customers and users can create PRs

Slide 53

Slide 53 text

Control and communicate your architecture ● ArchUnit ● API Guardian @API(status = API.Status.STABLE/INTERNAL) ● jQAssistant

Slide 54

Slide 54 text

Yes, you can use Optional

Slide 55

Slide 55 text

Yes, you can use Optional, If you are not doing real time big data processing

Slide 56

Slide 56 text

RTFM

Slide 57

Slide 57 text

No seriously, RTFM again

Slide 58

Slide 58 text

RTFM again

Slide 59

Slide 59 text

Thanks