Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

auryn project views on Service Locator are different from views here, correct? #2

Open
salcode opened this issue Jun 5, 2017 · 1 comment

Comments

@salcode
Copy link

salcode commented Jun 5, 2017

While reading the auryn Documentation, I noticed this blurb.

auryn is NOT a Service Locator. DO NOT turn it into one by passing the injector into your application classes. Service Locator is an anti-pattern; it hides class dependencies, makes code more difficult to maintain and makes a liar of your API! You should only use an injector for wiring together the disparate parts of your application during your bootstrap phase.

Since this project is part of Bright Nucleus Service Locator Component am I correct you disagree with this statement?

( Which I'm completely fine with, I just want to make sure I'm not missing a nuance here like when you helped me understand the difference between a Shared Instance versus a Singleton 😀 )

Thanks.

@schlessera
Copy link
Member

No, I completely agree with this statement.

First of all, the Injector is not really a part of the Service Locator, it is being used by it, just like the Config component. The Injector is one of the dependencies of the Service Locator, but that does not make one equal to the other.

The Injector is being used from within the Service Locator:

  1. To have a centralized convention for adding injector mapping configuration to the Injector when they are provided by service providers code.
  2. To instantiate the services themselves source.

The Service Locator itself is an Inversion of Control (IoC) container based on Pimple.

The Bright Nucleus architecture does indeed have two different IoC containers: a "Dependency Injector" and a "Service Locator".

So why do we need two of them and what are the differences between these? To explain this, let's first discuss how the ideal code base would look.

In an ideal code base, you would have 1 single point in your bootstrap code that would contain a single make call to do the instantiations. This instantiation would build the entirety of your web app, by knowing all of the mappings and building the complete structure from the top down.

Your code would look somewhat like this (simplified):

$injector = new Injector( $config );
$app = $injector->make( 'MyApp' );
$app->run();

This would cause the complete structure to be built out of that one instantiation call, with all of the dependencies being properly wired together, as the Injector has complete knowledge of all requirements, and access to the complete codebase.

Now back to WordPress... ;)

There's no central point where you can instantiate your entire WordPress stack through an Injector call. WordPress would have to be a real dependency, instead of the App it tries to be itself, and it would need to be OOP and properly type-hinted. Instead, for the purposes of our custom code, every plugin and every theme has its own entry point (what I call the plugin/theme's bootstrap file), and there's no central container that can build a bridge between these. And no, global variables are not a container.

To solve this, you could for example go ahead and just pass the Injector around and have every plugin just do its thing with it. But that's where you would do what the paragraph you've quoted above from the Auryn package warned against. You'd have turned the Injector into a Service Locator.

This is why the Bright Nucleus architecture has two containers. Technically, they could both more or less do the job of the other. But the difference is in their intent. Intent plays an important role in development, and it should be clearly communicated, not only through comments and docs, but also through the naming and structure of the code itself.

The Service Locator is known to be an anti-pattern, because in an ideal code base, it has some severe drawbacks. In the context of WordPress, the Service Locator's drawbacks are negligible compared to what WordPress forces you to do without such a mechanism (a good example of how the quality of something can be relative).

The goal with this two-fold structure is to allow for properly coded plugins that make use of these to be completely instantiated through the Injector, and only ever use the Service Locator to reach across boundaries imposed by the surrounding WordPress framework (boundaries between plugins, but also boundaries between layers, which lack the needed abstractions).

Although this could have been technically done by either the Service Locator or the Injector alone, splitting this up makes the decision of when to use "shortcuts" or "hacks" very deliberate, and clearly visible in the code.

This means that, whenever you're using constructor injection that started from the Service instantiation within the Service Locator, you're as close as possible to a clean code base within the confines of WordPress. That entire Service can then be instantiated with 1 single make call. When you're using the Injector directly within a Service, you're already compromising, as you failed to provide a complete chain from the Service instantiation to that object you need the Injector for. When you're using the Service Locator, you've given up and know that you've hit a limit of the WordPress framework and just want to make it work nevertheless.

Feel free to ask additional questions if something is not clear in the above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants