Tuesday, June 12, 2012

Why Would I Write Unit Tests When I Get Paid by the Hour?

This morning I read an entertaining post by Jonas Hovgaard about how he has abandoned some sound patterns and practices for what he considers to be increased productivity. It is timely in that just this weekend I read another great post about “flipping the bit” by Uncle Bob. These two completely opposite posts have one thing in common, they both are concerned with productivity.

Personally, I’m on Uncle Bob’s side. But I am on his side because I am going to be the one maintaining today’s code tomorrow. This has not always been the case. I once was a consultant churning out website after website with pseudo CMS capabilities. I suspect that Jonas is as well based on his statement, “In my personal scenario (creating around 20-30 apps every year).” I imagine Jonas doesn’t maintain applications, but rather cranks out site after site at Acme Webapp Co. In that kind of environment, the business model works by spending as little time as possible getting the minimal functionality possible to get client acceptance and payment. In that environment code that is hard to maintain isn’t a problem, it’s a business model.

Jonas hasn’t abandoned testing altogether, as he as adopted acceptance testing using Selenium, and he is right about the fact the the most important test for your code is the user acceptance test. But in the end if its working for him, more power to him.

I would like to take a moment to comment on some of his ideas.

I agree, it's absolutely awesome that I can change the concrete type or lifecycle with ease, but for gods sake, I don't even dare to count the hours I have spent creating these abstractions, making me able to do something I never freaking do.

I don’t like interfaces for their extensibility. I agree that we hardly every swap implementations. Occasionally we may swap a logger but I have never needed to replace my SQL data tier with an Oracle one. That’s not why I love interfaces. I love them because it allows me to write one section of my code without worrying about how I am implementing another section at the same time. I use interfaces mostly because I want mocks. Even if I didn’t do TDD but were doing F5DD, I would still want to program against an interface, implement fakes for lower level layers, and code my way down from the html.

But also I spent hours trying to understand what Ninject or StructureMap did with my classes. When I finally understood, I handed over the application to the next developer who also was forced to spent time understanding some IOC.

Ah, the magic of frameworks. It makes me sad that someone would abandon sound principles because they didn’t like the tools they have chosen. I love IoC containers, but like Jonas I have often been frustrated trying to locate “where the magic is happening.” I had one particularly sucky day trying to locate how something was being injected in a global action filter. Magic on top of magic. The aversion to magic is a bad reason to abandon a sound principle. IoC is not defined by the containers that we use. I myself am very fond of the Service Locator pattern (scroll down half-way.) This is a no-nonsense pattern for straightforward dependency injection.

At the end of the day, I want to write code that I am proud to share. For me this means well tested code because my tests are my insurance to myself that I have done well. My tests also serve as a guide to my fellow developers as to how I intend my code to be consumed and the current requirements it was written to fulfill. And most importantly my tests (and my commit messages, but that’s a whole different post) tell my future self what the hell I was thinking when I wrote this crap because we all hate the code we wrote yesterday.

But hey, I have to maintain my code, and I’m not getting paid by the hour to do it.

No comments:

Post a Comment