Extreme Precision Programming
What is “Extreme Precision Programming”? It is a style of programming that aims to perform the intended function, while being very noisy about anything that deviates from the intended mode of behavior. It is nothing like a complete methodology, but rather a philosophical leaning to guide choices at the implementation level.
Many, if not most, readers already practice very precise programming. This is not a radical departure from what you already know as good programming techniques. But there are areas where things might be done more than one way: either a more strict way, or a more forgiving way. EPP take an extremely strict approach to things that are under control of the programmer, while still being forgiving to end users. This makes the programming environment highly sensitive to programming mistakes. By being highly sensitive to programming mistakes, it helps the programmer flush out any and all logic errors. When the program is running, you have the best possible chance that it is running correctly. Most of the trivial, silly errors are flushed out immediately.
Guidelines
- Exceptions: make copious use of exceptions for truly exceptional things: things that should never happen. These are things that if they occur, the program is incorrectly written, and is not ready for production use. It is important to be as noisy as possible to alert the programmer to this program logic error.
- Test all parameters: An EPP program will test input values for correctness, and throw an exception if any value received is outside of expected values. Don’t leave any loosness or sloppiness. IF the test is expensive, then you might not want to include it always while running, but generally tests are very quick (boolean and numeric tests, tests for null, etc.)
- Test parameters for null: For some method parameters a null has a meaning, and in others it would be a programming error to pass a null. In those latter cases, test for null, and throw an exception that explains which parameter was null and which routine found it.
- Test parameters for boundaries: if negative values do not make sense, test for that and throw an exception.
- Use Generic Exception: do not make a new exception class for each kind of error. You are going to lots of tests and exception, and your only audience is the programmer, so just make a generic Exception object with a meaningful message.
- Clearly Mark as Developer Problem: Most of these exception can only occur because of a programming error. For example, a method to validate an object should never get a null. Once the program is written, and this validate is called in the middle of other handling of the object, it is pretty much impossible for a null to suddenly jump into the logic. I usually mark these with the text “Program Logic Error.” This is a message to me that once the program logic is written correctly, you should not ever see it. Also, include a clear message about what actually failed the test, and include the value in the message.
- Do Not Translate: If you program is being translated into multiple languages, do NOT design these exceptions to be translated. That can a waste a lot of time and effort. They should, in theory, only be seen while in development and by developers. If they do occur in a production situation, then this is a big problem, and having them translated is the least of your worries. I make a rule to never translate any exception that uses the words “Program Logic Error.”
- Clean Data when it enters: If the user is typing something in, be sure to check and clean the data as much as possible as soon as the value is received. If there is something wrong, you want to know it early.
- Warn About Unexpected Values: Consider a method passed some sort of option parameter that tells it to do one of four things. You probably have a switch statement or a set of IF statements that check for each option and does the right thing. If you get pass something that is NOT one of the four expected values, then do not just treat that like one of the the others. Check for the four valid options, and if NOT one of those, throw an exception. Do not test for three, and then assume if must be the fourth. If a new option is added, and that method is not prepared for it, you don’t want the code to just treat it like one of the other options.
- Avoid sloppy string comparisons: If a string value is expected to exactly match another string value, do not use a case insensitive compare. Some values are explicitly designed to be case insensitive, and those must be treated that way. But if the value is supposed to be exactly the same, don’t use the looser comparison. If you do, and it works, you are only pushing the problem to somewhere else.
- Avoid sloppy number comparison: If a number can have 5 values, then test for those file values. Don’t use a greater-than test for the highest value, but instead test for equals. Don’t let a larger-than-max value slip by as being the max value. Don’t let a negative value slip by as being the same as zero when the range is supposed to end at zero.
Summary
If the program is expected to run a particular way, then insist that it run exactly that way: no more, no less. If the program deviates from the expected behavior, then make a lot of noise and stop the program. You will find, during development, all the problems quickly and effectively. Even though the program is less forgiving, it will run better because it has more precisely been coded to run correctly, and it does not need the sloppiness to run.