These days IoC (Inversion of Control) become a must have approach for all types of projects. Developers just use their favorite DI container in any new project without any doubts and considerations ‘why?’. I will touch two reasons why teams should be careful while implementing and configuring DI in their projects. And these ideas are result of our mistakes and our experience in supporting shared module for different environments.
For example we have one integration module, and our development team knows that it should have extendable data access layer while parts of logic must be flexible to extend for different clients. The team decided to use usual set of tools including Castle.Core and Microsoft.Practices.ServiceLocation. Developed module worked just fine, different implementations were loaded via Castle.Core as required, all dependencies were injected via constructors and result looked good for developer’s eye.
Well, the module was good before it met real world, with different kind of ‘not ideal Sitecore implementations’ and all kind of possible versions conflicts. As a result we came to more simple but stable approach with reinvented wheels but happier clients. So here are main conclusions from our experience.
First point is about developing full Sitecore solution - new Sitecore instance, new solution in Visual Studio, newest versions of dlls from NuGet, everything is under control and can be easily configured. Develop, test, deploy, go to next project. Client is happy and uses the solution for some time. In a time client finds out that some new integration will work really well with for his business and there is a ready-made Sitecore module somewhere in GitHub with all functionality required. He installs the module and see well-known yellow page on CM server telling him to turn custom errors off. And the reason can be that Sitecore implementation has ‘selfish’ custom controller factory copy-pasted from some outdated posts with small letters ‘sample code! do not use on production!’. Some of such examples simply overwrite existing DI container without any fallback logic. Other show how to configure DI container but do not mention that at the same time in the same environment another code can run the same ‘selfish’ configuration for shared container. And oops! your service mappings are lost!
Second point is about creating Sitecore module. Are you sure you need this DI container and custom controller factory there? Think about those who trapped in the first situation. When people install your module, they do not care about design patterns and the most modern approaches. They must be sure it is safe for their Sitecore instance. That means we should not add any external references unless it is required for module functionality. We should not make breaking changes in shared functionality. We cannot be sure that target environment developed according to best practices and will support you in your best intents. No, main principle for a Sitecore module is KISS.
Current DependencyResolver will be overwritten by external code after you added your resolver with correct fallback. Your DI container library will be overwritten by older version. Version will be compatible but container will be cleared and reconfigured without your services. Your referenced library become outdated in a month and your module will cause Sitecore crash. That is why we should avoid all these nice and cosy DI containers and implement IoC principle in old fashioned but reliable way, for example maintaining interfaces mapping via simple Factory or hand-made ServiceLocator.