27 Jul
Posted by suresk as Technology, JEE, Enterprise Development, Software Development
(Note: This article is a bunch of high-level thoughts and tips I’ve come up with over the last little while. For more in-depth and comprehensive Hibernate information, I highly recommend Java Persistence with Hibernate)
A little over a year ago, I joined the project in part to add some Hibernate expertise. Since then, we have been using Hibernate’s JPA implementation, but the ideas remain the same. The project used a database that was rather large, rather old, and shared by multiple applications. I learned quickly that the examples in the books are one thing, starting a project from scratch and having a large degree of control is another, and trying to use Hibernate on a database that was large, extremely complex, and shared with other apps was an entirely different thing altogether. Had I known what I was in for, I probably would have run the other direction as quickly as possible!
In the end, however, I feel like I’ve learned some important lessons, and although our project isn’t completely done, I think we’ve been applying these ideas pretty successfully for a while now. I had to do some long, boring driving the past few days and had some time to reflect on some of the things we’ve learned, so here they are at kind of a high level:
1) Become friends with the DBAs.
There is a tendency for some Java developers to marginalize the importance of DBAs. This is a huge mistake - a good working relationship with the keepers of the data is critical to success with any ORM technology. This is important for two reasons:
- DBAs alone usually can’t make your Hibernate efforts successful, but they often can make them fail.
- They usually have really good insight into the database itself, good modelling practices, and any pitfalls or shortcuts for you. I can think of several instances where a timely suggestion from a DBA saved us days and gave us an elegant solution.
In most cases, having good DBAs and having good relationships with them is highly critical to the success of your ORM efforts. Plus, database guys are usually pretty cool people :)
2) Use (and enforce) good naming standards from the beginning.
Who knew naming standards discussions could be so contentious? One of the things we try to accomplish with ORM tools is to make our data model more meaningful, which makes it easier for developers to use and helps avoid confusion. To this end, how we name entities and attributes is very important. I have naming standards I like and think are best, but I won’t try to push them on you here. The important thing is that you decide on something upfront and get everyone to use it. Actually, this should extend beyond just naming standards and should be inclusive of other standards as well (ie, Boolean vs “Y/N” or 0/1, primitive vs Object, Integer vs Long, etc).
3) Don’t try to map every attribute (and association).
We started out trying to use tools like Dali to map everything on a table quickly (some tables had several hundred columns!). This turned out to be a bad idea. Why? Since we were on a shared, legacy database, there were a ton of fields we didn’t care about and never used. Mapping them led to performance issues and confusion.
4) Let the database do the things it is good at.
We really wanted to have a good, clean data model, and so we avoided at all costs writing extra queries to fetch things pertinent to an object or using stored procedures or functions at all. This was also a mistake - databases are good for stuff other than just holding the data Hibernate creates and reads :) For example, we had one object that had a status associated with it. The status was used all over the app so it had to be performant, but we also didn’t want to have to make a separate query every time we needed it. The problem is, the status was derived based on some calculations that operated on several one-to-many relationships. Pulling back all that data as part of each load of the object would have been way to expensive. Working with one of our database guys (see #1), we found a sql function we could use to get the status very quickly. We mapped this to a status attribute using @Formula and had everything we wanted - it was part of the domain model still, and was very performant. Sometimes little compromises like this can yield big dividends.
5) Break up the database.
When we first started, I wanted to model the whole databse in Hibernate at the beginning. This turns out to have been really impractical for a few reasons:
a) It was a huge job and would have consumed weeks of time while the customer would have seen no actual work being done.
b) I was unlikely to get it right the first time, meaning developers would have to change it anyway as we got started.
There is a tendency to want to map the whole thing out before starting, but a lot of times you just have to work on it as you go. I did find it useful to break it up into pieces and try to do a whole piece at a time as we went - which really seems to have helped.
6) Watch out for triggers.
Watch out for database triggers for two reasons:
a) They can do sneaky things behind the scenes that can lead you to pulling your hair out, wondering what happened.
b) Sometimes they do stuff that you need to replicate on the Hibernate side. Several times before we fully learned this lesson, we missed some important things that triggers were doing and almost caused ourselves some real grief.
7) Shy away from tools to auto-generate your model.
Yeah, they can save time (although we found Dali to be terribly buggy at the time we used it), but you end up having to re-do a lot of it anyway. It doesn’t take that long to map them by hand, and it gives you a chance to familiarize yourself with the data more as you do it.
8) Use NamedQueries where you can.
It is easy to just pound a query out in-line, but in a lot of cases it is better to use NamedQueries. This helps to do two things:
a) It fosters more re-use, since the named queries are generally located in central places in the code.
b) Your queries get validated on startup, making it so errors in the queries (especially down the road when they can get messed up by model or table changes) discovered much more quickly.
It sometimes takes a bit of getting used to (and strong-arming!), but it is worth the effort.
9) Manage Expectations.
This is probably important to keep in mind for any new framework, technology, or even concept. For some reason, people tend to get sold on certain features that simply don’t exist, or are highly exaggerated. Sometimes it is small and understandable (ie, underestimating the actual work required to map stuff in Hibernate), and sometimes I have no idea how they came up with such ideas (ie, that Hibernate can somehow manage schema revisioning). At any rate, finding out what the expectations are and then managing them can be really important. If your team thinks that Hibernate will make DBAs completely obsolete (usually quite false) and fires them all, you will probably have a big problem on your hands.
10) Use rich domain modeling.
One of the sadder things I’ve seen with projects that use Hibernate (and in some cases, I’ve seen it because I’ve done it!) is when the domain objects become no more than simple containers of data. The goal of tools like Hibernate is to let us use data in an object-oriented fashion - simply mapping the data only gets us halfway there. As I’ve made conscious efforts to practice rich domain modeling, I’ve noticed that we reuse a lot more code, our other layers become less cluttered, and our code is more testable and easier to refactor.
13 Responses
andrzej
July 30th, 2007 at 2:10 pm
1Regarding #10 — how have you managed to avoid anemic domain model? Especially when it comes to injecting data access layers/objects into domain model. Have you used for instance Spring combined with byte-code instrumentation (or @Configurable annotation) to inject those objects? To be honest, this is the only method i’m satisfied with as of today :-)
Riccardo
July 31st, 2007 at 1:06 am
2Hello,
in my experience #10 seems a consequence of #7 :-)
I’ve also often seen violations of #1 to #5, in the style ‘Java is better than Oracle’!
Patrick Peralta
July 31st, 2007 at 7:29 pm
3These are great suggestions for doing ORM in general. I found myself learning the very same lessons with the first Hibernate project that I worked on.
1. Very important, especially since a good DBA will help optimize queries. Sometimes you do have to break out of the ORM and run regular ugly SQL (/*+ rule */ anyone?) to get the performance you need.
3, 5, 7, 10. I did use Middlegen to generate pretty much every entity in the database. Although it was a huge help at the time (since I had no idea how to map the relationships) it did result in quite the anemic data model with quite a few unused fields. Knowing how relationships work now, I would do it by hand for any future projects.
4, 7. On occasion, things do belong in the database, in particular if it helps in keeping the data clean. We had triggers that performed optimistic locking that worked quite well, whether using ORM or plain SQL.
Gavin King
August 1st, 2007 at 11:18 pm
4Nice article :-)
Vinny Carpenter’s blog » Daily del.icio.us for Jul 30, 2007 through Aug 03, 2007
August 3rd, 2007 at 6:31 pm
5[…] 10 things I learned about using Hibernate/JPA successfully by SpencerUresk - I decided to share a few things I learned about using Hibernate/JPA in a large project with a complicated database setup […]
links for 2007-08-09 « betaalfa
August 8th, 2007 at 10:27 pm
6[…] 10 things I learned about using Hibernate/JPA successfully by SpencerUresk (tags: hibernate tips) […]
Web Development Resorce Articles
August 10th, 2007 at 7:32 pm
7[…] 10 things I learned about using Hibernate/JPA successfully by SpencerUresk - I decided to share a few things I learned about using Hibernate/JPA in a large project with a complicated database setup […]
Another Digest On AJAX Tutorials
August 11th, 2007 at 5:39 pm
8[…] 10 things I learned about using Hibernate/JPA successfully by SpencerUresk - I decided to share a few things I learned about using Hibernate/JPA in a large project with a complicated database setup […]
Sarah
August 13th, 2007 at 5:47 pm
9Just wanted to say that it was nice that you mentioned some ‘non-technical’ tips that are just as important. eg.. have a good relationship with the DBAs and the importance of managing expectations.
:-)
links for 2007-08-14 « On Being Ben
August 14th, 2007 at 2:28 pm
10[…] 10 things I learned about using Hibernate/JPA successfully by SpencerUresk (tags: orm nhibernate) […]
Eric
January 22nd, 2008 at 7:22 am
11Hi
Very good article. I have a few questions I want to ask but I could not find an email for you so I thought I would post them here and you can respond directly to me if you prefer.
I am working on adding a JPA/Hibernate layer to an existing database. The current system is simply two tier, Oracle and JSP. It makes use of a lot of stored procedures and the data set is massive and the structure is very much de-normalized.
2) Use (and enforce) good naming standards from the beginning.
What naming standards did you use? I can try and reinvent the wheel but why do that if you have already tackled this problem.
4) Let the database do the things it is good at.
very good example of when to let the database do the hard work. I am trying to avoid using stored procedures et al and so far it is working but we have not looked at performance issues. Do you have an example when it would be better to use stored procedures? The application we are using will have to load and update 100,000s rows at a time so i am wondering if letting Hibernate handle that is a good thing. If not do you have an example of doing this in a better way. I guess I am looking for more complicated examples.
10) Use rich domain modeling.
What is a rich model exactly? I have been surfing the web trying to find useful examples but all i am finding is really simple examples that don’t really help unless you are trying to build a really simple book store ;-) . I have seen lots written about domain driven design and the use of POJO’s and we are trying to use these patterns as much as possible but we feel we have not really grasped the concepts. Do you have an example of a class hierarchy or collaborators that make use of a rich model and that don’t. A before and after comparison would be much appreciated.
A few more questions not directly related to your article but you may have tackled these as well:
a) How did you decide whether to use JPA or native Hibernate? I understand JPA offers a subset of the Hibernate functionality so what did you decide on and why did you make that decision?
b) We have lots of business logic in the database in the form of Oracle constraints and many stored procedures. We are very much for the DRY principle but how do you decide whether to leave the Oracle constraint in the database or migrate the logic to the Entity? I guess it may depend on who else uses the database but assuming we are (or will be) the sole users of the database, does removing the constraints leave the database naked in that the data is there but the logic governing the structures is elsewhere? How about if we want to to use .NET apps say and Java apps where we can’t necessarily share the entities, where should this business logic be stored?
I know I have asked a lot of question but I am hoping you can shed some light on your experience.
Many thanks in advance.
Eric
suresk
January 22nd, 2008 at 1:55 pm
12Good Questions.
“What naming standards did you use? I can try and reinvent the wheel but why do that if you have already tackled this problem.”
I don’t necessarily know that *my* naming standards are the best - the important thing is to standardize on something. Some sample rules I like:
1. Use descriptive, intuitive names for things - even if the database doesn’t.
2. Entities should be singular, OneToMany relationships plural.
3. No underscores, no redundant names (ie, if the entity is Course, don’t name the description field courseDescription, just call it description).
“Do you have an example when it would be better to use stored procedures?”
When to use stored procs or functions will depend largely on your application and your database. I’ve worked on fairly large applications that never needed to use stored procs, or only used 1 or 2. If you need to operate on a lot of records at once, or use a lot of records to calculate something, stored procs can come in handy.
For example - One part of one application I worked on had to do with training. I needed to figure out how many people were scheduled for a course at a particular facility at a given date. Unfortunately, there were a lot of peculiarities in the data, so this couldn’t be accomplished with a straightforward query, and it would have involved pulling back thousands of records from the database. In cases like this, a proc or a function will always be faster - sometimes significantly so.
“What is a rich model exactly?”
Several years ago, you started seeing trends with Hibernate and with EJB entities where your model objects would be containers of data and nothing else - no behavior. Rich domain modeling, in this context at least, entails adding behavior to your object.
Simple example - Let’s say you have a Course object, representing a training course, and a name is generated for it based off attributes for that particular Course. With anemic domain modeling we’ve seen in the past, that code would go in a service layer object. With rich domain modeling, that logic goes in the model class. The benefit is that it is more reusable, easier to refactor, and better organized to have it in the model class itself.
“How did you decide whether to use JPA or native Hibernate? I understand JPA offers a subset of the Hibernate functionality so what did you decide on and why did you make that decision?”
Well, keep in mind that if you use Hibernate’s JPA implementation, you aren’t necessarily forgoing extra Hibernate functionality - you can still use Hibernate specific functionality wherever you need it. Going with the JPA standard makes it easier to upgrade (and potentially change implementations) in the future.
“We are very much for the DRY principle but how do you decide whether to leave the Oracle constraint in the database or migrate the logic to the Entity?”
I think it is generally a good practice to have the validation rules in both places, even though it is a bit of duplication. I mean, what happens if you have stored procs hitting that same data? Or you have to write native SQL in some spots? Or if other projects end up hitting the same DB?
I hope those answers help.
- Spencer
9 Links Today (2008-01-23)
January 23rd, 2008 at 9:20 am
13[…] 10 things I learned about using Hibernate/JPA successfully by SpencerUresk […]
RSS feed for comments on this post · TrackBack URI
Leave a reply
Categories
Archives
Links
Meta
Recent Entries
Recent Comments
Most Commented
SpencerUresk is proudly powered by WordPress - BloggingPro theme by: DesignDisease