Back in January I was writing a TCP/IP server for a client that acted as a connection gateway. Just as this project was coming to an end we started on another project which, at first, seemed quite similar; it was a TCP/IP server that provided gateway services. Just as we were starting out with this new project I made a fairly stupid decision and, well, four months later I’ve almost finished cleaning things up…
The stupid decision was to hoist some code that we’d used on the first gateway project into one of the core libraries of The Server Framework for use on the second project. The main piece of stupidity was that this wasn’t usually how we work yet I decided to go for the ’easy win’ and flout the rules.
As I’ve mentioned before, our core libraries are built up by harvesting code from existing projects. We don’t set out to write re-usable code, we set out to write usable code that works. When we have used the same code in several projects we harvest the code into a library, fix up the existing projects so that they use the harvested code and re-use the code from the library for future projects. This works well, mainly because by the time the code is harvested and the dependant projects updated the code for re-use has stabilised and future use doesn’t tend to pull it in unexpected directions…
So, back in January I broke the rule. I saw a concept that looked like a concept that we’d need in the next project, hoisted it into a library, fixed up the first project and started on the next one. The problem was that the concept wasn’t 100% good in the first project, it was good enough for us to get the first release out the door but we expected to refactor it a bit once things calmed down. Unfortunately the now shared concept turned out to be less that 100% good for the second project and it was a poor fit for different reasons…
So, time moves on. Project 2 pulls the concept in one direction, whilst some refactoring in project 1 pulls it in another. Since the concept is shared and lives in one of our core libraries we have to be more careful about how we bend it. Looking back, quite a bit of time was wasted thinking about how to make sure that the changes required for one project didn’t cause problems in the other project… The concept underwent a lot of churn, as can be seen from the CVS logs, this is a bad sign for things that live in our core libs, they’re supposed to be pretty well done and dusted by the time they get in there… Eventually we realise that it would be better to simply break the link. We copied the concept into project 2 and adjusted it so that it worked nicely in its new environment and only did what project 2 required of it. The original, shared concept stayed in the library, but now it was only used by one project, and our experiences had proved that it wasn’t quite as ‘reusable’ an idea as we had originally thought.
Time passed and project 1 required some changes so, whilst we were in there, we decided to have project 1 use the ‘shared’ concept locally in the same way that project 2 did. We pulled the code out of the library and adjusted the local copy so that it did just what project 1 needed. The code became simpler as all the changes that were needed to make it play nicely with project 2 could be removed.
The ‘shared’ concept still lives in the library, for now. It’s marked as deprecated and the .cpp files are set so that they don’t actually build into the library. Later in the week we’ll run all the build scripts and, once we’re sure that no other projects happen to use this concept, we’ll rip it out of the library for good.
If I had followed the rules then, I expect, work on project 2 would have been faster and the work required to clean up the library wouldn’t have been required at all; but I thought I knew better than the rule and, well, this blog posting is to remind me that I don’t know better.
So, in case I forget again; the rule for how code gets from a project into a core library is this: The code is being used in more than one project and, once refactored, is identical in both projects.
In summary; you can’t have re-use without use.