Writing a software library and your day-to-day coding

.NET, English posts, Lucene, Lucene.Net, Software Design


4 min read
When writing software, there is always this tension between writing good software fast and having good code structure, which usually results in a nice API. These two are completely orthogonal - you can definitely end up having one without the other, and it is really hard and time consuming to have both properly done.

Ultimately, one would go on a coding spree and write code as his fingers lead him. Starting with the stupidest code possible, even with Spaghetti Code, and slowly refactoring it to classes and interfaces and so on, as the need arises (if you're still not using a functional language, that is!). This is completely fine, and how it should be. The goal should always be to get things up and running fast, and optimize later.

Some people would call this approach short iterations, and say it's Agile. Me? I'm just up for what works. Work this way, and you'll find yourself spending more time on the places that actually matter, not wasting time on the unimportant bits, and delivering better applications faster.

When I say don't pay much attention to the API unless real need arises, what do I mean? Take method overloading as an example. Never provide several method overloads to simplify usage when you first write a method, as complex and with non-trivial parameters as it may be. Have one method signature and in your code create the required constructs. If you are starting to see a usage pattern which call for an overload, go ahead and create it if you don't have anything better to do.

This holds very true as long as we are talking internal projects written and maintained by you and your team. This renders almost completely false when we talk about creating a library or an API to be consumed by the public.

Take this Lucene code for example:

public static FSDirectory open(File path)

This method expects a File object. If you wanted to provide it with a string path, as you'd usually go when rapid-developing, you'd find yourself spending a few moments looking up the API for converting the string path you have to a File object. Admit that, nobody ever remembers those small bits unless this is what they do in their daily job.

And so it happens that this was exactly the case with Lucene.NET, being a strict port from Java. If you wanted to open a new FSDirectory, you would have to create a new DirectoryInfo object out of it, thinking for a moment if that should be made using a constructor which accepts string or perhaps via a static factory method.

And that is, ladies and gentlemen, bad library design. (And yes, I know I picked the smallest, stupidest bit possible).

Because if a common usage pattern is to open an FSDirectory using a string FS path, you should allow for that. If it was your own code, this may not have been a justified argument for spending time on API refactoring (although it might have been!), but once we talk public facing API - it becomes too important to dismiss. If only for all of those moments wasted by thousands of developers when wondering on how to translate a string path to a File / DirectoryInfo object, piling up to be wasted days or weeks in the software industry.

This was one of the first things I fixed in Lucene.NET after becoming a committer in the project, and starting with Lucene.NET 3.0.3 FSDirectory.Open has a public overload which accepts a string path.

Comments are now closed