So far I have written a couple of posts about bad practices I have found in other peoples code. Todays blunder is however one I was about to commit myself. A library I was extending had this (as usual, simplified) function:
void Library::write(const char* c, int i);
This was however not always a safe thing to do, so I found all the callers had wrapped it with almost identical code to protect it. I decided to add a method to the library, doing exactly the same thing, but with the added safety-wrapping. Fortunately, I didn’t even need to change the signature, so I could easily make a new function
void Library::writeSafely(const char* c, int i) { safety(); write(c,i); more_safety(); }
and change all the callers to use this new function. Luckily, we still had control of all the users of this API, so this was no big deal. Can you spot my mistake?
The title is kind of revealing, hinting at the API design best practice “Make Interfaces Easy to Use Correctly and Hard to Use Incorrectly”, which for instance Scott Meyers mentions both in 97 Things Every Programmer Should Know (Chapter 55) and Effective C++ (Item 18).
If you need to provide both a safe and an unsafe version of a function, make the safe version the easiest to use. In this case, instead of just adding the new function, I renamed the old function write_raw()
, and made a new, safe function write()
that wrapped write_raw()
.
In a few months, someone unfamiliar with this API will come along looking to write something, and will most certainly use write()
after skimming through the API. He will now be defaulting to the safe version, if he wants raw access he will need to dig a bit further.
And that someone might just as well be myself.