Monday, September 27, 2010

Here's a bug that I recently came across. I didn't figure it out, and it wasn't code I wrote, but it is an example of gratuitously bad code.

Originally, I had written some code for a quick-and-dirty demo that went something like:
    packetType = readPacket(input, buffer);
switch (packetType) {
case TYPE1: parseType1(buffer); break;
case TYPE2: parseType2(buffer); break;
...
}

where readPacket() read the appropriate number of bytes into the buffer depending on the packet type. Something like:
   packetType = input.read();
if (packetType == TYPE1) {
read some stuff into buffer;
} else {
count = input.read();
read count bytes into buffer;
}
return packetType;


Somewhere along the line, in a change in source control that was something along the lines of "update to the latest protocol", there were a number of changes, including gratuitously changing the code from something like the above, to something like:
    packetType = readPacket(input, buffer);
switch (packetType) {
case TYPE1: read more stuff from input; break;
case TYPE2: parseType2(buffer); break;
...
}

and readPacket() was changed to
    packetType = input.read();
if (packetType == TYPE1) {
return packetType;
} else {
count = input.read();
read count bytes into buffer;
}
return packetType;

which all would have worked fine, even though it was a stupid and gratuitous change, except that there was another place that called readPacket(), but ignored the packet. So, if that other place called readPacket() and got TYPE1, the packet wouldn't be fully read, and subsequent calls to readPacket() would return garbage. I don't know what the thinking was behind changing the code like that.

Monday, September 20, 2010

One component of this demo that I'm working on is a server in C++. The guy who did the work on it was laid off 5 months ago, and now I have to add crap to it. Most of it was 3rd-party code. I don't know what changes have been made to it, since it was checked into source control in one big chunk 9 months ago. However, there is one directory that has our specific configuration files and build and startup and shutdown scripts.

I found the build, startup, and shutdown scripts kind of annoying. They all assumed that the scripts would be run from the directory that the script were in, which I don't like to do. I prefer running /absolute/path/to/the/script, rather than cd /absolute/path/to/the, then ./script. So I added cd `dirname $0` to the top of all the scripts. Another goofy thing in the scripts were the use of pushd somedirectory >/dev/null, and then popd >/dev/null. Personally, I use directory stacks interactively all the time, and often have 3 or 4 directories that I switch between, but, for the script, cd somedirectory, then cd .. would work just as well.

As for the C++ server, I had to add a feature, which I did. And it worked some of the time, but mysteriously didn't work some of the time. There was a logging framework that I tried to use, and I spent a day trying to use it. When I tried making a new logger class, and tried enabling it, the server crashed. Finally, I just hacked in some code that fopened a file, and vfprintfed crap directly to it, and figured out that I had added an uninitialized variable to a class, and, depending on what value it had, the feature worked or didn't. So I fixed it by initializing it in the constructor.

Monday, September 13, 2010

There is some demo code at work that's been around for around 10 months, and I've added various features to it from time to time. Also, from time to time, the deployed code has to be put in a "known state" to actually do the demos. A month or two ago, some other guy added a feature, which makes the user interface fancier, so his changes need to be in all the demos, but he never checked anything into source control. Since then, I've added some features, all of them checked in. So now when there is a demo, this guy has to merge my changes into his code and then deploy it on the demo system. Except that what has actually happened is that they go back to the code that he originally deployed over 3 months ago, which doesn't have any the features I've added, which include changes that make the platform more robust. I can't deploy the demo including his features because I don't have his code.

One of these days, I'm going to ask him why he doesn't check his crap in.

I don't understand how some people can work on stuff while rarely interacting source control. I update my source trees often. I update before starting work. I merge in changes periodically during work. I merge in changes when I'm ready to check stuff in. I check stuff in when I'm done working on it.

Monday, September 6, 2010

There has been a bunch of attrition at work, so I have to help taking over some Android code. So, to learn the Android platform, I decided to make a sample application that receives incoming SMS messages and send them through the text-to-speech processor. I put the code on github. I managed to get it to work on an emulator in a couple of days, as the Android platform is pretty easy to learn and pretty well documented. I haven't tried it on a real phone, since I wrote it for Android 2.1, and phones at work run Android 1.6.

The one thing that I had problems with was the service lifecycle interfering with the asynchronous text-to-speech interface. My ugly solution was to have the service post an empty intent to itself while the text-to-speech was still speaking to keep the service alive, since the text-to-speech instance would have been considered leaked if it isn't shutdown when the service is destroyed. If I continue working on Android applications, I'll probably find a better way to do it.