Thursday, July 24, 2008

Making Java EE Suck Less

Ben Gidley has posted a medium length blog praising Tapestry 5. He took an interesting tack ... describing the requirements of a useful, useable web framework ... in terms of what Tapestry 5 does. I especially liked "Not require a large bespoke framework to be assembled around the framework."

He ends with:

This is the framework that could save J2EE from being a 'dull' and slow corporate tool and eventually fading as other toolsets come and replace it.

This, to me, hearkens back to how Dave Thomas defined Ajax, early on: It's whatever makes the web browser suck less.

To paraphrase, Tapestry is what makes the entire Java EE platform suck less.

Last week, when I was training in Cambridge, UK I saw a bit of this. The client was gearing up to create a full REST interface around their database access. They were starting to evaluate servers and APIs and think about integrations as well as how to represent object hierarchies and updates inside an XML or JSON structured REST query and response ... and how many more Java representations of entity objects would be required.

... but after working on the examples in the Tapestry Workshop they have abandoned the REST approach (until some external system actually needs access). Instead, they are modeling more of their application on the same light principals as the Tapestry Workshop:

  • Inject the Hibernate Session directly into pages, to perform simple queries
  • Use the @CommitAfter annotation to handle update operations
  • Move common queries (used on multiple pages) to a central, injectable service

This way they are able to leverage a single Java object representation of their database entities, as managed by Hibernate. They can use Hibernate features such as lazy loading and update cascading (things that would be prohibitively more difficult if there were a REST layer between the presentation tier and Hibernate) . This is all possible because Tapestry isn't just a web framework, it's also, because of Tapestry IoC, an integration platform. This allows the integration with Hibernate to be "light and tight".

9 comments:

  1. "Inject the Hibernate Session directly into pages, to perform simple queries"?

    Is this a prototype that they're planning on throwing away as soon as they've finished coding?

    ReplyDelete
  2. Nope. Where is it enshrined that the only way to do Hibernate query is to a) define an interface b) create an IoC Service / Spring Bean / EJB c) hook it all together? All you're doing is creating walls between two technologies, Tapestry and Hibernate, that can work well together.

    Is it more testable? Not really ... you can create unit tests using mocks to ensure that the queries are formed correctly, but ultimately this is an integration issue: integration between Tapestry and Hibernate, and integration between Hibernate and the database.

    Adding additional arbitrary layers between Tapestry and Hibernate and the database will not make things more testable (short of a real integration test), or more maintainable ... in fact, just the opposite. Adding additional layers just increases the maintenance burden.

    I would recommend that when there's duplication, you refactor the common code into a reusable service. This is another session in the Workshop: moving a duplicated query to a Tapestry IoC service. But I don't recommend doing this if the query is made in a single place ... adding the additional layer makes your code more rigid, in an undesirable way, and obscures the use of the query.

    Earlier versions of Tapestry were dinged because doing any work required so many open files: the template, the XML spec, the Java code, maybe a properties file. Tapestry 5 removes the XML and even the need for the configuration that used to be in XML, but that's just the start. A more pragmatic approach can do more good by eliminating unnecessary layers of Java code.

    ReplyDelete
  3. I am starting to use this kind of development, I mean, when I used struts (1.2) thinking on creating a page was really scary, formBean, Action, model, modify XML, DAO, etc. Was really a waste of time.

    Now I am using Tapestry 5 and Hibernate. I do not really see a good reason to use a DAO pattern, I mean, with Hibernate doing a lot of the persistence job (almost all), why creating another layer ?. I am still not 100% convice on using Session directly into pages, but I have an specific Service for simple query s where I do not see a really need to create a specialized service.

    It would be really interesting seen an article or even a book of the way that Howard use tapestry on real applications. I mean, the architecture, persistence, using ajax (where it really helps and where just is a loose of time, maybe), etc.. I know that this varies from an app to another, but a general overview would be great :D. And, of course, I am sure you are just so busy, but :), would be grate.

    ReplyDelete
  4. Yeah, it does start to look a little silly when you have a bunch of "DAO"s that don't do much more than a simple one to two line statement for every operation. The framework provides enough hooks already that you can avoid repeating system wide logic with dao semantics already.

    ReplyDelete
  5. Wow. This pretty much flies in the face of OOAD, at least from what I understand of it (I'm not a disciple by any means.)

    "Nope. Where is it enshrined that the only way to do Hibernate query is to a)..."

    Nowhere. That's a common pattern, of course, but it's not required for decent encapsulation.

    Also, since you've already recommended creating services for common queries, why go with half-measures, since the 'hard work' of creating a service/interface/etc and hooking it up?

    "Is it more testable?" I'm not a huge fan of testing, but one thing I do like to test is that my hibernate mapping is correct. This isn't impossible to test in your setup, but I find it's easier if I have a DAO. It's also easier to ensure consistency of access and even swap out the underlying persistence mechanism if necessary.

    "adding the additional layer makes your code more rigid" I don't think we share the same meaning for 'rigid'. To me 'rigid' means brittle code that breaks with even slight changes to an API which the writer has no control over (Hibernate, for example.)

    Anyhow, using DAOs is a bit more work up front--although if you use a Generic DAO pattern, not *that* much work--but I think you're underestimating the benefits. Not the least of which is not having HQL scattered throughout all you pages. Been there, done that, rewrote it because it was such a disaster.

    ReplyDelete
  6. "All you're doing is creating walls between two technologies..."

    Yup. Clever isn't it? So when we drop struts, tapestry5, webexfalvor3.0 we don't lose our domain logic and business code. And when we drop Hibernate we don't lose our view code. Decent app design transcends framework choices and separation of concerns is fundamental.

    ReplyDelete
  7. It's all about identifying the parts that might change and insulating the the rest of the system from them. If you think it's safe enough to use Hibernate explicitly, do that. If you have reason to think that that might change, you can use:

    1. JPA
    2. a service layer

    Using JPA takes you one step away from a hard dependency but still gives you similar streamlining. (You can always go outside of the spec and use Hibernate-specific features if you need to, but try to minimize and encapsulate those uses.) If you have specific, well-founded reasons to believe that that's still too hard of a dependency, go ahead and use a service, and feel good knowing that the extra up front cost will pay off in the long run.

    As for web frameworks (or, more generally, application view technologies), we're all aware of how volatile the landscape has been over the past few years... even within the Tapestry scene. I'm not going to bet my job on any one view technology for the project that I'm working on. Again, though, it really depends on the project and how likely you think it'll be that a day will come when a different choice will be necessary.

    Finally, applying this to the original case presented, it sounds like this client is expecting to need to provide alternate access to the data in the not-too-distant future. It would seem prudent to me to use a service layer to encapsulate the business and data access rules. In this case, it's not about switching web frameworks. It's about providing multiple, consistent views of the data.

    ReplyDelete
  8. Tapestry 5 does indeed "make J2EE suck less": the difference between using it to develop apps versus other Java frameworks is like fun versus arduous.

    While I wouldn't call encapsulating the ORM or data-access an "arbitrary layer", T5 eliminates so many of the other layers, as Howard points out, that there's no good reason not to simplify the code with direct access to the ORM. It's so easy to refactor later that it can be worth the time/effort savings.

    ReplyDelete
  9. from jaime: "It would be really interesting seen an article or even a book of the way that Howard use tapestry on real applications."

    Yeah, a cookbook from Howard would be really cool . . .

    ReplyDelete

Please note that this is not a support forum for Tapestry. Requests for help will be deleted. Please subscribe to the Tapestry user mailing list if you are in need of support, or contact me directly for professional (for pay) support.

Spammers: Don't bother. I delete your comments and it's a waste of time for both of us. 垃圾邮件发送者:不要打扰。我删除您的评论和它的时间对我们双方的浪费