Schlueterica Just slightly more than my twitter stream. 2015-11-20T19:09:00Z WordPress Isaac <![CDATA[This site is dead]]> 2015-11-20T19:09:00Z 2007-06-07T01:17:12Z My domain name is too long, and this site is too cluttered.

I moved over to, and then abandoned that for

This site is a static archive of what was previously a wordpress blog. I got tired of maintaining stuff.

Isaac <![CDATA[Dan and Erica are getting married]]> 2007-06-05T19:15:13Z 2007-06-05T19:15:13Z My friend Dan Nee and his lovely bride, Miss Erica Theberge, are getting married. I put together a webpage with information at

If you’re going to be there, I’ll see you there!

Isaac <![CDATA[The Most Important Things They Don’t Teach in CompSci 101 (but should): Maintainability]]> 2007-10-17T01:23:28Z 2007-06-03T03:20:52Z I stumbled across a great article about clean code from Jeff Vogel over at the IBM Developerworks blog site, via a /. article. Even more valuable was the How to write unmaintainable code article, which appears to have grown considerably since I first saw a version of it back in college.

A simple web search can uncover a lot of articles about writing maintainable code. There have been several books written on the subject. And yet, I consistently find that code examples and tutorials, not to mention programming text books, very often break all or most of these rules.

To a certain degree, what makes code “maintainable” is a matter of opinion. However, it is pretty universally accepted that the vast majority of programmer-hours are spent debugging, fixing, and extending existing code. It’s very rare, even when working on an entirely new project, that you open up a blank file in your text editor and start coding. After the first few hours of the first day of a project, you’re working in an existing code ecosystem. Is it a crazy jungle with vines and savage beasts? Or a well-lit sidewalk with friendly pedestrians?

I think these assumptions are pretty safe to make for any programmer in any language:

  1. At least 80% of a programmer’s time is spent working with an existing code base (possibly one they just created).
  2. Debugging code is more difficult than writing it. (Or, problems are harder to fix than to create.)
  3. Extending code (adding features) is the riskiest thing that you can do (bug-wise.)

Nevertheless, no matter what code you’re working on, every programmer faces these demands:

  1. Management allocates more time for development than for maintenance. (Usually after asking us for insight!)
  2. Maintenance is sloughed off onto the least experienced developer in the team.
  3. The existing feature set is looked at as a “base,” and new features are requested constantly.

It is thus impossible to overestimate the importance of writing code that is as easy as possible to fix, extend, and reconfigure, even if the person doing the fixing or extending has never seen the code before. (Or, as is perhaps more common, was the code’s original author, but has forgotten what they were originally thinking when they wrote it.) If you are a programmer or manager of programmers, look at it this way: at least 80% of your development budget depends on the maintainability of the code that you and your team produce. The techniques that create maintainable code are mostly free, but not using them costs you big time.

As a web developer, I tend to have a somewhat extended view of product lifetimes. There is still code on the internet from 1993, and that was back when we didn’t know what we were doing. Now that we’ve got all this experience, we should expect that the code we write will be around even longer. The programmer who gets to maintain your code might not have been born yet. Be kind to that poor soul.

These are the tips that I think are the most important contributors to writing maintainable code. It’s a matter of opinion, to a certain extent, and there’s plenty of disagreement, so take this for what it’s worth. Feedback is, of course, always welcome.

1. Don’t be clever

We already know you’re smart; prove it by writing code that monkeys can understand. Programming should be approached like a haiku, not a riddle. Make it simple, and don’t make me have to think hard when I come by years later to fix or change or add something.

Brian W. Kernighan famously said, “Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.” Try to find the balance between hard-coded and over-engineered.

2. Think clearly.

You can’t teach someone to think in an organized fashion. The best that you can do is find someone who does this already and convince them that they should do it when they write code. Create objects that make sense for the task at hand.

That makes it easy to:

3. Let the code describe itself

Comment your code, yes, yes, you hear it all the time. But don’t write comments that say how something is done. Write comments that say why, and let the code speak for itself. The only thing worse than this:

// increment i by 1
i += 1;

is this:

// increment i by 1
i += 2;

When you write comments that describe how instead of describing why, over time you inevitably end up with comments that lie, because code is much more likely to change than comments. Let the code say what it does. You just have to say why it does what it does.

4. Hungarian notion is eviler than eval

I sometimes think that Hungarian Notation was surely developed by some kind of mad scientist with an extreme hatred of maintenance programmers*. It’s almost never consistent, it’s hard to read, and it puts information where it doesn’t belong. It is a profoundly flagrant violation of the rule that comments should say why and not what.

Consider the basic case of “iCnt” for an integer counter, or ’sType’ as a string, or ‘oElement’ as an object. If your code is so convoluted that a maintenance programmer doesn’t know that your counter is an integer, or that the element reference is an object, or that “type” is a string, well, there’s something deeply wrong with either your code or your hiring process.

Avoid Hungarian notation like the plague.

* This is a joke. I’m sure it was actually developed by very well-meaning programmers who were honestly trying to address this problem. Nonetheless, it’s a very bad solution that tends to compound the problem significantly.

5. Small pieces, loosely coupled

A lot of maintenance checklists and lint programs instruct at the expression or syntax level. However, arguably the most important key to creating maintainable code is to build small pieces that interact with one another in loosely coupled ways. This minimizes dependencies, reduces the amount of code that you have to write and maintain, and makes extension and re-use much simpler.

Less code is almost always better. Instead of having 1 object that implements 10 features, it’s often better to have 10 small objects that implement one feature each, and just listen for and respond to the events that they need. Using a good event utility, this is an extremely powerful pattern for user interface code, especially. Widget-A just listens to an event from widget-B; when that event fires, it does its thing. If the event never fires, then widget-A never gets activated. This means that you can remove or change widget-B without fearing that you’re going to cause massive regressions.

Coding Horror is one of my daily reads. If you don’t read it, you should. Jeff Atwood put it quite well when he exhorted developers to Code Smaller. They he later wrote that the best code is no code at all. I couldn’t agree more.

6. Use OO (and other patterns) Wisely

Object Oriented programming can help you follow these rules. But, not everything has to inherit from something else. There is such a thing as over-engineering. “Silver bullets” approaches are common causes of this problem.

Use an Object Oriented approach that makes sense. Most of the time, in my experience, inheritance is not the best approach, unless you’re going to have a lot of types of things, where the types have a lot in common. This means that you’re dealing with a huge number of objects, which is not the case in most applications. Again, most of the time, “has-a” approaches are much simpler and more flexible than “is-a” approaches.

Think of it with a real-world example. “Sandwich” doesn’t inherit from “bread”. You wouldn’t say, “a sandwich is a type of bread that has stuff inside.” This might, arguably, be true. But, the way that most people talk (and more importantly, how we think,) is that a sandwich is a “thing” that has bread with stuff inside. Furthermore, a waiter is not a sandwich with legs; a waiter is a person who has a sandwich and brings it to you. Since said waiter may also have a second job as an actor, it’s not even right to say that the “waiter” class inherits from “person.” A waiter is not a type of person, it’s a person who has a job delivering food to tables.

Some languages implement multiple inheritance and other things that seek to address the “multiple hats” problem using classic OO techniques. If you ask me, don’t buck the epistemological trends–use the methodology that we use for everything else, and extend using has-a instead of is-a.

7. Be harsh on the code, gentle on the coder

We’re all human. We make mistakes. Even the best of us violate the rules sometimes, and most of us, by definition, are not “the best of us.” However, there is no excuse for bad code. It should be killed on sight. Be your own harshest critic, and never shy away from criticism. Seek it out. Turn to your coworkers and say, “Hm. You know, this thing I’m working on just seems like I’m making it too convoluted. Can I run my approach by you and see if I’m over-thinking this?”

Give honest criticism without any hesitation, but never ever say, imply, or even think that the programmer must have been dense. Sure, maybe the programmer really was dense. But if you’re growing as a developer, hell, as a person, then you should think the same thing about the stuff you did last year. Nothing is more humbling than having to support your own code a year later. Pepper your criticism with a light-hearted attitude, and be generous in praising the parts that you think are good. Keep your venting to yourself. It will raise your status if you help someone else succeed; tearing down just hurts us all.

Sure, this might be good advice, obvious, even. But how does it help make maintainable code? By fostering positivity, you’ll help create an atmosphere where bad code is not tolerated, but where everyone is encouraged to grow and experiment. The best way to avoid bad code is to make the programmers better.

I personally think that a few interpersonal communication classes would be a good addition to any computer science curriculum.

8. Fail

You won’t be able to create resilient systems unless you know how they’ll break. You won’t know how they’ll break until they do.

Failure is a prerequisite for success. So, get ready to do it. A lot. I’ve written LOTS of very bad code. (Some of it is even here on this website!) Plan for an alpha and beta. Do them as fast as possible. Bang on them. Then throw them out and start over, taking what you learned into the next version.

Share your failure. Have a code review session where everyone brings in the worst code that they’ve written for the project, and solicits ideas for what went wrong. (It’s kind of like an AA meeting: Hi, my name is Isaac, and I wrote bad code. Hello, Isaac….)

It’s so often these days, especially in big corporations with lots of different teams, for each team to share their successes loudly, but sweep their failure under the rug. We’re all afraid of getting a bad review, but this virtually guarantees that all the other teams will fail in exactly the same way. Even in a small company with only one or two teams, sharing failure can result in an exponential reduction in errors.

Furthermore, sharing your own failures, and asking for criticism, makes it easier for others to take criticism when you point out bad code that they wrote. It is very difficult to separate “me” from “my code”. If you criticize one, the other might get hurt. Sharing failure helps to sever this connection, and allows everyone to associate and connect with the success of the product as a whole.

Building a few prototype/failure builds into your development process will also help to produce stable builds faster. It allows for user-research sooner. By planning a throw-away build, it helps get everyone focused on which features are actually important/necessary, and which are either too difficult or unimportant to bother building. It gets product and engineering talking sooner.

Failure (and handling it intelligently) is not just important, it’s absolutely vital when it comes to building systems that are going to stick around for decades.

Isaac <![CDATA[How Unison Changed My Life and Made Me a Better Remote Worker]]> 2007-05-22T18:37:15Z 2007-05-22T18:36:13Z A while ago, I shared some bash scripts that I’d written to sync my local MacOS machine to my FreeBSD dev environment. Earlier, I’d written about mounting a NFS share on a Mac.

I will be using pushchanges and pushall no more! I found Unison, and my troubles are lifted. Unison is a great little app that hooks up a local folder with a remote folder via SSH. Since it runs on both machines as a user-level application, there’s no need for changing kernels and no lag from trying to scan a remote filesystem. However, you get the same effect that you’d have from an NFS or SSHFS mount. Changes take about a second to propagate between the two systems, but that’s pretty forgivable, since it happens in the background and only uses the network bandwidth that it actually needs to.

I did run into a few caveats with it:

  1. You have to install it on both machines, and it has to be the same version on both machines. Since my yahoo BSD machine could only find version 1.16, that was what I had to install on the mac.
  2. Read the command-line options, and use them. The UI is pretty nice, but without the -repeat option, it’s pretty much useless.
  3. Older versions are a bit flaky, especially when it comes to symbolic links. Make sure that you carefully set the -ignore flags to avoid any symlinks in your sync folders. (Frequent use of gmake-symlink is a big culprit.)
  4. If it dies on an error, it might corrupt the archive. Delete the archive on both machines, and try again. (Archive files are in ~/.unison/ and start with “ar”.)
  5. The mac puts its unison stuff in ~/Library/Application Support/Unison/. Do ln -s "~/Library/Application Support/Unison" ~/.unison and you’ll save yourself a lot of remembering.
  6. Sometimes, it’ll hit some file that makes it barf. I don’t know why. In my case, it was “Rate.php”. I just deleted the offending folders on both machines, and it ran fine. Then, while it was running in -repeat mode, I checked out the folders, on one machine and it synced them without any hiccups. Don’t know why, but it works.
  7. Changing the .prf file in ~/.unison/ and running from the command line is a lot faster than loading up the GUI each time and changing the text fields.

The error message that I saw most often was Uncaught exception Invalid_argument("String.sub"). Once that showed up, I’d get disconnected from the server, and had to delete the archive and try again. The -debug option is handy for figuring out what’s going on.

I’m still mounting my home folder from my BSD box onto my mac. But I curse at my slow-as-dirt VPN connection a lot less now that I’m editing code files locally and only transferring the changes without any effort on my part.

Isaac <![CDATA[Arrr!]]> 2007-06-02T20:38:48Z 2007-05-18T17:20:44Z Check it out!

It’s the first of many brand universe sites, and in retrospect, hopefully will have been our least satisfying or successful. (If it’s our best, then it means that we’re not improving after this one.) Nonetheless, it was a ton of work by everyone involved, and kind of feels like we all gave birth to a huge baby. With an eyepatch. Hmm… need to work on less disturbing metaphors.

Anyway, go look at the pirates site. And if something breaks, well, I’m sorry :)

See what the blogosphere says about this. Currently, only myself and Ben Margolin have written anything about it, but hopefully that’ll change once there’s some decent marketing sending traffic at it.

Isaac <![CDATA[Bash Scripts for the Masses! (CVS Helpers)]]> 2007-05-10T18:50:30Z 2007-05-10T18:50:23Z I decided that I’d share a few little functions in my .bashrc that have been making my life nicer lately. (Yeah, nothing much to blog about. Or rather, I don’t feel like writing anything creative, because my brain is fried from lots of work and being away from home.)

Since we’re in the beginning stages of a project right now, everything is working out of HEAD in the CVS tree. It’s in maintenance modes when you really need to worry about a lot of tagging and branching and whatnot. So, I’ve been finding that it’s easiest to just use the command-line CVS client. Also, I’ve been up in Sunnyvale, working long hours on my laptop in a hotel room. VPN is a lot of things, but it ain’t quick, so my NFS mount has been pretty much worthless most of the time.

So, I wrote a few bash shortcuts so that I can quickly copy *just* my changed files over to my FreeBSD box.

This one copies all the changed files (according to CVS) in the current folder over to the corresponding folder on my FreeBSD box. Replace “DevBox2″ with your local sandbox, and the tillnearly…/isaacs/dev/ with the corresponding servername and folder on the server. It won’t copy conflicts.

copychanges () {
  if [ "$target" == "$target0" ]; then
    echo “not in code folder!”
  echo “copying changes in $target to${target}/”
  for i in `cvs update -dP | egrep “^[ABD-Z] “`; do
    if [ -f "$i" ]; then
      # get the path from here to there..
      pathToFile=`dirname $i`
      scp $i${target}/$pathToFile/

Forgetting to put in the dirname call almost led to me crashing my box by building up a 3,857,666,294 byte apache error log. *^_^*

This one is for clearing conflicts. Set up edit to be an alias for your favorite text editor. (Old-schoolers can put alias edit=`which vi` in their profiles. Mine is alias edit="open -a 'TextMate' ".) It walks through each conflict.

clearconflicts () {
  for i in `cvs update -dP | egrep "^C "`; do
    if [ -f "$i" ]; then
      echo -n “$i - what to do? (C)lean copy, (E)dit, (S)kip (skip) ”
      read -n 1 action
      if [ "$action" == "C" ] || [ "$action" == "c" ]; then
        cvs update -C $i
      elif [ "$action" == "E" ] || [ "$action" == "e" ]; then
      edit=”$edit $i”
  for i in “$edit”; do
    if [ -f "$i" ]; then
      edit $i

Last but not least, a one-liner that just shows you the files that matter, and skips all the ? files that I seem to accumulate in my CVS sandboxes. (”ug” stands for “update and grep”. Is it really any more poorly named than ls or chmod?)

alias ug='cvs update -dP | egrep "^[^\?]“‘

Isaac <![CDATA[New Resume]]> 2007-04-30T21:31:42Z 2007-04-30T21:25:05Z So, I’m still happy with my current employer, but since I was out of commission for a week on percoset from the surgery, I decided to wile away the hours building a snazzy new resume with a style switcher and a few funky themes. (Of course the info is all updated, too.)

Lemme know what you think! Terminal is my favorite :)

Isaac <![CDATA[If you’re reading this, then I’m…]]> 2007-04-23T19:00:28Z 2007-04-23T19:00:20Z …having my face cut open.

Hopefully, I’m not feeling a thing, and won’t come out of my drug-induced stupor for the next few days.

I’ll see if I can get a copy of the panorex and post it here. It’s wild to see your face from the inside.

Isaac <![CDATA[It Wasn’t as Easy as We Made It Look]]> 2007-04-22T20:20:18Z 2007-04-22T20:20:18Z I read this line once on a post-mortem review of a project that was handled by a very small team and accomplished big results.

It wasn’t as easy as we made it look.

It’s very important to make it look easy. It’s a morale booster for yourself and your teammates and dependents when you can say, “Piece of cake!” with a bit of swagger and a cocky smile. It’s just as important to communicate up the ladder that things are not always as easy as they seem.

Management likes to get the most out of workers that they can. That’s their job, and if they didn’t do it, then you’d never be your best. Thank them for pushing you. But, just the same, along with the swagger, make sure they know that the brilliant work you did was not as easy as you made it look; that it took a few late nights and stressful deadline-looming crunches.

Isaac <![CDATA[Fix for Vi’s broken arrow key support in iTerm]]> 2007-04-17T18:45:36Z 2007-04-17T18:45:36Z So, I got turned on to iTerm, a prettier and more user-friendly alternative to Apple’s native

However, for some reason, I got the following error message whenever I tried to use arrow keys in Vi:

Usage: [[

The problem is that Vi is faithfully responding to the TERM variable that iTerm is sending. (I’m not sure why and PuTTY don’t suffer from this issue, but c’est la vie.) So, you should keep the terminal setting in iTerm to xterm-color, since this is great for most things, but then add this setting to your .exrc file to tame Vi:

set term=linux

Not sure why this fixes it, but it does. set term=cons25 was another fix that I found, but it seems to break if you have line numbers turned on, because all tab characters are turned into backticks (`).