At work we use Omniture for our web analytics, and for a long time I’ve wanted query our Omniture Data to run some internal reports. I discovered that Omniture has a restful reporting api, and after using it for a little bit I decided it would be nice to write a wrapper library for it.
Since I had recently taken the PHP Testing Bootcamp from Chris Hartjes, I decided I wanted write it using Test Driven Development and really get my feet wet. I also decided I wanted to make the library compatible with Composer. After the weekend was over, I had an almost finished library that just requires some more work to be done, but I learned a great deal that I thought I’d share.
Every other time I tried to start writing tests, I would get frustrated because I couldn’t really understand how to write tests in “real applications.” I understood the basics of assertions, but I couldn’t connect the dots to really write tests for real code. The problem was that to write testable code, you need to have loosely coupled code, which is much more easily said then done.
This is when the Law of Demeter comes into play. It basically states “only talk to your immediate friends”, and from an OOP stand point, it means your code should be broken up into pieces that only communicate with other pieces it’s immediately related to. There are some articles written about it, and Chris’s book on Building Testable PHP Application talks about it pretty well.
Basically, if I ever ran into a situation where I thought “Man, these tests are hard to write” then I likely had a tight coupling issue with my code.
Once I used a few mock objects, I really started to “get” testing (at least I think so). I can honestly say this was the missing key in my previous education with testing. I found the Mockery library which makes writing mock objects quick and painless.
As I started coding, I did notice it felt like it was taking a great deal longer to write the tests, and then the code, more than I expected. I first attribute this to my inexperience in writing tests, figuring out how to test certain scenarios, etc. But I imagine even when I get the hang of it more, it’ll still increase development time significantly.
And you know what? Thats okay, because I realized that I was catching lots of little bugs up-front. I was “hardening” the code so to speak making it feel much more solid than when I just write code by itself.
Even after a few hours of coding, I realized that I had created some classes that I didn’t write tests for. It was really easy to just slip out of the discipline of writing the tests, and to be honest there are a few more tests I still need to write. However, I did also notice that as soon as I stopped writing tests first and writing code to satisfy the test, I introduced a few bugs that took me some time to figure out.
Because you’re writing tests for your code, you get a feel for how you’ll be using the code. For me, when I was writing this library, there were a few times where I thought “Hrm, this is kind of kludgy, I should have written it another way.” I discovered these problems so much sooner in the process of coding, and I really was starting to really understand the power of writing tests.
So what did I do? I just changed the code to the new way and ran my tests. I saw what it all broke, fixed the code that depended on the old functionality to the new functionality, and I was done. It was amazing how much more simple refactoring was when there were written tests in place.
I didn’t nearly have much trepidation about sharing the code I had written. I knew that what I had completed worked, and it was likely a great deal more bug free than most quickly written libraries I have lying around. I also can easily share this code with other teams here at work to help them pull their own data.
So I don’t know how many people who will read this will be in need of a PHP library for interfacing with the Adobe/Omniture Site Catalyst Reporting API, but they could quite easily start using my library and contribute back if they wanted.
I still have so much more to learn about writing testable, but I’m excited that things are starting to “click” in my head. I can see and understand just start writing testable code, and having my code be much more durable in the future.