Thoughts about architecture

Selecting the right stuff for each slice of your cake
September 23, 2015 by Michael

Most people slice their cakes like this:


14962767_53ec6ef41e_o

Image by Elaine Ashton

and in most cases not horizontally but still many developers, like i did in the past, slice their packages that way.

Really, just slapping classes into packages named “Model”, “View” and “Controller” doesn’t implement that pattern. @jensschauder has written much more eloquent than i about this here (Jens does also a pretty good talk about that topic and has some really nice drawings in it as well, if you should have the opportunity, check it out) and @olivergierke has taken it further here. Take your time, read both posts. Its worth it. Rethinking my own organization of code the last years helped me writing better code. Looking at a recent project that isn’t divided into libraries yet, i could easily rip those modules apart and deploy them separately.

So, why am i writing this, when so much has already been written by smarter people than i?

The last weeks i’ve been working on a new frontend for an old but really not outdated project that handles a lot of time series, prices and tenders, all in a multi tenant fashion. The database model is really complex but not complicated and is there to stay. The current codebase does many things right in the database (stored PL/SQL procedures) and that won’t change much.

In the course of the last 5 to 8 years I’ve learned so much about Hibernate and got to love the stuff that the Spring Data team is doing on Spring Data JPA and i can say that i really come far, using HQL or now JPQL and also the criteria query api (together with the static meta model) that nobody else seem to like. For example, using semi-joins to determine if stuff is active or not:

public static Specification<Projekt> isAktiv() {
	return (root, query, b) -> {	    
	    final Subquery<String> outerSubquery = query.subquery(String.class);
	    final Root<Projektversion> outerSubqueryRoot = outerSubquery.from(Projektversion.class);
	    final Join<Projektversion, LieferangebotEntity> joinLieferangebot = outerSubqueryRoot.join(lieferangebot);
 
	    final Subquery<String> innerSubquery = query.subquery(String.class);
	    final Root<Projektversion> innerSubqueryRoot = innerSubquery.from(Projektversion.class);
 
	    return b.exists(
		outerSubquery
		    .select(b.literal(""))
		    .where(b.and(
			    b.equal(outerSubqueryRoot.get(projekt), root),
			    b.isNotNull(joinLieferangebot.get(vertragsabschlussdatum))),
			    b.not(b.exists(
				    innerSubquery
					.select(b.literal(""))
					.where(b.and(
						b.equal(innerSubqueryRoot.get(projekt), outerSubqueryRoot.get(projekt)),
						b.greaterThan(innerSubqueryRoot.get(versionsdatum), outerSubqueryRoot.get(versionsdatum))
					))
			    ))
		    )			  		    
	    );	    
	};
    }

Using this with Spring Data Repositories and specification makes JPA actually fun. But with jOOQ i can write it down like i would in SQL:

private static final Condition IS_ACTIVE_CONDITION = 
	exists(
	    select(val(""))
	    .from(outer)
		.join(LIEFERANGEBOTE)
		    .on(LIEFERANGEBOTE.LIEFERANGEBOTS_ID.eq(outer.LIEFERANGEBOTS_ID))
	    .where(
		    outer.PROJEKT_ID.eq(p.ID)
		.and(LIEFERANGEBOTE.ABSCHLUSSDATUM.isNotNull())
		.and(not(exists(
		    select(val(""))
		    .from(inner)
		    .where(
			    inner.PROJEKT_ID.eq(outer.PROJEKT_ID)
			.and(inner.VERSIONSDATUM.gt(outer.VERSIONSDATUM))
		    )
		)))
	    )
	);

Lukas promotes jOOQ for that kind of usage very well. But i say, it’s the simple things. I cannot only write elaborate queries, I can also write down what i want to select. jOOQ doesn’t try to be a mapping from a relational world into the slices of my application, it just maps tables and their columns 1:1. It’s up to me what i select. I could achieve this with native or JPQL queries as shown here, but than what’s the point of mapping all those entities anyway (to be honest, i’ve already done this on several occasions)? Another solution would be the new entity graphs but than i end up with either half-empty entities or getting nice surprises from lazy loaded associations.

What every JPA solution has in common, at least to me, is the fact that one ends up with one big package containing pretty much every entity there is. To create complete mappings from the relational into the object oriented world those entities depend on each other and i cannot slice it the way the application works.

You might say that this persistence package is analogue to the generated jOOQ tables and records, but i think they are quite different. The generated tables and records are mere means of accessing the same thing in the database, not more but also not less. Building a full fledged mapping is a lot more and implicates a lot more.

Not being forced to put effort into defining a logical and accurate class hierarchy to work with JPA but instead modeling and filling DTOs and business objects right from the database in a way that fits architectural slices of an application gives back a lot of freedom for writing cleaner and easier to understand applications.

7 comments

  1. thomasd wrote:

    Nice post 🙂

    Quick remark – you can also use query method specific fetch graphs with Spring Data JPA and it’s “new” @EntityGraph annotation. It allows to refer to a fetch-graph specified by a JPA @NamedEntityGraph on your entity class or it can even dynamically generate a Fetch Graph based on the fetch attributes specified via the “attributePaths” attribute in the @EntityGraph annotation.
    An Example for this can be found here:
    https://github.com/spring-projects/spring-data-examples/pull/126

    Regarding customizing the query projection – we have something in the works for this:
    https://jira.spring.io/browse/DATAJPA-804

    Posted on September 23, 2015 at 5:16 PM | Permalink
  2. Michael wrote:

    Hi Thomas,
    thanks for stopping by, much appreciated.

    Regarding your links: We’re using already NamedEntityGraphs and also the fact that they are neatly supported by Spring Data 🙂

    DATAJPA-804 looks very promising as a solution for the problem with bad “surprises” (null fields, lazy collections etc. in standard entity classes).

    I hope my post made it clear that don’t want to bash JPA and or Hibernate. I use them on several projects and they work fine. Furthermore, i really enjoy having Hibernate Search around. Thats so great to use, wouldn’t want to do it manually.

    But on the other hand, those statements above are real world problems of mine and that stuff doesn’t fit into the ORM constraints.
    I tend to ran into stuff like HHH-8632, HHH-8886 (None of which are even commented on. Partly i can understand that, because those are not average use cases).

    Have a great evening.

    Posted on September 23, 2015 at 7:21 PM | Permalink
  3. thomasd wrote:

    Sure I got your point – your feedback is very welcome 🙂

    Wish you a nice evening as well 🙂

    Posted on September 23, 2015 at 7:26 PM | Permalink
  4. Lukas Eder wrote:

    Coincidentally, there has just been a very similar article by Petri Kainulainen, which also claims that entities are used too often out of convenience:

    http://blog.techdev.de/top-5-p.....plications

    Posted on September 27, 2015 at 2:37 PM | Permalink
  5. Michael wrote:

    Hi Lukas,

    thanks for stopping by! Thanks for the link, yes, that goes exactly the same direction.

    I just noticed that i had written before JPA and SQL… 3 years ago: http://info.michael-simons.eu/.....plain-sql/

    Posted on September 27, 2015 at 7:08 PM | Permalink
  6. Lukas Eder wrote:

    Nice conclusion: “And the price? As soon as i have written this post i forget how this stuff actually works.” 🙂

    Posted on September 28, 2015 at 8:47 AM | Permalink
  7. Michael wrote:

    You can quote me on that.

    Posted on September 28, 2015 at 8:48 AM | Permalink
4 Trackbacks/Pingbacks
  1. […] While JPA offers JPQL and Criteria API, which will help you express some amount of complexity in your queries, you will eventually be limited by the features offered in those languages and APIs, as Michael Simons has recently documented in an interesting Criteria API to jOOQ comparison. […]

  2. […] While JPA offers JPQL and Criteria API, which will help you express some amount of complexity in your queries, you will eventually be limited by the features offered in those languages and APIs, as Michael Simons has recently documented in an interesting Criteria API to jOOQ comparison. […]

  3. […] While JPA offers JPQL and Criteria API, which will help you express some amount of complexity in your queries, you will eventually be limited by the features offered in those languages and APIs, as Michael Simons has recently documented in an interesting Criteria API to jOOQ comparison. […]

  4. […] adding them and writing something useful I was happy that I chose good slices that fit exactly my building […]

Post a Comment

Your email is never published nor shared. Required fields are marked *