I've been using Symfony to develop my web applications but I keep running into one problem. I always end up with too much clutter in the constructor of my services since I want to be able to unit test my services properly.
Theoretical use case
Let's say I need a service which allows me to process an XML file and save it's contents into the database.
<?xml version="1.0" encoding="UTF-8" ?>
<users>
<user>
<id>1234</id>
<username>Example User</username>
<email>user#example.com</email>
<usergroup>
<id>567</id>
<name>Example User Group</name>
</usergroup>
<permissions>
<item>ALLOWED_TO_CREATE</item>
<item>ALLOWED_TO_UPDATE</item>
<item>ALLOWED_TO_DELETE</item>
<item>ALLOWED_TO_view</item>
</permissions>
</user>
</users>
Already quite a few things come to mind which you need to inject into this service:
DomCrawler (to read the XML file)
UserRepository (to get existing Users)
UserGroupRepository (to get existing UserGroups)
PermissionsRepository (to get existing permissions)
EntityManager (to persist en flush new/updated objects)
The real XML file I'm working with contains much more data which requires me to inject many more repositories and other services which handle certain logic.
Solution 1: Use Doctrine service
Inject the Doctrine service directory into my service and get the repositories via $doctrine->getRepository(User::class)
Pros
Significatly reduces the amount of arguments
Cons
Unit testing becomes a lot harder since I don't know what the service accesses anymore which renders them useless
Solution 2: Use setter injection
Remove all services and repositories from the constructor and create setter methods and call then in the services.yml
services:
AppBundle\Service\MyImportService:
calls:
- [setUserRepository, ['#app.user_repository']]
Pros
Arguably easier to read
Cons
More code
Services no longer mandatory, optional validation may be required
Question
What are solutions to make the argument lists in my services more maintainable in terms of readability and ability to unit test?
Is it even considered bad practise to have a long list of arguments?
Having many arguments in your constructor is a code smell called Constructor Over-Injection. This code smell is often an indication of the class taking on too much responsibility, meaning it violates the Single Responsibility Principle (SRP). SRP violations cause maintenance problems, which is why you should keep a close eye on them.
Although refactoring to Property Injection might reduce the number of constructor arguments and therefore the amount of clutter in the constructor, it does not solve the underlying problem, which is that this class is becoming too complex. Property Injection is therefore not a solution to Constructor Over-Injection.
The solution to this code smell is to reduce the complexity of the class at hand. There are many ways to do this, but a very common approach is the Facade Services refactoring:
Facade Service [is] closely related to Parameter Objects, but the main difference is that a Parameter Object only moves the parameters to a common root, while a Facade Service hides the aggregate behavior behind a new abstraction. While the Facade Service may start its life as a result of a pure mechanistic refactoring, it often turns out that the extracted behavior represents a Domain Concept in its own right.
Pros:
Reduces the class' complexity and thereby solves the underlying problem
Prevents depending on the Doctrine service (which is an application of the Service Locator anti-pattern)
Introduces new concepts and improvements to the Domain language.
Prevents property injection (since property injection causes Temporal Coupling)
Cons:
Facade Services might not be the right refactoring. Alternatives are Domain Events and Decorators.
These are topics that Mark and I in our book Dependency Injection Principles, Practices, and Patterns. Section 6.1, for instance, specifically talks about refactoring from Constructor Over-Injection to Façade Services or Domain Events, while chapters 9 and 10 do a deep dive into using Decorators.
Related
Is there a reasonable way to ensure that you aren't unnecessarily re-instantiating expensive object instances in PHP?
I have an application that deal with US States. Each state is an instance of the USState class. I'd like to ensure that the application only ever has one instance of each state object, although they are used in many places throughout the application.
I looked into the singleton pattern, but that seems to be used for times when a class only has a single instance - here there are 50 instances, but no more.
I guess I could put them in the global scope and always refer to them that way (global $california), but that seems wrong.
I would use Service Locator Pattern or Dependency Injection, which is provided by your framework. Usually I go with Zend Framework, but not knowing your circumstances, I assume you have no framework at all. In this case I would suggest very simple Dependency Injection Container, but that would add a dependency on DIC itself. Pimple is one of them.
I've been investigating a lot about dependency injection theory and it makes great sense except for the fact that it seems to introduce complexity/bloat in certain scenarios.
Firstly, it is assumed that a DI Container instance is never passed into any object. Bad practice and all that...
For example: Consider a "user" class that relates to all other business objects created in the system by/for a specific user.
If a user instance is to be deleted, all related objects (i.e. records, files, images, etc.) also have to be deleted. Does this mean that an instance of each and every dependency is to be injected into the user instance to allow for the lookup and deletion of all related objects? i.e. an instance of ImageMapper (or ImageMapperFactory) must be passed in in order to delete all images created/uploaded by the user instance being deleted?
If not, is such a scenario a good example of where a service locator should be used?
I find it repeated over and over again in the articles & tutorials that a programmer must avoid using "new" within any class like the plague. However, is this really feasible for instances of controllers that may need to create a variety of views or the like?
A concrete example of adherence to the SOLID mantra, at least as far as DI is concerned, would be appreciated... One that makes it clear how one would either stuff instances of ALL required dependencies into a controller class or how best instances of such dependencies would be located or created?
I don't know PHP but I'll try to explain some things so your question doesn't get neglected, so bear with me. ;-)
I find that dependency injection works best by separating your application in layers:
Presentation Layer - Some (user) interface that provides interaction with your application.
Business Logic/Service Layer - The actual behavior of your application.
Persistence/Data Access Layer - The layer that stores/reads data from a back-end (try searching for repository pattern).
These layers all transfer data to each other in a structured way, using domain models. These models can be for example a user and an image.
When your application logic states that a user's images are to be deleted when a user is deleted you'll want this in the middle layer (Business Logic). The business logic layer calls the data access layer in order to delete entities.
Let's demonstrate using Python (I hope you can read that).
# Define a class that manages users.
class UserService:
# A constructor accepting dependent DAL instances.
def __init__(self, user_repo, image_repo):
self.user_repo = user_repo
self.image_repo = image_repo
def delete(self, user):
self.user_repo.delete(user)
self.image_repo.delete(user.profile_picture)
The repo arguments that go in the constructor are instances of repository classes, this is dependency injection (constructor injection).
The important thing to remember is that an object doesn't instantiate another object, it accepts instances of objects.
The architecture of the Session component in Zend Framework 2 is yet undocumented and I'm having some trouble understanding it's practical use (compared to the very intuitive Symfony Session for example).
A short summary of the important pieces:
Zend\Session\Storage\SessionStorage maps and replaces the $_SESSION superglobal
Zend\Session\SessionManager is a facade to manage the storage, the session cookies, session configuration, session validation, etc.
Zend\Session\Container is a sort of replacement for the old Session_Namespace, different Containers share one Manager instance (via a static field).
There is no component that represents a collection of namespaces (containers) and therefore there is no way of using methods like 'issetNamespaceX', 'unsetNamespaceX', etc. Nobody (including the Manager as well as Storage) knows about the containers, whether there are any, and if, how many with what names.
Matthew Weier O'Phinney explained this circumstance as follows:
The Container is a special class for working with isolated segments of
the current Storage instance. [...] If anything, a Storage adapter
would contain Containers, not the Manager. However, we also want to
allow more basic usage of storage, which makes the Container
orthogonal to Storage, and which explains the difference in has-a
relations.
I see a couple of practical problems with this solution with regard to proper dependency injection. Obviously the Manager can be seen as a service with a rather long lifetime and therefore qualifies for constructor injection. Unfortunately, the Manager has no clue about the Containers which forces me to either inject Containers as well (bad because rather short lived and takes slots away), write my own additional functionality to make the Storage or the Manager Container-aware (should be framework functionality) or create Containers in my Consuming classes (which I want to avoid obviously).
So the Zend solution doesn't seem practical to me. If I want to use the Manager, the FlashMessenger and an additional container, I need to inject 4 (four!) classes. If I do the same with the Symfony Session, I only need to inject 1 (one) class.
Furthermore Containers don't qualify for injection since they're potentially short lived run time objects, which may exist or may not at a given point during script execution. With Symfony Session this is not a problem since the Session is aware of it's bags (containers), with ZF2 this is a problem since the Manager is NOT aware of the Containers.
Main question: How am I supposed to use Zend\Session with Containers in practice?
Additional question: Is there a good reason not to provide real namespace functionality similar to ZF1 or for example similar to the Symfony SessionBag?
I'm not 100% certain I understand what issues you're getting at.
First, the constructor for a Container accepts both the namespace for the container, as well as optionally the Manager instance: $container = new Container('your container namespace here', $manager). You can specify a default manager instance to use as well: Container::setDefaultManager($manager).
Second, a Container represents simply a named array within the Storage instance used. As such, you can test for existence of a container by doing an isset($storage['your container namespace here']) call.
What exact issues are you running up against that the above do not solve? From your description, it sounds like (a) you were not aware that containers have a 1:1 relationship with the storage, and (b) that you can inject a manager into the container instances. If there are additional problems, I'd like to better understand them.
I just started practicing TDD in my projects. I'm developing a project now using php/zend/mysql and phpunit/dbunit for testing. I'm just a bit distracted on the idea of encapsulation and the test driven approach. My idea behind encapsulation is to hide access to several object functionalities. To make it more clear, private and protected functions are not directly testable(unless you will create a public function to call it).
So I end up converting some private and protected functions to public functions just to be able to test them. I'm really violating the principles of encapsulation to give way to micro function testability. Is this the correct way of doing it?
There is a pretty standard answer to this in TDD circles. If there is functionality in a class that you both want hidden and directly tested, you should sprout a class with that functionality. This is a great example of how TDD improves your design.
In the original class, that extraneous functionality is gone, wrapped within the sprouted class, so the original class' design is simpler, and better conforms to the Single Responsibility Principle. In the sprouted class, the extracted functionality is its raison d'etre, therefore it's appropriate for it to be public, and therefore it's testable without test-only modifications.
With respect there Carl Manaster's fine answer, there are some drawbacks you should at least consider before embarking on the path Carl suggested.
The most significant of which is this: we use encapsulation to minimise the number of potential dependencies that carry the greatest probability of change propagation. In your case, you have encapsulated private methods inside your class: they are not available to other classes and thus there are no potential dependencies on them: the cost of any changes you make to them is minimised and has a low probablility of propagation to other classes.
It seems that Carl suggests moving some private methods from your class into a new class, and making those methods public (so that you can test them). (Incidentally, why not just make them public in the original class?)
By doing this, you remove the barrier to other classes' forming dependencies on those methods, which will potentially increase the cost of chaging those methods should any other class take to using them.
You may judge this down-side minor and a worthwhile price to pay for being able to test your private methods, but at least be aware of it. In a small number of cases, it may indeed be worthwhile, but if you institute this throughout your code-base then you'll drastically increase the probability that these dependencies will form, increasing the cost of your maintenance cycle to an unknown degree.
For these reasons, I disagree with Carl that his suggestion is, ” … a great example of how TDD improves your design.”
Furthermore, he states, ”In the original class, that extraneous functionality is gone, wrapped within the sprouted class, so the original class' design is simpler, and better conforms to the Single Responsibility Principle.”
I would argue that the functionality being moved is not at all, ”Extraneous.” Also, ”Simpler,” is a not well-defined: it certainly may be the case that a class's simplicity is inversely proportional to its size but that does not mean that a system of simplest-possible classes will be the simplest possible system: if this were the case, all classes would contain only one method and a system would have an enormous number of classes; the removal of this hierarchical layer of multiple-methods-within-classes, it could be argued, would make the system much more complicated.
The Single Responsibility Principle (SRP) is, furthermore, notoriously subjective and entirely dependent on the level of abstraction of the observer. It is not at all the case that removing a method from a class automatically improves its conformity to the SRP. A Printer class, with 10 methods, has the single responsibility of printing at the level of abstraction of the class. One of its methods may be checkPrinterConnected() and one may be checkPaper(); at the method level, these are clearly separate responsibilities, but they do not automatically suggest that the class should be broken down into further classes.
Carl finishes, ”In the sprouted class, the extracted functionality is its raison d'etre, therefore it's appropriate for it to be public, and therefore it's testable without test-only modifications.” A functionality's importance (it's raison-d'etre-ness) is not the basis for the appropriateness of its being public. The basis for the appropriateness of functionality's being public is the minimising of the interface exposed to the client such that the class's functionality is available for use while the client's independence of the functionality's implementation is maximised. Of course, if you are moving just one method into the sprouted class, then it has to be public. If you are moving more than one method, however, you must make those methods public which are essential to the client's successful use of the class: these public methods may be far less important than some of the private methods from which you wish to shield your client. (In any case, I'm not at a fan of this, ”Raison-d'etre,” phrase as the importance of a method is also not well-defined.)
An alternative approach to Carl's suggest depends on how large you envisage your system to grow. If it will grow to fewer than a few thousand classes, then you might consider having a script to copy your source code to a new directory, change all occurances of, ”private” to, ”public” in that copied source and then write your tests against the copied source. This has the down-side of the time it takes to copy the code but the benefit of preserving encapsulation your original source yet making all the methods testable in the copied version.
Below is the script I use for this purpose.
Regards,
Ed Kirwan
!/bin/bash
rm -rf code-copy
echo Creating code-copy ...
mkdir code-copy
cp -r ../www code-copy/
for i in find code-copy -name "*php" -follow; do
sed -i 's/private/public/g' $i
done
php run_tests.php
I have just read a great article on letting mock objects drive you design:
http://www.mockobjects.com/files/usingmocksandtests.pdf
When Carl says "you should sprout a class with that functionality", the author of this article explain how your tests can guide you, through the use of mock objects, how you can design your class so you 1) don't need to worry about not being able to test private parts, and more importantly 2) how this will improve your design by (I'll paraphrase Carls quote) discovering collaborators and roles with the right responsibility.
The author takes you through an example step by step to make his point very clear.
Here's another article with the same approach:
http://www.methodsandtools.com/archive/archive.php?id=90
A quote:
Many who start with TDD struggle with
getting a grip on dependencies. To
test an object, you exercise some
behaviour and then verify whether an
object is in an expected state.
Because OO design focuses on
behaviour, the state of an object is
usually hidden (encapsulated). To be
able to verify if an object behaves
like expected, you sometimes need to
access the internal state and
introduce special methods to expose
this state, like a getter method or a
property that retrieves the internal
state.
Apart from not wanting objects
cluttering their interfaces and
exposing their private parts, we
neither want to introduce unnecessary
dependencies with such extra getters.
Our tests will become too tightly
coupled and focused on implementation
details.
A group of agile software development
pioneers from the United Kingdom were
also struggling with this back in
1999. They had to add additional getter methods to validate the state
of objects. Their manager didn't like
all this breaking of encapsulation and
declared: I want no getters in the
code! (Mackinnon et al., 2000 &
Freeman et al., 2004)
The team came up with the idea to
focus on interactions rather than
state. They created a special object
to replace the collaborators of
objects under test. These special
objects contained specifications for
expected method calls. They called
these objects mock objects, or mocks
for short. The original ideas have
been refined, resulting in several
mock object frameworks for all common
programming languages: Java (jMock,
EasyMock, Mockito), .NET (NMock,
RhinoMocks), Python (PythonMock,
Mock.py, Ruby (Mocha, RSpec), C++
(mockpp, amop). See
www.mockobjects.com for more
information and links.
I'd like to:
Make commonly required services visible to all classes that need them,
with a minimum of boilerplate, and
without sacrificing testability!
It's a small project and I think DI might be overkill, but maybe I'm wrong? Anyhow, I have been focusing on the ServiceLocator pattern as described by Martin Fowler
In a client class' constructor, I have something like this:
this->db = Locator::getDb();
this->log = Locator::getLogger();
Then the rest of the class' methods access the service through those member attributes, e.g.:
this->fooModel = new fooModel(this->db);
fooItem1234 = this->fooModel->findById(1234);
However I would also like this level of visibility for "model" objects (like fooModel above) because they are accessed from several different places and there is no need to have more than one instance.
So my initial thought was to extend Locator to have a ::getFooModel() but now it seems I'm violating the Open/Closed Principle, since I'll have to modify Locator every time I introduce a new model class.
To satisfy OCP, I could use the Dynamic Service Locator (also described on Fowler's page) however I'm not totally sold on this for the same reasons as him, i.e. it's not explicit enough.
Another solution would be to just make all my models' methods static. So:
fooItem1234 = FooModel::findById(1234);
I like this because it's zero boilerplate. I can just create a new model class and start calling it from anywhere with a single line. But now the model depends on Locator to find its DB connection and I'm not sure how I feel about that. For one, if I ever needed to have two fooModels open on separate database connections, it would be a mess and/or impossible. That said, I don't actually need to do that currently so this option seems a little tempting.
Finally, there's DI. But like I said above I think it might be too much for this little project.
Conclusion: I'm a little stuck here and would appreciate some advice from the gurus of StackOverflow!
Why do you think that DI is overkill for your project? DI patterns such as Constructor Injection is way simpler and cleaner than Service Locator (which I consider an anti-pattern).
I consider Service Locator to be an anti-pattern since it is totally opaque to the user of the API which dependencies need to be in place; thus, one could easily invoke methods on your objects in a context where the Service Locator would throw, and the API gives you absolutely no clue that this is the case.
You don't need a DI Container to use DI. If just have a simple project, you can use what is known as Poor Man's DI where you wire up dependencies manually.
... and there is no need to have more than one instance.
You're mixing apples and oranges. The fact that you only need one instance of a class for an application, is not the same thing as it being a good idea to make that instance globally available. With DI you don't change the cardinality - there is still just one instance. What you change is the scope of variables that address said instance. There's a difference.