Dependency Injection: a discussion of the pros and cons

I don’t use code such as that. My controller does not activate any validation method, nor does it inject the model with the database object. My implementation is much simpler:

$result = $dbobject->insertRecord($POST);

The insertRecord() method performs several steps as shown in my UML diagram at http://www.tonymarston.net/php-mysql/uml-diagrams.html#add1. If the validation stage fails then the model immediately returns to the controller without touching the database. If the validation is OK then it obtains its database object so that it can construct and execute the relevant SQL query.

I don’t use DI and I don’t use the proxy pattern. I don’t need a placeholder for a real object simply because I create the real object when, and only when, I have a need to use it.

My framework, and my ERP application which I built using that framework, is over 10 years old, and both have been maintained and enhanced up to the present day. All my dependencies have been hard-coded, and I have never encountered any circumstances where I have had to change those dependencies, and I have never felt the need to employ a technique such as DI for which I have no use.

But why should I change how I get and obtain dependencies? My code is simple and direct, therefore easier to read and maintain.

I don’t have an example in my code as none of my table classes use constructor arguments. However, I have seen examples in other people’s code where constructor arguments are used, so my point is that if the consuming object does not construct the dependent object then it cannot pass any arguments in the constructor. But what happens if the value of one of those arguments cannot be determined until you are about to consume the dependent’s service?

The the consuming object is the dependent. The roles reverse.

So let’s say you have the following:

class myClass {
  // constructor with an optional argument of $importantArgument
}

And it needs to implement the database object.

So if $importantArgument is important to creating the database object and myClass is in charge of creating the database object, then myClass is a dependency of the databaseObject, the databaseObject is no longer a dependency of myClass.

From a DI perspective though, this is all moot. As since I had to pass in $importantArgument, I could have just created the database object using the data $importantArgument had and passed that into myClass.

$dbObj = new DatabaseObject($importantArgument);
$myClassObj = new myClass($dbObj);

Not saying one is right or wrong, just saying that if you have a dependency like that, your consumer is no longer a consumer, is it a dependency for another object you need to instantiate.

And if you needed to use $importantArgument inside myClass to come up with a different property for your database object, again, myClass becomes a dependency of the database object. You needed it to establish your database object, you didn’t need the database object to sustain myClass.

Yes. My framework supports MySQL, PostgreSQL, Oracle and SQL Server as I have a different object for each of these. I can switch between any of these DBMS engines by changing a value in my configuration file. I can even deal with having different databases on different servers, and the multiple server option also allows me to use multiple DBMS engines at the same time.

What pattern am I using? None. Each table class contains the database name as well as the table name. It inherits vast amounts of code from abstract table class which contains a method called getDBMSengine(). This uses the config file to determine which DBMS engine is required for the current table, then it uses my singleton::getInstance() to obtain the relevant object. The abstract table class then continues its operations on whatever object it has been given. Easy Peasy Lemon Squeezy.

No, and I’m not going to explain why as that is a totally different topic.

Thank you.

Okay, I’m starting to picture it in my head now. Thank you for that.

No need to. Just more curious than anything, because if you were, I was going to ask how you dealt with dependencies. But I won’t start that topic :wink: Just trying to get a feel of your application, so I can see your position better (consider it a learning exercise for me… trying to learn how your project is setup/established so I can better understand where you are coming from – no ulterior motive).

In the applications which I write I don’t NEED to instantiate the dependent objects inside the consumer just as I do not NEED to instantiate them outside. It is my practice to instantiate such objects just before I need to use them simply because I cannot think of a good reason to do otherwise. It is simple, it works, and introducing DI would not improve it in any way.

Wouldn’t it be easier to just use PDO?

Now you’re going round in circles. Is it actually possible to have circular dependencies where a dependent of a consumer is also the consumer of its own consumer?

Is that not what was asked with the following question? (if it wasn’t, then I misunderstood your question)

If data from the consumer class must be established to setup the database object, doesn’t that mean the database object is dependent on the consuming class?

Again, not saying it is right or wrong, just a very odd edge case scenario that should be carefully dealt with. As you get into a real mess with that design decision and I’m sure there is a better alternative to clean it up.

PDO wasn’t around when I needed to create a database abstraction layer. I looked at what was available in the PEAR library and didn’t like it, so I wrote my own.

The problem with all the other database abstraction layers that I have seen is that they take an SQL query and send it to their specific database engine without dealing with any differences in syntax that may exist between the different engines. For example, the expression DATE_ADD(field1 - INTERVAL $field2 unit) in MySQL has to be changed to DATEADD(unit, +$field2, $field1) for SQL Server. My code can deal with these differences.

It should be “dependent object” and not just a “database object”. This scenario only causes a problem if you use DI. As I don’t use DI I will never have this problem.

Why not?

myClass needs to use a database object, can’t use it until after it initializes it using data myClass establishes.

class myClass {
   function myMethod() {
      // get myClass related data to initialize database object
      $dbObject = new databaseObject(..);
      // now use $dbObject in myClass
   }
}

If the // get myClass related data to initialize database object needs to get data from the database, you have a circular reference regardless of DI, or you at least have to make two instances of your database object.

The issue doesn’t exist because of DI, it exists because there is a lack of separation of responsibilities (which can exist in both cases).

1 Like

The alternative to DI is another method of dependency resolution In your case singletons which are widely acknowledged to be a bad idea. I provided plenty of sources in the last thread and this is not something that is up for debate.

You are misrepresenting what I said. Even though I keep saying that I have no use for DI I am constantly being told that I should be using it anyway.

You wrote an article called “Dependency Injection is evil”. Saying “I don’t want to use DI” is different from arguing that it’s “evil” and trying (and failing) to explain why another approach is better. Whether or not you want to use DI is irrelevant, if you don’t it’s your loss but trying to convince others it’s “evil” is misleading and potentially harmful to other developer’s understanding. We’re calling you out on spreading misinformation. If you want to code things in an inferior way that’s up to you, but trying to tell everyone else they should be doing that to is rather infuriating.

“From anywhere” is not good enough for me. I need to know exactly where and how the object was created and with what options, which is why I leave an object’s creation to the last possible moment

As compelling as the argument “I don’t like it is”, this is your sticking point. Until you understand the merits of encapsulation and information hiding, having a discussion about a nuanced subtopic such as DI is pointless.

The problem with avoiding DI is that your components become very tightly coupled, as you admit.

So why should I pollute my application with

This is the difference between you and everyone else. You’re building applications everyone else is building components. The difference is non-trivial and important. I and others are arguing for the merits of reusable components, not for static individual write once and forget applications.

Let’s analyse your method and mine:

Client: Tony, make me a model ship!
Tony Here you go!

Whereas, my (and others) approach is this:

Client: Tom, make me a model ship!
Tom Here you go!

By building around reusable lego blocks, changes to the structure are easy. Most blocks can fit into other blocks and be moved around the application. No block is dependent on anything other than its nearest neighbour.

With singletons, if your dependency has a dependency then your top level object has a dependency on both. This makes restructuring the program difficult:

Client: Tony, can you make the mast a bit longer?
Tony er… give me some time

Client: Tom, can you make the mast a bit longer?
Tom Done!

What’s even better is that when another client comes along and asks me to build a castle I can reuse the block blueprints I made for the ship! With your ship in a bottle everything is connected in such a way that it’s very difficult for it to be built into anything apart from a ship

When I build my components I build them in such a way that they don’t know if they’re part of a ship or a castle (the fundamental point of encapsulation). This means they can be easily used in either and because they’re blocks that aren’t glued to each other I can replace one block leaving the others as they were.

I do not have to switch any dependencies anywhere in my application.

And this is the problem this creates. You end up creating rigid applications rather than reusable, easily connected components.

" has about as much sense as the argument “inheritance breaks encapsulation”

Which is a very valid topic that isn’t worth going into until you understand encapsulation

5 Likes

Great reply Tom. I love how you get the conceptual differences down to simple lego block logic and visualization. LOL! :smile:

Scott

And where do you get that he even comes close to calling you an idiot? (even though he might be right?)

You keep referring to YAGNI. When do you ever consider SOLID? Or rather, how can you keep up the principles formulated in SOLID without some sort of dependency injection pattern? In other words, DI is a pattern to simplify keeping within the SOLID principles, namely the D at the end, Dependency Inversion. So it isn’t a question to say, when or when not to use it, but as Ralph rightfully said, how to use it properly.

You may have come up with a different way to do dependency inversion. But, it doesn’t give you any right to say DI is something bad or evil (and you are most definitely WRONG in that opinion). It also doesn’t give you any right to call me or anyone else using DI mindless boss following ninnies either.

Scott

I keep hearing the phrase “singletons are widely acknowledged to be a bad idea” but without any explanation as to precisely WHY they are a bad idea. Unless you can provide me with a code sample that identifies the problem I shall continue to treat this notion as an unsubstantiated opinion.

I wrote that article in response to other articles which state “Don’t think about why should use Dependency Injection, just use it”. Rather than saying that “DI is universally accepted to be a good idea” my message was “Think for yourself. Don’t let others tell you what to do”. I gave an example where I thought that DI was a good idea, but just because it is a good idea in SOME circumstances does not mean that it is automatically a good idea in ALL circumstances. It is my opinion, and the opinion of others (as shown in the list of references) that unless you have the need to change your dependencies on a regular basis then the overhead of implementing DI is simply not worth the effort.

Dependency Injection has nothing to do with encapsulation, and encapsulation does not mean “information hiding”, it actually means “implementation hiding”.

I do not develop “write once and forget” applications. I built my framework over years ago, and I have been maintaining and enhancing it to this day. I built an ERP application using this framework over years ago, and I have been maintaining and enhancing it to this day. I have all my dependencies hard-coded, and this does not cause me a problem as I NEVER have to switch those dependencies. Even if I had to change a single dependency, the cost of making that change manually would still be far, far less than the cost of implementing DI.

I have never had any such difficulty, so I cannot accept your argument.

Firstly, I create complete applications with reusable components, not libraries of components which others may want to use in their applications.

Secondly, my main ERP application is anything but rigid. It is actually a package which I sell to many organisations, and one thing about packages is that every different customer will want a different set of customisations. In my framework any such customisations are kept separate from the core code, and each customer’s customisations are kept separate from the others. This mechanism allows screen or report layouts to be changed with ease, and it is possible for core logic to be either replaced or extended with custom logic.

If my coding style was such a pile of crap then this level of flexibility and extendability simply would not be possible, so it can’t be as crappy as you think.

My understanding of “encapsulation” is quite simple:

‘Encapsulation’ means that the class must define all the properties and methods which are common to all objects of that class. All those properties and methods must exist inside a single container or ‘capsule’, and must not be distributed across multiple locations.

I do not need to use particular design patterns to make my implementation of encapsulation “correct”.

Except that his conceptual differences do not exist in real life. They are opinions, not facts.

I do not place any value in the SOLID principles. You obviously haven’t read my article http://www.tonymarston.net/php-mysql/not-so-solid-oo-principles.html

Again you are saying “Don’t think about the reasons why or why not you should use Dependency Injection, JUST USE IT!”

If you implement a solution without having the problem for which the solution was designed to solve then in my book you are not much of a programmer. I write code to solve problems that I actually have, not problems that I don’t have.

It does if you implement DI simply because someone tells you to, and without investigating if you actually have the problem for which DI is the solution.

So using his example, if your code was designed to build a Ship, can you reuse any of your code easily to build a Castle? As that is what takes it from opinion to fact. Tom’s design can, that is indeed a fact.

1 Like

But why would you want to? A wall in a castle is dramatically different than a wall on a ship. And a boat that is built like a castle would be called an anchor :anchor:

There needs to be thought placed into how things are designed. If something is never going to be re-used, why would you build hooks in there to do so? That just adds unnecessary weight to your coding which isn’t going to be used.

The end game always needs to be thought of before a line of code is going to be done. And sometimes the lighter, efficient way is a better solution than a robust, flexible solution which does more than will ever been needed or used.

1 Like