4 ms·
I've been the elephant in the application architecture room for years. I was opposed to Dependency Injection for years for the primary reason of Complexity, Rea
by ChicagoDave 12y ago
I've been the elephant in the application architecture room for years. I was opposed to Dependency Injection for years for the primary reason of Complexity, Readability, and Teachability.
As a consultant, I have the opportunity to traverse many different development environments managed by diversely capable development teams. This experience has led me to the conclusion that there are many more entry-level, mid-level, and worker-bee developers than senior programmers and architects.
So when architects design new systems, you'll see a lot of highly complex, loosely-coupled code that's simply unreadable, and no amount of "knowledge-transfer" will bridge the gap with the wider audience of developers who are not as skilled.
You end up with those mid-level developers altering code in ways that break the original intent with the primary concern of being productive and completing tasks. I can't tell you how many times I've had to unravel shoddy code baked on top of or into an otherwise "normal" architecture.
This is why I eventually postulated that complexity trumps loosely-coupled architectures. Our "customer" as architects are those mid-level developers. We need to build frameworks and code bases that _anyone_ can maintain and enhance.
So let's change it to SOLID-C. SOLID principals minus the Complexity. If we can achieve that, everyone will succeed.
- tel 12y agoIt's funny to me from a mathematical POV. Dependency injection is clearly "just" function abstraction. It could not be simpler. Yet here we are belabored by whole frameworks to achieve it.
- platz 12y agoapparently LSP is just a contravariant functor https://apocalisp.wordpress.com/2010/10/06/liskov-substitution-principle-is-contravariance/ https://apocalisp.wordpress.com/2010/10/06/liskov-substituti... But I don't see how the relationship of contravariant functors to OO-style subclasses is as clear as the DI <-> function abstraction example (functions are just functions in OO or FP)
- tel 12y agoThe trick of that article is noting that Rúnar translates "S is a subtype of T" to "S => T", e.g. subtyping implies coercion. This is the first part of subtyping. The second part is that we must have that definitions of Q[S] for any Q must follow naturally from definitions of Q[T]. So let's say that Apple is a subtype of Fruit. That means that there exists a natural coercion function f : Apple => Fruit. It also means that if we have a predicate Delicious that we define for both Fruit and Apple then the answer Delicious[Apple] must be exactly Delicious[Fruit].comap(f). If they don't align then your coercion function is somehow wrong and not implementing subtyping properly.
- ChicagoDave 12y agoThere are ways to talk about it that help developers understand. Instead of focusing on the pattern overall, talk about the core dependency manager as often as possible. If a junior or mid-level developer gets it pounded into their heads that there's a magical piece of code doing some stuff they can't see, then they might just figure things out. But that's only a band-aid. It's my experience that they still won't truly understand why they can't just call A from B and they certainly don't understand how to get B in A through an injection.
- tel 12y agoIt always just feels like unnecessary terminology and technology. Here's the core pattern. function app(injected) { return injected.doSomething(); } function main() { var injectable = new Injectable(); var result = app(injectable); console.log(result); } Everything else is around obscuring that core pattern or making it "convenient" by providing some kind of naming abstraction. That at least makes a little bit of sense in Javascript, like above, since you need the stringy names to simulate types... but in any language with nominal typing you're just killing yourself with unnecessary complexity.
- guelo 12y agoI think what you describe only happens when there is not a good unit testing and code reviewing culture. When the mid-level developers are required to write unit tests they start to appreciate the loosely coupled architectures and Dependency Injection. This culture has to come from all the way to the top to avoid the "just get it done" pressure to cut corners, or give up and hire consultants.
- ChicagoDave 12y agoCulture doesn't always help. It's a step in the right direction, but even in the best development environments, some developers just don't improve their understanding of complex code. So then the company solves the problem by having a higher standard for hiring new developers. Eventually this becomes unsupportable because finding developers who can pick and use an in-house framework is costly and often impossible. Keep it simple overrides make it SOLID.