The Perils of Writing Reusable Code
If you've taken a programming course, the chances are that you've been told to write reusable code when possible. It certainly sounds great. Writing software is time consuming, so being able to reuse code instantly improves your productivity.
I'm going to push back a little. Yes, code reuse is great. I reuse code; I use libraries (which is code reuse). In fact, I know of nobody who writes all the code executed by their software completely from scratch. However, it's really easy to get carried away and end up wasting tons of time...
ZitaFTP has a TemplateEngine class, which is used to generate the HTML code for the web-based User Interface (UI). It uses a hard-coded the directory structure. It would be more reusable if the directory structure storing the templates were configurable, so let's add that. Also, we (or somebody else) might want to switch out the mstch library for a different one. Or maybe, we'll want to switch to Handlebars, a more flexible Mustache-compatible templating system (when the C/C++ library is good enough). This is implementation hiding, which we've been taught is a good thing. So, we write a whole abstraction layer to hide any mstch-specific data structures, and provide our own methods to build the data.
Next, we realize that... Stop! We've already added a lot of extra work to our plate, and for what benefit?
Best Case Scenario: Extra Code Nobody Uses Or Cares About
The hard-coded directory structure was simple, logical, and easy to use. Most likely, nobody will use the code we wrote to enable custom directory structures. The abstraction layer will obviously be used because it's part of the class' API. However, in the end nobody ever changes the underlying template library. So, the abstraction layer and extra features were a complete waste of time.
Worst Case Scenario: Code So Complex That Nobody Wants To Touch It
Let's say that you added every additional feature/option to the class' constructor and public methods. Now, you've got this hideously complex monster that is hard to use and maintain. Nobody wants to use it let alone touch the code inside. So, when the next project needing a template engine comes along, the code is abandoned and a new more sane template engine class is written. Bottom line: no code reuse.
Code Is Written For A Specific Purpose
Taking code reuse to absurd levels, and you'd end up with code that's so generic that it does everything and anything. It would also take forever to write and debug, and be so complex that nobody uses it. Completely generic code is useless precisely because it has no specific purpose.
We write apps to perform specific tasks. Their value lies in their specificity. The code inside those apps is no different.
Clearly, a balance needs to be struck between being too specific and too generic & reusable. But how? Getting the balance right takes experience, but here are two "yardsticks" you can use to help you decide:
1. Application Frameworks and Code That Will Be Used By Multiple Applications Are Clearly Intended to be Reused
If you're writing a framework that will be used to build applications, then it's clearly intended to be reused. Likewise, libraries that provide low-level functionality (e.g., graphics, encryption, etc.) are meant to be reused. So, their APIs need to be designed carefully to make reuse as easy as possible.
2. Code That You Frequently Copy, Paste & Modify Are Candidates For Reuse
If you find yourself duplicating the same code often, then that's a good sign that you should pull that code out into a dedicated function/module, and make it generic enough that it can be reused. Copying and pasting code is code reuse. It's just in a horribly unmaintainable style.
I didn't mention this directly in the video, but the biggest issue comes from trying to write reusable code first time round. The yardsticks above only work if you've already written code to solve whatever problem/task you're working on. Trying to write reusable code right from the start is where things tend to go wrong. You end up over-engineering the code, writing stuff that nobody needs, and end up wasting a heap of time.
Why do things end up going wrong if you try to "get it right" first time round? Because you're guessing. Notice how yardstick number 2 specifically requires you to have written code first. It's in writing the code that you find out what's actually needed, which gives you the hard data needed to make good decisions. So, write code that works first, and make it reusable later.
Post your comment