Thursday, November 20, 2008

Make CMD Useful

Cmd is the command line processor in Windows. This post will describe a few of the absolutely required things you need to do to make cmd a useful tool.

Step #1: Stop using cmd and use Powershell.

I'm only half joking. Powershell is much more powerful and useful, so if you can use it, you really really should.

But if you can't or can't always use Powershell, here's the short list on how to make cmd useful:
  1. Use auto-completion (the Tab key)
  2. Use macros
  3. Setup colors
Auto-completion is on by default. For example, go to C: and type "cd Win<Tab>". Cmd will automatically complete your thought and replace Win with WINDOWS. If that's not what you wanted, hit Tab again and it will go to the next likely match.

Macros are like abbrievations. They allow you to create a shorter name for something. For example, suppose you are looking for a certain file but you can't remember exactly where you put it on your file system. You'll be moving from one directory to another. Every time you arrive in a new directory you'll want to see if the file you're looking for is there. The command dir shows you that. But dir gives you a list with file names in one column and all kinds of information you don't care about in the other columns. That's not a very efficient use of space when all you care about is the file names.

What you really want to see is just the names, laid out in a many columned format. dir /w will do that. But you want it to pause after each page to give you a chance to read. dir /w /p does that. Finally, you want it to sort alphabetically with folders on top, then files. dir /w /p /O:GN does that.

Clearly, dir /w /p /O:GN is way too much to type over and over again as you navigate around. What we need is a macro so we can shorten that up. I use the name dw for my macro.

So how do we create macros? We use a program in cmd called doskey. First, create a text file and call it "doskeyMacros.cmd." In this file define all your macros, one per line. For example:
dw=dir /O:GN /w /p $*
Now, in cmd type:
doskey /macrofile="doskeyMacros.cmd"
This will load in all your macros. So you can now type dw instead of dir /w /p /O:GN.

There is still a problem. Who wants to execute that doskey command everytime they open cmd? We need that to happen automatically. To do this we will have to edit the registry. But first, create a text file called "cmdAutoRun.cmd" and type this in it:
@echo off
doskey /macrofile="C:\full\path\to\your\doskeyMacros.cmd"

Now we edit the registry. Start->Run->regedit.exe. Navigate to HKEY_CURRENT_USER\Software\Microsoft\Command Processor and in the AutoRun key (create it if it's missing) type the full path to your cmdAutoRun.cmd file enclosed in quotes.

Close and reopen cmd and your macros will be loaded.

Setup Colors
If you like the white on black you're done! I like the powershell look, so I change my colors in cmd. Right click on the window header and click "defaults" then switch to the "Colors" tab.

I set Screen Text to r:238, g:237, b:240 and Screen Background to r:1, g:36, b:86

And there you go! Cmd is now a bit more useful than it was before. Enjoy.

Thursday, November 13, 2008

Why Write Good Code?

If you give two programmers the same task, and they both complete it in the same amount of time, and the results both pass the same unit tests, and no bugs are discovered in testing, does it make any difference who's code you choose?

Or, to put it another way, does it matter how the code is written, or does it only matter that it works?

I'm going to make the case that it does matter. Good code matters.

But why? If the code works, who really cares? After all, the purpose of code is not to be aesthetically pleasing. The purpose of code is to tell the computer how to do whatever it is that your user wants it to do. If it meets that end, why would you ask for anything more?

The answer is quite simple: because it doesn't end there.

You Will Have To Go Back
If you could write your code once, get it working, and never touch it ever again, that would be one thing. But that is not how it works in real life. You will have to go back to it.

You might go back to add something new, like a new feature.
You might go back to modify it its behavior, or its look and feel.
You might go back to resolve a bug.
You might go back because you have to do something similar, and you want to see how you did it before.
You might go back so that you can refactor and use part of it for another purpose.

There are a huge number of reasons why you *might* have to go back. So extrapolate that to its logical conclusion and: You will have to go back!

Someone Else Will Have To Go Back
Worse still, it might not even be you who has to go back to that code you wrote. It could be someone else. Maybe someone who was around when you first wrote the code, or maybe a new hire, straight out of school. Or an intern, still in High School!

So not only is it very likely that you will have to go back, it's even more likely that someone else will have to go back!

They Don't Teach That In School
This is something you don't learn in school. In school, you're given an assignment. You hack on the code until it seems to work. You turn it in. The teacher black box tests it (I've only heard of a few professors who actually read the code and graded on style, design, etc) and you get a grade. You leave the code on your hard drive and never open it again.

In school, working code is the only thing that matters because you almost never have to go back. You certainly never have to go back a year later, when you've forgotten everything about it.

Because of this, the real hard cord nerds like to get into code golf matches. "My program was only 200 lines!" "Mine was 150 lines!" Sadly, exceedingly verbose code doesn't translate into code that is easy to come back to. Quite the opposite, usually.

Good Code Matters
Good code matters precisely because you (or someone else) is going to have to go back to code you've written in the past. If its good code, you stand a chance of being able to add features, fix bugs, update behavior, whatever. If its really good code, you stand a chance of being able to do those things and still have good code when you're finished. If its bad code... maybe not so much.

Though the bad code might work, it's a veritable house of cards. It may be nearly impossible to understand, and therefore nearly impossible to work with. Or it may be so fragile that the smallest change causes seemingly unrelated things to break. Or, in the least severe case, you may just have to do a ton of refactoring to make what at first glance should have been a fairly inconsequential update. Of course, in that case, the chances you do the refactoring are kind of low. Its more likely you just hack it in. And now the code is even worse than before.

There's another form of bad code. It could be riddled with errors. When you read the code, you see potential for errors all over the place. You know that no errors have been found in testing or production, but the code clearly has errors. And you have no idea how it's possible no one has run into those errors yet. What do you do if you've come back to code that looks like that?

So that's why bad code is bad. Its very difficult to work with when you have to go back to it. You may have noticed that I've managed to get this far without ever really defining what "good code" is, or what "bad code" is.

Bad Code:
  1. Code which doesn't work or has major bugs
  2. OR Code which is difficult to work with when you have to go back to it
Good Code:
  1. Code which works and has few minor bugs
  2. AND Code which is easy to work with when you have to go back to it
This definition has an interesting implication. You could go back to a piece of code to add a new feature and feel that it falls into the Good Code category. This is because the way the code is written has made the change you're making easy to make. But you could go back to that code again to add a different feature and this time decide it falls into the Bad Code category. This is because the way the code is written has made the change you're making hard to make.

Same code, one time it was good, one time it was bad. Agile methods and TDD talk about this in terms of "guarding against change." The simple and unfortunate truth is that you can't possibly write your code to guard against every change someone might want to make to it. You just have to take your best guess and hope it works out.

Degress of Bad
Of course, there are degrees of good and bad code. Code that has been written in a loosely coupled fashion, that does one thing well, that applies sane design patterns, and is as simple as possible will always be easier to go back to than code that has none of those properties.

Someone may still look at it, and for their purposes, think it is bad. But clearly, it could have been worse. Much worse. Much much much much much worse! Maybe even so bad that it seems the only path forward is to completely rewrite it.

The Netscape Fallacy
A company called Netscape used to make a web browser called Navigator. There are probably people alive today who never even heard of it. It used to be the best and it had the most market share. I know, unbelievable.

After Navigator 4.x they decided that the code was simply too hard to deal with, and if they were going to make any progress moving forward they would have to rewrite it. Three years later they came out with Netscape 6. But by then, Internet Explorer had stolen all but 10% of the web browser market.

And then Netscape was bought by AOL (read: went out of business). And sometime later, Firefox was born! Which was able to climb back to having something like 12% of the browser market!

Joel Spolsky writes about this in Things You Should Never Do.
And again in Netscape Goes Bonkers (I think it really pissed him off).

The lesson to take away is that receding into a hole for three years so you can rewrite your code is not a good idea.

Why? Because everyone else passes you by in the mean time. Because you end up with "Good Code," but it has more bugs than the "Bad Code" had.

What's the alternative? Write good code to start with. Failing that, take baby steps. That is, refactor the code, don't throw it all away. Failing that, refactor in parallel with on going maintenance and development. And last but not least, go out of business.

Why Write Good Code?
So why write good code?

Good code saves you time in the long run. You will have to go back to that code. If it's good, you'll be able to work effectively with it. If its bad, you're screwed.

Good code helps keep you from falling pray to the Netscape Fallacy. You'll have a better chance of updating and refactoring your code to stay modern if it's good. If its bad, you're stuck having to rewrite.

Good code gives developers a fighting chance when they have to work on code they didn't write. They'll probably still think its bad code. But they'll be more likely to survive the experience.

But Doesn't Good Code Cost More Up Front?
In our hypothetical scenario that started this whole post, two developers took the same amount of time to write code to do the same thing, and both ended up with code that worked and had no bugs.

You may have scoffed at that and asked, "In reality, doesn't it take longer to write good code than bad code?" And further, "Are the benefits of good code worth the up front time investment?"

First off, it won't always take longer to write good code. An experienced developer can write good code in the same time it takes an inexperienced developer to write bad code. So it doesn't necessarily take longer to write good code.

But it clearly takes time for an inexperienced developer to become experienced. And it will take time for them to experiment as they try to learn how to write good code. After all, it's one thing to know the definition. It's something else entirely to actually fullfill the definition. I'm certainly still working on that one.

So the second question should actually be, "Are the benefits of good code worth the up front cost of developers learning how to write good code?"

Given all the downsides to bad code, and all the up sides to good code, I think the answer to that is a clear "Yes!"