Saturday, December 04, 2010

To Reuse or To Rewrite?

It is amazing how many developers like to rewrite functionality from scratch instead of reusing a library when most common problems such as validating a zip code or parsing currency have been solved already countless of times.

In a recent Ruby on Rails application I have been working on, I wanted to parse phone numbers in different formats, and figured why waste time re-inventing the wheel when I could use a library? I know it is easy to implement the parsing logic. I wrote such code in Java in the past. But, experience has taught me that thinking it is easy to rewrite when it is solved already is a trap. After all, so many hidden edge cases often lie in a seemingly simple problem that only reveal themselves after a long period of usage and testing. That makes it more than worthwhile to rely on a library than write things from scratch no matter how simplistic. Unfortunately, in the past, I did not have the foresight for it, and whenever I wrote things from scratch, I thought I delivered business value, and did not notice the cost sunk into fixing bugs for all the discovered edge cases over the course of using the application.

I used to like rewriting code from scratch for problems already solved with libraries for several reasons:
1- Seemed easy
2- Gave a satisfying feeling of accomplishment at the end
3- Seemed like more fun than learning the API of a library
4- Prevented me from feeling dumb while attempting to learn a library
5- Kept the code base simple

What seemed easy often ended up having so many edge cases that it became a much more complex task than anticipated, especially when some edge cases were discovered by users in embarrassing bug reports. Now of course, libraries may still have undiscovered edge cases themselves, but taking probability into account (instead of thinking black and white), it is a lower chance to find a bug in a well-used library than code I just wrote.

Regarding the feeling of accomplishment, it was a misleading reason as it could also be obtained from solving the main business problems instead of writing code for already solved lower level problems.

About the fun aspect, while it is important to do something that I enjoy in order to stay motivated, it is also important that what I find fun is most useful to clients or else somebody else more focused on the client needs will do my work faster by reusing a library, rendering me a less valuable developer who selfishly spends time on rewriting code for the fun of it.

One of my biggest fears in reusing a library was feeling dumb or overwhelmed by sheer complexity while learning it. Now, rationally speaking, if the highest goal is serving the client in the best way possible, then if it meant feeling dumb for a little while in order to implement a higher quality solution with a proven library instead of coding stuff from scratch, then so be it. Not being concerned with feeling dumb for the sake of serving a client shows both self security and humbleness. The opposite is simply selfish, insecure, and ineffective for the client. Still, if I can think of a simpler way of writing the library API, then it would be a good idea to write a facade on top of it or contribute the simpler API to the library directly.

Finally as for keeping the code base simple, this really depends on the library being used. There are cases where writing code from scratch is more efficient than using an incredibly complex library. However, I have often generalized from one bad experience with some badly designed over-complicated library, avoiding libraries for a while and losing out on the benefits of many other better and simpler libraries for other problems.

The way I think of it now is if a certain library that I am exploring seems to require me to write more complicated code than if I had written code from scratch, then I should be careful in considering the library a time waster as it may still save me time by handling edge cases I have not considered. Many times, when I wrote something from scratch for a solved problem that seemed simple, I ran into so many edge cases eventually that any productivity gained from not spending time on learning a library was offset completely with the problems encountered. And, as I stated before, I used to not notice that and think I was being productive without reusing a library, but experience taught me otherwise. My opinion now is a bit more strongly for reuse than it was a couple of years ago.

The only time I would solve a problem from scratch now is if no library out there solves it according to the quality standards required for my client. That is when it is a good opportunity to write my own library and open source it to let the community help test it and reveal edge cases quickly.

Luckily, I found a library that parses phone numbers in Ruby called phone_number. :)

No comments: