The more I read this post by Joel, the worse it looks. And mind you, I wasn't impressed during the first read. I just noticed that Mark Derricutt didn't think much of the "no exceptions" idea either. So let me give a concrete example of how and why I don't agree. Here's a longish snippet from the update loop of BottomFeeder - above this is the loop, the snippet is from the feed, at the point where it's trying to update:
safelyParseAndProcess: anUrl into: anObject forceUpdate: forceUpdate
[| cache |
self doFeedUpdateWithForce: forceUpdate.
cache := HttpClientModel cacheAt: anUrl.
(cache notNil and: [cache hasMoved])
ifTrue: [self modifyMovedFeedFrom: cache.
on: self xmlExceptions , Object errorSignal
HttpClientModel removeCacheFor: url.
on: self xmlExceptions, Object errorSignal
do: [:ex2 | ex2 return]]
Now, the relevant message send here is #doFeedUpdateWithForce:. That method (optionally) does the Http query (if it's time, based on etags, etc). The result of that query is presumably an XML document. Now, I handle the HTTP errors at the point of the HTTP query - mostly they are ignored, unless they are interesting - a 304 (not updated), a 301 (moved) - most other errors are just ignored and presumed to be transient issues (there's slightly more to it than that, but it's not important for our purposes here).
Notice that I catch the XML errors here. Why is that? Well, I've made changes to the parser itself - it ignores rafts of invalid feed issues in an attempt to be "liberal". At this level though, failure to parse means one of two things:
- Either the XML is hosed, and there's nothing we can do
- The document returned was actually not xml (likely an html error page of some sort)
Notice how I try the query a second time on XML errors? What I do is try the query again masquerading as IE, and specifically not asking for mod gzip. Testing has shown that, for whatever reason, looking like IE yields a much higher rate of success. I've also stumbled across encoding issues (both in VW and from feeds) that prevented the proper handling of gzipped feeds. Which is why it's caught at this level. Caught here, the system can make a rational choice about what to do. At the level of the http query or xml parse, those modules have no idea what the higher level application code is up to.
Say I followed Joel's advice. I'd have to make sure that every possible execution path handled and returned error objects, all the way down. That's just stupid. It would make the code very brittle, and highly resistant to change. The way I've done it, the http level or the rss parsing level just toss exceptions, and leave it to the application layer to deal with those. Intermediate levels of the call stack neither know nore care. In Joel's scheme, I end up with nasty case statements littering every single level of the call chain. In the exception scheme, there's the toss, and then the application layer with enough information to catch does so. The error passing scheme leads to baroque code that rapidly becomes brittle. Just say no