Dependency Injection Breaks Encapsulation

But the singleton class is written once then reused thousands of times. Your sample code for DI uses extra code for every instance where there is a dependency.

That statement is based on nothing but personal opinion, and I do not share that opinion.

Then why is it that when I supply sample code which does not use DI you keep telling me that I should switch to using DI because it is a “better” approach?

Are you saying then that someone who is starting a new project should always use DI for every dependency even where a dependency does not have alternatives? That is patently bad advice.

I do not use an autoloader for the simple reason that I do not have the problem for which an autoloader is the solution. Besides, an autoloader cannot do anything that cannot already be done using include_path.

Because you keep using your code as examples and cannot decouple the concepts from your existing codebase. While its perfectly reasonable to compare two solutions and anaylse the relative benefit you can only ever provide examples from your code base. Then when I and others say “This code can be improved by doing [whatever]” you read it as us telling you what to do.

This was highlighted multiple times in the last thread and repeated in this one, your inability to discuss things in terms of concepts and continually bringing everything back to how it affects your current codebase is the source of all the problems you have discussed. If you were able to discuss the merits of approaches and not just think in terms of “My code cannot do that” then this discussion would be a lot simpler and considerably more beneficial for everyone.

I pointed this out in Post 22, you chose to ignore it and carry on regardless. Here we are over a hundred posts later and you’re still doing the same thing.

I am saying that should be the case unless you can adequately demonstrate a use-case where DI is inferior, something you have repeatedly failed to do.

But by insisting that DI should be used EVERYWHERE even when it does not fit the circumstances for which DI was originally designed you are actually employing a solution to a problem you don’t have, which is a sign of poor programming. I repeat, I DO use DI in places where it is appropriate, but I DO NOT use DI in those places where it is NOT appropriate. So please stop telling me that I should use DI everywhere.

But only in the right circumstances, not in all circumstances.

Anybody who implements a design pattern without thinking is a poor programmer. That is not just my opinion. If you read http://en.wikipedia.org/wiki/Dependency_injection you will see the following statement:

in article http://www.loosecouplings.com/2011/02/non-di-code-spaghetti-code.html you will see the following statement:

[quote]
Is it possible to write good code without DI? Of course. People have been doing that for a long time and will continue to do so. Might it be worth making a design decision to accept the increased complexity of not using DI in order to maximize a different design consideration? Absolutely. Design is all about tradeoffs.

It is of course possible to write spaghetti code with DI too. My impression is that improperly-applied DI leads to worse spaghetti code than non-DI code. It’s essential to understand guidelines for injection in order to avoid creating additional dependencies. Misapplied DI seems to involve more problems than not using DI at all. [/quote]

A competent programmer knows when DI is an appropriate solution and when it is not. Anyone who implements DI without thinking is not a competent programmer.

I disagree. It is not up to me to identify when DI is inferior, it is up to you to identify when DI is superior, something you have repeatedly failed to do. I will not use DI unless I have a good reason to do so, and I’m afraid “because I said so!” is not a good enough reason.

Well clearly you do! You used the fact that require_once lines are needed for classes as an example of DI needing more lines of code. Those repeated require_once lines are a perfect example of where an autoloader can solve the issues you had. Besides, I already answered this in detail with an example, using your own codebase that solves the problem.

… I have repeatedly demonstrated this. DI is:

  • Fewer lines of code
  • Faster to execute due to less code
  • Quicker to write
  • Infinitely more flexible

You’re the one making the claim that “DI IS EVIL (sometimes)” It’s is 100% up to you to back up that claim.

You must be trolling at this point.

I will repost this, because it’s a nuance you seem unable to grasp:

You are misquoting me. What I actually said was:

  • Do I have the problem for which DI was designed?
  • If YES then DI is an appropriate solution.
  • If NO then DI is an inappropriate solution.

Do you see the difference? Do you understand the difference?

I never said that my codebase was perfect since “perfect” means different things to different people. All I will say is that it is more than adequate in providing a cost-effective solution.

Incorrect. I am merely identifying those situations where the problem for which DI was originally designed as the solution does not actually exist, so if the problem does not exist then the solution which solves that problem is completely pointless.

Except it’s obviously not. You’re clearly trying to rationalise/justify existing code which is why you refuse to take a step back and discuss the merits of different approaches based on the concepts alone. You keep bringing it it back to “Well I did this here, and this here so that’s why you should do it that way too”.

Let’s turn this around: If you weren’t trying to justify existing code, you wouldn’t need to point to it in the first place. You could give us bare-bones, minimal examples that aren’t coupled to an existing codebase.

I disagree. I have identified circumstances where the problem for which DI was designed as the solution does not exist, and I have supplied sample code from my own application as an example. If I don’t have the DI “problem” then what is the point of implementing the DI “solution”? Other developers may recognise the same situation in their code, in which case they should be asking themselves “Do I need DI in this situation or not?”

You will never agree with my opinion, and I will never agree with yours. I suggest we agree to disagree and stop posting. If you stop telling me “You are wrong” I will not have to respond with “No I’m not”.

DI also has the following disadvantages:

  • It employs eager loading instead of lazy loading, which means that dependent objects could be instantiated without ever being used. This leads to performance problems.
  • It fragments the code so that in order to identify which class was instantiated, and how it was instantiated, the developer has to look in multiple places. This makes reading the code more difficult, and also altering the code to do something else more difficult.

How can including extra code which provides absolutely no benefit be “preferable”?

Your example code has a ~30 line “singleton” class. Using DI in its place is roughly 28 lines shorter.

If eager loading is a problem (other than in some very exceptional circumstances) then: http://misko.hevery.com/code-reviewers-guide/flaw-class-does-too-much/

  • It fragments the code so that in order to identify which class was instantiated, and how it was instantiated, the developer has to look in multiple places. This makes reading the code more difficult, and also altering the code to do something else more difficult.

This is not a problem! Because of encapsulation I need only know about the API of the class being dealt with and not the implementation. This simply is not an issue. It’s like saying “I can’t see the code for the $mysqli object!” and claiming it’s a problem. You only need to know what methods are available. This is the essence of OOP. This is the difference between loose and tight coupling. It’s widely acknowledged that loose coupling is preferable.

Who is insisting DI be used everywhere? They aren’t saying you should use it. As I wrote in my last post, the statement is, if you want loosely coupled, reusable and testable code, then using DI is a good design pattern. Is that an incorrect statement? If so, why? Your post actually supports that statement.

The opposite reason for not using DI is, you DON’T want loosely coupled, reusable and testable code. If that is what you want, then don’t use DI. Simple. Just use singletons and service locators. Oh wait, that is what you do in your framework, right?

Now ask all of those idiot PHP devs out there, if they want to work with tightly coupled, non-reusable and non-testable code.

You know what the answer will be Tony?

No way! We all want to work with modern OOP methodologies.

But you simply made the blank statement that most devs are incompetent. Let me quote what you wrote again.

How do you know that they don’t have the brain power Tony? That is a pretty bogus assumption and the insult you add to the end of that paragraph is even more bogus.

DI is a good design pattern. It is widely used in a number of frameworks. There are a number of libraries that offer DI and a DI container system. This is a fact and the reason DI is so accepted is because the aim of most of today’s OOP code is to be reusable, testable and modular. That doesn’t mean “everywhere”. It means in modern OOP code. Don’t you agree?

Scott

2 Likes

So you work alone I take it? And even if you don’t, how long would it take someone to thoroughly learn the ins and outs of your framework? How much time would you need to spend teaching them?

I’m guessing it would take awhile - you admitted to not using an autoloader which means you’ve personally memorized the file paths to all you classes. It would take someone else a while to do such a memorization, so on that factoid alone I can determine your framework, however it is set up, would not be easy to learn.

These training costs are enormous and are why custom solutions like yours are losing market share. There’s a limit to the size of contract you can hope to fulfill working alone.

Running with the big dogs requires using solutions that can be rapidly deployed with the workload spread over large staffs. So enjoy your contracts valued in the thousands, your welcome to them. Meanwhile I can’t remember the last time my company took on a web application project for south of a million.

Just a warning: Tony is going to spin this and say “Well that just shows that I can deliver those projects at a lower cost!”

I disagree. Using DI I have to instantiate and inject all the dependent objects before I can call the method. This means that the implementation of that method is no longer hidden, and as implementation hiding is one of the aims of encapsulation you have therefore broken encapsulation.

I repeat, your solution requires more lines of code for each and every dependency than my solution.

This is demonstrably false yet again and I have already done this several times… but fine… how is:

class Person {
    function doStuff () {
        ....
        $objAddress =& singleton::getInstance('address');
        $address = $objAddress->getPrimaryAddress($customer_id);
        ....
    } // doStuff
} // end class Person

class singleton
// ensure that only a single instance exists for each class.
{
    function &getInstance ($class, $arg1=null)
    // implements the 'singleton' design pattern.
    {
        static $instances = array();  // array of instance names

        if (array_key_exists($class, $instances)) {
            // instance exists in array, so use it
            $instance =& $instances[$class];
            
        } else {
            // load the class file (if not already loaded)
            if (!class_exists($class)) {
                switch ($class) {
                    case 'date_class':
                        require_once 'std.datevalidation.class.inc';
                        break;

                    case 'encryption_class':
                        require_once 'std.encryption.class.inc';
                        break;

                    case 'validation_class':
                        require_once 'std.validation.class.inc';
                        break;

                    default:
                        require_once "classes/$class.class.inc";
                        break;
                } // switch
            } // if

            // instance does not exist, so create it
            $instances[$class] = new $class($arg1);
            $instance =& $instances[$class];
        } // if

        return $instance;

    } // getInstance
    
} // singleton

 new Person();

Fewer lines of code than:

class Person {
    public function __construct(Address $address) {
        $this->address = $address;
    }

    function doStuff () {
        ....
        $address = $this->address->getPrimaryAddress($customer_id);
        ....
    } // doStuff
} // end class Person

$address = new Address;
new Person($address);

You can actually download Tony’s framework. I did out of interest. This is used on every single page for everything as far as I can tell. Judge for yourself: http://pastebin.com/m76ZAUZc This is from the guy who claims to have a “Minimalist approach”: http://www.tonymarston.net/php-mysql/minimalist-approach-to-oop-with-php.html and “Keep it simple”.

1 Like