Recently in code Category
I'm doing something pretty goofy today: I'm leaving Google. My tattered old employee badge goes back to HR during my exit interview at 4:00 this afternoon. After that I'll be an ex-Googler.
Working at Google was as amazing as everyone says it is. Sure, the perks were nice. I'll miss the delicious meals, the ski trips, the commuter shuttle, and TGIF. But any company could provide such benefits, given enough free cash flow. What makes Google unique is its culture of respect. The tough interview process means that engineers are treated with respect from their first day. In such a supportive environment, even the most timid person works with self-confidence, which is marvelous to witness. This element of the company's culture was the biggest difference between Google and every other place I've worked in the past. I hope to take it with me throughout the rest of my career.
Which brings me to the future. What's next? I'd originally intended to take a year off and bang on a few software ideas that have been rattling around my head. I'd then pick the most promising one, find some friends, and start up a new venture. As it turned out, things went faster than I expected, and not exactly in the order I'd expected, but the result was the same.
My new venture is a software startup called FSX. I think of the company as a mashup of eBay, Charles Schwab, and American Idol. FSX will use a highly accurate, simulated brokerage to identify skilled stock portfolio managers. For the majority of participants, the fun of FSX's community and fantasy stock exchange will be its own reward. But there will be a tiny number of managers who we find can consistently outperform the field. For those newly discovered stars, we'll provide a market of investors willing to entrust real investment funds to their management.
The business idea is risky, no doubt. The Random Walk Down Wall Street crowd has seen all this before. But the premise that stock-picking is a legitimate, repeatable skill also forms the foundation of the hedge fund and mutual fund industries. If you (or your pension plan) have any of your money in a managed mutual fund or hedge fund, then you believe the premise, too.
The technical challenges are less risky, but to me they're even more fascinating. The uptime and integrity demands are arguably higher than those of a real brokerage. A slow trade in a real brokerage might cost one customer a certain amount of money. In fact, depending on how the ticker goes, the mistake might even earn the customer more money. But every complaint about FSX's performance damages its status as a faithful brokerage simulation, and that in turn damages the value of its entire community. Building a top-tier brokerage website would be hard enough. Our goals are much higher than that.
eBay built a global marketplace out of Pez dispensers and Elmo dolls. They made it possible for you to find that one guy out there who wants to buy your dusty old deluxe chartreuse dinglehopper. He completes his dinglehopper collection, you get some cash and some extra space on your shelf, and the world's a better place. FSX will do the same thing for investments and investment managers. If you think you have management talent, we'll prove it for you. If you want hedge fund-level talent cheaper than the cheapest mutual fund, we'll find it for you.
If you'd like to see a preview, add the Fantasy Stock Exchange application to your Facebook account. If you're a smart software engineer in Silicon Valley and want to join something big while it's still small, .
With apologies to Nelson, The Regex Coach is good software. It's an interactive regular expression authoring tool for Windows. Rather than typing a given regex directly into your Java/Python/Perl/C++-with-PCRE-library code and building your entire program, you type the expression into the top window, type a sample string in the bottom window, and if it matches, the matching part is highlighted. Such a time saver.
My one feature request: menu items that copy the regex to the clipboard, but properly escaped to paste into less regex-aware languages like Java. E.g., ([A-Za-z]+)\\\.[0-9]? would be copied for Java as ([A-Za-z]+)\\\\\\.[0-9]? (at least, I think that's right). The version of the feature that copies into a Bash command line would emit something like \\\\\\\\\\\\\\\\\\\\.
Two problems:
1. The CSS just ain't right, as far as I can tell. Go to Design -> Templates -> base_styles.css. Find the p element and copy it into its own separate block. Change padding to 0px 0px 20px 0px and rebuild.
2. Thanks to Joe Siegler on the Movable Type forums for this: change convert_breaks="0" to convert_breaks="1" in the three places it appears in the RSS/Atom feed templates.
It's live! Congratulations and thanks to the rest of the team: Aaron, Aaron, Andy, Chris, Dan, Danny (emeritus), Darin, Erik, Joanna, Linus, Michael, Othman, and Scott, as well as many other Googlers in supporting roles too numerous to mention.
It is a small pet peeve of mine that many people in software development use screenshots to send around reports of errors in Windows applications. The path of least resistance is to press the Print Screen key and paste the resulting BMP in email. These files can be multiple megabytes. Even if you use alt-PrtScn, which copies just the active window, that's typically 350KB. Moreover, it loses critical information: if the recipient actually wants to grep source code for the error message, he or she must retype the string in question.
Instead, try pressing control-C. This copies the text of any standard messagebox (including assertion failure dialogs) into the clipboard.
Example:
--------------------------- Microsoft Visual C++ Debug Library --------------------------- Debug Assertion Failed! Program: temp_demo_project.exe File: c:\foo.cpp Line: 40 Expression: 2 == 1 For information on how your program can cause an assertion failure, see the Visual C++ documentation on asserts. (Press Retry to debug the application) --------------------------- Abort Retry Ignore ---------------------------
Thanks to Adam Dingle for the tip.
You may be surprised to find that the Mozilla xpidl compiler doesn't support #ifdef, which seems to be the right way to conditionally define members in your IDL files. So how are you supposed to define debug-only stuff, for example?
Turns out it's quite possible through a flexible passthrough mechanism. Just wrap your C++-isms in blocks like this:
%{C++
#ifdef DEBUG
%}
readonly attribute long myDebugStuff;
%{C++
#endif
%}
This will appear as expected in the generated .h file. Thanks, Darin, for the tip!
Update 2/22/2007: This is just enough rope to hang yourself. Be careful about mismatches between the caller and callee's understanding of the vtable layout!
Disable your sarcasm detectors; none follows.
mymsi.wxs(16) : error CNDL0014 : The File/@Id attribute's value, 'foo-bar', is not a legal identifier. Identifier's may contain ASCII characters A-Z, a-z, digits, underscores (_), or periods (.). Every identifier must begin with either a letter or an underscore.
I don't know whether this is the Microsoft MSI XML compiler or the open-source tool Wix. But whoever is responsible for it, you get the Best Error Message of 2006 Award. This message is perfect: it tells you exactly which part of the file was wrong, and the rule you need to follow to fix it. If every error message were this informative, we wouldn't need documentation.
Pretty slick! It even searches tarballs! (This search was for term in a .c file I posted long ago to my 3Com Audrey hacking page.)
I've been using Password Safe for years. It's a little Windows application I keep on my USB drive that contains all my passwords encrypted with a very long Diceware-generated password.
There's one usability problem with Password Safe that's plagued me over the years. I keep backups of the password file on nearly every computer I use, and occasionally I need to get a password but I don't have my USB drive handy. So I open the backup on the local machine, get the password I need, and get on with my life.
The problem is that Password Safe remembers the location of the last file you opened, and tries to open it automatically for you next time. So the next time I add or edit a new password on that machine, I might not notice that I'm opening the backup file rather than the original on my USB drive. If that happens, I edit the backup file, not the original. Then next time I back up the original onto that machine, my edits are gone. Since the edits always consist of unguessable passwords, I end up locked out of a site, possibly forever.
Here's a patch to version 1.92c that fixes this problem by not remembering backup file locations:
diff -E -w -r pwsafe-1.9.2c-src/DboxMain.cpp pwsafe-1.9.2c-mt-src/DboxMain.cpp
845a846
> if (0 != m_currfile.Right(4).Compare(".bak")) {
854a856
> }
I also edited PasswordSafe.rc to change all instances of 1.92c to 1.92c-mt in order to distinguish the modified build. I would provide a compiled binary, but I'm sure you're too smart to store your passwords in a random program downloaded off a shady poker player's website, so you get to build it yourself.
By the way, Password Safe is up to version 3. Unfortunately, it's not backward-compatible with my old files, so I don't use it. When I get around to it, I'll submit a patch to the developers for v3.
Step 1. Create a new file called stdafx.cpp.
Step 2. In that file, add one line: #include <stdafx.h>
Step 3. Debug for many, many hours.
Step 4. Change stdafx.cpp to this: #include "stdafx.h". Note that the compiler now stops assuming you meant the stdafx.h buried deep inside the MFC source.
Step 5. Go home and have a drink.
Hot off the presses. For National Novel Writing Month, or NaNoWriMo, helps you tell whether you're on pace for reaching 50,000 words by the end of November.
Hey, Visual Studio .NET, pop quiz: User searches for "RemoveDirectory." Does he want to see the documentation for RemoveDirectory() in the Platform SDK, or the documentation for "CFtpConnection::RemoveDirectory"?
You get two guesses.
Compared to the pre-GUI era, the typical workstation display these days is big. We're stocking new engineers with dual 1920x1200 widescreens. That's the equivalent of six side-by-side VGA screens! In spite of this growth over the years, my basic monitor real-estate coding rules haven't changed: stay within 80 columns, and try to keep each function short enough to fit vertically on a single screen.
The 80-column rule is a coding style convention that enhances readability and helps you play nice with your teammates. I'm not sure about the origin of the specific number 80, but it is the default width of a terminal window. A line of a typical book also happens to average 80 characters, and a book page is about the widest the human eye can read without getting lost in the middle. Whatever the exact limit is, it's polite to stay within it because you don't know the width of the window used by the person reading your code.
Resist the relentless pleas of your teammates to increase the 80-column limit. Wider monitors enable greater productivity by allowing activities you can't do on smaller screens, like comfortably diffing two side-by-side GUI windows of 80-column code, or debugging an application while simultaneously stepping through its code. But you lose these new abilities if a wider monitor merely means that your code sprawls farther and farther to the right.
The height rule is more of an engineering principle than a mere style guideline, and as such, it's more subjective. Just as long paragraphs in a book are tough to slog through because they contain too many ideas, long functions contain too much code to understand. Splitting one long function into smaller functions encourages documentation by forcing the programmer to give a (possibly) meaningful name to each new function. At the same time, the programmer will probably shorten the overall code by identifying repetitive, copy-paste code and replacing it with calls to a single general-purpose function.
I haven't had to adjust my function-height rule over the years, but lately it's making me feel lonely. I'm the lone engineer on my team who hasn't rotated his LCD to portrait position. I see no reason to do so, because it'll only make it easier to write longer functions.
Yesterday I discovered the shell commands pushd and popd. For some reason every time I read the man pages I didn't grok what they were for, but this time it clicked.
Suppose you're in some directory somewhere like ~/src/main/project/module/test/data/, and you need to work with a file in your ~/scraps directory. Without pushd and popd, you have three choices: open a new shell, cd to ~/scraps and then cd back again when you're done, or use path completion to type the full path to the file in ~/scraps.
But what you really want is the hyperspace button, where you jump to the other directory, do your work, then jump back wherever you were before. This is what pushd/popd does:
[~/src/main/project/module/test/data] $ pushd ~/scraps [~/scraps] $ (work with the file) [~/scraps] $ popd [~/src/main/project/module/test/data] $ (I'm back here again!)
As you can guess from the command names, it's a stack. So you can push all the locations you want and then get back where you were when you're done.
A belated thanks to my friend and partner in entrepreneurial endeavors, Erik Kay, who mentioned these commands to me two years ago.
Because I always forget, here's how to manually send a mail given a telnet client and an SMTP server in order to test and make sure the server's working:
$
telnet mail.example.com 25
Trying 12.34.56.78...
Connected to mail.example.com (12.34.56.78).
Escape character is '^]'.
220 mail.example.com ESMTP Ready on Mon, 21 Mar 2005 16:29:31
-0800 [a.mail]
HELO mail.somewhere.com
250 a.mail.somewhere.com Hello 98.76.54.32.somewhere.com
[98.76.54.32], pleased to meet you
MAIL FROM:<mike@somewhere.com>
250 2.1.0 <mike@somewhere.com>... Sender ok
RCPT TO:<someone@example.com>
250 2.1.5 <someone@example.com>... Recipient ok
DATA
354 Enter mail, end with "." on a line by itself
Hello there!
OK, bye!
.
250 2.0.0 0987654321 Message accepted for delivery
QUIT
221 2.0.0 a.mail.example.com closing connection
Connection closed by foreign host.
$
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\7.1\Text Editor]
"Guides"="RGB(255, 32, 32) 80"
Add this to your registry and restart Visual Studio .NET 2003. You'll have a nice 80-column marker in your editor windows.
As a followup to Chris' article about getting query-param behavior in a URL without query params, this is a fairly simple way to make the URL look more regular by eliminating the .php extension in the middle. Edit your Apache conf file something like this:
<Directory /var/www/test> # everything in /test is now executed as a PHP script ForceType application/x-httpd-php </Directory>
Now put a file like the sample one that Chris made in your doc root:
/var/www/test/foo
Note that the file is called foo, without an extension! Now you should be able to go to http://www.example.com/test/foo/bar/baz, and PHP PATH_INFO will be /bar/baz.
Some disadvantages of this approach are that it requires an Apache config change for every new script directory, and you still need a parent directory in the URI, unless you want your _whole_ server to serve only PHP files. So if you wanted to do this:
http://www.example.com/users/mike
http://www.example.com/users/chris
Then you'd have to config your root directory with ForceType, or you'd have to settle for something like this:
http://www.example.com/get/users/mike
http://www.example.com/get/users/chris
If you're trying to delete, move, or replace a file that's in use on Windows, install this utility, then right-click the file and it'll tell you who's using it! (Thanks, jam!)
M-l: Convert following word to lower case (downcase-word).
M-u: Convert following word to upper case (upcase-word).
M-c: Capitalize the following word (capitalize-word).
C-x C-l: Convert region to lower case (downcase-region).
C-x C-u: Convert region to upper case (upcase-region).
I last worked on the C version of WINW in April 2004. I'd been working on it for nearly a year and was starting to get frustrated with a lack of focus that expressed itself as an irresistible desire to continue to rewrite perfectly good parts of the code. This is expensive to do in C, and it wasn't making WINW any better. Nor was I coming any closer to the essential feature of the program: file sharing.
So I quit for a while. I have continued to think about WINW, though, and have used it as an excuse to investigate and learn new technologies and methodologies, which is always fun.
This one is very simple. To replace tabs with spaces, select a region and type:
M-x untabify
I built this using the following tools:
clearsilver-0.9.12.tar.gz
MinGW-3.1.0-1.exe
MSYS-1.0.10.exe
Python 2.3.3 (#51, Dec 18 2003, 20:22:39) [MSC v.1200 32 bit (Intel)] on win32
MD5 sum of neo_cgi.pyd is bdbedfe1a27fbeda7f39ec8a4973b2bf.
download neo_cgi.pyd (79K zipped)
You should unzip this and throw neo_cgi.pyd in c:\Python23\lib\site-packages\.
Thanks to Adam for this amazing tip:
"A little-known Windows fact: you can press Ctrl+C in any dialog box generated with MessageBox() (or any of its variants) to copy the message text to the clipboard."
More than once I've added an authorized key to my SSH configuration and logged out without setting the permissions back again. My login passwords are all very long and randomly generated, I generally don't use them, and I certainly haven't memorized them. This makes it quite inconvenient to recover from accidentally disabling public-key logins. So I put this in ~/.bash_logout today:
chmod 400 ~/.ssh/authorized_keys
Seems to work fine. I haven't thought of a reason why this is a bad idea, other than it promotes forgetfulness.
x - delete a character
! - start of line
$ - end of line
dd - delete line
i - go to insert mode
a - go to append mode
esc - go back to command mode
u - undo
:wq - write and quit
:q! - just quit
:e! - undo what you did to the file and start over
:q! emacs - anything more complicated
This was hard to figure out. I've had a little Debian fileserver for about a year, and after discovering Cygwin X, wanted to be able to use X applications on that machine, rather than boring old PuTTY sessions.
I configured an awful lot of X stuff on the machine, but nothing worked. Every time I tried to start xclock, there was no server running, the connection was refused, or various other problems ended up getting in the way. I finally figured out the problem had nothing to do with X. It was ssh: the X11Forwarding option in /etc/ssh/sshd_config was turned off. I turned that on, tried again, and it worked.
Keywords for others having the same problem: audit client rejected connection refused xlib display xauth localhost
Every one in a while you discover something that is so pitifully basic yet also so marvelously productive that it's worth exposing yourself as an Emacs dummy who's been using the editor for years and thus has no good excuse for not already knowing this. For me, this is one of those times. Here is my discovery:
Meta-q word wraps the current paragraph.
In particular, it wraps comments correctly according to whatever comment-delimiting convention you're using (e.g., // or /* */ or /* with a leading * on each new line). I don't know how many comments I've manually wrapped to 80 columns, painstakingly adding the leading * for each line. Never again, thanks to Meta-q!
(And as long as I have you here, you probably know this one too, but in case you don't, control-R in bash searches your history in reverse. Try typing "<ctrl-r> emacs" at a bash prompt for an example.)
A few weeks ago a coworker introduced me to Cygwin's X server. This was in connection with my gripe that there is no dual-DVI USB KVM currently available that doesn't look like an Altair 8080.
To convert an Emacs buffer from DOS line endings to Unix, type C-x [ENTER] f unix [ENTER].
Useful article: Compiling and Debugging C in Emacs
if you are coming up against real syntax errors in the code, such as missing semicolons and whatnot, compile-mode lets you jump to them quickly. Rather than using goto-line and typing the line number of a suspected error, just type C-x ` in the code window. (that's a back-tick, or back-quote, which is either in the upper left of your keyboard, or to the right of the single quote.) C-x ` jumps to the next compiler error, so you can keep typing C-x ` until you get to an error you know how to fix.
"A C program is like a fast dance on a newly waxed dance floor by people carrying razors." - Waldi Ravens
This is the best I could come up with for printing out a bunch of bytes from a file into a format that you can put in a C program. I couldn't figure out how to get rid of the trailing junk:
hexdump -e '8/1 "0x%02x, " "\n"' file_to_dump.bin
This is a new Dave's Quick Search Deskbar search, cf (short for "clip file"), that takes either the search arguments or whatever text is on the clipboard and saves it on the desktop as an appropriately-named text file.
Examples:
cf dentist 555-1212
cf [a snippet of text just copied from a web page]
Note that you'll get an ActiveX warning the first time you run. This is probably a good thing.
I was playing around with some ideas for WINW that involved identifying blocks of content by their SHA-1 hashes. That was what I was doing for peers, but I generalized it to all content. Then I stumbled across the Venti filesystem, which crystallized my vague thoughts very nicely.
I want a cross-platform makefile generator. It should take an easy-to-generate list of dependencies and emit the most natural file for the given platform. E.g., .vcproj files for Visual Studio .NET, .dsp files for Visual Studio 6, makefiles for Linux, and so on.
I'm sure this exists already.
I like lazy initialization like this:
const char *get_name(void) {
if (NULL == name_) {
name_ = generate_name();
}
return name_;
}
This was a fun Windows bug to catch. ("fun" is a euphemism for "not fun.")
Here's my pseudocode:
HWND g_hwnd = NULL;
main() {
// Spin off a thread that discovers other people on the network.
startDiscovery(myCallback);
... do the main work in my app ...
// Cleanup.
if (IsWindow(g_hwnd)) {
DestroyWindow(g_hwnd);
}
assert(!IsWindow(g_hwnd));
}
myCallback() {
g_hwnd = CreateWindow("I found someone!!!");
}
Now, can you tell why the assertion fails?
There are plenty of comparisons out there on the web, so I won't rehash that; I'll just relate my personal experience.
You will finally automate a task the last time you need to do it.
These are the options I could strip from OpenSSL and still get it to build with RSA:
no-md2 no-md4 no-mdc2 no-ripemd no-rc2 no-rc5 no-idea no-cast no-des no-krb5 no-ec no-engine no-hw no-err
libeay32.dll is 572K.
ssleay32.dll is 128K.
Note that speed.c in the test suite wouldn't compile because DES was missing.
Bloom filters are cool. Start with a hash table, which is an efficient way to look up items in a set. A bloom filter is like a hash table, but it tells you only whether an item is in a set, and it sometimes incorrectly says yes (false positives), and the data structure is much smaller than a hash table.
This could be used to make a P2P filesharing client where searches could be performed offline. Peer A computes its Bloom filter signature, then broadcasts it to the world. Peer B collects Bloom filter signatures, then when it wants to search for an item, it iterates all the signatures, looking for a likely match, and broadcasts queries to one or more of the peers that come up positive.
Same idea but generalize it: a peer itself can be an item, so peers could exchange Bloom filters of connected peers to determine how to reach a particular peer without broadcasting queries to the whole world.
Being too cheap to buy Purify, I finally had to figure out how to use the built-in leak detector in VS.Net. Turns out it's really easy.
Here is source code for Reed-Solomon encoding/decoding using the Berlekamp algorithm.
To do a case-sensitive search in Emacs, type M-c while in the incremental search box. Emacs also guesses that you wanted a case-sensitive search if your search term contains at least one capital letter.
Over the past couple of weeks I've been getting OpenSSL to build on Windows, and I've been writing test programs to explore the API. I have also removed all the custom encryption code in WINW, which is a good thing. I like the BIO abstraction in OpenSSL; it's similar to what I was trying to do in WINW, but it's better. The similarities have also made it pretty easy to integrate WINW and OpenSSL.
ps axwww | grep httpd | awk '{print $1}' | xargs -n1 kill -9
A "file" consists of the blocks of data in a file, and metadata describing the file (such as the filename).
Using this terminology, a hard link points to the data, and a soft link (also called a symlink or symbolic link) points to the file. Every file has at least one hard link, but not every soft link points to a file.
This explains why the Unix command for deleting a file is called "unlink." When you unlink a file, what you're really doing is removing a hard link to the file data, and when the last hard link to that file data is removed, the system removes the data, too (well, it doesn't delete the data, but it marks it as free).
The Unix command script captures a terminal session to a file. It's useful when documenting how you did something in a shell.
This allows you to skip the Linux step.
- Download the OpenSSL tarball and extract it.
- Find the file util\mk1mf.pl.
- Find the line
($key,$val)=/^([^=]+)=(.*)/;and add this line after it:$val =~ s/\s+$//;(this is at line 487 in OpenSSL 0.9.7c) - Now follow the instructions that came with the tarball.
The problem is that mk1mf.pl parses the generated MINFO file into key-value pairs, but in the process picks up the end-of-line character at the end of each value. I bet this is a problem only if you install Cygwin Perl with DOS line endings, which I did (though I tried converting MINFO to Unix linefeeds and it still didn't work).
I know how to build OpenSSL on Visual Studio .NET!!! So can you.
Ingredients:
One Windows machine with VS.NET (my version is 2002, a.k.a. 7.0)
One Linux machine (mine is Fedora Core 1)
One tarball of OpenSSL 0.9.7c.
Why doesn't my modeless WTL dialog act like a dialog? This is old hat for any MFC programmer, but it took me a little bit to get it right.
I'm having fun this weekend with WTL, the Windows Template Library. Feels a little like Java programming, oddly enough. All the code tends to get written in header files, inside the class declaration.
There is a huge amount of sample code on Code Project, often with helpful articles.
I finished the refactoring of WRouter. The reason for the refactoring was my observation that each time I wrote a new object in the system, the unit tests were getting harder and more complex to set up -- each new object required instantiation of at least one of all the previous objects in the system. This was a clue that I wasn't encapsulating things very well.
All the sample code I found on the net dealing with async Wininet uses globals for various items shared between the main flow and the callback function. The use of globals masks a problem.
Wow, Clay Shirky mentioned WINW! I was wondering why the hits on winw.org suddenly went from dozens to thousands.
He says "In response to the RIAA's suits, users who want to share music files are adopting tools like WINW and BadBlue, that allow them to create encrypted spaces where they can share files and converse with one another." Well, that's true except for the word "are" -- replace it with "will, if Mike ever finishes his project, be" -- and it's a little closer to the true state of affairs.
What do you usually do when you need to set text in a Windows control? You do one of the following:
- SetWindowText()
- SetDlgItemText()
- SendMessage(WM_SETTEXT)
- SendMessage(WM_SETTEXTEX)
It's tempting to do the same for a Rich Edit control, and sure enough, this will work on almost all versions of Windows.
Wise guidelines to follow when working on team programming projects
Be friendly to team members who don't know your code as intimately as you do or who shouldn't need to be familiar with it
Choose filenames that do not include magic words like "error," "warning," or "project." When a build engineer (or you when the build engineer has gone home) needs to find certain events in a build log such as all errors in a 50-project product build, it helps not to turn up false positives like "errordisplay.h."
When choosing file and target names, make life easy for your fellow grepping developer. For example, if your team is working on the Foo Project and you've chosen FP as the prefix for your file and target names (FPMain.c, FPDocument.h, FPHelper.exe), avoid names that will turn up in every search (FP.DLL, fp.c, fp.h).
Use a consistent commenting style. If you usually type pending(miket): fix this, never type pending (miket): fix this. Sometimes, comments are the only element of source code that enables someone else to find every area affected by a code change. If you think of comments as grep-friendly tags rather than just notes to yourself, they'll become a reliable (though last-ditch) method to locate important parts of code.
Anticipate the questions and needs that product marketing and QA will have
Decide what's going to be user-visible and what won't be, and keep a clear distinction between the two. If there's any possibility that the product name will change at the last minute from Foo to Bar (and that always happens), you as an engineer should be able to say the following:
Yes, we can make that change by modifying one header file and three resource scripts. No code will change. No build steps will change. In fact, this job is perfect for our junior engineer who started on Monday. I will tell him or her the names of the header file and the resource scripts, and he or she will be able to do this task without knowing anything at all about our code.
Along the same lines, there will be some items that will always be hard to change, such as a shared library filename that is a dependency for every other binary in your released product. Choose filenames in a way that avoids their being tightly wedded to a brand or product name. Most modern operating systems provide a way for files to describe themselves nicely (MacOS and Windows give you standardized version resources, for example). That's where the brand names, product names, trademarks, descriptions, and any other user-visible text should go.
And finally, a tip particular to Windows: seriously consider using GUIDs as registry key names. The Windows Registry is a shadowy area between user-visible and opaque binary parts of a product. Somehow, though it's the most dangerous part of the system for a non-engineer to manipulate, every product manager and QA tester seems to know how to type "regedit" at a command prompt and start browsing the Registry "just to see what's there." This is exactly like a product manager opening a hex editor and looking at a binary file "just to see what's there," but the reason that never happens is because Windows doesn't ship with any nice friendly-looking GUI hex editors. There are many examples of registry keys in the current Windows Registry where the current product name doesn't match the product name in the Registry, and each of those surely caused a conniption at some software company when the product manager or QA started logging bugs about how the registry key still had the old product name. A GUID avoids this problem. It's exactly what an engineer needs: a guaranteed unique path to find certain data pertaining to a software project, and using a GUID instead of a product name makes sure that nobody mistakenly believes it's anything more than that.
Learn how to use your source control system
Don't use branching or tagging technology in your source control system as product version control. If you find yourself branching the tree and having to copy and paste your code changes to two or more live branches repeatedly, it's likely you're misusing the system. What you've effectively done is asked the system to handle an extra dimension -- not just a history of changes within a series of files, but also multiple series of files, which by now have only an incidental relationship to each other (as opposed to the traditional use of branching, which is to preserve the state of the 1.0 product to allow maintenance releases, while work continues on the 1.1 release. Once the 2.0 product is begun and it's meant to be a clean break from the 1.0 product, it makes more sense to start a brand-new source tree).
Windows programming tips
Platform SDK: All the free stuff you need to develop for Windows. Get this, a text editor, a compiler, and a linker, and you can develop Windows programs. The Platform SDK is usually more up-to-date than the subset of tools, libraries, and header files you get with Visual Studio, so it makes sense to have both Visual Studio and the Platform SDK installed on your system.
dumpbin.exe: a utility that comes with Visual Studio and is also available in the Platform SDK. This thing extracts useful information from binary images (.exe, .dll, .cpl). Two invaluable functions are disassembling binaries and seeing which functions they export.
depends.exe: a utility that comes with Visual Studio and is also available in the Platform SDK. GUI-based; tells you lots of good stuff about binary images. A normal installation of Visual Studio usually registers this application to handle certain filetypes, such as DLLs, so opening a DLL from Windows Explorer takes you right to Depends.
.map file: lists the addresses where interesting things start in a binary image. If a program crashes at a particular address, you can use the map file to guess which function it was in where it crashed (and you can disassemble the binary with dumpbin to find the exact instruction).
Why do I get these weird debug assertion failures saying my heap's corrupted when I know it isn't? Chances are you're using different versions of the C runtime library within the same process (e.g., foo.exe is compiled with the debug multithreaded DLL runtime, and a dependency, bar.dll, was compiled with debug multithreaded).
(Not a Windows programming tip): God damn it, I just pressed send by mistake before I finished that e-mail. Can you help me? No, but next time you might want to start getting in the habit of putting the addressee in last, assuming you're using an e-mail client that lets you tab around from field to field. Then you can't send the e-mail until you really mean it.
