Some help for the struggling programmer
— qdb
After Jonathan’s post yesterday, I decided that I can pretend to be as wise as he is. So, now I present to you, my list of the first things that come to mind when I’m working:
- Corollary to Jonathan’s item vi: One of the highlights of Visual C# 2005 (aka C# 2.0) was the support for the “partial” class specifier. While C# improved on C++ (sort of) by ridding the world of header files, type libraries, etc., mandating the use of only a single file for a given class caused problems when things got too complicated. The “partial” keyword easily allows a C# class to be spread across multiple files, allowing code-generated portions to be in the same class, as well as easier editing. (I’m sure VB.Net has the same feature, but I don’t like VB.Net).
- A #region directive is most useful when you’re writing and editing code. When debugging, it’s mostly useless. When printing out code, it’s useless. But in order to keep subsections partitioned off either when you’re adding a whole lot of related code or when you’re implementing an interface and just want to “close it off” when you’re done, it’s useful. (C# again — would you believe I rarely write C# code?)
- Learning to use Windbg for your unmanaged debugging is priceless. You’ll lose some ease of use, but it’s:
- Incredibly fast
- apparently more accurate at both symbol location and source location than Visual Studio
- the only thing to use in some cases, so it’s better to be familiar with it early on
- got the best debugging feature I’ve seen in a long time: the “x Function” command, where Function can be a wild-carded search string… say you know you need a breakpoint on some function in some assembly shipped by your team. “x VSTO*!*ReportError” will return every function with a trailing ReportError implemented in every class in every DLL that is named starting with VSTO. It’s just useful.
- Never presume that other developers understand the difference between class and interface inheritance. Whenever someone starts casting from an interface to a class, begin getting suspicious. Whenever anyone explicitly casts from one interface to another not in a QueryInterface call, assume that that person may be making a mistake. Outside of non delegating IUnknown::QueryInterface implementations, there are very few places where that’s a good idea.
- The AddRef/Release Factory pattern is a very good one for a reason; ask anyone who’s ever had to track down a bug due to the difference in heap allocation and deallocation (Hi Jonathan!)
- Cross-thread logic is never as simple as you would like.
- It’s sometimes better to start debugging by observation, rather than jumping right into the debugger. Two minutes with SpyXX and a single breakpoint told me precisely where a bug lay in our code; a senior developer has spent several hours with no luck.
- On a related note: if a program isn’t responding to a button press: 1) it’s not handling the button press (correctly, in some cases), or 2) it’s not getting the button press. They’re both reasonably easy to verify with minimal debugging, and knowing which it is saves you hours of time.
- Debugging a crash that occurs in obvious code (ie, crash on a line: pInterface->Func() with a NULL pointer access violation) is far simpler than inordinately complex code — if it’s the former case the problem is usually right nearby or immediately obvious (the member was never set properly, a QueryInterface call isn’t being verified as having returned S_OK, etc.) The latter case usually will take a great deal of headscratching and puzzling and will eventually lead you to arcane bugs that occur somewhere entirely different — where the stack or thread data is getting royally trashed.
- Component != class; Interface defined in a header file != IDL / Typelibrary / IMarshal-capable component.
I’m done now. I’m not nearly as coherent as Jonathan, but I’m twice as angry. 🙂