ava-innersource / Liquid-Application-Framework-1.0-deprecated

Liquid is a framework to speed up the development of microservices
MIT License
25 stars 13 forks source link

Move from Service Locator to Dependency Injection #39

Open bruno-brant opened 5 years ago

bruno-brant commented 5 years ago

At the heart of Liquid lies a service locator, accessed through WorkBench.GetService. This class is used everywhere to retrieve service instances and do the application wire-up¹.

This seems that was a conscious choice by the team, because Liquid is supposed to present a very opinionated programming model. However, there are many drawbacks with using Service Locators, mainly, doing proper mocking for unit tests. In fact, SL is considered by many an anti-pattern because of those drawbacks.

I believe that we could still maintain the desired rigidness without it, just by having our base classes require certain dependencies on their constructors, which should make developers of derived classes expose those dependencies on derived constructors as well.

There might be some other options like even removing base classes all together and having Liquid glueing the classes by itself, without interference from the programmer, or even programming a Roslyn Analyzer that asserts the injection is done correctly.

In any case, it is my belief that, moving forward, we need to ditch the Service Locator for a more modern programming model.


Footnotes ¹ If it can be considered wiring up, since, given the static nature of service locators, a Liquid application is wired up from compile time.

guilhermeluizsp commented 4 years ago

I second that. Switching to DI would bring us a lot of benefits. Not only it encourages the developers to apply fundamental principles such as OCP, ISP and DIP (as well as SRP, if done right), but also push us to make use of composition over inheritance, which make things like testing (as you mentioned) way more easier and natural to do.

Moreover, it is a good practice for today's standards.

I'd say that we can completely remove the current service locator implementation and favor the well-established IServiceProvider (in conjunction the generic host) for specific scenarios where a service locator would make really sense

bruno-brant commented 4 years ago

My approach would be to start exactly by migrating to IServiceProvider (and turning Workbench into a facade) and then moving completely to DI model.

I would, however, like to explore an hybrid approach to ease the transition of existing apps. I have yet to come up with a clean solution for that - all I can think of is a bunch of conditionals so only call the locator when the dependency wasn't injected.