ContractLib is a simple-to-use PHP component for easily enforcing programming contracts throughout your PHP components. These programming contracts can go a long way to helping you, and the users of your components, develop more robust code.
ContractLib is loosely inspired by Microsoft Research’s work on the Code Contracts Library for .NET.
What Are Programming Contracts?
Programming contracts are tests around functions and methods, and they are normally used:
- to catch any ‘bad’ data that has been passed into the function or method from the caller, and
- to catch any ‘bad’ data generated by the function or method before it can be returned to the caller
These are pre-condition and post-condition tests, and they are tests that either pass or fail.
Why Have Programming Contracts?
Two reasons: code robustness and time saved.
Programming contracts catch errors early, and (unlike unit tests) they don’t just catch your errors, they catch errors made by programmers who reuse your code.
- Catching errors early
There is a class of bugs best described as garbage in, garbage out. The “garbage in” is data that is of the wrong type, or out of range, or missing (think empty arrays, empty strings, nulls). Often, the garbage being fed in is also garbage that has come out of a buggy function or method.
Simple pre-condition checks at the start of your functions and methods quickly catches garbage data before it can propagate through your code. The more functions and methods contain pre-condition checks, the easier it becomes to catch garbage data closer to where it is being created. This allows you to spend less time tracking down the original source of a bug, and more time writing new code.
These pre-conditions also greatly increase the chances of bugs in your code being caught in development, especially when combined with a healthy amount of unit testing.
You can also add post-conditions at the end of your functions and methods, to make sure that you’re never returning any garbage back out of your function or method. There’s a lot of overlap between post-conditions and unit tests; the main difference is that your post-conditions will run 100% of the time, whereas your unit tests will only run when you run them and against the (often extremely limited) data you use in your unit tests.
- Catching errors when code is reused
Unit tests are great, and a very important part of creating high-quality code. But they’re your tests. They’re written to prove that your code does what you think it does.
Unit tests don’t prove that someone else is reusing your code the way you meant them to.
And neither do integration tests, because if someone is reusing your code, integration tests are their tests. Integration tests are tests to prove that they have glued their code on top of your code in a way that they are happy with.
Simple pre-condition checks at the start of your functions and methods are your best opportunity to test how someone else is reusing your code, and to tell them if they’re getting it wrong.
Programming contracts are about building trust (just like unit tests). Code that you can trust is normally code that is quicker to work with. They’re really quick to write (normally far quicker than unit tests), and they can make it really quick to track down the origin of bugs in your code.
Don’t Programming Contracts Make Code Stupidly Strict?
An appropriate amount of strictness is a requirement of all high-quality code. The trick is knowing what to be strict about. Not strict enough, and you let in shitty data that causes your code to fail or be insecure. Too strict, and people will think that your code is too much trouble to work with.
As a general rule, pre-conditions should check for:
- data that’s in an incorrect format
- data that’s out of range
- data that’s missing
Post-conditions should check the same things. They can also be used to check for data that should have been changed, but hasn’t been changed.
Aren’t Programming Contracts Too Old-Fashioned For PHP?
The concept has been around for decades. As a C programmer, I first learned about programming contracts in the early 90′s, when I was writing code that had to run for months at a time with zero downtime. We were debugging and improving code dating back from the 1980′s, and introducing programming contracts played an important role in getting to the bottom of many of the bugs that users reported.
PHP code (and other modern languages like Java, Ruby, Scala etc) is fundamentally similar to older languages like C, although you may not realise that this is the case. It’s the same fundamental paradigm – data is passed into blocks of software, and blocks of software may also pass data out too.
The advantage we have with PHP is that our programming contracts don’t have to be as lengthy as they would for a C program, because PHP itself can enforce type checks through type hinting, and we don’t have to worry about low-level details like proper handling of null-terminated strings.
You can take a look at ContractLib’s unit tests on GitHub.
I’ll post some detailed examples in my next blog post.