I’ve noticed that sometimes when developer want to embed in they own infrastructure an external library they feel the needing of encapsulate that dependency in a common-versus-tool library. So we have a plethora of, just for say CommonLogging, CommonIoC, CommonOrm and so on, every one claiming the ability of “Just Plug The Tool”.
I would like to try to show why this is a tremendously ugly antipattern in my opinion, by showing the side effects of this approach, and alternative solutions.
The first impressive attempt is trying to insulate the IoC kernel we want to use. So instead on having the application depending on the IoC, we just have the App depending on the CommmonThing, we do some work in creating it, we have back nothing but a boring piece of code to maintain. The spectacular attempt is when the encapsulated guy is the service locator, that guy kill by its own the entire effort in code decoupling, make component dependency obscure to everyone else but the developer who code the component in the first week. So creating the common layer just multiply the side effects and the result is a squared antipattern that scares any reasonable professional.
The solution: In this case there is a pattern that is a real silver bullet : Composition Root. Just have the IoC used in a single point and have it’s effect propagating trough all the application by using the proper IoC features: Inject into constructors, use factories and have the IoC effect recursively propagate among all the application without referring directly the kernel. In the root, use all the IoC features you have, by not having the common thing around you, you have no lowest common denominator to deal with. If you want to change the IoC in the future, you completely rewrite this single file, and you will use all the new kernel features. You must avoid using byzantine attributes for injecting your properties, if the IoC you mind to use need them, is not the correct one. A side effect of this approach could be an increasing amount of factories class. While this could be considered a problem some IoC offer some sort of automatic factories, out of the box or with additional plugin. I’m not sure if they help or not, i fear that code became too magic, and this will possibly violate the “Coding For a Violent Psycopaths” principle. As a least consideration: IoC is for applications, it is not for libraries. If you are writing an infrastructure reusable component, you must not base it on any IoC strategy. Things are a little different if you are creating a framework, and this framework leverages and offer services when an IoC exist in the hosting application. Even in this case, instead of creating a common thing, the framework should provide its own IoC abstraction, and the hosting application must provide an adapter to the IoC currently used. The framework abstraction must be designed in order to fully satisfy the framework requirements, leaving the adapter implementer the challenge its own IoC. A good example of a framework using the described strategy is Caliburn Micro.
Since every good appealing applications logs, this is a real temptation for the CommonLogging beast. Even not considering the fact that the logging libraries used in production are about two, why we need this? Please enumerate how many time you decide to drop a logger in favour of another, end eve if this was the case, was really this refactoring time jeopardizing the project? Another danger coming from the CommonBeast here is the fact that being such a library “too small” to be justified, it can possibly collapse in another anti pattern: “The enterprise magic library”, a library containing a set of more or less useful thing that every developer want to maintain when new stuff has to be added, and no one feel responsible when it breaks.
The solution: Is the same as above: define the logging interface in the library, and let the application implement it. A great example on this comes form NHibernate. NH was strictly bound with log4net till version 3.xxx, starting from there you can implement its own abstract logging interface. Beautiful to have, NH uses log4net as a default by dynamically loading it ( eliminating the needing of having log4net at compile time ) degrading gracefully to the old behavior.
This is probably the worst. An OR/m already introduce a sensible impedance toward the database, adding an home made abstraction layer pretending to deal wit NH, EF add another multiplying impedance to your application. Writing an application that leverages an OR/M is usually a collection of best practices that OR/M imposes to make the data access as faster as possible. Such trick are usually difficult to abstract and you don’t know a lot of them until you face it.
The solution: First solution is don’t do it at all. it is not a so strange scenario to choose the or/m you want to use in the design phase, and bring it to production and maintenance simply with that or/m. By the way software makes money when it does what the customer want, not when is modified to follow the latest trend in data access. Another less strict solution is to use the “query object pattern”, that does not mean implement your ad hoc query provider, but means encapsulate each aggregates operation in single classes responsible for all the data access, exposing proper and useful methods to refine the query specialized for the aggregate. This allow a conceptually easy refactoring if we want to change the OR/M. And by the way in an every day experience scenario, you mostly don’t swap NH or EF, but more probably you want to change some of your query object to use some micro OR/m for performance reason.
The example series could be extended to the same degree of utility libraries we use. A CommonMessaging the first one comes in mind.The point is that the “CommonThing” is a worst practice, it gives us no advantages but just pain and problems, so use all the effort to avoid it and focalize into the real problem.
a@href@title, b, strike, strong
The opinions expressed herein are my own personal opinions and do not represent
my employer's view in any way.