Framework misuses are still your bugs.

I spent a few hours tonight trying to diagnose a problem we were running into tonight with some web application code.

That was on top of the better part of a day that was spent by another developer digging into the code.

Development ain’t easy, and frameworks for all their glory strive to make the easy stuff easier and the difficult stuff… well it’s still difficult.

Take Seam for example, a couple simple @In annotations here and there, and all of a sudden you have an application up and running. 

But throw transactions and exceptions into the mix and the expected behaviour is up in the air.

Imagine the following scenario:

Component A calls Component B.update() which in turn calls EntityManager.persist(someEntity).

someEntity fails a database constraint and an EntityAlreadyExists exception is propagated from Component B.update(). 

Can Component A turn around and update someEntity and call Component B.update() again?

It depends.  In Seam there is a RollbackInterceptor behind the scenes that will rollback any transaction crossing an injection boundary (it’s slightly more complicated than that but we’ll leave that for another day). 

If Component A was a POJO Transactional Seam component, and Component B was a Seam EntityHome component, this wouldn’t work.  In this sitation, Component B throwing an exception would actually rollback the transaction before control was returned to Component A.  Component A could very well handle the exception but the underlying transaction would still be rolled back.

From the looks of the implementation, the EntityHome (Component B) is relying on the entity existing in its PersistenceContext when doing an update.  You can update() multiple times as long as the transaction remains open and long-running.

Throw an exception into the mix and that transaction is likely to get rolled back by the RollbackInterceptor and the persistence context reset.

From that point on, calling Component B.update() (equivalent to EntityHome.update()) is going to report a success but do nothing but flush an empty persistence context. 

 

The short term fix was to have Component B.update() re-merge in someEntity.  However, rather than perverting the framework, it likely makes sense to dig deeper into the implementations and merge Component A and Component B to prevent the RollbackInterceptor from firing and rolling back the transaction on an exception that is recoverable.

The things you learn!

“No matter how cool your interface is, less of it would be better.”

Interesting little article over on InfoQ talking about Alan Cooper’s book About Face.

 

Few key points:

  • Design for Intermediates Users
  • Use Tools that Help Beginners to Become Intermediates
  • Less is More
  • Design for the Probable, Provide for the Possible
  • Eliminate Errors or Confirmation Dialogs

 

There’s an interesting closing comment discussing the need (or lack there of) for error or confirmation dialogs. 

“Cooper notes that while they [error dialogs] are used to signal that something went wrong with the code, the user tends to interpret them as “I’ve done something wrong.”  When users are told that they are wrong repeatedly, they start to hate your product”

I suspect there’s some truth behind the statement, however all things being equal, if your product is blowing up, there’s a good chance that users aren’t going to be happy campers anyways.

That being said, I agree that showing an error dialog with some cryptic exception message only decipherable by the originating author, is probably not doing anyone a favor.  

Using the Java IDE IntelliJ as an example, it’s quite rare for a user to get an actual error dialog.  Instead, there’s a little status icon in the corner that will blink red whenever there’s a problem.  Clicking it will provide additional details with the option of submitting it back as a bug report. 

It’s important to remember who the user is, and considering the article’s focus on differentiating between beginner, intermediate and expert users, this status icon approach is probably best suited for intermediate/expert users, and not beginners. 

Ribs ribs ribs RIBS!!!!

Glenn, if you’re reading this, we’re doing it again.

About 4 years ago, some friends and I decided to venture down to the neighborhood rib house for some an all-you-can-eat rib spectacle. 

It’s taken us awhile (years really, some even had to leave the country) to recover, but this time we’ll be 29 co-workers strong. 

The plan is to round everyone up and head to the saloon (yes, bonus points again because the place has saloon in it’s name) for a feast after work.  Should be a night to remember, everyone has been encouraged to wear a white shirt and make a mess of it. 

Food (and drink) is always a good bonding experience, so all-you-can-eat must be even better, right?

 

I’ll post an update after the fact, should have some better pictures this time as well.  If nothing else, ghetto iPhone photos will have to do us justice.