6 ms·
"The only reason was to inject mocks". Must disagree...the reason for DI is to support the Dependency Inversion Principle : "High-level modules should not depen
by chunkyfunky 6y ago
"The only reason was to inject mocks". Must disagree...the reason for DI is to support the Dependency Inversion Principle : "High-level modules should not depend on low-level modules. Both should depend on abstractions (e.g. interfaces)." Won't even go into the host of side-benefits that are gained from adhering to the DIP.
In C# the idiomatic way to achieve this is via constructor injection, which is made much easier to manage in ASP.Net with a DI library that works with the framework for you (either the built in one or AutoFac / SimpleInjector, etc.). But you don't have to use a library; many times I'm writing a simple-ish console app and just use good old "Poor Man's DI" where I manually construct my object graphs at startup.
- AndrewSChapman 6y agoI'm not even a C# coder and I can't understand the complaints about this. If you want to code fast and fancy free, use Python or PHP. If you want to use enterprise patterns that will make your code clean, testable and nicely modular, then go for something like C# or Java. Why even use C# if you can't be bothered with DI because... too many lines? mindblown
- mattmanser 6y agoSimply because not only does it not have to be like that, for years we weren't forced to use this stuff if we didn't want to. I like C#, no, I adore C#. I have a bad memory for even the simplest method calls and the sheer power the intellisense in a statically typed language gives me to just not care means I can just code with joy. My personal view on it has always been that someone in MS wrote MVC 1 in response to Rails on the sly. It was fantastic, a breath of fresh air into the MS constant misunderstanding of the web. Especially compared to webforms. For a while, everything was good. Then somehow 7 or 8 years ago the ASP.Net team got obsessed with ramming "best practices" down our throat and everything's gone a bit downhill from there.
- taco_emoji 6y agoYou still are not forced to use it. The documentation will heavily emphasize it, but you can still manually new things up to your heart's content if you want.
- moron4hire 6y agoThis isn't even about C# at all, actually. This is about the web application framework ASP.NET Core. And they don't even have a point in this regard, because nothing is forcing you to use the DI. You wanna make a database connection with ADO.NET and a static connection string in your Controller? Go ahead. You can do that. It's no more effort than it ever was. You want to grow your app to run it in multiple environments and be confident you don't clobber your configuration during migrations? Use ASP.NET Core's DI. Every app framework has some "magic convention over configuration". I personally think ASP.NET Core's "magic" is a lot less pervasive than in, say Django, or RoR. When I was first learning ASP.NET Core--coming from WebForms--there was a learning curve. You don't just throw everything into a Web.config XML bag of doom anymore, with a single, static configuration reading tool that reads just that one file. That particular magic has changed. I mean, if you want to do that, you can, just read the file yourself. But it's not wired up by default anymore. And the new way of doing things was easily learned with a couple of afternoons of reading the documentation. Which you can do, because there is actually documentation, and a lot of it. I think part of the problem might be that people are used to other web app frameworks where the documentation is pretty lacking, so they don't even think to go looking for documentation on ASP.NET Core and think they can just jump in and figure it out. I don't think you could do that going from Django to RoR or vice versa, but people complain when they can't go from ASP.NET WebForms to ASP.NET Core without learning new ways of doing things. Don't like ASP.NET Core? You don't even have to use it. You can (rather easily) write your own web app framework. I've done it in the past, and there are FOSS projects for doing it (https://suave.io/ https://suave.io/, https://www.abp.io/ https://www.abp.io/, https://giraffe.wiki/ https://giraffe.wiki/, https://dotnetify.net/ https://dotnetify.net/, https://www.dotvvm.com/ https://www.dotvvm.com/, https://coalesce.intellitect.com/ https://coalesce.intellitect.com/).
- philliphaydon 6y agoYou don’t even need to use DI with .NET... everyone complaining of DI. Just don’t use it...
- ivanche 6y agoYou're 100% right. People that complain about DI don't understand 2 simple facts: 1) that graph of object creation is NOT equal to graph of object usage 2) if you don't use DI, problems won't automagically go away - code will _still_ have dependencies, just they'll be hidden and tightly coupled
- mrits 6y agoIt sounds like it's you that does not understand there are alternatives.
- zzbzq 6y agoI hope that's a typo because it's literally the opposite of what you're saying in #2. It is precisely when you use a DI container that the problem is hidden, whether or not it's solved. In most projects that use a DI container, the problem is usually not solved correctly, but the developers are oblivious and overconfident. They think, as you do, using a DI container means they did it right. False! The DI container only guarantees everything is hoisted up to the object constructor. This is NOT DEPENDENCY INVERSION. The objects can be in the constructor, but the dependency arrow can still point the wrong way. An obvious example of this I've seen a million times is an interface sitting right next to its only implementation. That's NOT Dependency Inversion. If you don't use a DI container, the problem also may or may not be solved, but it is never obscured, it is completely visible.
- ivanche 6y ago
- zzbzq 6y agoThis is the common misconception/defense of DI that drives me so cRaZy I've jumped to different languages. DI containers do NOTHING, NOTHING to make Dependency Inversion easier, nor does use of a DI container guarantee (as dozens of projects I've worked on prove) that DIP is correctly adhered to. DIP is achieved precisely when the components (be they packages, projects, classes, types) are organized with the low-level modules depending on the high-level modules rather than vice versa. In English, this usually means the I/O and any heavy framework code is kept out of the program logic. What DI does do is confuse this matter. Class relationships which are mere IMPLEMENTATION DETAILS of a module are elevated alongside the actual component architecture of the program. The object graph becomes obscured. Program execution order becomes nondeterministic. The callstack is completely ruined, undoing decades of enlightenment since Dijkstra's "GOTO statement considered harmful." And all my experience with the pattern proves, the DI container causes programmers to not even evaluate or understand whether their dependencies are even inverted, because all classes and their relationships just become one amorphous blob floating aimlessly inside the container.
- chunkyfunky 6y agoSome fair points but I would disagree on the fundamental definition of the DIP. In my book it absolutely does not mean that low-level modules depend on high-level modules. That's just high coupling turned upside down. You have to have shared abstractions as the "loose coupling" between modules and nothing more, to say you are adhering to the DIP. Simply, this means that no implementation module, high or low, depends on any other implementation module, ever. It only ever depends on abstractions which are shared between modules. I don't see how using a DI container can change the program execution order, unless one is misusing it terribly - after all, its sole purpose is to provide the correct concrete implementation of a dependency to an object at the time of its construction, the execution order from the perspective of the program is 100% preserved. Sure, maybe the container itself creates my graph in a non-deterministic way, but why would I care? If my program depends on this that's just bad design imo, no amount of libraries is going to save it :) And the object graph is not obscured, in fact it is clarified, because you look at a class constructor and immediately can see what it's invariants are! And I have yet to come across a DI library that wouldn't immediately halt and catch fire if you introduced a circular dependency chain, so it's literally not possible to have these amorphous blobs (great expression though!) in any proper DI container.
- starik36 6y agoOne of the issues with solving a problem via constructor injection is that anytime you need to access a new object in the class is you need to DI it. We'll now you have to go change a 100 unit tests that are failing because of this. I am not sure what is a better way to solve this problem, but the original OP is right - it's far too much ceremony.
- tored 6y agoYes, this can be a problem, that is why I have come to the conclusion that unit tests in larger projects (not libraries) is mostly a waste of time, because as soon you change the dependencies of a class you should rewrite your unit test for that class anyways because the class is not really the same class anymore (it works differently), you are just keeping the class name for convenience. And there is always a danger of changing a unit test, are you sure you are testing the same thing? I think it is ok to depend on a DI-container in your unit tests for dependencies you are not directly testing, instead of stubs or manually instantiating them, to avoid updating unrelated unit tests when some class changes it's dependency somewhere in your project. Instead I prefer system/integration tests where you test lets say a complete request from start to finish. Now your code base can change as much as you like, dependencies can be added or removed or classes or packages can be completely deleted, the tests stays the same. And now you are having tests that much closer matches reality instead of tons of mocks and stubs that can easily fool you to believing that they represent a good estimate of reality. By doing this way a constructor based DI does not become a nuisance instead it helps you to organize your project, as it should be. Using a DI container makes it natural to break down your classes and automatically share the same decencies between them. Counterargument to my argument is that if you don't use constructor based DI you can rewrite your class in anyway you like and the test stays the same, that is all true, however what DI gives you is the possibility to change the behavior of a class from the outside by injecting different dependencies, this makes your code better structured and easier to reuse. If you want to accomplish that in the non-DI case you have to go thru trouble of configurable proxy classes which just introduces one more layer of bureaucracy, the thing you wanted to avoid by not doing DI. My own criticism of DI containers is that they introduce magic to the project, personally I truly dislike code magic, however a DI container is nothing more than on the fly factory creator. In theory you could remove the DI container from a project by manually writing factories for each execution path, for me that becomes an acceptable level of magic as long as the DI container doesn't do lots of other things that factory couldn't solve. Edit: misspelled convenience
- didibus 6y ago> the reason for DI is to support the Dependency Inversion Principle : "High-level modules should not depend on low-level modules. Both should depend on abstractions (e.g. interfaces). You can still depend on abstractions without DI. Just use an interface or asbtract class in your code. DI only plays into how you acquire yourself an instance of the concrete class for that abstraction you depend on. So it can be given to you by your caller (DI). You can go fetch it somewhere (ServiceLocator). You can create it through a utility (Factory). Or you can create it yourself old fashion way with new. > But you don't have to use a library; many times I'm writing a simple-ish console app and just use good old "Poor Man's DI" where I manually construct my object graphs at startup I will support that. I'd like people to be precise in their criticism, do you find the DI pattern troublesome, or some particular DI framework?
- chunkyfunky 6y agoNeither, I'm a fully paid up and card-carrying DI-club member :) I was kind of making the same point as you did, that you don't need to use any kind of DI library to achieve the DIP, but that in something like ASP.Net it is there and simple to use.