3 ms·
And this is how we end up with spaghetti code. Dependency management is a critical design decision. If you're polluting your global namespace with random classe
by _gabe_ 4y ago
And this is how we end up with spaghetti code. Dependency management is a critical design decision. If you're polluting your global namespace with random classes that get injected everywhere, you end up with a massive tree of intertwined dependencies. Not relying on a DI framework forces you to see that god-awful mess of spaghetti and do something about it or live with the consequences. If you're not thinking about how the major systems in your code interact and where the dependencies flow, then you are missing one of the most important design decisions.
- oezi 4y agoDesigning dependencies is critical but managing them is not. I often found that unless you have CI you don't have flexibility at all to make more than superficial design changes. People spend days passing instances down convoluted hierarchies because they don't have any other way. Much better to use DI and start designing who needs what as a direct dependency. A dependency injection framework also helps you encapsulate dependencies into contexts which can be used instead of global namespace. At least it should if your DI framework isn't just doing glorified singletons.
- _gabe_ 4y agoYou seem to be missing my point. Every time you inject a dependency, you are adding another node in the graph of object interactions in your codebase. What's more, DI frameworks only specify the lifetime of injected classes in the configuration file. So if there's an object with a scoped lifetime to the class it's being passed into, this isn't apparent without checking the configuration file. If you just look at it and see that it's added via a `new` in the constructor of the class, it's immediately apparent that the scope of that object is tied to the scope of the parent class. > People spend days passing instances down convoluted hierarchies because they don't have any other way. And this is a sign that either: you're architecture is flawed and this dependency is probably doing something more than intended, or it's actually a global dependency and probably doesn't even need to be an object. This can be solved by cleaning up your architecture, or making the "dependency" a stateless function. One immediate example I can think of is a logging interface. I don't get why programmers think you need a "logger" (probably because of the warped idea that everything in a program must be an object). Instead, you could just make a log function that's available in the global namespace with the appropriate thread safety. Some things are global in nature, and that's ok. Adding a convoluted DI framework to hide that fact is not ok. I like to know which interfaces are truly global instead of hunting through a codebase to find out what the mess is actually doing. > A dependency injection framework also helps you encapsulate dependencies into contexts which can be used instead of global namespace. At least it should if your DI framework isn't just doing glorified singletons. Sure, by hiding the lifetimes of all these objects in some massive configuration file. Now if I'm looking at class `Foo` all I see are a bunch of dependencies injected into the constructor. Any notion of which dependency is tied to the lifetime of `Foo` or global in nature or shared is now lost. Additionally, ditching the DI framework allows you to be more explicit about the lifetimes of all these constraints and formulate your code in a logical manner. One where dependency chains flow strictly one direction instead of the mess that a lot of code bases are left with. Lastly, you didn't really refute my claim. You even seem to agree with me that managing dependencies is important, otherwise you wouldn't be using a DI framework. My point is, this is an important design decision and should be treated as such. Using a magic DI framework allows you to hide all the messy chains that you're creating. If you ditch the framework and manually configure stuff, it forces you to really think about whether your architecture makes sense or not.
- hot_gril 4y agoWhen you cross service boundaries, those globals get reset. I don't know how to say this exactly, but sometimes you're writing crappy code in a crappy language (Java), and nothing matters more than doing it quickly and integration-testing it. Worst case your code becomes such spaghetti that someone rewrites it, which is fine cause it's self-contained.