In a recent Programmers Stack Exchange Q & A session discussed on Ars Technica, codebreaker asks: “Why follow defensive programming best practice when code will never be public?” After writing a card game for Java, the developer described how they used “a method in the Zone API, move(Zone, Card), which moves a Card from the given Zone to itself (accomplished by package-private techniques).” They continue, “This way, I can ensure that no cards are taken out of a zone and simply vanish; they can only be moved to another zone. My question is, how necessary is this kind of defensive coding? It’s “correct,” and it feels like the right practice, but it’s not like the Zone API is ever going to be part of some public library. It’s just for me, so it’s kind of like I’m protecting my code from myself when I could probably be more efficient by just using standard Collections.”
Good question, codebreaker – so what are defensive programming techniques and when should they be used? Should they be used in every circumstance or only when a piece of software could be misused? As an example, if the code allows you to sell more items than you have, because the dial/ticker/selector didn’t prevent you from clicking “down” past zero, preventative safeguards should be put in place. Defensive programming is a method for improving software and source code, for reducing the number of software bugs, for making source code understandable, and for making software run in a predictable and appropriate manner, regardless of user actions. Responders on Stack Exchange provide their reasons for keeping code under lock and key:
Michael K answers:
“Maybe there are coders out there who remember the nuances of every class and method they ever wrote and never mistakenly call into them with the wrong contract, but I often forget how code I wrote is supposed to work within hours of writing it. You have tools to combat that. These tools include: conventions, unit tests and other automated tests, precondition checking, and documentation. I have found unit tests to be invaluable because they both force you to think about how your contract will be used and provide documentation later on about how the interface was designed.”
“I usually follow some simple rules:
- Try to program by contract, where elements of a software system collaborate with each other on the basis of mutual obligations and benefits.
- If a method is publicly available or receives input from the outside world, enforce some defensive measures (e.g. IllegalArgumentException).
- For everything else that is only accessible internally, use assertions (e.g. assert input != null).
- As to your specific case, if Zone isn’t supposed to be used and/or accessed by outsiders, either make the class package-private (and possibly final), or preferably, use the collections Java already provides you. They’re tested, and you don’t have to reinvent the wheel.”
Guard Against Cheaters
“Defensive programming is a very good thing, until it starts getting in the way of writing code.
It sounds like you’re right at the edge of taking things too far. The challenge (and the answer to your question) lies in understanding what the business rules or requirements of the program are.
Using your card game API as an example, there are some environments where everything that can be done to prevent cheating is critical. Large amounts of real money may be involved, so it makes sense to put a large number of checks in place to make sure that cheating can’t occur.
However, asking the container class to effectively audit where cards are going may be a bit much. It may be better to have an audit layer between the card container and the function that receives the move requests.
You also need to understand what components of your API are publicly exposed versus what is private and less exposed. The best return of your effort is to harden the exterior of your API.”