Reuse
Did you ever find yourself facing a problem, wishing you had a program to solve it for you? I certainly did. Repeatedly.
Many years ago, I decided to give Getting Things Done a go and, therefore, needed to manage my tasks in some system. Since a computer science student cannot simply use pen and paper, I went looking for a tool. I found at least a thousand.
The problem of task management is very common, which causes a large need for such tools, but in the end, everybody’s preferences are a little different, which causes many-and-one to write yet another worlds-best task manager. I, too, had these two options: Use one of the existing tools or write my own. I made the sensible choice and went with the former option.
While an existing tool may not always fulfill all my wishes, I was reasonably sure I would get what I needed and most of what I wanted, immediately and practically without any effort. Plus I could call somebody else in case I had trouble with the tool.
The sensible programmer can swallow his pride and become an end user.
When working on my research prototypes, I often face similar choices: reuse an existing component or implement my own solution. If the problem is as common as task management, then there’s certainly a mature library or framework out there, which I can reuse to save me time. If the problem is so special that there’s nothing at all I could reuse, I’ve got no choice but to get my hands dirty. But in between those two extremes, things are more difficult.
Sometimes, I face a task and I find that there is an existing implementation that claims to solve that task or at least something that appears to be very similar. Now I have the two options again: reuse or write from scratch.
What’s the sensible choice to make?
Given the infinity of possible ways to think about a problem, it’s almost certain that an existing program for (something similar to) my problem does not solve my exact problem. Especially, if the program has a small user base, i.e., has been employed in but a few use cases.
On the other hand, if my problem is specific, but I went to search for existing implementations, It means that I expect a solution to be a non-trivial implementation task. Hence, although my own solution might be a better fit, it’s a non-negligible effort to write it in the first place. Especially, if I’m not an expert in the respective problem domain.
Obviously, there’s a trade off to make.
To make it, I have to look at the existing implementation. Do I understand how to use it to solve my problem? Do I understand how it works? What quality does the code have? Does it feel like I can go and adapt the code to my needs, if necessary?
To decide these questions, I usually write some exploratory tests. I find that it helps me make up my mind, when I have something I can execute and observe results, if only because I make my expectations explicit to myself. Plus, such tests are acceptance tests that I can reuse when I decide to switch to another existing solution or to write my own, ultimately. Hence, I would write them in any case.
I usually set myself a timebox, say 30-60 minutes, for such exploratory work. When I realize within that timebox that the code doesn’t solve my problem and cannot be adapted with reasonable effort, I stop. When time is up, I take the leap of faith and reuse the code.