On SOLID Code: DPosted: July 5, 2011
To close out the discussion on SOLID, the D in SOLID stands for “Dependency Inversion” and is currently a bit of a darling in the industry, with significant efforts from many communities and companies to provide infrastructure that allows developers to implement this practice.
Now, dependency inversion does not require an inversion of control container, nor does it even imply that one must use dependency injection. These patterns are natural outcomes of this principal, that states that components should not depend upon concrete implementations, but on abstractions. More concretely, and often, that components should not depend on classes, but on interfaces.
The most powerful example of how this principal can help companies scale is in unit test suites: In a company that I’ve worked at previously, which built on of the world’s biggest applications, running regression tests on even a tiny part of the system could take days, and entire labs and teams were responsible for test execution and reporting. Startups simply cannot afford this kind of overhead (arguably, these days, no one can afford this kind of overhead.) The requirement for tests to run fast is a matter of survival. So consider the example of a startup, such as Sociable Labs, that is hosted in the cloud (Amazon, in our case) and makes use of many cloud services – key stores, binary storage systems, databases, distributed queues, Facebook’s Open Graph, the Twitter API, and much more. Now imagine running a full regression suite that runs thousands of tests against all of these systems. It would, and does, take hours to days, and new tests are constantly being added.
In order to be able to regression test our own systems independent of all of these systems, we provide mock implementations of all of the above services: We have mock Facebook implementations, mock S3 implementations, mocks of the database repositories and of our configuration server. In order to be able to tell our code to use these mocks, the code must not rely on any concrete implementations of S3 or Facebook clients – they must rely on interfaces so that we can provide one implementation at unit test time, and another during full regression passes or in production.
There are many systems that enable this sort of configuration, and most come down to some central authority, such as a service locator or container, which is configured via some mechanism so that it knows what concrete implementation to provide for a particular interface.
As an interesting aside, the classic Singleton pattern can easily become a massive source of violations of this principal. We use a combination of the service locator pattern and inversion of control to give our developers a very clean, intuitive view of the system that is actually more convenient and simple than the Singleton pattern, but without that pattern’s hard dependency code smell.