Defensive versus Brittle Code
August 30th, 2006We have more options these days for creating robust applications. Back when I wrote a lot of code in Perl I wrote very defensive code. Each subroutine would verify assumptions about incoming parameters and correct problems whenever possible. And I found that it saved me some headaches because later the code had been changed, and while the change introduced a bug, the code continued to work in the Production environment. It was all due to the defensive strategy.
The brittle code strategy is another concept I have used. Essentially, if something is broken I want it to break. And I want it to break universally.
A common point where I always insert brittle code is the startup of an ASP.NET application. You can handle the Application_Start event and validate the configuration for the runtime. If you have settings to define locations of folders which are necessary to the proper running of the website, I simply throw an exception to state that fact. I call this a sanity check. And whenever the application is deployed I know immediately if the application will run properly, because if it was going to break, it would break universally.
Now that we have testing frameworks, which are more mature each year, we can put less effort into the defensive coding strategy because the tests will catch it, right? Well, I think it comes down to how mature your testing framework allows you to get and how complete your test suite checks your application. Assuming you do have a powerful testing framework with a comprehensive test suite you can start writing brittle code which will break when a developer introduces code which does not follow the rules. And a comprehensive test suite will throw some garbage at the system to verify that it handles the garbage properly.
Should I now abandon defensive coding and just trust in the test framework to validate my brittle code? I am not ready for that. I think a hybrid approach should be applied where you do not fully give up on the defensive strategy but still maintain strong object encapsulation. And then wrap a healthy amount of tests around your encapsulated objects to ensure strict conformance to your requirements.
As a part of that encapsulation, modern testing frameworks can evaluate the complexity of your code. If a single method is over 300 lines long and has 25 control statements (if, for, while), it should be simplified by breaking that method into smaller methods with specific tasks. (see Cyclomatic Complexity) Code analysis is different than brittle or defensive code, but does fall back on relying on the testing framework which allows you to lean in the direction of brittle code. The code complexity analysis is now more than just an indicator of whether or not the build was successful, but also a guide for your architectural decisions.
When Extreme Programming and Agile Methodologies became hot just a few years back I felt that unit tests were great, but also lacking. Now it seems the available frameworks are quite rich. And when they are used properly, they should dramatically improve the quality of the applications we deliver.

August 31st, 2006 at 2:47 am
Hi Brennan,
Could you please explain a situation in which introducing a bug won't stop an app work correctly by employing the defensive coding approach?
Regards,
Behi
August 31st, 2006 at 3:05 am
I remember one point with the Perl code I wrote I could not be sure if a variable would be defined or not. With Perl 5 you can mix procedural and object-oriented code freely so there was no good way to create disciplined encapsulation. Many variables are global for the sake of simplicity. In this one case I had discovered months later that I had a bug in one part of the software which was automatically corrected by another before the value was used. A variable (scalar) was loaded with information but mistakenly fell out of scope before it was used one last time. But I had set the code to always check if the value was empty and load it as needed. With languages like C# or Java I would define those variables as private and load them in the constructor or perhaps in an event handler during the ASP.NET life cycle so that I know I would have the values defined when I will need them. With such languages I can rely on the disciplines of the language to support my assumptions. And with unit and functional testing I can test for a broad range of scenarios to validate those assumptions. Essentially I have the option of moving the defensive line from within the code to an outer perimeter. Of course, I can keep the defensive strategy throughout each layer of the system. I can also fortify that outer perimeter over time without adjusting the internal code.