Dependency Injection Breaks Encapsulation

You missed my point though, you can’t use that as an argument against DI. I agree with you and separation of concerns is a very big topic in in itself but you’re describing a problem with the initial code then comparing a solution to that problem to the problem itself, not a solution to the problem with another solution to the problem which is the only way to get a fair comparison.

The question here is “Would this code be improved by separating out the display logic?” the answer in most cases will be “Yes”. So the question you now need to ask, if you have determined that the code would be improved by separating out the display logic then the question becomes “Which method of doing that is preferable?” not, as you are, “Is this solution to the problem more code than the original problem”.

The difference is subtle but important. If you have determined that you need to separate out the display logic then you can look at different methods of doing that, but conflating the initial problem with one possible solution is not helpful in this discussion.

This is true but it’s not really relevant, you don’t generally hard code primitives, you use variables which are set in the constructor. Saying “The first argument is an Integer” is no different than saying “The first argument is an Address object”. There’s no difference here. And on-topic, I can define an argument as a float and accept an integer, I just need some kind of numeric value, most programming languages will allow this basic form of primitive polymorphism by doing the conversion for you. PHP and other loosely typed languages do this to a greater extent, I can pass “123” as a string into an argument that requires an int and it will just work.

I’m not sure I understand this. If you get a bug that exists only in production then your testing is sub-par but that’s a whole different issue.

As I said before, if someone is complaining that they passed an invalid argument it’s their own fault. You’re essentially saying people are complaining when they do this:

abs("ABCDE");

And then complaining when it breaks which is clearly user-error.

If you’re providing a library for others to use, loose coupling is even more important because unless the requirements for their project are exactly the same as yours then they won’t be able to use your library. If they can inject the dependencies themselves, they can use at least some of your code.

But by the same token in reality and out side these theoretical examples requirements change often. Let’s take the code you quoted:

 new J(new I(new H(new G(new F(new E(new D(new C(new B(new A())))))))));

And imagine the non-DI version that J create H, H creates G, etc:

new J();

Then the constructor for A changes to need a text file location. This has to be provided by the application developer not the library author as hard coding it in the library presents all kinds of portability issues.

So the only way to do this is alter J to have a constructor argument:

new J('file.txt');

which then passes it to I that passes it to H that passes it down to G etc, etc.

The problem again is the lack of atomicity in this discussion. Rather than being able to discuss the problem at hand it keeps getting pulled back to “What if this happens, what if this happens”. Let’s talk about the pros/cons of DI before discussing further concepts such as containers otherwise we are clearly crossing concerns and conflating different (albeit related) problems.

There are two different discussions happening here. The initial topic was clearly centred around what constitutes well designed software in relation to DI and the reasons for that but we keep straying into anecdotes and unrelated or loosely related topics.

As an analogy: I am trying to discuss the merits of different CPUs. I’ve stated my metric as being “I want the fastest one available for a specific task” so I look at the CPUs analyse them according to my stated criteria and you and tony keep saying “Well what about this motherboard” “Doesn’t this case look pretty?”, “Does it have to be silver??”, “That won’t work with my RAM”, “I have this processor and it works just fine for me”… all I want to do is directly compare processors.

Now, It would be fine to come along and look at them from a different metric and say “I want the cheapest one available” but both Tony and yourself keep failing to identify the metric you are using to compare the different approaches. We’ve briefly skirted around lines of code/development time but as we’ve seen, this isn’t very clear cut as all your examples are mixing in other details (SoC, DI containers, etc).

To reiterate, the metric I am using is essentially the list I posted earlier:

As “Best” in programming tends to mean flexiblity, and the list here is quite good http://c2.com/cgi/wiki?GoodArchitecture :

Robust - lacking bugs and tolerant of external faults
Maintainable - easy to maintain and extend
Useful - utility, beyond the immediate need (due to flexibility and extensibility)
Scalable - ability to grow in capacity, not in features
Common Vision - direction, strategy
Agile - simple and “elegant” enough to refactor easily; flexible
Extensible - ability to grow in features or in depth
Responsive - performance now and after adding features or expanding scale

Edit: And if you do identify another metric. We then need to ask the question: at what point does that metric become important?

You have just confirmed what I have been claiming all along that there is no single document called “best practices” which is universally accepted by all programmers. Instead there is a vast collection of documents written either by individuals, groups or organisations which do nothing more than identify what “best practices” means to them. So if I, or any other programmer for that matter, wishes to find out what is considered to be the current set of best practices, where do I look? If I search google for “best practices” I get 142 million hits. If I search for “best practices software” I get 132 million hits. It would be physically impossible to read through all those documents and obtain a common consensus for the simple reason there is no common consensus. There is no “best for everybody”, just a vast collection of different ideas of what is considered best by different groups. So when you tell me that I am not following “best practices” I am justified in asking the question “which of the 132 million variations of best practices am I not following?” As far as I am concerned I AM following best practices, but not the same practices as you. There is no law that says that I, or every other programmer, has to do everything the same as you, so don’t tell me that I am wrong for not doing so.

Besides, can you point me to any best practices document from any reputable organisation or group which agrees with your idea that I SHOULD use DI, or any other design pattern for that matter, at every possible opportunity, even when the circumstances for which the pattern was designed do not actually exist?

Sometimes a principle or idea gets labelled “bad” because someone tried to implement that idea but failed. But was the failure due to their faulty implementation rather than a fault with the idea? For example, I have been told on numerous occasions that my idea of having a separate class for each database table is just plain wrong. “It’s just not done that way” is the common argument. I even heard from one programmer that he tried the idea but couldn’t get it to work, so he assumed that the idea was unworkable. The simple fact is that I tried that idea in 2002 and got it to work and have been using it very successfully ever since. I proved that the idea works simply by producing an implementation that did not fail.

Any modular or layered system will have dependencies, and where there are dependencies there will automatically be coupling. It is impossible to have a completely de-coupled application as it simply would not work. Unfortunately too many programmers treat any form of coupling as tight coupling when in fact it is actually loose coupling. Loose coupling has fewer problems than tight coupling.

As for “broken encapsulation”, this is caused by the inappropriate use of DI.

I suggest you look at post #1, #10, #12, #26.

I have explained more than once the circumstances where DI is a good solution, which therefore means that where those circumstances do not exist then DI is not a good solution.

This is the point I have been trying to make. I use DI where it is useful, but I don’t use it where it is not useful, but there are some posters in this discussion who seem to think that I should use DI at every possible opportunity, whether it provides any benefits or not, simply because they think it is the right thing to do.

I can’t help it. I have to answer.

Tony, are you seriously just searching for “best practices”? Or did you add “PHP” to the search, because if you do, you’ll end up with a good list of sites with best practices. Below are some of the results I got filtering for results only from 2013 onward, because yes, best practices change over time, as the technology changes.

PHP Best Practices
Best Practices for Modern PHP Development - also mentions dependency injection
Best practices that you must follow
Even Sitepoint’s article is in the list - PHP Tips, Resources and Best Practices for 2015
With some interesting references, like…
PHP the Right Way - even with a section about Dependency Injection (this page is also result number 1, if you search only for “php best practices”.

You can stay blind to the current PHP world Tony. It won’t mind. It will happily leave you in its dust.

Scott

1 Like

None of those millions of sites say that creating a 9000 line class that mixes 10+ responsibilities is a good idea. The fact that dozens or more professional and/or academic well respected programmers all independently come to the same conclusion actually gives it more weight.

So no then. None of these posts do what I asked. I am still waiting for an example of when DI is inferior and for you to explain the metric you are using to measure the difference. Until you do this, I’m going to assume you can’t, which makes your opinion void.

It does not matter how many pages you select from the web labelled “best practices”, they are simply the personal preferences of the person or group who wrote the document based on their experiences. You should see from some of the comments that plenty of developers disagree with what has been written, so it is totally wrong for anyone to say that just because I do not follow a their chosen practices that I must therefore be following bad practices which automatically makes my code bad.

I repeat, there is no single document which is universally accepted as “best practice”, just a huge collection of possible candidates, so I am free to choose whichever standards suit me the best.

The fact that I do not employ the same design patterns as you, or implement them in the same way that you do, is totally irrelevant. Each pattern is a possible solution to a set of circumstances, but if those circumstances don’t exist in my code then I do not see the point of implementing that pattern. Dependency Injection only has benefits when a dependency can be supplied from a number of alternatives, so when I do have a number of alternatives I do use DI, but when don’t have a number of alternatives I don’t use DI. It’s as simple as that.

This is 100% wrong and just proves yet again that you are purposefully missing the point as you have been backed into a corner. Best practices exist and they exist for a reason. They are “Best practices” not the 10 commandments. And while it’s fair to say there is some disagreement about some of the nuances, overall people agree that things like:

  • flexibiltiy
  • maintainability
  • separation of concerns
  • reusability
  • Ease of testing

are good things and

  • Tight coupling
  • Action at a distance
  • Broken encapsulation
  • Global state

Are bad.

You’re trying to turn this into a false dichotomy and imply controversy where there simply is none. It’s like I said in the last thread. You’re sitting on the “vaccines cause autism” side of the debate when all the evidence both independent and from professionals proves they do not. Please either back up your points or stop posting. The burden of proof is on you and you seem incapable of backing up the claims you make.

There is no rule that says that a class cannot contain more than N methods, or that a method can only contain N lines of code. In fact the rule of encapsulation says quite explicitly that ALL the methods and ALL the properties for an entity SHOULD be contained in a single class for that entity.

As for the mixing of responsibilities, your definition of “responsibility” must be different from mine. The class you are complaining about is not a concrete class but an abstract class, and contains all the methods and properties required to deal with an individual database table. There is no direct communication with any DBMS as that is handled in a separate object. There is no creation of HTML or PDV or CSV output as that is handled in a separate object.

I have told you repeatedly that Dependency Injection was designed for those situations where a dependency can be supplied from a number of alternatives, so where I have a number of alternatives I am quite happy to use DI. But in those circumstances where a dependency can only be supplied from a single object without any alternatives then using DI is a waste of time.

I have provided code samples showing where I do use DI as well as a sample where I do not use DI, so I am not going to waste my time in duplicating that effort.

No, you have not. Where you do/not use something is irrelevant. You need to demonstrate how one is better than the other and explain how you’re measuring “better” something you have spent 500+ posts avoiding.

http://misko.hevery.com/code-reviewers-guide/flaw-class-does-too-much/

No, it is not wrong. If there are 1 thousand pages on the web labelled “best practices”, but they contain contradictory information, then which of those thousand pages do I choose to follow? Just because I do not follow the same documents as you does not make me wrong, just different.

I disagree. The topic under discussion here is Dependency Injection, and if there are any circumstances where DI is not a good solution. I have already explained many times the original purpose of DI which was to deal with the case where a dependency can be supplied from a number of alternative objects. Where I have a number of alternatives I use DI, but where I do NOT have a number of alternatives I do NOT use DI. I certainly do not have to prove that the code which I use to NOT implement DI is superior to any code you can dream up which DOES implement DI. I use DI where it is appropriate, but I do not use DI where it is not appropriate.

[citation needed]

Again, you’re not backing anything you say up with anything tangible. Best practices exist and the fact that professionals, academics and the authors of languages independently come to the same conclusions about what is a good way of working and what is a bad way of working adds weight to the arguments.

Just because you choose to avoid/misunderstand best practices doesn’t mean they shouldn’t be used and it certainly does not mean you should advocate their avoidance.

Not that it’s even relevant. Let’s ignore that for now. The argument best practices advocates are making is "X is bad because it causes Y, Here’s an example of method 1, here’s an example of method 2, method 1 is better beacuse… " Your response to this is “No it’s not”.

Arguments for best practices are backed up with reasoning and code examples comparing the different approaches. Your responses are not.

I feel like we’re going in circles here. Has it not been stated that Tony does use DI, when he feels it is appropriate to his application? And then chooses to not use it, when he feels it isn’t?

Hasn’t it been said that DI can provide benefits and efficiency to an application?

Has the actual question been answered? “Dependency Injection Breaks Encapsulation?” Probably not. Do I see us ever getting down to that answer? No. Do I feel that both of you have made your same points roughly 15 times now? Definitely.

As much fun as it is to see the bantering back and forth, let’s call it what it is and let it be. The two of you will never get on the same page and that’s life. Let it go. The rest of us have.

8 Likes

You obviously did not read what I wrote. None of my objects which is based on this abstract class constructs any HTML, PDF or CSV output as those functions are handled by totally separate objects. My table classes simply hand over any data to one of those objects, and those objects construct the output in the relevant format.

In this article http://blog.8thlight.com/uncle-bob/2014/05/01/Design-Damage.html Robert C Martin had this to say

[quote]
How do you separate concerns? You separate behaviors that change at different times for different reasons. Things that change together you keep together. Things that change apart you keep apart.

GUIs change at a very different rate, and for very different reasons, than business rules. Database schemas change for very different reasons, and at very different rates than business rules. Keeping these concerns (GUI, business rules, database) separate is good design. [/quote]
Note here that what he is saying that GUI, business rules and database access are three responsibilities which should not be mixed in the same class. That separation is PRECISELY what I have achieved in my framework as I have separate classes for GUI, business rules and database access. I designed my framework to implement the 3 Tier Architecture, and this achieves precisely that level of separation.

What you’re doing in your own code is 100% irrelevant to anyone but yourself. Provide reasoning for your arguments along with minimal code examples.

I’m not burning my eyes out looking through that 9000 line class again but it’s clear it’s doing more than that. What exactly to “buttons”, “workflows”, “popups” and various other things it has methods for have to do with interacting with a database table?

But before you answer that, please give us some code examples for this:

The problem is, I’ve spent around 500 posts asking tony to provide some code examples and he keeps avoiding the question.

In post #2 I asked for:

And I’m still waiting.

And you will be forever. That’s the point. You are proving the definition of insanity.

6 Likes

Well, I wouldn’t call Tom insane. It’s more like Tony is the epitome of the old adage…

…you simply can’t teach old dogs new tricks.

Scott