Defensive Programming
{{c1::Legacy code}} is archaic programs written by code monkeys that are now long gone.
Defensive programming is an informal set of guidelines that can prevent many different coding problems. Defensive programming techniques are easier to apply when writing code the first time but should be used all the time.
The first thing to do to program defensively is do not make any assumptions. Do not assume that something will not happen. Remember Murphy's Law. If you make assumptions, as the code base evolves and time passes, you will forget what assumptions you had made. Assume nothing. Smash unwritten assumptions by explicitly checking for them in the code. Do not get into a cycle of tinker -> run -> crash -> tinker -> run until it works.
Three things that some people might believe are {{c1::defensive programming}}, but are really not, are {{c2::error handling}}, {{c3::testing}}, and {{c4::debugging}}. Error checking is a part of writing correct code. Testing is also a normal part of development. Defensive programming prevents problems. Debugging is the act of removing bugs after they have already been introduced.
Defensive programming also avoids a number of security problems. Sloppy code can be exploited to gain control of an application which can have huge implications.
Adopt a good coding style. Choose meaningful variable names, use parentheses judiciously. These increase clarity and reduce the probability of faults slipping through. Also consider the larger-scale design before rushing into the code.
Always think carefully about what you're typing as you type it. A common mistake is mistyping == as =.
Always do all of the tasks involved in completing a code section before moving on. Every time you do not do the right thing now, you become more likely to continue not doing the right thing in the future. Do it now!
Treat all inputs with suspicion.
Write code for clarity, not brevity. It may be up to a junior to maintain your code one day. Unusual language tricks may prove your knowledge but do not help maintainability. Keep it simple. Code that cannot be maintained is not safe. Never make code more complex than necessary.
Prevent access to internal class data by keeping it private in object-oriented languages (encapsulation). Keep variables in the tightest scope possible.
Compile with all warnings switched on. When warnings are generated, fix them immediately. Never be satisfied with code that doesn't compile quietly when warnings are enabled. They are there for a reason.
Use static analysis tools. Static analysis will prevent the compiler warnings before the code is run and pick up many more errors than your compiler alone.
Use safe data structures. The most common security vulnerability may result from buffer overrun. This is caused by the careless use of fixed-size data structures. Code that writes into a buffer without checking its size first allows for the possibility of writing past the end of the buffer. This is frighteningly easy to do with a small snippet of C code. This can lead to data corruption. It can also allow a malicious to put executable code on the program stack and run an arbitrary program.
Handle memory and other precious resources carefully. Release any resources that you acquire during execution.
Initialize variables at their points of declaration. Declare variables as late as possible.
Use standard language facilities. Be clear about what language version you are using. Do not rely on compiler weirdness or any nonstandard extensions to the language. Do not rely on undefined behavior. This will lead to very subtle bugs when the compiler is updated.
Be careful when casting data from one type to another. Consider what may happen when casting a 64-bit integer into a 8-bit type. What happens to 56 of the bits? Be extremely careful with C and C++ here because they are vague about the precision of data types--you cannot make assumptions about data type interchangeability.
When using switch statements, if reaching the default case is an error, make that clear. If it is allowed and nothing is supposed to happen, make that clear.
Make everything as const as you can. This acts as code documentation and allows the compiler to spot certain mistakes.
Physically incorporate any assumptions you make into the program. This codifies the constraints on program functionality and behavior. Preconditions are conditions that must hold true before a section of code is entered. Postconditions must hold true after a code block is left. Invariants are conditions that hold true every time the program's execution reaches a particular point. Assertions are any other statement about a program's state at a given point in time. Good constraints make your program clearer and more maintainable. This technique is also known as design by contract.
Defensive programming is an informal set of guidelines that can prevent many different coding problems. Defensive programming techniques are easier to apply when writing code the first time but should be used all the time.
The first thing to do to program defensively is do not make any assumptions. Do not assume that something will not happen. Remember Murphy's Law. If you make assumptions, as the code base evolves and time passes, you will forget what assumptions you had made. Assume nothing. Smash unwritten assumptions by explicitly checking for them in the code. Do not get into a cycle of tinker -> run -> crash -> tinker -> run until it works.
Three things that some people might believe are {{c1::defensive programming}}, but are really not, are {{c2::error handling}}, {{c3::testing}}, and {{c4::debugging}}. Error checking is a part of writing correct code. Testing is also a normal part of development. Defensive programming prevents problems. Debugging is the act of removing bugs after they have already been introduced.
Defensive programming also avoids a number of security problems. Sloppy code can be exploited to gain control of an application which can have huge implications.
Adopt a good coding style. Choose meaningful variable names, use parentheses judiciously. These increase clarity and reduce the probability of faults slipping through. Also consider the larger-scale design before rushing into the code.
Always think carefully about what you're typing as you type it. A common mistake is mistyping == as =.
Always do all of the tasks involved in completing a code section before moving on. Every time you do not do the right thing now, you become more likely to continue not doing the right thing in the future. Do it now!
Treat all inputs with suspicion.
Write code for clarity, not brevity. It may be up to a junior to maintain your code one day. Unusual language tricks may prove your knowledge but do not help maintainability. Keep it simple. Code that cannot be maintained is not safe. Never make code more complex than necessary.
Prevent access to internal class data by keeping it private in object-oriented languages (encapsulation). Keep variables in the tightest scope possible.
Compile with all warnings switched on. When warnings are generated, fix them immediately. Never be satisfied with code that doesn't compile quietly when warnings are enabled. They are there for a reason.
Use static analysis tools. Static analysis will prevent the compiler warnings before the code is run and pick up many more errors than your compiler alone.
Use safe data structures. The most common security vulnerability may result from buffer overrun. This is caused by the careless use of fixed-size data structures. Code that writes into a buffer without checking its size first allows for the possibility of writing past the end of the buffer. This is frighteningly easy to do with a small snippet of C code. This can lead to data corruption. It can also allow a malicious to put executable code on the program stack and run an arbitrary program.
Handle memory and other precious resources carefully. Release any resources that you acquire during execution.
Initialize variables at their points of declaration. Declare variables as late as possible.
Use standard language facilities. Be clear about what language version you are using. Do not rely on compiler weirdness or any nonstandard extensions to the language. Do not rely on undefined behavior. This will lead to very subtle bugs when the compiler is updated.
Be careful when casting data from one type to another. Consider what may happen when casting a 64-bit integer into a 8-bit type. What happens to 56 of the bits? Be extremely careful with C and C++ here because they are vague about the precision of data types--you cannot make assumptions about data type interchangeability.
When using switch statements, if reaching the default case is an error, make that clear. If it is allowed and nothing is supposed to happen, make that clear.
Make everything as const as you can. This acts as code documentation and allows the compiler to spot certain mistakes.
Physically incorporate any assumptions you make into the program. This codifies the constraints on program functionality and behavior. Preconditions are conditions that must hold true before a section of code is entered. Postconditions must hold true after a code block is left. Invariants are conditions that hold true every time the program's execution reaches a particular point. Assertions are any other statement about a program's state at a given point in time. Good constraints make your program clearer and more maintainable. This technique is also known as design by contract.
Summary
Craft code that is correct and also good. Document any assumptions made. It will be easier to maintain and have less bugs.Â
Defensive programming is about expecting the worst and being prepared for it. Codified constraints can make your software far more robust. Like other good practices, by spending a little extra time early on, more time can be saved later. This can save the entire project.
Good programmers care (attitude is important). They make sure any assumption is explicitly captured. They ensure well-defined behavior for garbage input. They think carefully about the code as they write it. They write code that protects itself.
Bad programmers ignore what can go wrong. They are careless and hope others will figure it out. They do not document assumptions and then forget them themselves. They do not apply much thought to the code they are writing. This results in unpredictable and unreliable software.
Article notes
What does Code Craft call an informal set of guidelines that is a practical way to prevent many coding problems?
Defensive programming
What is the definition of legacy code given by Code Craft?
Archaic programs written by code monkeys that are now long gone
What summarizes the Code Craft stance on making assumptions in programming?
Assume nothing (in bold)!
When is the easiest time to use defensive programming techniques?
The first write of the code
When should defensive programming techniques be deployed?
All the time
What is the first rule of defensive programming according to Code Craft?
Do not make assumptions
What are two reasons you shouldn't make assumptions according to Code Craft?
You will forget them and they will not hold true
How does Code Craft recommend you smash unwritten assumptions?
Explicitly check for them in the code
What do good programmers also do when they make assumptions according to Code Craft?
Document them
What are three things that some people mistakenly believe are defensive programming techniques?
Error handling, testing, and debugging
How is defensive programming different from debugging?
Defensive programming prevents problems
What happens when you do not do the right thing right away according to Code Craft?
You become more likely to not do the right thing next time
How should all inputs be treated according to Code Craft?
With suspicion
What do good programmers do with garbage input according to Code Craft?
Ensure well-defined behavior
What scope should variables be held in according to Code Craft?
The tightest scope possible
Where should variables be declared according to Code Craft?
As late as possible
When should variables be initialized according to Code Craft?
At their points of declaration
What does Code Craft claim causes the most common security vulnerability?
Buffer overrun
What does Code Craft say to do when you see warnings being generated?
Fix them immediately
Why does Code Craft recommend using parentheses judiciously?
They increase clarity and reduce faults
Defensive programming is a practice where time invested in the beginning saves time later, and it can even do what?
Save the entire project
What does Code Craft give as a common mistake that happens when you do not think carefully about the code you are typing as you are typing it?
Typing = instead of ==
What happens when programmers are careless, do not apply much thought to the code they write, and do not document assumptions?
Unreliable/unpredictable software
What question does Code Craft state regarding casting a 64-bit integer into an 8-bit type?
What happens to 56 of the bits?
Code Craft describes what kind of programming as ensuring well-defined behavior for garbage input, making sure any assumptions are codified or explicitly captured, and writing code that protects itself against the worst that could happen?
Defensive programming
[...] is archaic programs written by code monkeys that are now long gone.
Legacy code is archaic programs written by code monkeys that are now long gone.
Three things that some people might believe are [...], but are really not, are [...], [...], and [...].
Three things that some people might believe are defensive programming, but are really not, are error handling, testing, and debugging.