Fun with Programming

February 2, 2004

This one's going to be full of computer-related stuff. If you know what I'm talking about this may bore you. If you don't do this on a regular basis you probably won't care.

There are a few things in the client site that I'm not entirely pleased with, even though they work well enough as they are. In the interest of getting things done quickly I made a lot of closely-related functions instead of one general-purpose function. I don't really like that -- things are harder to find, and the pages take a tiny bit longer to load on the server since the includes are larger.

I have a few options, the most tempting of which is to just blow it up and start over. Not the best choice by a long shot though. The easiest choice is to just leave it alone, but that has its own problems, like having a lot of redundant code sitting around.

Which leaves a gradual rewrite. The methods change a little bit depending on which programming language you use, but the basic idea is the same: Change as little as possible and switch everything else over when you can.

As an example, right now I have a function called reQuote that fixes up information coming out of a database. It has two functions that look a lot like it: reQuoteNoP, which ignores paragraph breaks, and reQuoteRTE which populates rich-text editors, like IE users see in Hotmail. About 2/3 of the code is similar, and they should be the same function, but it was just easier to hack out three copies and move on. Now I want to fix that.

First rule: reQuote should keep the same functionality during the rewrite. In Java this would done by overloading, or writing a function with the same name but different parameters. In PHP, though, this is done with optional parameters. I add a parameter to the end of the list and assign it a default value. As long as I make the default value what will make reQuote do what it does now, I'm living up to the first rule.

Second rule: Make the code as easy to follow as possible. If my options are to do A-D-E, B-D-F or C-D-G, then I should write something like
if (option 1) {
    A; D; E;
} elseif (option 2) {
    B; D; F;
} else {
    C; D; G;
to take care of it, instead of writing an if-elseif-else for the first step, writing the second step, then writing another if-elseif-else for the third step. That may be more correct (saving duplication of D) but I think it causes more problems than it solves.

Third rule: Test as you go. Once the new version of reQuote is working, add options one at a time and test one at a time. Once reQuoteNoP's functionality is duplicated and verified I can do a global search and replace, but there's no sense in breaking everything until it works right. Ditto for reQuoteRTE.

Fourth rule: Decide on optional parameters. Once everything is under the new-and-improved reQuote's control, decide on whether the new optional argument stays optional. In Java it's not such a hot idea since you handle "optional" arguments with overloading, so you're still writing and maintaining two copies of your code. PHP makes it easy to keep optional parameters though, and sometimes I use them. My dividing line is how differently the function acts with each parameter. In this case all the work reQuote does is about the same so I'd make the parameter required. If you go that route make sure you add the parameter to each call of reQuote before making it required, then test each page to make sure it's not broken.

In some cases, though, it makes more sense to me to keep a parameter optional. In the client site I did, I have a function called checkAdminAccess. Its first parameter is a particular bit of SQL to check, specific to where you are in the site: Does the user have access to modify users? To create a new project? That parameter is optional; when it's not present the function checks every single admin permission, essentially asking if the user should be there by any stretch of the imagination. I did that because as the project goes into later phases, there will be more admin functions, and a wider range of people will be able to see the list. Keeping that inside the function lets me change it in just one place.

The second (also optional) parameter determines what to do if the check fails. In some cases, simply failing is OK. I don't show a portion of a page and the user is none the wiser. But when the parameter is absent a failure redirects to a "permission denied" page. Since the action is so different I felt justified in making it optional.

Fifth rule: Once you're done, don't throw out the old code. Cut-and-paste it into a new file with a useless extension (maybe call it "old.code") and keep it nearby in case you ever need it for something. Dreamweaver, which I learned to like once I got it to stop "helping" me, lets you filter out files by their extension when you do an update; adding ".code" to its ignore list keeps your junk code off the server.

And that's all. Well, if you're a non-programmer, congrats on making it through that crap. If you are a programmer, feel free to tell me why I'm wrong :)

January 30, 2004February 3, 2004