business logic in jpa entities

1,143 views
Skip to first unread message

Sebastian Trueman

unread,
Nov 18, 2014, 10:43:45 AM11/18/14
to clean-code...@googlegroups.com
At the moment I'm thinking about an known problem. It's about putting business logic into jpa entities or not. There are 2 ways to handle relating domain object logic:

1. put the logic into jpa entities. 
If I choose this way I feel uncomfortable in different ways. At first I commit to a jpa solution. So I can't easily unplug jpa but I think its still ok. The second pain is mixing different areas of responsibility. One part of it is the persistence unit, that is responsible for storing data to the persistent storage with untouched clear domain logic. I think I'll profit of writing less code if I put all the strong related logic in the jpa entities and the further related logic in some interactors / usecase classes.

2. put the logic into pure domain logic entities
It feels more correct if I would put all the logic into separate entities. But it feels like doing some bad things with such a great ORM framework like hibernate. I also need to pipeline the entities to the jpa framework. I definitely have to write more code resulting in adding more complexity. The profit is a good separation of irresponsibles. 

Maybe you can give me some more pro and cons, maybe with some storys :). I also still know the statement of Martin Fowler , who call variant 2 an anemic domain model. 

br

Sebastian Trueman

unread,
Nov 18, 2014, 10:46:24 AM11/18/14
to clean-code...@googlegroups.com
To all Uncle bob fans: If you know what R. J. Martins suggests, feel free to tell me the truth :D.

Sebastian Gozin

unread,
Nov 19, 2014, 4:42:22 AM11/19/14
to clean-code...@googlegroups.com
You can subclass the entity and put the JPA annotations on that instead while keeping the business logic in the parent.
This is not always practical though so then I tend to fall back to option 2 or instead use the JPA annotated class as a data structure being passed to a function like object.

Sebastian Gozin

unread,
Nov 19, 2014, 4:44:10 AM11/19/14
to clean-code...@googlegroups.com
I would have a lot less issues with JPA if those annotations didn't leak SQL.
Basically, if it was a true persistence abstraction instead of a persistence abstraction for SQL vendors.

Böszörményi Péter

unread,
Nov 19, 2014, 12:22:09 PM11/19/14
to clean-code...@googlegroups.com

Well, I always say, be pragmatic. The JPA gives all the neccesary abstraction, there is no need another layer that just copies data, and delegates method calls. Just put the proper logic into the JPA entites. If the JPA annotations really annoy you, then you still can put the mapping into xml files.
I can recommend you to read the Real World Java EE Patterns from Adam Bien.

--
The only way to go fast is to go well.
---
You received this message because you are subscribed to the Google Groups "Clean Code Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clean-code-discu...@googlegroups.com.
To post to this group, send email to clean-code...@googlegroups.com.
Visit this group at http://groups.google.com/group/clean-code-discussion.

Caio Fernando Bertoldi Paes de Andrade

unread,
Nov 19, 2014, 12:56:25 PM11/19/14
to clean-code...@googlegroups.com
Well, I always say, be pragmatic: TDD gives you all the necessary decoupling, there’s no need to choose JPA before you build your business logic. Just build your entities first and your persistence mechanism afterwards, your logic will automatically be decoupled from your persistence. If subclassing your entities for persistence really annoys you, then you still can marshall fields manually into your gateway classes.
I can recommend you to read all books from Uncle Bob. ;-)

Caio

P.S.: Böszörményi, sorry for copying your email’s structure, but I found it just too funny to resist. :-P

Böszörményi Péter

unread,
Nov 19, 2014, 2:24:19 PM11/19/14
to clean-code...@googlegroups.com

Hey, I like this answer. I like this kind of attitude. :) Right now, I'm not in the position to give a proper answer, but I hope the weekend will be more relaxed and then we can discuss this further.

P.S.: You can use my first name, Böszörményi is my family name.

Caio Fernando Bertoldi Paes de Andrade

unread,
Nov 19, 2014, 2:40:32 PM11/19/14
to clean-code...@googlegroups.com
Sure, I look forward to hearing what others have to say too.

Caio

P.S.: Sorry about that, Péter. Thanks for the clarification.

Sebastian Gozin

unread,
Nov 20, 2014, 4:27:40 AM11/20/14
to clean-code...@googlegroups.com, caio...@icloud.com
Same.
I admit subclassing to hide annotations irks me a little as well same as putting those annotations on the actual entity. I just err on the former rather than the latter.

I've also worked with other frameworks which do not use annotations but do allow some degree of subclassing (Grails/GORM) but it can be really tedious sometimes to use well within the rest of the framework.
I'm not sure but I'm strangely looking forward to Uncle Bob's upcoming "let's write a compiler" episode as I have this idea floating in my head I could use that to help with situations like this.
To unsubscribe from this group and stop receiving emails from it, send an email to clean-code-discussion+unsub...@googlegroups.com.

To post to this group, send email to clean-code...@googlegroups.com.
Visit this group at http://groups.google.com/group/clean-code-discussion.

--
The only way to go fast is to go well.
---
You received this message because you are subscribed to the Google Groups "Clean Code Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clean-code-discussion+unsub...@googlegroups.com.

To post to this group, send email to clean-code...@googlegroups.com.
Visit this group at http://groups.google.com/group/clean-code-discussion.

--
The only way to go fast is to go well.
---
You received this message because you are subscribed to the Google Groups "Clean Code Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clean-code-discussion+unsub...@googlegroups.com.

To post to this group, send email to clean-code...@googlegroups.com.
Visit this group at http://groups.google.com/group/clean-code-discussion.

--
The only way to go fast is to go well.
---
You received this message because you are subscribed to the Google Groups "Clean Code Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clean-code-discussion+unsub...@googlegroups.com.

James Green

unread,
Nov 20, 2014, 7:12:56 AM11/20/14
to clean-code...@googlegroups.com
I'm afraid I take the hybrid approach.

Sub-class your domain entities that have your business methods with classes that have the JPA/Spring-Data/other annotations for a framework chosen by the "master" application.

I do not bother "pipelining" the entities into any JPA framework, they exist has object instances which to my application have no frameworks attached. I've not yet uncovered a real-world problem with this approach but that may simply be nativity. If I come across one I'll better understand the problem but right now it's doesn't exist as a mental model.

One can easily view the persistence framework as the part implementing the gateway between application and persistence technology. That's not unclean provided your persistence framework is fed your run-time subclasses that inherit from the domain entities.


--
The only way to go fast is to go well.
---
You received this message because you are subscribed to the Google Groups "Clean Code Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clean-code-discu...@googlegroups.com.

Böszörményi Péter

unread,
Nov 23, 2014, 9:42:22 AM11/23/14
to clean-code...@googlegroups.com
Let's say we are writing the order process of an online store. We have a
bunch of domain entities: product, discount, order, order item. These
entities have state (price, type of discount, etc), and behavior
(product can calculate its discount price, with the help of the
discount, order can calculate the grant total, etc).

The save is done by an OrderRepository. This is the gateway in the clean
architecture.

So, we have a bunch of domain object to persist, and it's time to create
an OrderRepository implementation.

First, we choose the technology for the order persistence. Of course, we
choose relational database, because of:
- Most of the developer familiar with it.
- There is plenty of know-how on the internet.
- The relational database is a proven technology.
- Most of the time a database can handle the given load.

In java, we have two possibilities to use a database: JDBC and JPA.

The JDBC implementation of the OrderRepository is straightforward: a
handful of prepared sql statements, and the JDBC API.
Advantage:
- Our business entities are independent from the underlying database
tables, we can change our database structure without affecting the
business entities.
Disadvantage:
- Requires a lot of code that map the business entities to the database
and vice versa. This is cumbersome and error prone.

In case of JPA, we have two options again:

We create JPA entities, and then we map the business entities to the JPA
entities. This solution has the same advantage and disadvantage. The
experience says that with this approach we just duplicates the classes,
because usually the JPA entities looks like as the business entities,
without any behavior.

We can use directly the business object as JPA entities. For this, we
need supply mapping metadata, what can be either annotation, or xml.
With this approach, we have the opposite advantage and disadvantage: We
don't have to write plumbing to java -> db map, but if we want change
the database structure, it might affects the domain objects. However, my
experience says that we don't change the database structure too much, so
we can live with the disadvantage.

So, we have a few alternatives, and it looks like all of them have the
same amount of advantages and disadvantages.

Now, everybody please look at her/his past experience, and answer this
question: How many times did I change underlying persistence technology
of a software? I doubt it that it was many times.

Therefore, I believe that putting the JPA annotations directly onto the
business entities, is a good trade-off. With this, we can eliminate the
tedious plumbing code write, yet we still have the flexibility to change
the the persistence technology.

Of course if the requirement is that our product have to support several
persistence technology (relational db, mongodb, csv, ldap, etc), then we
must write the mapping code by hand, but I thing usually this isn't the
case.

My motivation therefore: be practical, don't try to implement something
that you aren't gonna need it.

P.S.: No harm done.

On 2014.11.19. 20:40, Caio Fernando Bertoldi Paes de Andrade wrote:
> Sure, I look forward to hearing what others have to say too.
>
> Caio
>
> P.S.: Sorry about that, Péter. Thanks for the clarification.
>
>> On 19 of Nov, 2014, at 17:24, Böszörményi Péter <zmble...@gmail.com
>> <mailto:zmble...@gmail.com>> wrote:
>>
>> Hey, I like this answer. I like this kind of attitude. :) Right now,
>> I'm not in the position to give a proper answer, but I hope the
>> weekend will be more relaxed and then we can discuss this further.
>>
>> P.S.: You can use my first name, Böszörményi is my family name.
>>
>> On Nov 19, 2014 6:56 PM, "Caio Fernando Bertoldi Paes de Andrade"
>> <caio...@icloud.com <mailto:caio...@icloud.com>> wrote:
>>
>> Well, I always say, be pragmatic: TDD gives you all the necessary
>> decoupling, there’s no need to choose JPA before you build your
>> business logic. Just build your entities first and your
>> persistence mechanism afterwards, your logic will automatically be
>> decoupled from your persistence. If subclassing your entities for
>> persistence really annoys you, then you still can marshall fields
>> manually into your gateway classes.
>> I can recommend you to read all books from Uncle Bob. ;-)
>>
>> Caio
>>
>> P.S.: Böszörményi, sorry for copying your email’s structure, but I
>> found it just too funny to resist. :-P
>>
>>> On 19 of Nov, 2014, at 15:22, Böszörményi Péter
>>> <zmble...@gmail.com <mailto:zmble...@gmail.com>> wrote:
>>>
>>> Well, I always say, be pragmatic. The JPA gives all the neccesary
>>> abstraction, there is no need another layer that just copies
>>> data, and delegates method calls. Just put the proper logic into
>>> the JPA entites. If the JPA annotations really annoy you, then
>>> you still can put the mapping into xml files.
>>> I can recommend you to read the Real World Java EE Patterns from
>>> Adam Bien.
>>>
>>> On Nov 18, 2014 4:43 PM, "Sebastian Trueman"
>>> <akri...@googlemail.com <mailto:akri...@googlemail.com>> wrote:
>>>
>>> At the moment I'm thinking about an known problem. It's about
>>> putting business logic into jpa entities or not. There are 2
>>> ways to handle relating domain object logic:
>>>
>>> *1. put the logic into jpa entities. *
>>> If I choose this way I feel uncomfortable in different ways.
>>> At first I commit to a jpa solution. So I can't easily unplug
>>> jpa but I think its still ok. The second pain is mixing
>>> different areas of responsibility. One part of it is the
>>> persistence unit, that is responsible for storing data to the
>>> persistent storage with untouched clear domain logic. I think
>>> I'll profit of writing less code if I put all the strong
>>> related logic in the jpa entities and the further related
>>> logic in some interactors / usecase classes.
>>>
>>> *2. put the logic into pure domain logic entities*
>>> It feels more correct if I would put all the logic into
>>> separate entities. But it feels like doing some bad things
>>> with such a great ORM framework like hibernate. I also need
>>> to pipeline the entities to the jpa framework. I definitely
>>> have to write more code resulting in adding more complexity.
>>> The profit is a good separation of irresponsibles.
>>>
>>> Maybe you can give me some more pro and cons, maybe with some
>>> storys :). I also still know the statement of Martin Fowler
>>> <http://www.martinfowler.com/bliki/AnemicDomainModel.html> ,
>>> who call variant 2 an anemic domain model.
>>>
>>> br
>>>
>>> --
>>> The only way to go fast is to go well.
>>> ---
>>> You received this message because you are subscribed to the
>>> Google Groups "Clean Code Discussion" group.
>>> To unsubscribe from this group and stop receiving emails from
>>> it, send an email to
>>> clean-code-discu...@googlegroups.com
>>> <mailto:clean-code-discu...@googlegroups.com>.
>>> To post to this group, send email to
>>> clean-code...@googlegroups.com
>>> <mailto:clean-code...@googlegroups.com>.
>>> Visit this group at
>>> http://groups.google.com/group/clean-code-discussion.
>>>
>>>
>>> --
>>> The only way to go fast is to go well.
>>> ---
>>> You received this message because you are subscribed to the
>>> Google Groups "Clean Code Discussion" group.
>>> To unsubscribe from this group and stop receiving emails from it,
>>> send an email to
>>> clean-code-discu...@googlegroups.com
>>> <mailto:clean-code-discu...@googlegroups.com>.
>>> To post to this group, send email to
>>> clean-code...@googlegroups.com
>>> <mailto:clean-code...@googlegroups.com>.
>>> Visit this group at
>>> http://groups.google.com/group/clean-code-discussion.
>>
>>
>> --
>> The only way to go fast is to go well.
>> ---
>> You received this message because you are subscribed to the Google
>> Groups "Clean Code Discussion" group.
>> To unsubscribe from this group and stop receiving emails from it,
>> send an email to
>> clean-code-discu...@googlegroups.com
>> <mailto:clean-code-discu...@googlegroups.com>.
>> To post to this group, send email to
>> clean-code...@googlegroups.com
>> <mailto:clean-code...@googlegroups.com>.
>> Visit this group at
>> http://groups.google.com/group/clean-code-discussion.
>>
>>
>> --
>> The only way to go fast is to go well.
>> ---
>> You received this message because you are subscribed to the Google
>> Groups "Clean Code Discussion" group.
>> To unsubscribe from this group and stop receiving emails from it, send
>> an email to clean-code-discu...@googlegroups.com
>> <mailto:clean-code-discu...@googlegroups.com>.
>> To post to this group, send email to
>> clean-code...@googlegroups.com
>> <mailto:clean-code...@googlegroups.com>.
>> Visit this group at http://groups.google.com/group/clean-code-discussion.
>
> --
> The only way to go fast is to go well.
> ---
> You received this message because you are subscribed to the Google
> Groups "Clean Code Discussion" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to clean-code-discu...@googlegroups.com
> <mailto:clean-code-discu...@googlegroups.com>.
> To post to this group, send email to
> clean-code...@googlegroups.com
> <mailto:clean-code...@googlegroups.com>.

Sebastian Gozin

unread,
Nov 24, 2014, 4:25:11 AM11/24/14
to clean-code...@googlegroups.com

Now, everybody please look at her/his past experience, and answer this
question: How many times did I change underlying persistence technology
of a software? I doubt it that it was many times.

Quite frequently actually.
Not in terms of replacing a specific SQL vendor with another but in terms of requiring an index engine like Lucene or a data storage engine with completely different specifications due to performance constraints.
In the case where this kind of stuff has not been decoupled I all too often find the big if statement of death right under the UI layer branching the code into a path tightly coupled with SQL and another tightly coupled with whatever they picked.

As people have pointed out already.
If all you need now is SQL/JPA then mapping the classes in config or subclassing them is not much effort to keep your options open.

Having said that.
I don't believe simply mapping or subclassing prevents the persistence layer from leaking so I tend to have more than 1 persistence strategy on every project I work on. 1 in memory used for testing and 1 to be used in production. Using quite possibly more than 1 persistence strategy for different parts of the domain. I treat the ability to swap these strategies as a little test for proper decoupling.

Sebastian Gozin

unread,
Nov 24, 2014, 4:32:33 AM11/24/14
to clean-code...@googlegroups.com
In terms of self awareness.

I know that JPA annotations don't actually do anything unless you activate them with an implementation.
I know you can literally not package even the jar file which holds those JPA annotations and your application will still run.

In that sense I am aware that being difficult about the dependency is a little silly.
Still, I don't like to see stuff which does not need to be there. Y'know like excessive braces, repetitive naming habits (AccountManager.getAccountByAccountId(accountId)) and in this case annotations which talk about SQL.
I also don't like how changes to these annotations require recompilation of all modules which are merely interested in the unchanged API.

Cheers,
Sebastian

Jeff Hall

unread,
Nov 25, 2014, 9:25:26 PM11/25/14
to clean-code...@googlegroups.com
I've been thinking about this issue, having recently finished watching all of the clean coder videos and reading a few of UncleBob's books.

And having recently been on a project where we had to map many of our business entities to both SQL and XML databases simultaneously presented some interesting challenges. We all agreed after we got the app launched we wished we had gone purely NoSQL like MongoDB, but the application was so coupled to the persistence dependencies that leaked through our entitities it was too much to overcome. We made the mistake of putting all of our annotations on our entities which were used directly by our apps' middle and client layers. This was unfortunate!

Had we completely hidden all database dependencies from our entities, it would have been a good thing. So I'm of the opinion that if you can, make the business entities abstract, that is, they define the common, protected business specific fields and public enterprise business methods. Derive classes to invert any persistence dependencies (JPa annotations on the overridden getters, and even the persistence Id field(s)). An Order ID should be allowed to vary independently of the order's row Id in a database or document id in a NoSQL database. If you do this, it makes it easier to swap out SQL for Mongo, in case you want your mongo keys to be more sophisticated than just an integer.

The Jpa, jdbc, or Morphia specific gateway implementation can downcast the abstract entity type to get at the persistence id where needed. There may be some undesirable consequences of this approach though I haven't thought of any deal killers yet. There's always a trade off, but I want to keep as many dependencies as I can out of the business model and the application specific classes that interact with them.

For sophisticated gui frameworks like ExtJs where primary keys of entities are fequently used for client side stores, I'd use a business identifier rather than a persistence key if possible. In doing so you guarantee nothing above the gateway layers are coupled to persistence key design decisions you might want to change later. I'm going to put together an example to demonstrate this approach, and when it is ready I'll post a link in a post to this forum.

Jeff
BrainWreckage.com
Reply all
Reply to author
Forward
0 new messages