Quite a lot of bad questions that I see on StackOverflow can be described with the following formula:
Here is my homework solution. It does not work.
[20 lines of code]
And ... everything.
Note Trans.: This is a translation of the article " How to debug small programs ", which is referenced in the informational section of StackOverflow in English , dedicated to the creation of minimal, self-sufficient and reproducible examples. It seems to me that it perfectly describes what every programmer should know - the basics of debugging non-working code.If you are reading this note, then most likely you followed the link that either I or someone else left under your question on StackOverflow shortly before this question was closed and deleted. (If you are reading this note for another reason, leave your favorite tips on debugging small programs in the comments).
StackOverflow is a question and answer site, but for very specific questions about a specific code. “I wrote some buggy code that I can’t fix” - this is not a
question , this is a
story , and not very interesting. “Why, when subtracting a unit from zero, do I get a number greater than zero, which is why my comparison with zero in line 12 is incorrectly calculated to be
true
?” - this is a specific question about a specific code.
')
So, you ask the Internet to
fix your broken program . Surely you have never been told how to debug small programs, because - attention -
what you are doing now - is not the most effective way . Today is a great day to learn how to debug the code yourself, because StackOverflow will not do it for you.
Below I assume that your program is compiled, but does not work correctly, and, moreover, you have an example that demonstrates this incorrect behavior. So, how to find a bug:
First,
enable all compiler warnings .
There is no reason why a correct program with 20 lines of code could get a compiler warning. A warning is when the compiler tells you: “this program is compiled, but does not do what you think,” and since
this is exactly the situation you are in , you should listen to it.
Read the warnings very carefully . If you do not understand why this or that warning was issued, this is a good question for StackOverflow, because it is a
specific question about a specific code . Add to the question the exact warning text, the exact code on which it was issued, and the exact version of the compiler you are using.
If your program still has a bug,
find a rubber duck . If there is no rubber duck, find another student programmer - there is almost no difference between him and the duck. Explain to the duckie in simple words, why each line of each method in your program is obviously correct. At some point you will encounter difficulties: either you do not understand the method that you wrote, or there is an error in it, or both. Concentrate on this method;
most likely, the problem is in it . No, really,
the duckling method works. And, as legendary programmer Raymond Chen added in the comments below (comment
: per.
To the original post ): if you can't explain to the duck why this or that line is needed, maybe because you started writing code before you got a plan.
If your program is compiled without warnings, and the duck has no serious questions for you, and there is still a bug, try
breaking the code into smaller methods , each of which performs
exactly one logical operation . A popular mistake of all programmers, not only beginners, is to write methods that do several things at the same time and make them bad. Small methods are easier to understand, and as a result, it’s easier for you and the duck to spot errors.
While you convert methods to smaller methods, stop for a moment to
write a technical specification for each method . Let it be one or two sentences, but having a specification helps. The technical specification should describe what the method does, what parameters are allowed, what return value is expected, when an error will occur, and so on. Often when writing a specification, you realize that you forgot to handle a certain case, and the bug turns out to be exactly that.
If you still have a bug, check and recheck that your specifications describe the
preconditions and postconditions of each method. A precondition is something that must be performed before the method starts. A post-condition is something that will be executed when the method finishes its work. Examples of preconditions: “the argument is a valid non-zero pointer”, “there are at least two vertices in the transferred link list” or “this argument is a positive integer number”. Examples of postconditions: “there was one element less in the coherent list than it was at the input”, “a certain piece of the array is now sorted” or something like that. If the precondition is violated, it is an error in the place where the method was called. If the fulfillment of all preconditions violated the postcondition - this is an error in the method. Again, when formulating pre- and post-conditions you will often stumble upon a forgotten event.
If the bug still has not gone away, learn how to write
assertions to check the pre and post conditions. A statement is almost like a comment, only it tells you when a condition is violated; and a broken condition is almost always a bug. In C #, you can say
using System.Diagnostics;
at the beginning of the code, and in the middle write
Debug.Assert(value != null);
or something similar. Every language has a mechanism for formulating statements; Ask someone to tell you how to use them in the language you write. Write statements for preconditions at the beginning of the method, and statements for postconditions before the line where the method ends. (Of course, this is easiest to do when there is exactly one cusp in each method.) Now, if you run the program and some statement turns out to be incorrect, you will know what the problem is and it will be easy to debug.
After that,
write tests or examples for each method that verify that it works correctly. Test each part separately from the rest until you are sure of it. Use a lot of simple tests; if your method sorts lists, try an empty list, a list of one, two, three identical elements, three elements in reverse order, several long lists. Most likely, your bug will manifest itself on a simple test, and then it will be easier to analyze it.
Finally, if your program still has a bug,
write on paper the exact description of the action that you expect from each line of code when you start up with your example . Your program takes only 20 lines. You should be able to write
everything that she does. Now go through the code
with the debugger , checking each variable at each step and line-by-line checking the behavior of your program with a piece of paper. If the program does what is not written on the piece of paper, then the error is either on the piece of paper (in this case, you do not understand what your program does), or in the program (in this case, you wrote something wrong). Correct what is wrong. If you do not know how to fix it - you at least have a specific technical question that you can ask at StackOverflow! In any case, repeat the process until your description of the program's behavior and the actual program's behavior coincide.
While you are working in the debugger, I urge you
to pay attention to the slightest doubt . Most programmers naturally assume that their code works as expected, but you are debugging it exactly because it is not so! Many times I debugged the code and noticed a quick flicker in Visual Studio, which meant “this memory has just been changed,” and I knew that this memory was not related to my problem at all. So
why has she changed ? Do not ignore these nagging, learn strange behavior until you understand why it is either correct or incorrect.
If it seems to you that this is all very long and requires a lot of effort, then only because it is. If you cannot use these techniques on a twenty-line program that you yourself wrote, it’s unlikely that you will be able to use them on a program of two million lines that someone else wrote. However, industry developers are doing it every day. Start training!
And the next time you decide your homework,
write the specifications, examples, tests, preconditions, postconditions and statements for each method before writing the method itself ! You will significantly reduce the likelihood of a bug, and if it does appear, you will most likely be able to find it pretty quickly.
This technique does not help to find all the bugs in each program, but it is extremely effective for those short programs that novice programmers write in their homework. It can also be used to find bugs in non-trivial programs.