Saturday, November 17, 2007
Share the Wealth
The day I left I cleaned out the CVS directories in my local copy of the directory tree, zipped it up and emailed that zip file to him. I didn't want to give him the CVS repository itself because I didn't want to confuse him any more than necessary.
I also changed the password on my email (Lotus Notes) and made sure that all my emails had been put into my local email database. I then gave him a copy of that database along with the password and made sure that he could open that local database on his machine. He looked at me, slightly puzzled, and asked if there weren't emails that I didn't want him to see. I told him that I knew from the day I started that these emails were really property of the company and they didn't belong to me. I never, therefore, used it for any personal purposes or sent any emails that I wouldn't want "read out loud in the town square" (to quote my brother-in-law).
I don't know if he ever actually looked at any of this, or whether he considered it wealth or dross. I did, however, feel better leaving the information with him, rather than letting it be wiped when my work machines were returned to the company pool.
Sunday, November 11, 2007
The "Dead Leaves" Guy
I've always gotten along well with our next door neighbors, who have been there for more than a decade. Last weekend I noticed the husband up the roof of his garage, merrily sweeping the oak leaves into the space that I have been squeezing into all these years. He looked a little sheepish, but said he had been doing this all along. I told him that if I hadn't been cleaning them out, we would have had oak trees trying to grow between our buildings. I then assured him that it was OK with me, and we went to our various tasks.
I have also been cleaning out a lot of "dead leaves" that others have put into our code at work. I am concerned when I see code that is so obviously cut-and-pasted instead of refactored. I sometimes wonder what people think when they are doing this. Are they concerned because they don't understand the code well enough to do refactoring? Are they too overloaded to think about the fact that what they put in may sprout into oak trees in the worst possible place? Are they too rushed to think a few months down the road, or a year or two?
It concerns and mystifies me.
Wednesday, October 24, 2007
Glosses on Linus Torvalds Coding Style
I strongly agree with almost everything said in this document, and have been glad for the "backup" when I've had to argue a point with some of my fellow workers. There are, however, a couple of items where I diverge.
The first point that I would gently argue is that 8-space tabs are too deep. I haven't "been looking at [my] screen for 20 straight hours" for a couple of years, but at the very outset I worked with 4-space tabs, and I find them very readable. I haven't worked with anyone who has strongly defended 8-space tabs. I will admit that I have had to try to persuade people to switch from 2-space to 4-space tabs, but that was back in the Apple ][ Basic days when people were trying to keep their programs as small as possible (remember cassettes?). I don't know of any readability studies on this topic, and would be interested to see them.
My second argument (or shall I say "disagreement" to be less disagreeable...) is with his distaste for mixed-case names. I find mixed-case easier to read (maybe it's just me), but, more importantly, I find it a lot easier to type than underscores. I know I'm not the best touch-typist in the world, but I always find myself looking down to make sure that my ring-finger is indeed hitting the dash/underscore key and not one of its neighbors. Using camelCase keeps my fingers on the home row much more, makes my typing faster and reduces the number of errors.
These are just friendly disagreements, however, and don't diminish the fact that I'm glad this document exists, and is available to us all.
Saturday, October 20, 2007
Pythonics Anonymous
When I first looked at Python a few years ago I was put off by the fact that white space was significant. I also thought that having to do "self." to indicate object fields (vs. global variables or parameters) was just noise. I got tired, however, of always looking up Perl syntax, and I really didn't care for the Perl TMTOWTDI (I prefer one good way to do things, not many). I then came across Eric Raymond's article and decided to learn and use Python.
Now, after a few years of working with the language I appreciate the fact that white space is significant (no more bracket-placement wars!). I also appreciate the cross-platform-ability and the fact that (even though it is open-source) it isn't GPL, which has allowed us to use it at a company I used to work for. I like having the various supporting packages (although the minidom has a problem when pretty-printing XML that I had to work around).
However, I now find myself thinking that I'd better go back to Java. I was put off Java because the reality took a really long time to catch up with the hype. Remember "Write once, run anywhere?" (which was really "Write once, debug everywhere?") It also seemed too heavyweight to me. I liked being able to run the Python interpreter in command line mode and experiment without having to fire up an editor, create files, save them and run them. It was also satisfying to be able to be able to write a one-line "Hello World".
It seems now, however, that the world (at least the world of enterprise software) has decided that It's A Java World. I guess I better get back on board. I know I'll fall off the wagon occasionally, but it's time to put Python back in the corner and get back to business.
Tuesday, October 9, 2007
Data Always Goes In A Database, Right?
I have worked on a number of software products where data (usually metadata) is stored in text or binary files. The code opens the file, reads from the file and parses the text (if necessary) into the structures used internally by the code. Over the years, the question has been asked more than once: why don't you put this data into a database?
There are a number of reasons not to use a database. First, all the data needs to be in memory for performance, and there is no advantage to keeping parts of it out on the disk. Second, the data is usually not appropriate for being "table-ized." That is, the data is complex and tree-structured rather than row-structured. I know that one can always flatten data into multiple tables with the appropriate keys and joins, but parsers built with tools such as Yacc and Lex will always be faster than doing multiple database joins and reads.
A third reason is that upgrading the data in the database requires scripts to add or modify tables or columns (deletes not being done to reduce the potential for referential integrity problems). Parsers can recognize a version number and do an upgrade-on-read, which doesn't require another program to run to perform the upgrade.
Fourth, files are easier for end-users to handle. For example, if a user needs to send some of his data to tech support, it's much easier for him to package up one or more files, rather than having to run some database dump utility and send the dump file. There is also no issue with (once having that database dump) the possibility that tech support does not have the particular version of the database software that the user is running.
A fifth reason (for text files at least), is that in a pinch the file can be opened and edited in a text editor if there are problems with it. With a database you have to run the appropriate database client software, then tease out the table relationships to understand where changes need to be made.
When all you know how to use is a hammer, everything looks like a nail.
Saturday, September 22, 2007
Fail Early (But Not Often)
My primary principle is "The earlier the failure, the less the consequences." For example, if I didn't check the return code on a file open, the code would merrily continue on and try to write to the bogus file descriptor returned from the "file open". Most current operating systems give you a bad handle error, but earlier ones would just return junk at best and might do something grotesque to the file system at worst. Also, the code has probably already gone past the point where it can put up a coherent error message that includes the filename and system error code. This the leads to my second principle about failure handling, which is: "The better the error message, the less tech support hates my guts." One annoying error message that I've had to deal with (as an end user) is "The [someLibrary.DLL]
Most contemporary programming languages have some sort of exception mechanism to help me write code to handle failures. In a language like C++ where I can throw just about anything, I create a superclass designed to handle failures (subclassed as appropriate) combined with a macro that catches all possible types that any code in my executable might throw. As long as I put my catch blocks in the right places (e.g., at the top of a thread or in top-level event handlers) I can return errors without bad side effects. Java, on the other hand, will only allow me to throw descendants of Throwable, which removes the need for the "glue" class and macro that I described for C++, but adds the complexity of having to deal with multiple subclasses of Throwable. There's no such thing as a free lunch.
What if I am working in a language that supports exceptions, but I am using some API that doesn't? For example, suppose I needed to use fopen (the low level 'C' routine) while working in C++. In this case I always check the return code from that call (as well as all other file system calls). If an error is returned from any of those calls, I convert it into a coherent exception and throw that exception.
To move farther back in the evolutionary ladder of languages, what happens when I am working in a language (such as shell script) where there is no exception mechanism at all? Here I check for errors after every possible line of shell script that can possibly fail ("assume the worst"). I keep the code readable by putting the status check off to the right of the "meaningful" code. This means that when I read the code I can concentrate on what it should be doing in most cases, rather than the edge cases of failure. For example, this shell script contains a shell function that displays an error message, the name of the script and how to get instructions for running the script.
Note that the error might not be caused by inappropriate usage, but this at least gives the person who ran the script something to see before reading the code in the script.
In the spirit of continuous improvement, I've tried moving the status test down into the shell function, but I discovered (at least on Cygwin) that making the function call changes the global status variable ($?). I even briefly considered doing something like this where the _chk_ function runs lines of script and then checks the error code.
_chk_( 'first line of script' )
_chk_( 'second line of script' )
I rejected this, however, because (a) the noise level is too high, and (b) I had serious concerns about quoting problems within each line of shell script code.
Sometimes you have to know when to stop refactoring.
Tuesday, September 11, 2007
The Two Commandments of Blogger
- Don't copy and paste from anywhere else, unless you have no special formatting such as lists or fonts. If you do, you will end up retyping your post anyway because Blogger incorrectly converts the formatting. I have tried this from a number of different sources including Google Documents and somehow the text after lists always ends up with the wrong linespacing.
- Don't trust the preview. In scenario above, the preview looks fine. When I post, however, the linespacing is messed up and I have to "Save as Draft" to pull the post and re-edit it. This happens in both Firefox and Internet Explorer.