Pages

Tuesday, June 19, 2012

why you shouldn't do things in your constructor

Last week I needed a free HTTP server for a project I was working on at my job.

Naturally, most folks would suggest Apache here, but I had the caveat that my server's footprint needed to be very low - no bells or whistles. After adventuring through Google for a while, I finally turned up a cute little free-to-use thing, a single Java .class file called NanoHTTPD. It was an ultra-lightweight HTTP server, built off the core ideas of the HTTPD monster but without all the bulk - where Apache is the big brother, NanoHTTPD is the anemic, weaselly stepchild. Simply compile and run the class file and you have a working web server on your machine. Need more functionality? Easy as cake: just override the "serve()" method, called when the server process an HTTP request. It was perfect.

All was proceeding as planned - I was extending the NanoHTTPD class and overriding "serve()", just as the creators intended - when I came across a problem. I had added several member variables to my subclass, so I had some initialization that I needed to do before the server ran. Problem was, calling NanoHTTPD's constructor was the trigger that started the server. But better yet, the creators didn't implement a default constructor. Any constructor I wrote would be forced to call "super(foo, bar)" as its first command, which would send the whole shebang on its merry way to serve the Internet's web page appetite.

There's a lesson to be learned here: never do non-initialization stuff in your constructor. NanoHTTPD didn't follow that rule, so it created a pseudo-final class for anyone in a situation like mine - in other words, completely defeating the purpose of an extend-as-necessary, bare-bones implementation. Pulling the server start code out into a separate method to be called after instantiation would have been trivial to do, yet such a small omission caused a good-sized headache on my end.

Whenever you're tempted to fudge other things into your constructor, remember the name of the method: constructor. It builds things; don't make it do more than that (I'll bet you'd get a hammer to the head if you tried to make a builder run a server anyhow, as you rightly should). When in doubt, extract the code into a public method and let the developers who build on your code decide when to use it. I guarantee they'll thank you.

As for my project, I was fortunate enough that NanoHTTPD was licensed under the Modified BSD license, so it was free-to-modify as well as free-to-use. I finally ended up copying the whole source code over to my project and began directly modifying it from there... no calls to "super" needed.