Archive for October, 2011
With some precious free time today, I sat down to read Lukas Smith’s Interfacing The PHP World. It was good timing since last night I heard someone complain, again, about tight coupling in Zend Framework so I was in a good frame of mind to digest the blog post.
Before we start, tight coupling exists in a scenario where any one class relies upon another concrete class type (usually enforced using type hinting). Because the coupling is between two concrete classes, the only way to bypass it is through monkey patching the dependent class. Monkey patching has long been the lazy option for fixing stuff in PHP and we’re trying to get away from it. Loose coupling, on the other hand, exists when a class is dependent on an interface. Because we can write any class that adheres to that interface, we can inject any class we can imagine so long as it implements that interface. This is a far simple and maintainable situation since a) we are favouring composition over inheritance and b) there’s no fracking monkey patching!
The common denominator in loose coupling is therefore ensuring your dependent classes accept any dependency matching an agreed interface. Question: Whose interface are we agreeing on?
Every PHP framework has it’s own unique set of interfaces for common operations such as logging, caching, http clients, filtering, validation, etc. This creates a situation where a framework tends to be loosely coupled but only within the scope of its own interfaces. Thus, Symfony 2 components using HTTP can’t simply swap the existing client for Zend\Http\Client. Symfony 2 and Zend Framework 2 do not abide by an agreed interface – they have two distinct and incompatible ones.
Loose coupling is therefore a bad joke. It is a narrowly defined concept usually described within the scope of one particular application. We never really apply the concept across multiple applications written with different frameworks because, at that point, the disparate interfaces of both frameworks would immediately make loose coupling unobtainable.
That is the crux of Lukas’ idea – and it’s a really good idea. More interestingly, it’s almost an even better idea for Zend Framework 2 than Symfony 2. Zend Framework would benefit even more because we also distribute scores of component libraries and the interfaces relied upon make using Zend Framework components almost certainly contingent on the use of many other Zend Framework components to meet dependencies.
A simple example is Zend\Feed\Reader. For want of an agreed HTTP Client interface, we’re stuck with using…Zend\Http\Client. You could use Symfony 2′s client but then you’d need to create an abstract class to mediate between that client’s methods and the mismatched interface implemented by Zend\Http\Client. The result is therefore obvious – it requires more work and you’ll probably end up using both HTTP Clients rather than taking the hard road. Throw in a few more framework odds and ends, and you can be putting a lot of duplicated functionality to work just because they won’t speak the same language.
This is actually a bad deal for PHP programmers. Instead of one common interface for HTTP Clients, you have dozens. They won’t interoperate, they can’t be swapped for each other, and they directly encourage framework specific implementations instead of interface specific implementations (i.e. with common interfaces the need to duplicate functionality because of NIH Syndrome might be significantly reduced). You’re also forgetting those libraries who feel compelled to internally and eternally duplicate HTTP client functions rather than simply depending on a preferred client using a common interface. Not to mention half those mini-clients are poorly written and tend to disable SSL certificate verification because they can’t be arsed about handling the errors from invalid certs even if it does amount to putting your users’ private data at a real risk of being compromised.
The detractors from Lukas’ proposal may point to Java (since it’s the antithesis to everything PHP except the PHP OOP syntax ). While a worthy scapegoat, Java lives in a whole other environment. The scary Enterprise world. There, common interfaces are not merely programming conveniences but a business necessity. Competing products can gain a competitive advantage if they can replace a competitor’s product, service or middleware with a minimum of fuss. One way to help achieve that is to fund, support and advocate common interfaces for a variety of purposes. Not to mention it still benefits start ups since they already have the template for what to implement. It’s no wonder you see these debates stocked with members from competing companies actually cooperating so they have the future opportunity to back stab each other with one less barrier .
Then again, do I really want my baby, Zend\Feed\Reader, injected with Symfony 2 classes? It even sounds dirty. Filthy Symfony 2 classes (Zend Framework, my precious! Gollum! Gollum!). Yet, that’s the only real reason not to want common interfaces. By making your classes more accessible to the competitions’, you risk being commodotised as programmers mix and match from a selection of notable libraries instead of being hogtied to just a handful of sort-of-loosely coupled frameworks. Then again, HTTP Clients are already a dime a dozen. The real goal of competitiveness is having a better overall implementation in terms of features and all the other important stuff that meets the needs of the users you are targeting (this doesn’t include useless benchmarks though those do make a great butt for jokes).
So yes, common interfaces would benefit PHP and would make framework libraries more interoperable and thus usable within competing frameworks. Hey, if you can’t beat them at least make sure you can inject your classes into them. Hmm, still sounds dirty.
In Part 1 of this miniseries, I expounded (it’s better than exploding) about Dependency Injection (DI) and Dependency Injection Containers (DICs). To summarise, DI is an obvious and ubiquitous design pattern used daily by most programmers to allow objects accept their dependencies from an external agent (e.g. a unit test which needs to inject mock objects). In an application, the ideal external agent is some container that can assemble objects on demand and create the necessary object graph from scratch outside of the application’s control flow. It is this object assembly function that can be fulfilled by a DIC.
For Part 2, we’re going to dig more into what a DIC is and isn’t. I’ve already noted one very simple DIC called Pimple which will continue as one of my reference points since it best illustrates just how simple a DIC can be. In Part 3, we’ll (finally) turn our attention to some actual source code. Baby steps. Parts 1 and 2 should get you thinking so that ZF 2.0′s DIC is a lot easier to understand and critique. We don’t want anyone panicking just by throwing them into the deep end .
Make sure to read Part 1 if you haven’t already!
Things Which Are Not A Dependency Injection Container (DIC)
Now, in explaining a DIC it’s worth noting there are related solutions which you should find very familiar.
You could use lots of Factories (classes or methods on a class in which the logic necessary to create an object is packaged for reuse). If you followed Part 1, you’d soon realise that the Pimple DIC, as simple as it is, looks very much like a collection of Factory Methods (as Closures). Zend_Application also appears to use Factory Methods or Classes to generate its resources. Along this line of thinking, a DIC is a container of executable Factories. These tend to be the simplest kind of DICs since they rely on source code instructions which can be combined in sequence to assemble a final dependent object and its injected dependencies.
The differences however all come back to the concept of an “external agent”. Factories are traditionally executed within and by an application object whereas a DIC operates from outside an application. Since this is a simple inversion of control, DICs following this mechanism can be written over a coffee break since it’s just a matter of aggregating and mixing Factories – or you can just standardise on Pimple .
Another possible solution is to use a Service Locator. This is often interpreted as an object which can create and retrieve objects. The Service Locator is injected into dependent objects as needed so they can lookup their own dependencies. For example, in our earlier Leprechaun class example from Part 1, we could have created a Service Locator capable of creating Pot classes, injected it into Leprechaun, and allowed the Leprechaun class to lookup whatever Pot it needs.
This too looks very similar to how a DIC appears to operate. It’s also similar to a Factory Class except it can construct many kinds of objects instead of just one particular type. A Pimple container, for example, can be passed into other objects which in turn can ask it to retrieve necessary objects or dependencies. The same holds true of Zend_Application’s resulting bootstrap object. So, in yet another line of thinking, a DIC is always a potential Service Locator – the difference is that we generally don’t inject DICs into dependent objects but allow the DIC create the dependent object from the outside (i.e. it’s an external agent).
In summary, a Dependency Injection Container is not simply a standalone invention – it’s a combination of a few well known patterns we use in PHP that, when combined, create something greater than its individual (and obvious) parts when acting solely as an external agent. That helps explain why most DICs you look at feel a bit too complex. You might see the simple task it performs but not quite grasp why it needs to be so complex until you realise it’s a combination of patterns. We’re used to seeing the constituent patterns isolated and scattered across our application – not brought together in one single entity.
The primary differentiating factor from the simpler patterns, especially Service Locators, lies in one simple concept: Is our DIC truly an external agent? All other solutions tend to require the container to be an internal agent, i.e. a dependency of other objects. Service Locators are injected into dependent objects, and Factories are called from dependent objects.
External Agents See The Bigger Picture
The ideal DIC is an independent external agent. I use the term “external agent” a lot because it’s a good description that’s easy to grasp. The idea is that the DIC creates all other objects, and their dependencies, and will inject the correct dependencies into the right dependent objects. In other words, it’s a master manipulator orbiting our application but not actually embedded in it. In a framework, it would be used to create almost everything without the rest of the framework even being aware of its existence. Nearly all other possible solutions can’t operate in this fashion. A Service Locator must be embedded into other classes and Factories are all called from within other classes too, i.e. they are internal agents…not external.
Now, programmers have two fundamental questions when it comes to basic OOP:
1. Where do I create objects?
2. How do I transport objects across application layers?
DICs answer the first question. You can create objects using a DIC which is independent of the application. It’s our external agent. They also answer the second question. In applying Dependency Injection, your DIC knows how to inject dependencies into the objects needing them, even if those objects come from different layers of the application. This should render the need for Service Locators, Factories, and the always popular Registry pattern almost defunct.
This is what makes the concept of Dependency Injection and DICs useful in frameworks. If you’ve ever used Zend Framework before the arrival of Zend_Application you’ll be familiar with the two questions from above. Creating and transporting objects was an unanswered question at the time, with users running in all directions using Registries, Service Locators, In-Controller instantiation and bootstrap instantiation (mixed with non-static Registries and the handy FrontController parameter transport) – and that’s just the generic groups. In reality, people developed dozens of varying implementations on these themes. This lack of consistency was an irksome problem. By implementing good DICs, both Symfony 2 and Zend Framework 2.0 have settled on one consistent direction.
However, using a DIC in its designed role requires something of a leap of faith. PHP programmers use Service Locators, Factories and Registries all the time. We’re comfortable with those patterns and many of us will always crave their simple natures even when we understand why Dependency Injection is a better solution. This craving can end up corrupting the idea of DI by implementing a common antipattern: turning the DIC external agent into an internal agent.
DICs As Dependencies Are Evil: They Are Not Service Locators
For example, bearing in mind my earlier creation/transportation question duo. Let’s say we create a NewsletterController in a Zend Framework 1.x application using a DIC like Pimple. Our Controller requires an instance of Zend_Mail for its emailAction method. How do you get the Zend_Mail object into the Controller? Well, using Dependency Injection the answer is very obvious – you define either a setter, a constructor parameter or a public property on the Controller class. Then you can program Pimple to a) create the Zend_Mail instance, b) create the Controller and c) inject the Zend_Mail instance into the Controller (e.g. using a setter method). Creation and transportation are neatly solved. The best part is that none of the participants are aware of the DIC, the acid test being that anything a DIC can do, you could have done it by hand without a DIC (hint: a DIC can replace a lot of what ZF users would normally call bootstrapping).
Both Zend Framework 2.0 and Symfony 2 optionally allow another possibility. When we create the NewsController, we can inject the DIC into the Controller itself. This would allow the Controller to lookup resources from the DIC instead of the DIC injecting them from outside the Controller, i.e. our external agent just became an internal agent.
The switch may appear very convenient and comforting. Instead of all this running around with a DIC magically creating Controllers, you could have a typical Dispatch/Execute cycle and add the code for object creation/retrieval into your Controller actions. This has benefits – object creation is clearly visible in all your controllers. However, your intuition is slightly off base.
Firstly, this isn’t Dependency Injection. Our dependent objects have now internalised dependency creation. Since it’s not DI, a DIC is obviously a misplaced tool. So instead of a DIC, you are actually mutating it into a Service Locator. The side effects of eliminating DI are to make it harder to understand dependencies (not easier as you might suspect!). A Service Locator just needs a name to lookup – there are no setters or constructor parameters with typehinting or useful Docblocks to refer to. So your intuition was wrong – it might make your life easier, but everyone else who lacks your familiarity with the source code you’re writing will spend a lot of time dissecting your DIC to figure out what the concrete dependencies really are. Yes, it’s the age old justification for many practices these days – ensuring the long term costs of change are minimised.
Secondly, it creates objects which are useless without the specific DIC interface it depends on. Given an application tends to use only one DIC, importing classes from other sources which need a completely different DIC in order to work is a PITA. Classes which don’t need to be framework specific MUST NEVER be framework specific (i.e. frameworks all use different DICs and depending on one excludes using your classes with another). If classes are DIC specific – you have done something horribly wrong in practicing OOP (and by extension DI).
This is very similar to my past arguments as to why my idea of Zend Framework Modules does not include Libraries/Components. Apples and oranges. Putting a generic library into any form of framework specific packaging or tying it to a framework specific import/DIC mechanism is just plain wrong if it restricts reuse outside of your preferred framework. It gets a lot worse should such dependencies expand from your Controllers (where they could be restricted in practice) to your service/model layer which shouldn’t be aware of the framework at all!
Thirdly, DICs are really bad Service Locators. Since your average DIC likely knows almost everything about objects in the application across multiple application layers (by design since it’s an external agent with that specific purpose), any object into which a DIC is injected might now have access to any other object the DIC knows about. This is crazy. If every object can access every other object, it will result in the same thing as having every function able to access every other function (which we endured before PHP got a good OOP model): Spaghetti Code.
Then again, the Flying Spaghetti Monster might be offended by good OOP…
The potential for enabling Spaghetti Coding, DIC/framework specific dependencies, and elimination of Dependency Injection practices are all serious issues – which is why injecting DICs into any other object outside a controlling bootstrap mechanism used to initiate the DIC and get your MVC framework prepped is referred to as an anti-pattern by some. It’s a Bad Thing.
Why Do Frameworks Enable Bad Practice?
Why is water wet? Frameworks operate to a specific set of needs: a compromise between the ideals of the developers and the needs of the users. The goal of a framework is not to hold your hand 100% of the time but to offer an opinionated (all of them are to some degree!) framework which developers hope is capable of meeting a broad set of user needs so that you can get your application off the ground on the cheap and focus on developing your application’s model. Since many PHP programmers will very quickly want the DIC-Injection anti-pattern, frameworks will inevitably offer it. It may not be considered good practice, but it’s one that nearly all PHP programmers have used to some degree. The trick is knowing whether the cost is worth it and, if not, how to opt-out of (or avoid opting-in to!) the anti-pattern.
If it makes you feel any better, framework developers spend an inordinate amount of time debating similar topics. We’re not out to hang you but compromise and education are often a better solution to being overly restrictive. In reading this topic, I hope this little slice of education will inform you on future decisions around how to recognise, implement and use DICs. Even if you wrote it over your coffee break.
In any case, in Part 3 we’ll meet Zend\Di. Code at last .