Dependency Injection Breaks Encapsulation

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

I suggest you read post #90 where TomB says the following

[quote]
Even in situations where DI doesn’t directly add a benefit it’s still preferable any of the other approaches you have listed.[/quote]

Incorrect. The reason for not using DI is that I have no need to inject alternative dependencies simply because there are no alternatives. Using DI in the wrong place does not automatically make your code “better”, it can actually make your code worse.

If you are saying that modern OOP requires that I use DI even in those places where it is not appropriate, then I have to disagree. OOP does not require me to use any particular set of design patterns. I will use a particular design pattern when it is appropriate to do so, and when it is not appropriate then I won’t.

They are if they implement a design pattern without thinking if it is the right solution for the problem at hand.

If they cannot evaluate DI, or any other design pattern for that matter, to see if it is the right solution for the current situation then every solution which they implement is liable to be the wrong solution. It takes brain power to implement the right solution. Any idiot can implement an inappropriate solution.

I read the variable list (which is longer than many of my class files if you prune the comments) and I couldn’t determine if the class was dealing with database tables, html tables or some type of PDF distillery. If a ten year veteran programmer can’t make that determination by line 100 the code is not straightforward. If anything it’s a swiss army knife class.

1 Like

The common name is “God Object”: http://en.wikipedia.org/wiki/God_object But yes, it’s incredibly unclear what it does, making any changes to it would be… problematic as it’s difficult to know what knock-on-effects it will have and there are no test cases remember!

1 Like

That in turn is part of this tried and true anti-pattern - Ye 'Ole Big Ball of Mud.

1 Like

I worked alone on my framework, although some other developers supplied some bits and pieces which I found useful. Other developers have used my framework to write their own applications. I developed my main ERP application on my own, but I am now sharing it with my business partner who has added some modules of his own. He has even trained up some developers in India to use my framework. Both he and his Indian developers like it because it is not filled with useless rubbish, is easy to understand, enables new components to be developed very rapidly, and has features which allow any sort of customisation to be quickly and easily added for any customer.

It is easy to memorise the file paths for my classes as there are only two possible locations:

  • The INCLUDES folder supplied with the framework
  • The CLASSES folder within each subsystem.

I don’t have complex class hierarchies or complex directory structures, so finding the right class file is as easy as falling off a log.

That is why I have a business partner who helps sell the ERP application which I wrote, and which we have enhanced together with the aid of his Indian developers. Our joint efforts have recently resulted in a significant sale to a major multi-national corporation. If it was such “unmaintainable crap” as some of the posters to this discussion have intimated, then none of this would be possible.

Incorrect. Tens of thousands, sometimes hundreds of thousands.

Remember that I wrote both my framework and my application years before autoloaders existed, and there would not be any benefit in changing my code now.

This simply isn’t true either. Your own code aside, CEOs and key decision makers in large organisations’ priorities are often different to the technical part of the company. They look at the bottom line. It’s difficult to explain the concept of code quality to these people simply because they don’t have the background to understand it. They look at the cost and little else. PHP vs ASP.NET? Which is cheaper? Go with that. Business people are not interested in the same things programmers are and while it can be easy to demonstrate the difference between Notepad and Word, it’s difficult to explain the difference between tightly coupled and loosely coupled code without taking them on a long, expensive course… for little benefit to them.

Oh my. :open_mouth:

Scott

And remember that this discussion would be better if it were conceptual rather than discussing existing implementations. Nobody is asking you to change anything, we’re just using your code to highlight bad practices and as an example of where improvements can be made.