Sunday, July 29, 2012

PHP Dependency Injection, Part 2


A few months ago I blogged about Diesel, a dependency injection framework for PHP. Since then, it's gotten a lot of use in our internal PHP code as well as our open source project, Bart.

It's also gotten a good deal of feedback from the rest of the team and been the subject of many a debate. The product of all that feedback and debate is a new version of Diesel that is easier to use and integrates more seamlessly into your existing class structure.

One of my initial goals with Diesel was that it would provide non-singleton nature, both from a per-class perspective and from the dependency registry point of view. Such that users would be able to define custom dependencies, and chains of these, when creating dependent classes. However, in practice, we observed that this was pretty much never necessary outside of unit tests.

Since we're able to reset pretty much any state we want in between tests, we concluded that the added complexity, not to mention burden on class signatures, was unnecessary and the Diesel interface could be simplified to static methods. The result is below,

 /**
  * Create an instance of class
  * @param string $className Name of the class
  * @param array $arguments Any arguments needed by the class
  * @return $className New instance of $className($arguments)
  */
 public static function create()
 {
 }

 /**
  * Get singleton instance of this class
  * @param type $className
  * @return $className Singleton instance of class
  */
 public static function singleton($className)
 {
 }


So users of Diesel, now only need to call either Diesel::create($className) or Diesel::singleton($className). If nothing is registered (which should be the case for production code), then Diesel will use reflection to create a new instance of the class with the supplied arguments.  If a singleton is desired, a new instance is created and cached for any future requests.

This is much simpler than previously, where all dependent classes had to define the dieselify() method and needed to accept Diesel instances in their constructors.

For tests, stubs or mocks can be registered via anonymous functions that can verify the arguments and then return the stub. Another improvement is that Diesel now supports enforcing during test time that a method be registered for any requested class. I.e. if a new instance or singleton is requested during tests for which no instantiation method exists, an exception is raised. This will prevent accidental creation of real classes during tests.

Monday, July 23, 2012

PHP Quality Metrics with Jenkins

I recently took over management of a few PHP projects and my first order of business was enhancing the code quality. Code quality means different things to different people. In my case it means relevant, thoughtful test coverage and well balanced code (a la Robert C Martin). I scoured the internet and came up with some good tools for measuring both.

See http://jenkins-php.org/http://erichogue.ca/2011/05/php/continuous-integration-in-php/, and there's even a book!

We're already using PHPUnit for our tests, but I wasn't doing any coverage analysis. That was easy to add. Next, I started using all the mess detection and robert-c-martin analysis tools. All in all, I was able to follow the directions and put a build shell script together without too much trouble.  The pieces with which I had to pay some attention were the machine setup, the jenkins project configurations, and the PHPUnit exclude options. See my gist for a sample phpunit configuration to exclude files over which you have no control, or matter not, in your project.

To save myself some trouble I put the installation steps and quality build steps into Bart, our open source project, on which all of our other projects depend (via composer). The script can be found here, https://github.com/box/bart/blob/master/build/nightly-quality-metrics.sh

Finally, my jenkins config file template can be found on github, https://gist.github.com/3168354. You can replace the template variables with their respective values for your project.

Comments welcome!

Saturday, July 7, 2012

Keep It Simple, Stupid


I had a great time last week at DevOps Days in Sunnyvale. The presentations were great, I attended some thoughtful break out sessions, and I learned about some pretty cool new tools. Much of this is being covered by the rest of the folks there, so I won’t reiterate it here, but what I did want to discuss is the underlying theme to much of the successful tools, methods, and ideas that were presented: keeping it simple.

We’ve all heard it before: keep it simple, stupid. However, almost every time I hear it, we’re talking only about software or process. Yes, that makes sense. We can observe many of the most successful tools and processes in our industry achieved that description because they were simple. What struck me extends beyond just the software and the tools. Keeping it simple succeeded on a grander scale because of human nature, and that human nature applies to so much more than just software and process.

 Many, if not all, of us involved in DevOps or pragmatism have a certain mindset. We are passionate, outgoing (albeit if only technically), and curious. We are a minority. The success of a new process or tool within our group does not promise success anywhere else. The majority may not have the drive, the passion, or they just lack the time. To achieve success with that majority, the new system must cater to those characteristics.

Consider the technical reader’s preferred source of knowledge. Only a small percentage of people I see nowadays still read entire technical books. However, innumerable people seem to be reading blogs, feeds, hacker news, etc. Why is that? It’s probably because a blog isn’t complicated. A blog is short, to the point, and often summarizes a longer (harder to read) technical piece.

In the non-technical world, consider cooking. Much the same, few people I know nowadays cook elaborate (read prep time > 25 minutes) meals for themselves. The norm seems to be defrost-able, quick prep time, or eating out. And how many young couples buy cookbooks and use them versus just searching the web for simple recipes?

My proposition is that the adoption of new process, tools, or approaches to thinking is driven by a minority and succeeds when those new processes, tools, or ways of thinking are presented to the majority in a simple, digestible fashion.

If we want to spread the adoption of DevOps (cultural changes, new tools, and states of mind) throughout our industry, then we must commit ourselves keeping things simple. I fear that heavy featured tools with long technical manuals, lengthy technical books, or new groupthink will not be readily adopted or consumed. Rather, their wondrous benefits and knowledge will stay locked in their manuals, between their covers, or in our minds alone, their collective surfaces barely scraped by some curious, but time-strapped or non-motivated, souls.