Monday, December 13, 2010

RuntimeExceptions and Neo4J

I'm currently working with Neo4J(http://www.neo4j.org) - in the evaluation stage really, trying out various use cases. TestNG is my test framework of choice, so most of my work is driven by it.
What really irritated me is the fact that some tests failed. When I looked at the TestNG report, I found that in some cases my test data was bad, so in effect, I was creating a self relationship (which Neo4J frowns upon). There were also cases where, during trial and error, I did not clean the db so I ended up doing a node.getSingleRelationship and instead of one relationship, there were more.

So why was I irritated? My test cases did fail due to an exception. However, they were Runtime exceptions. When I wrote the code, I did not think they may be thrown- I did not look at the JavaDoc in detail- just used IntelliJ to show me what I could possibly do with Node, and winged it from there. So, when my test failed, I was a bit disbelieving. First checked the exception- and it was a Runtime exception (duh). Then pulled up the JavaDoc and saw that Neo4J does indeed indicate an exception can be thrown in these cases.
This caused me to tweet about Neo4J and their runtime exception philosophy. (Pleasantly surprised to see @emileifrem respond to it)

Anyway, somewhere in one of many open windows, I happened to search for any such issues related to Neo4J. I came across Stephen Colebourne's blog instead (http://www.jroller.com/scolebourne/entry/checked_exceptions_bijava)

So really, did it matter whether Neo4J threw RuntimeExceptions or not? Apart from the test results, which were surprising because I neglected to read the JavaDoc in detail, I went through some exceptions that Neo4J throws (leaving out the very obvious Runtime exceptions).
Now if a DeadlockDetectedException, HaCommunicationException, NotFoundException(thrown if a request is made to a node, relationship or property that does not exist), NotInTransactionException, ReadOnlyIndexException or TransactionFailureException were thrown, what would I really do about it? Nothing much, unfortunately. There is no way I could be smart and recover from these. At the most I'd log it and re-throw it.

Now on to the ones I was disturbed with- methods mostly on the Node.

getSingleRelationship() which (as the name indicated) returns the only relationship of a given type and direction. Well, the fact that I'm using this method does mean that I really expect there to be just one relationship, so when a runtime exception is thrown, there is no way to recover from it.

delete() throws a RuntimeException if it has relationships attached to it. Can I do anything about it? Maybe- depending on functionality, I might attempt to do a cascade delete and re-try the operation. Not sure how many use cases would really want a cascade delete though.

createRelationshipTo() throws a RuntimeException if you try to create a self relationship. Note here, that the JavaDoc does not specify this in the Throws, but rather in the description. This arguably could be dealt with by creating an intermediate node- but at the same time, this situation can easily be avoided by defensively coding for it.

So did it really matter that Neo4J threw Runtime exceptions? After a lot of thought, not really. Why some exceptions are true classes of RuntimeException and why some (the Node exceptions) are just RuntimeExceptions in themselves, I am not sure. The source does not indicate that they do anything over and above being a RuntimeException.
Does it really matter that there is a split convention? I'd think if I needed to recover from a delete exception, then it does matter.
It will be interesting to see as I develop more with Neo4J, how much these Runtime exceptions come into play and whether they are really as disturbing as I initially thought.

Disclaimer: I still do not believe that we should do away with checked exceptions altogether :-)

No comments: