Debugging Applications for MicrosoftВ® .NET and Microsoft WindowsВ® (Pro-Developer)
|
Before we get into the meat of debugging, I want to cover what you must know to be a good debugger. The first quality that all expert debuggers have in common is being good developers too. You simply can't be a good debugger without being a good developer, and vice versa.
The Skill Set
Good debuggers and, conversely, good developers all have strong problem-solving skills that are particular to software. Fortunately, you can learn and hone those skills. What sets great debuggers/developers apart from good debuggers/developers is that in addition to having basic problem-solving skills, great debuggers/developers understand how all the parts of a project relate to the project as a whole.
The following list contains the areas in which you need to be proficient to become a great—or at least a better—debugger/developer:
-
Your project
-
Your language
-
Your technology/tools
-
Your operating system/environment
-
Your CPU
Know Your Project
Knowing your project is the first line of defense for user interface, logic, and performance bugs. By knowing how and where features are implemented in the various source files, you can quickly narrow down who is doing what to whom.
Unfortunately, because each project is different, the only way to learn your project is to read the design documents (if they exist), and to walk through the code in the debugger. Modern development environments have class browser views that can show you the basics, but you might want to turn to a real browsing tool such Source Dynamics's Source Insight. Additionally, you can use real modeling tools such as Microsoft Visual Studio .NET Enterprise Architect with its Microsoft Visio integration, which can show you the relationship or Unified Modeling Language (UML) diagrams that describe the code. Even poorly documented source code is better than nothing if it saves you from having to interpret a disassembly listing.
Know Your Language
Knowing the language (or languages) your project uses is more difficult than it sounds. I'm referring to knowing what your language is doing behind the scenes as well as knowing how to program in it. For example, C++ developers sometimes forget that local variables that are classes or overloaded operators can create temporary items on the stack. Alternatively, an assignment operator might look innocent enough, but it can cause a great deal of code to execute. Many bugs, especially performance problems, are the result of language misuse, so it's well worth the effort to spend some time reading up on the idiosyncrasies of the programming languages you use.
Know Your Technology/Tools
Getting a handle on the technologies you're using is the first big step to tackling the harder bugs. For example, if you have an idea of what COM does to instantiate a COM object and return an interface, you'll have a much easier time tracking down why a specific interface request failed. The same goes for something like ISAPI filters. If you're having a problem with your filter being called correctly, you need to know where and when INETINFO.EXE should be loading your filter. I'm not saying that you need to quote files and lines from the source code or a book. Rather, I'm saying that you should have at least a general understanding of the technologies you're using and, more important, you should know exactly where you can find more detailed information if you need it.
In addition to knowing the technology, it's vital to know the tools you're using. A big portion of this book is spent discussing advanced usage of the debugger, but many other tools are out there, such as those distributed with the Platform SDK. Taking a day simply to explore and learn all the tools you have at your disposal is a very wise investment. This exploration includes downloading and evaluating commercial tools because those can make a huge difference in your development.
Know Your Operating System/Environment
Knowing the basics of how your operating system or operating environment goes about doing its work can make the biggest difference between solving a bug and just floundering around. If you're working on native code, you should be able to answer questions like the following: What is a dynamic-link library (DLL)? How does an image loader work? How does the registry work? For managed code, you should know things such as, How does ASP.NET find the components a page is using? When do finalizers get called? What's the difference between an application domain and an assembly? Many of the worst bugs appear when you misuse the operating system or environment. My friend Matt Pietrek, who taught me a great deal about debugging, maintains that knowing the operating system/environment and the CPU is what separates the debugging gods from mere mortals.
Know Your CPU
This brings me to the last thing you must know to be a debugging god for native code: the CPU. You must know a little about the CPU to solve most of the nastiest bugs you'll encounter. Although it would be nice if you always crashed where source code was available, the majority of your crashes drop you right into the Disassembly window. It always amazes me how many engineers don't know—and say they have no interest in knowing—assembly language. Assembly language isn't that hard, and three or four hours spent learning it can save countless hours in the debugger. Again, I'm not saying that you need to be able to write your whole program in assembly language. Even I don't think I could do that anymore. The point is that you need to be able to read it. All you need to know about assembly language is in Chapter 7.
Learning the Skill Set
With any job that regularly deals with technology, you have to study continually just to keep up, let alone get better and advance. Although I can't help you learn your specific projects, in Appendix B I list all the resources that have helped me—and can help you—become a better debugger.
Besides reading books and magazines on debugging, you should also write utilities, any kind of utilities. The ultimate way to learn is by doing, and in this business, coding and debugging are what you need to do. Not only will you enhance your hard skills, such as coding and debugging, but if you treat these utilities as real projects (that is, by completing them on time and with high quality), you'll also enhance your soft skills, such as project planning and schedule estimating.
To give you some impetus to complete your utilities, consider this: completed utilities are excellent show-and-tell items to bring to job interviews. Although very few engineers bring their own code to demonstrate their skills to interviewers, companies consider those candidates who do well before those candidates who don't. Bringing a portfolio of the work you did on your own time at home shows that you can complete work independently and that you have a passion for software engineering, and it will almost immediately put you in the top 20 percent of engineers.
Another practice that has helped me a great deal, especially when it comes to learning more about languages, technologies, and the operating system, is to look at other engineers' code. As you probably know, a great deal of code that you can look at is floating around on the Internet. By running different programs under the debugger, you can see how someone else tackles bugs. If you're having trouble coming up with a utility you'd like to write, you can simply add a feature to one of the utilities you find.
Another technique I would recommend to learn more about technologies, the operating system, and the virtual machine (CPU) is to do some reverse engineering. It will help get you up to speed with assembly language and the advanced features in the debugger. After reading Chapter 6 and Chapter 7, you should know enough about Microsoft Intermediate Language (MSIL) and IA32 assembly language, respectively, to get started. Although I wouldn't recommend you start out by completely reverse engineering the operating system loader, you might consider tackling some smaller tasks. For example, I found it very instructive to walk through the implementation of CoInitializeEx for native code and the System.Diagnostics.TraceListener class in managed code.
Reading books and magazines, writing utilities, reviewing other engineers' code, and doing reverse engineering are all great ways to improve your debugging skills. However, your greatest resources are your engineering friends and coworkers. Never be afraid to ask them how they did something or how something works; unless they are in the middle of a deadline crunch, they should be happy to help. I enjoy it when people ask me questions because I end up learning more than the individuals who ask the questions! Programming newsgroups are also excellent places to pose questions. I read them all the time because their responses are so good, especially from those folks Microsoft has designated MVPs (Most Valuable Professionals).
|