Welcome Guest, Not a member yet? Register   Sign In
Poll: D.I. vs Service locator?
You do not have permission to vote in this poll.
yes
37.50%
3 37.50%
no
25.00%
2 25.00%
maybe
37.50%
3 37.50%
Total 8 vote(s) 100%
* You voted for this item. [Show Results]

True D.I. vs service locator.
#1

(This post was last modified: 04-10-2015, 06:46 AM by ciadmin.)

From expiramenting with a lot of frameworks, to building my own, I've found at the core of the whole framework lies a decision that makes a huge difference in the ease of use. I'm talking about dependence injection vs a service locator, and the specific implementation. This is a make or break feature. For instance, I think we can agree that CI's loading of resources is about as simple as it gets. A person who uses CodeIgniter is not going to step right into Symfony 2 dependency injection and feel at home. There is a DI container that is called Pimple which is extremely easy to use, but I've seen where some consider this a service locator. I truly think Pimple should be looked at by the CI4 planners, because it is just so easy to use. I built a framework using it and used some CI classes, and it was very simple, and still has a CI feel to it.

I'm not in a position to open up my repo to the public, but wouldn't mind sharing what I've done with some of the higher ups who will be making the decisions. If anything it might help show a complete implementation of what CI4 could be, and might help with the decision making process.

So, needless to say, I'm interested to hear what other people think about this.
Reply
#2

I messed around with Pimple a bit just out of curiosity. My question to you so I can  understand what exactly you are looking for is, how is attaching objects to the Pimple Container and passing it into the class any different than attaching the objects to the CodeIgniter "Super Object" and calling it directly ( get_instance()->my_library->do_work() ?) I understand for testing sending in mocks (when using DI) is a little easier but, it seems the CodeIgniter team has unit testing working regardless. Besides unit testing what other benefits am I not understanding?

As a side note:
I assume most dev's like me add a ci() function as a shortened version of the get_instance() function

DMyers
Reply
#3

(04-10-2015, 06:44 AM)dmyers Wrote: I messed around with Pimple a bit just out of curiosity. My question to you so I can  understand what exactly you are looking for is, how is attaching objects to the Pimple Container and passing it into the class any different than attaching the objects to the CodeIgniter "Super Object" and calling it directly ( get_instance()->my_library->do_work() ?) I understand for testing sending in mocks (when using DI) is a little easier but, it seems the CodeIgniter team has unit testing working regardless. Besides unit testing what other benefits am I not understanding?

As a side note:
I assume most dev's like me add a ci() function as a shortened version of the get_instance() function

DMyers

You are right, that passing the Pimple container around is sort of like the current way CI has a super object, but Pimple can provide true D.I. as well. You can actually do both at the same time if you wish. Another thing I have done is create a static class to complement the standard CI class, so that I have even more flexibility by being able to call the CI class through the container, through the DI object, or through the static class. It's pretty nice for me, but what I'm asking is that whoever makes the decision as to what CI4 will implement, consider all of these things.

As has been the case with CI in the past, I know one of the main objectives is to keep it easy to use, so that's why it's important to review and talk about this issue. How would you like to see DI handled?
Reply
#4

(04-10-2015, 06:59 AM)skunkbad Wrote:
(04-10-2015, 06:44 AM)dmyers Wrote: I messed around with Pimple a bit just out of curiosity. My question to you so I can  understand what exactly you are looking for is, how is attaching objects to the Pimple Container and passing it into the class any different than attaching the objects to the CodeIgniter "Super Object" and calling it directly ( get_instance()->my_library->do_work() ?) I understand for testing sending in mocks (when using DI) is a little easier but, it seems the CodeIgniter team has unit testing working regardless. Besides unit testing what other benefits am I not understanding?

As a side note:
I assume most dev's like me add a ci() function as a shortened version of the get_instance() function

DMyers

You are right, that passing the Pimple container around is sort of like the current way CI has a super object, but Pimple can provide true D.I. as well. You can actually do both at the same time if you wish. Another thing I have done is create a static class to complement the standard CI class, so that I have even more flexibility by being able to call the CI class through the container, through the DI object, or through the static class. It's pretty nice for me, but what I'm asking is that whoever makes the decision as to what CI4 will implement, consider all of these things.

As has been the case with CI in the past, I know one of the main objectives is to keep it easy to use, so that's why it's important to review and talk about this issue. How would you like to see DI handled?

skunkbad, what do you mean when you say "provide true D.I." what are some of the other benefits of using DI Vs a service locator besides the unit test stuff I listed above? (here is you big chance to sell others reading this on DI Vs keeping as is).


DMyers
Reply
#5

Since this never got answered, I'll give it a go here. And hopefully my understanding is correct. Smile

A Service Locater is a class that knows where to find a class and return it when requested. It doesn't know how that is to be instantiated, so it's not Factory.

The DI Container (or IoC Container, if you will) also knows where to locate classes, and can determine the class to be inserted into a class' constructor at the time of instantiation. That's a mouthful and vague, I know. And I might be fuzzy on the differences. Here's an example of my understanding of a "true DI container".

You have a class that you want to instantiate. It requires an instance of another class to be passed into it's constructor.

Code:
class User {
    public function __construct( App\UserModelInterface User_model )
    {
        ....
    }
}

The User_model is passed in and saved as a property of the class. Since it's an interface, you can easily swap out different versions to get passed to the class. This is helpful for testing, as mentioned, because you can pass in a mock class. However, it's also extremely handy when working on a v2 of an app. You can create a new User_model that is specific to v2 of the app, but still implements the same methods (and adheres to the interface requirements), but does things differently. Alternatively, you could have different User_models that have different storage services. Maybe one stores the data in a local database that you want to use in development, but you have another for production that uses two different databases for read and write queries, and caches to a Redis setup.

The DI Container allows you to simply configure it to know WHAT classes should be passed into the User class, and it will automatically pass in an instance of the Dependency. It will do the same thing for any dependencies the User_model might have, also.

Hopefully that makes sense, though I'm not sure I did a great job explaining it.

From a framework viewpoint, it could be used the same way, but allows you to very easily change the way the framework works by simply telling the DI Container to use a different class when it's creating dependencies. At that point, there is no need for MY_Router files (or whatever). If you want to modify the way the router works, you simply create a new class that adheres to the Router Interface, and let the DI Container know to use your class. Now, any place the Router class is needed, your new class is automatically used.

That's the true beauty of a DI Container.
Reply
#6

To clarify on the Service Locator part, the Service Locator usually does return an object instance. Whether the Service Locator instantiates the class itself or simply returns a pre-existing instance doesn't matter (but it could do either).

The Service Locator is used by a class to retrieve any services required. So, using Lonnie's DI example, you would use the Service Locator to retrieve an object which conforms to the App\UserModelInterface, instead of passing the User_model through the User's constructor. You might have a pre-defined interface to the Service Locator (for example, something similar to $this->load->xxx()), but a more modern approach would be to pass the Service Locator through the User's constructor. This shows that DI and a Service Locator aren't mutually exclusive, but if you inject a Service Locator, you still don't know what the User class' dependencies really are without examining the code for calls to the Service Locator, and now the User depends on the Service Locator, too.

The key difference is that a class never needs to be aware that a DI Container is being used. Your application requests objects from the DI Container and maybe can configure the DI Container, but the classes managed by the DI Container don't know the difference between being instantiated and managed by a DI Container vs. being managed and instantiated directly by the application. The Service Locator, on the other hand, becomes a dependency of the class using it, and the class has to understand how to get its other dependencies from the Service Locator. In an ideal world, every dealing with a Service Locator involves enough abstraction that the services supplied by the Service Locator and the Service Locator itself are defined by interfaces, so testing is still viable and you can still change out classes without changing everything that uses it, but in practice it's difficult to make Service Locators interchangeable, and classes that depend on a Service Locator are often tied to that specific implementation.
Reply
#7

See http://paul-m-jones.com/archives/5853
  • When the container is used outside a non-Factory object, you are using the container for Depedency Injection.
  • When the container is used inside a non-Factory object, you are using the container as a Service Locator.
Reply
#8

(07-27-2015, 02:33 PM)kenjis Wrote: See http://paul-m-jones.com/archives/5853
  • When the container is used outside a non-Factory object, you are using the container for Depedency Injection.
  • When the container is used inside a non-Factory object, you are using the container as a Service Locator.

Thank you for posting that article. That makes a lot of sense when described that way!
Reply




Theme © iAndrew 2016 - Forum software by © MyBB