Saturday, January 31, 2004
Stick with the Defaults
"It crashes in the call to bpGetStatus()."
"Do you have structure-packing set to 1?"
"Uh, no. Let me try that..."
Five minutes later:
"OK, now it crashes the output routine."
"Are you using the standard library?"
"You need to use the Gee-Cool-Whizzy port of the STL. I'll e-mail you the URL."
"OK, I'll try that..."
Don't do this to people. The default settings for many compilers and IDEs are perfectly reasonable. If you are going to use some bizarre settings, write up a document or something to explain what other have to do (and explain why while you're at it). The rest of us will appreciate it.
But even better, don't use bizarre settings. I've never understood why some people go to such lengths to find what they consider to be the perfect set of compiler flags for their particular application. If proper operation of the program depends upon some strange set of compiler options, then it is almost certain that the programmer is doing something (a) non-standard, (b) tricky, (c) incompatible with other people's code, and (d) that is going to break when moved to another platform or another compiler. If proper operation doesn't depend on a strange set of compiler options, then why use them at all?
There are exceptions to this rule. For example, Visual C++'s default settings are to statically link to a single-threaded version of the C++ runtime. For real work, almost everyone uses dynamic linking to the multithreaded DLL. But this is not really an exception: if everyone uses the same non-default setting, then you can consider it to be a standard.
Whenever you are doing something that nobody else does, and which makes life more difficult for everyone else, you really need to ask yourself whether you are doing the right thing. Usually, the answer will be No. Sometimes following the herd is best for everyone.
Sunday, January 25, 2004
C++ Testing Frameworks
I've always rolled my own unit-testing frameworks for C++. I don't like CppUnit, because it is too Java-like and not C++-like. It has always been easier to throw together what I need than to try to figure out someone else's framework. I can throw together the basics in ten minutes, and then evolve the test rig as necessary.
So I'm not really sure why I decided to re-examine off-the-shelf frameworks for my current testing needs. I guess it comes down to a desire to learn something new, and to make sure nobody else is doing something smarter than I am.
After looking around, I settled on the Boost Test Library. What I like most about this library is that it can be used by simply #include-ing a header file; there is no need to build a library and link to it. The Boost Test Library worked out-of-the-box. The only special thing I did was to use a debug output stream so that the output shows up in the Visual C++ output window. The output format makes it possible to double-click a line in the output window and VC++ will open the source file and go to the source line. There is no need for a TestRunner-style GUI.
I also ran across Michael Feathers's CppUnitLite. He created this as a reaction to the bloat of CppUnit. CppUnitLite is intended to be just a simple example of a testing framework, which should be modified and extended as necessary by its users. While I like the idea of using a simple barebones framework and modifying it as needed, CppUnitLite still seems too complex to me.
I think that C++ unit testing is one of those things where an off-the-shelf framework never seems right. I've come to believe that small off-the-shelf frameworks are a bad idea. The smaller the framework, the less it does for you and the easier it would be to roll your own that does the job better. Only really big frameworks (MFC, etc.) provide enough value to justify spending the time to learn them. C++ unit testing is just too easy to justify learning a framework.
But I'll keep using the Boost Test Library for now. I hope I'll learn something in the process. Using an off-the-shelf library might help me to "test-infect" my co-workers.
Friday, January 23, 2004
I have a sudden need for a store-and-forward mechanism for a C++ application I'm working on. I'm sure countless others have done this, and there is probably an off-the-shelf solution somewhere I could use, but I have decided to implement one from scratch.
I did spend some time on Google trying to find something that would suit my needs, but none of the hits gave me a good feeling that I would actually save any time or effort by using an off-the-shelf product. I have to have this feature implemented in a couple of days, or the world is going to end (or so customer believes), so I don't have a lot of time to figure out someone else's product, and I definitely don't have time to wait for a bug fix. So I've satisfied myself that I am not reinventing the wheel without good reason.
The buy-vs.-build question is one that comes up often, and I am never satisfied with my decision. I was once strongly in favor of "buy", but after being stung by many low-quality products over the years, I now tend to believe I can usually do better by myself.
The best thing about doing it myself is that the solution will be specifically designed for my use. I don't have to learn how to manage all the various configuration parameters that a generic off-the-shelf "solution" would have. I don't have to worry about whether it will be compatible with my compiler, my OS, and the other libraries I am using. I don't have to figure out whether it is thread-safe, or how it manages memory, or how to properly initialize and terminate it.
And of course, doing it myself is a lot more fun.
Sunday, January 18, 2004
Pay Me What I'm Worth
Recently receiving a nice raise got me thinking about the relationship between work and financial compensation.
Some people claim that high salaries encourage hard work. Maybe it does for some people, but it doesn't work that way for me. My work ethic has little to do with how much I am being paid, or how high my taxes are. I've always felt that if one has accepted a job, one does it as well as possible. I expect to be paid well because I do a good job; I don't do a good job because I want a raise. If I'm not being paid enough, I may quit, but I won't slack off.
I know people who obsess over exactly what percentage their raise was, and how that compares to others' raises. During the 90's, I was getting raises of 20%, 25%, or more per year for a while. Those raises were so ridiculously high that I will probably never be able see any raise as being indicative of my abilities; they are more a reflection of how well my employer is doing, and how much clout my manager has.
I have never chased after maximizing my income, but have been fortunate to receive nice salaries. Making lots of money has provided a counter to Imposter Syndrome. My work must be providing some sort of value, although I've never figured out exactly what it is. So for me, salary is symbolic of approval and respect.
As long as I'm being paid "enough", I don't worry too much about salary. I just want to feel that I am being paid what I am worth, and right now, I think I'm being paid a lot more than I'm worth. (But please don't tell my boss.)
Tuesday, January 13, 2004
Software and Hardware
Charles Miller had an amusing blog entry about the hazards of computers. I am currently working with development of embedded systems software, so I spend a lot of my day plugging and unplugging PCI cards, comm ports, etc. My hands are covered with little scratches, cuts, and punctures.
Computer programming is supposed to be a cushy intellectual job, but it's amazing how much physical labor and torment programmers go through. RSI and sore backs are common. Electric shocks are common as well. We have to crawl around on floors to figure out which cable is connected to what. We've all over-strained ourselves carrying around big CRTs and servers. Many of us have had equipment racks fall on top of us. Incidents like these stress the importance of the first syllable of hardware.
I've heard that there are some programmers who never have to deal with hardware. The computer is off in some other room somewhere, and it is someone else's job to keep it running. Somebody else installs the device drivers, and configures the networks, and connects the keyboards and the monitors. I've always felt that these programmers are somewhat like the ivory-tower academics who never have to deal with the reality of computers. Without playing with the hardware, how can one really appreciate what the software does?
Sunday, January 11, 2004
Helicopters and Simulations
I've always been fascinated by helicopters. The way they float in the air, and the throbbing "chop-chop-chop" provide a Zen-like experience for me, where I can stop thinking and just experience the helicopter overhead.
Actually learning to fly a helicopter would be nice, but I'm not willing to devote the time and money required to do so. But I like models. When I was a kid, I spent many hours/days with the Mattel VertiBird toy helicopter. I looked into RC helicopters a few years ago, but at the time they were very expensive and lacking in capabilities.
A couple of months ago, my interest was re-kindled when I ran across some small electric RC helicopters designed to fly indoors. This is perfect for me; I am an apartment dweller, and I don't have wide open spaces available for larger RC aircraft. The thought of flying a small chopper from room to room intrigued me. I put in on my Christmas list, but I guess my friends and family didn't want to spend several hundred dollars on my gift (cheap buggers). So I guess I'm going to have to buy it myself.
While reading various online pages about the mini-helicopters, I noticed many recommendations to "use the simulator" when learning to fly. At first I was amused to find out that there are flight simulators for model aircraft, but it does make sense. A crash of a model can require expensive repairs (both to the craft and to whatever it hit), so a safe simulation is important. So I've bought the simulator. I hope to have several hours of simulated flight time under my belt before flying the real model helicopter.
So, my interest in real helicopters led to an interest in model helicopters, and that in turn led to an interest in simulated model helicopters. I'm definitely moving between meta-levels here. My only regret is that neither the model nor the simulation is going to provide a satisfyingly thunderous "chop-chop-chop". I guess I'll need a simulated digitized synthesized sound effect for that.
Saturday, January 10, 2004
What Can One Person Do?
I'm all in favor of teamwork. I like the sharing of ideas, the leveraging of individuals' skills, and the camraderie that comes from working with other people. However, I notice that a lot of my work habits are focused on insulating myself from others.
It's not that I avoid other people, or that I try to keep them away from me. Rather, a lot of my habits are focused on eliminating any dependence upon others. I keep everything I can on my own machine, in case the network goes down. I keep my own backups of important files. I know how to set up the server software on my own machine in case the real development server goes down or gets funky. When something breaks, I tend to fix it myself and then notify others later, rather than co-ordinating with them first.
While this self-reliance and initiative keeps me out of a lot of jams, I wonder if it interferes with teamwork. Would we work more closely together if we were more dependent on one another? Are we each doing a lot of redundant work to keep ourselves self-reliant?
Being dependent upon others is a little scary, as is having others depend upon you. You never know how they might unintentionally mess you up, and there may even be a few who will do with it intentional malice. But I have learned that I can trust others. If I ever think I can't trust my co-workers, it will be time to find another job.
Even with that trust in others, I am going to continue my self-reliant habits. Groups don't really accomplish things; individuals do, and I want to be an effective individual.
Friday, January 09, 2004
Reading Beginners' Books
I am reading the Pragmatic Programmers' new "Starter Pack" books. Most of the content is nothing new to me, but I always enjoy reading good books about the basics.
I like seeing things put simply. The real world is rarely simple, and we forget how following a few easy-to-understand principles can help de-complexify things. Reading beginners' books reminds me that while software development can be chaotic, it can be kept under control.
Reading well-written books for beginners gives me pointers on how to better explain the concepts to beginners (or to non-beginners who shoud know better). Sometimes I even learn something new myself.
Reading beginners' books reminds me of my youth. I remember where and when I first learned these things. I try to remember what I did before I learned the lessons. I remember how I learned the lessons - generally, the hard way. I remember my teachers, mentors, and fellow students. I remember the time when writing a linked-list was the most challenging thing I had to do.
The danger of reading a book for beginners is that it sometimes gives me a false sense of mastery. "I already know everything in this book, so I am no longer a beginner," I think, or "See, it really is just that easy." But those false feelings don't last for long, so I don't think that indulging in them once in a while causes any harm.
Of course, the best thing about a well-written beginners' book is that it is a well-written book. Such books are so rare that they should be celebrated whenever they are found, no matter what the subject matter or level of expertise required to understand them.
Joseph Pelrine notes that "as Alistair Cockburn rightly states, 'simplest' has no metric. It is not a quantifiable amount." While it is true that one cannot put a number on it, there is an obvious test: you have the simplest solution if nobody can think of anything simpler.
Of course, different people have different ideas of what simple is. For example, C++ templates provide simple solutions to many C++ problems, but many C++ programmers will consider any use of templates to be "complicated". (And some would say that C++ provides no simple solutions for any problem!) Similarly, some prefer break up a class into many small classes to make things simpler, whereas others think that a small number of big classes is simpler. Who's right?
Ward Cunningham wrote somewhere that his definition of simple is whatever is easiest to reason about. I would add that it is also whatever is easiest to communicate to others. If you are trying to explain your "simple" solution to others, and they don't get it, that is a good sign that you haven't really found a simple solution. The reason that XP advocates simplicity is that simple code is easier for somebody else to understand and to modify in the future.
So, when judging the simplicity of a solution, it is important to remember that you are writing code for an audience. You have to make some assumptions about that audience. Do they understand the language features that you are using? Are they going to understand the idioms? Does the code you are writing fit in with the rest of the project's code in a way that will make sense to them?
Always remember that the value of simplicity is that it makes future change easier. The simplest solution is the one that will be easiest to replace.
Thursday, January 08, 2004
JacksOrBetter is a video poker game I wrote for Palm OS. After spending a couple of hours playing KDE's KPoker one night, I decided I wanted to be able to play it on my PDA.
I developed JacksOrBetter using Quartus Forth. This was my first "real program" written in Forth. When I look at the code now, there are a lot of things I'd like to redo. But the code has been stable for over three years now, so why mess with a good thing?
Obviously, a video poker game isn't rocket science. The most challenging aspect of it was developing the scoring algorithm, to determine whether the hand contains a pair, a full house, a flush, or whatever. I wanted to design an algorithm that was simple. What I came up with was this:
- Initialize a thirteen-element array of "rank counts" to zero.
- Initialize a four-element array of "suit counts" to zero.
- For each card in the hand, increment the associated rank count and suit count.
- Use the rank counts and suit counts to determine the hand score. For example, if any suit count is 5, then you have a flush; if any rank count is 4, then you have four of a kind; if the rank counts contain a 2 and a 3, you have a full house; and so on.
I originally released it under the name "Videopoker". A couple of days after releasing it, I discovered there was another commercial game for Palm OS with that same name, so I renamed it. Luckily, nobody complained or sued me.
I released the code for free, under the GPL. It has had tens of thousands of downloads from PalmGear, Handango, and other outets. It was rated pretty highly. I often wonder how much money I could have made by charging $5 for it, but it is nice to know that a lot of people are enjoying it.
Update: Now available: JacksOrBetter for iPhone.
Wednesday, January 07, 2004
Why Bother with .NET?
Someone asked me "What's the big deal about .NET? Besides the fact that the Microsoft world is steering that way and so knowing it is probably a good career move. Is there a specific problem that it solves that I couldn't solve as easily with, say, Ruby or Perl?"
This is a question I asked myself a lot while studying for the MCSD exams. The conclusion I came to was that the primary value of .NET is that it provides a better way to write Windows programs than C++ or Visual Basic.
Over the years, I've learned that the best thing to do when developing for Windows is to do it Microsoft's way. Third-party libraries and development tools always end up "breaking" at some point because Microsoft changes an API or doesn't provide sufficient information to other vendors. When using non-Microsoft tools, it always seems like I spend more time working around incompatibilities than getting my job done. So I try to stick with Visual C++, MFC, COM, ODBC, etc., and nobody gets hurt too badly.
So, now Microsoft provides a Java-like development platform, and is going to be integrating it more tightly with the OS as Longhorn comes together. What I've read in the Microsofties' blogs leads me to think that things are generally going in the right direction. This is good in that C++ is no longer the best way to write Windows software. Knowing .NET lets me write better Windows software.
But aside from its ties to Windows, is .NET "better" than alternatives? No. It has some very nice features, but I'd rather be using Python (or Ruby, or Scheme, or Squeak, or ...).
It's not that those other things are "better" than .NET. A lot of people knock .NET because it is not innovative, and that it is just a collection of features that have been better implemented elsewhere. I actually find the non-innovativeness of .NET to be comforting. The fact that Microsoft is "stealing" a lot of good ideas from other places and isn't trying anything too radical suggests to me that .NET is going to be a pretty usable framework. I don't want innovation; I want something that works.
The big drawback to .NET is that it will always be a Microsoft-specific technology. Despite the efforts of open-source developers, I don't think there will ever be an industrial-strength non-Microsoft implementation. I'm not going to be able to run my .NET code on Linux, or Solaris, or QNX Neutrino, or Palm OS, or another of the other operating systems I develop software for.
Is it worthwhile to learn about .NET? If you develop Windows applications, then I would definitely recommend it. If you don't develop Windows apps, then you may want to study .NET to see how the approached issues differently from other platforms' designers. But I can't find anything in .NET that makes me say "Wow! This is exactly what I've been waiting for!"
Tuesday, January 06, 2004
I committed several developer sins today. (Actually, I only committed a couple today; the others were committed in the past but came to light today.)
First, I assumed that the bug was in the other guy's code. I was sure there could be nothing wrong in my simple straightforward object-oriented code, so it must have been in his quagmire of multi-threaded straight ANSI C. So I spent most of my time trying to read his code instead of examining my own more carefully. I cursed him for not providing documentation or unit tests.
Second, I put off as long as possible the arduous task of reading through the voluminous logging information his code generated. After all, if he is a bad programmer it stands to reason that his log will hold only useless information. When I finally did read through the log, it became clear that the code I had copied-and-pasted from another program was doing bad things.
Yes, that was the original sin: I copied-and-pasted code from another program without reviewing it sufficiently. I know it's wrong. I scream at people when I see them do this. But it was the easiest thing to do at the time.
And when i discovered the copied-and-pasted bug, my first instinct was to curse the name of the writer of that code I had copied. But of course, he does not deserve my ire. The real culprit is my boss, who suggested that copying and pasting was the fastest way to get the feature implemented! No, that isn't right either. I committed the act; it is my responsibility.
I keep thinking I am getting better at this stuff. I think I have better habits than others. I only break my own rules when I think it really won't hurt anything.
I am ashamed. I ask forgiveness.
On Being a Microsoft Certified Solution Developer
I earned the Microsoft Certified Solution Developer for .NET certification last year. My resumé is mired in C++ and CORBA, and I wanted something that would indicate to potential employers that I could do something else. I missed out on the Java bandwagon, and couldn't compete with the junior Java developers with 3+ years experience who would work for $25/hour. So I thought being an MCSD might get me in early on .NET development.
The tests weren't the cakewalk that I had been led to believe by the detractors of Microsoft's certification program. I agree that the tests don't provide a good indication of whether a candidate would be a good developer, but they do indicate that the candidate has an encyclopedic knowledge of the .NET API and the features of Visual Studio .NET.
The architecture exam, usually considered to be the toughest of the MCSD exams, was the easiest one for me. It was the one exam where careful reading and common sense would get you through, rather than a lot of rote memorization.
Getting the MCSD didn't help me much in getting a job. I suspect it is actually considered a black mark by those who believe anyone taking Microsoft's tests must be a clueless, mindless drone.
I think that studying for the exams did help me to learn some things about .NET that I would not have learned otherwise. The exam guides gave me a plan for learning .NET, rather than just stumbling around randomly. So that is what is of most value to me: the learning, not the piece of paper.
Saturday, January 03, 2004
The most significant personal change I've gone through in the past few years is an increase in my assertiveness. I am a very different person from who I used to be, due to this change.
I am a stutterer. That, coupled with natural introversion, caused me to grow up avoiding any situation where I had to talk to anyone. Many people fear speaking because they think they will sound stupid, but a stutterer knows he will sound stupid no matter what he is saying. All through childhood and college, I avoided any role or situation that required me to speak up.
I was able to keep my mouth mostly shut for several years when I started working. I only had to talk to my boss and a few co-workers. So I was able to get things done, but I shied away from any roles or situations where I would have to speak my mind to people outside that circle. I also avoided looking for better jobs, because I dreaded the interview process.
Then, I got promoted. I was put in charge of development of an important project. I faced a crisis: my job now required me to speak to clients and higher level managers, and to tell other people what to do, but I didn't think I could do that. I considered all sorts of ways to avoid those responsibilities, but none made sense. So, I just decided I would just do it, because it was my job.
And a funny thing happened: it learned it was surprisingly easy. I asked people to do things, and they did it. I explained technical issues to clients, and they understood and believed what I was saying. I talked to those scary upper-level managers, and they turned out to be pretty cool guys who trusted my judgment. All my fears had been unfounded.
It makes me a little sad to think about all the missed opportunities I had before learning this simple lesson at age 35. I wish I had gone out and played with other kids instead of sitting in my room reading books. I wish I had taken advantage of everything that was available in college, instead of just sitting in the back row, keeping my mouth shut, and passing the tests. I wish I had talked to more girls when I was in my teens and twenties. I know there's no going back, so I just have to console myself by realizing that I won't have to miss future opportunites. I think I've finally grown up.
After my epiphany, I now have little sympathy for programmers who complain that their managers don't let them do what they want. Managers aren't stupid; if you think you have a good idea, then tell them about it and fight for it. If you don't like your job, then go get a better one.
Having become assertive myself, I have a greater respect for other assertive people. I once thought people like that were just arrogant jerks, but now I understand that they are just fighting for their beliefs and ideas the same way that I am. I would much rather argue with another intelligent assertive person than to try to talk to someone who just agrees with everything rather than presenting their own opinions.
I hate to sound like a motivational speaker, but this is the one lesson I've learned that I want to share with the world. If there is something you want to say, then say it. If there is something you want to do, then do it. Nobody else is going to say and do these things for you. The course of your life is up to you.
Friday, January 02, 2004
The Making of ...
When I was a kid, I really liked the "Making of Star Wars" and similar documentaries that gave behind-the-scenes looks at the production of movies. These days, the "Making of ..." pieces are really just ads for the movies, usually being released before the movie itself.
But we have DVD commentary tracks. That's my favorite part of owning a DVD player: being able to hear commentary from the directors, producers, writers, and actors in movies. A lot of what they say reminds me of software development. My favorite parts are when they discuss what they would have done if they had more time and money, and make their complaints about stuff that wound up in the movie but they really don't like.
(By the way, if you liked the movie Fight Club, then you've got to listen to the commentary tracks on the DVD. Best commentary I've heard.)
I also enjoy "Inside the Actor's Studio" on the Bravo channel. Hearing actors talk about their craft, how they learned it, and how they continue to study it inspires me to continue improving my knowledge of my craft.
Commentary from software developers about their projects would not be as entertaining, but I wish we had such a thing. "The Making of Windows", as told by its developers, would certainly have some interesting bits.
Thursday, January 01, 2004
Giving The Lord of the Rings Another Chance
I didn't like The Lord of the Rings when I read it as a teenager. I loved The Hobbit, but Rings just bored me. It had too much singing and story-telling, and was just too long. I lost interest before finishing the first volume, so the other two volumes were a long slog. I had to read it because of peer pressure (I got tired of hearing "What, you haven't read the Rings trilogy?"), but it was a lot like reading books my teachers assigned.
After seeing the three Rings films, I am ready to give the books another chance. The films were entertaining, and have given me enough knowledge of the story and characters that I can read the books without losing interest. I hope to enjoy all the stuff that didn't make it into the movies, and to be able to say something intelligent when I get trapped in one of those stupid "The movie wasn't like the book" conversations.
Who knows? If this works out, maybe I'll give that horrible Dune series another chance as well.