MacBook, defective by design banner

title:
Put the knife down and take a green herb, dude.


descrip:

One feller's views on the state of everyday computer science & its application (and now, OTHER STUFF) who isn't rich enough to shell out for www.myfreakinfirst-andlast-name.com

Using 89% of the same design the blog had in 2001.

FOR ENTERTAINMENT PURPOSES ONLY!!!
Back-up your data and, when you bike, always wear white.

As an Amazon Associate, I earn from qualifying purchases. Affiliate links in green.

x

MarkUpDown is the best Markdown editor for professionals on Windows 10.

It includes two-pane live preview, in-app uploads to imgur for image hosting, and MultiMarkdown table support.

Features you won't find anywhere else include...

You've wasted more than $15 of your time looking for a great Markdown editor.

Stop looking. MarkUpDown is the app you're looking for.

Learn more or head over to the 'Store now!

Thursday, August 26, 2021

From microsoft.com:

Notice that the controller class depends onย ProductRepository, and we are letting the controller create theย ProductRepositoryย instance. However, it's a bad idea to hard code the dependency in this way, for several reasons.

  • If you want to replaceย ProductRepositoryย with a different implementation, you also need to modify the controller class.
  • If theย ProductRepositoryย has dependencies, you must configure these inside the controller. For a large project with multiple controllers, your configuration code becomes scattered across your project.
  • It is hard to unit test, because the controller is hard-coded to query the database. For a unit test, you should use a mock or stub repository, which is not possible with the current design.
[emphasis mine - mfn]

You know, I've often wondered why dependency injection is so popular. It truly is just an inversion of control. The control concerns themselves don't change. It's another variation of "it's all zeroes and ones" where you rearrange some deck chairs to make things look new again.

That's not all bad. Cargo culting is much too popular a development mentality. At least rearranging deck chairs makes people look at their architecture closely with fresh eyes, though I fear the result is often trading one cult for another that has better marketing or community buy-in when the decision to join is made.

And I often get the answer highlighted in green when the discussion comes up: "But we have to have interfaces so that we can test it!" Um... not always true. There are other equivalent options. And because there are good ways to test that existed before DI, that's really not a good explaination for its adoption.

DI isn't free; it has a significant cost. It requires a good head rethread and a ton of boilerplate. Easier testing doesn't (again imo) explain its explosive popularity. (Though I'm very happy it's become the industry's party line to proclaim we value testing so much.)

But this line (highlighted in yellow earlier) from Microsoft actually explains the DI advantage:

If the ProductRepository has dependencies, you must configure these inside the controller. For a large project with multiple controllers, your configuration code becomes scattered across your project.

I really think that's it -- put another way, DI helps enable clean encapsulation that, in turn, fosters anonymous collaboration between coding teams.

If I have to learn how to spin up Foo and pass in all of its dependencies, I'm having to schlep around a lot of objects I may have never used before, much less contributed to. If I'm a single-person indie shop, the advantages of Dependency Injection are slim. But if I want to access Foo.NeatMethod without bothering to open the Foo box, well, I'd rather you put all of its dependencies in a row for me.

That's what DI does. It's a decent amount of extra work up front to save everyone down the line from being nickel and dimed -- or, when they're protected from having to learn a whole new domain, dollar and pounded.

This shows that DI's advantages clearly appeal to enterprises; DI is literally an enterprise architecture strategy, not to improve system load or because it's an inherently superior -- again, for a small team, the DI boilerplate might ultimately slow them down -- but because it can help enable a specific type of work, which is work by multiple teams and workers with very little knowledge transfer overlap.

Enterprise development is really a pretty fascinating study in cultural evolution.

Labels: ,


posted by ruffin at 8/26/2021 06:43:00 PM
Wednesday, April 27, 2016

A few quick additions to yesterday's Thoughts on Dependency Injection...

From the second:

This EF behaviour can result in subtle bugs as it is possible to be in a situation where queries may unexpectedly return stale or incorrect data. This wouldn't be possible with NHibernate's default behaviour. On the other side, it dramatically simplifies the issue of database transaction lifetime management.

That would have been good to know a few months ago. ;^)

That post's real take-home is this, however:

While it can be fine to re-use a DbContext across multiple business transactions, its lifetime should still be kept short.
...
Re-using the same DbContext instance for more than one business transaction can also lead to disastrous bugs where a service method accidently commits the changes from a previously failed business transaction.

I believe it also rightly argues against overusing lazy-loading. I tend to invoke queries fairly quickly, often forcing EF queries to call the database, with a ToList() call. As anyone who has read this blog for long would know, I'm painfully aware of pulling too much, and I don't put database logic in the business layer as a rule -- use the database engine; that's what it's there to do. Doing complicated logic in your "business" layer outside of your rdbms is kind of like writing your own JIT compiler for string manipulation in C. Insane. Use your tools; that's why you license them.

Know that an overuse of lazy-loading can get you into insanely inefficient queries. That is, just because you're "lazy loading" doesn't mean that you're using your rbdms correctly. You should have what amounts to a query builder inside of your business logic. Understand your use cases, write a view or sproc, and let your rdbms optimize. Don't get lazy with the justification that you're going to lazy load and that it's the same as writing SQL [in that it's work pushed to the dbms]. It's not the same.


Also keep in mind that Dependency Injection isn't nearly as fancy as it sounds. I think DI is usually couched in a very specific context that also involves an injection system, making the actual injection a somewhat obfuscated process, as I complained earlier. Getting familiar with all of that system's dependencies can be overwhelming at first glance, but, trust me, the concept itself is simple.

AndN .et MVC already has DI installed! Though I can never approve of sleeveless shirts for men in tutorial videos, this one is otherwise quite useful showing how quickly and easily DI can be in a .Net MVC project.

And even then, keep in mind how simple Inversion of Control really is. You probably do it a lot already to keep your code defensive and maintainable. You don't want your objects to depend on anything extraneous, so you'll often find yourself sending along something major to help your business objects get their work done. For instance, when you send along event handlers to widgets, that's a sort of IoC already! Told you you were familiar with it.

Labels: , , ,


posted by ruffin at 4/27/2016 08:00:00 AM
Tuesday, April 26, 2016

Edit (27 Apr 16): I should've probably led by saying that I am a big fan of Inversion of Control. That also means I'm a decent fan of DI. But I'm also a fan of not over-engineering, and somehow the "culture" around DI is one where over-engineering seems to be fairly commonplace (see the Joel on Software post I talk about, below -- he's not talking about DI specifically, but I think you can inject it (hahahahaha) into his generic critique in this case).

I love separation of concerns. What I don't love is hipster programming. If you're never going to reuse something, and it's significant to insane work to abstract it, don't. If abstraction was a bit more, knock yourself out, but, for instance, QueryOver in NHibernate when you're so deeply invested in SQL Server there's no great business case to leave, stop it. If your devs know SQL, stop it already.

A better solution to a potential change in stack is to become familiar with microservices, and use them appropriately. The only place I can think of where this sort of gross abstraction might make some sense is when your stack is just getting off of the ground. But then it's no big deal to rip it all up if your old, crufty C# guy leaves and is replaced by Node Grrrl.


Was doing some quick reading before talking about Dependency Injection tomorrow, and ran into a link from an SO question to a Joel on Software post I don't think I've run across before, Don't Let Architecture Astronauts Scare You:

These are the people I call Architecture Astronauts. It's very hard to get them to write code or design programs, because they won't stop thinking about Architecture. They're astronauts because they are above the oxygen level, I don't know how they're breathing. They tend to work for really big companies that can afford to have lots of unproductive people with really advanced degrees that don't contribute to the bottom line.

A recent example illustrates this. Your typical architecture astronaut will take a fact like "Napster is a peer-to-peer service for downloading music" and ignore everything but the architecture, thinking it's interesting because it's peer to peer, completely missing the point that it's interesting because you can type the name of a song and listen to it right away.

All they'll talk about is peer-to-peer this, that, and the other thing. Suddenly you have peer-to-peer conferences, peer-to-peer venture capital funds, and even peer-to-peer backlash with the imbecile business journalists dripping with glee as they copy each other's stories: "Peer To Peer: Dead!"

The Architecture Astronauts will say things like: "Can you imagine a program like Napster where you can download anything, not just songs?" Then they'll build applications like Groove that they think are more general than Napster, but which seem to have neglected that wee little feature that lets you type the name of a song and then listen to it -- the feature we wanted in the first place. Talk about missing the point. If Napster wasn't peer-to-peer but it did let you type the name of a song and then listen to it, it would have been just as popular. [emphasis mine, as usual -mfn]

Man, that's good.


Honestly, Wikipedia currently does an excellent job explaining the pros and cons of Dependency Injection. Here are a few from each...

[Some] Advantages [taken from Wikipedia's entry on DI]

  • Dependency injection allows a client to remove all knowledge of a concrete implementation that it needs to use. This helps isolate the client from the impact of design changes and defects. It promotes reusability, testability and maintainability.[20]
  • Dependency injection allows concurrent or independent development. Two developers can independently develop classes that use each other, while only needing to know the interface the classes will communicate through. Plugins are often developed by third party shops that never even talk to the developers who created the product that uses the plugins. [that's give or take what the last point said -mfn]
  • Dependency Injection decreases coupling between a class and its dependency.[21][22]

[Some] Disadvantages [taken from Wikipedia's entry on DI]

  • Dependency injection creates clients that demand configuration details be supplied by construction code. This can be onerous when obvious defaults are available.
  • Dependency injection can make code difficult to trace (read) because it separates behavior from construction. This means developers must refer to more files to follow how a system performs.
  • Dependency injection typically requires more upfront development effort since one can not summon into being something right when and where it is needed but must ask that it be injected and then ensure that it has been injected.
  • Dependency injection can cause an explosion of types, especially in languages that have explicit interface types, like Java and C# [23]
  • Dependency injection forces complexity to move out of classes and into the linkages between classes which might not always be desirable or easily managed.[24]
  • Ironically, dependency injection can encourage dependence on a dependency injection framework.[24][25][26]

Okay, I admit it. I kept all of the disadvantages up there.

I have worked with a system that overused DI before, and we had it so far upstream of our entities and controllers that you could work for months without ever coming into contact with the construction of a repository. That's not necessarily good. The "explosion of types" was definitely a problem, which means that over-abstraction was as well. "DI! DI! We can run the whole world with DI! DI venture capital funds!" /sigh

I like interfaces. And my C# rdbms finally talked its way to using DI. I'm (slowly; I haven't had much time to work with it right now, as I don't have a product for which it's an absolute requirement) factoring it into a portable library, and that means I have to inject a class in that writes to files. Not a big deal, and certainly The Right Way to do it.

What I dislike is when the DI is so abstracted that you're essentially cargo culting your way through repo instantiation, where you can create a repo from scratch and the inheritance hides that some base class is doing all the DI for you. That is, it's way too easy to end up in that last "con" from above: "Ironically, dependency injection can encourage dependence on a dependency injection framework."


Wikipedia has an interesting link to some Uncle Bob Consulting jive. I haven't closely read it all, but some of this rings true on first skim...

But Uncle Bob, youโ€™ve violated DIP by creating concrete instances!
...
I donโ€™t want a bunch of secret modules with bind calls scattered all around my code. I donโ€™t want to have to hunt for the particular bind call for the Zapple interface when Iโ€™m looking at some module. I want to know where all the instances are created.

But Uncle Bob, Youโ€™d know where they are because this is a Guice application.

I donโ€™t want to write a Guice application. Guice is a framework, and I donโ€™t want framework code smeared all through my application. I want to keep frameworks nicely decoupled and at arms-length from the main body of my code. I donโ€™t want to have @Inject attributes everywhere and bind calls hidden under rocks.
...
But Uncle Bob, That means I have to use new or factories, or pass globals around.

You think the injector is not a global? You think BillingService.class is not a global? There will always be globals to deal with. You canโ€™t write systems without them. You just need to manage them nicely.
...
I like this because now all the Guice is in one well understood place. I donโ€™t have Guice all over my application. Rather, Iโ€™ve got factories that contain the Guice. Guicey factories that keep the Guice from being smeared all through my application. Whatโ€™s more, if I wanted to replace Guice with some other DI framework, I know exactly what classes would need to change, and how to change them. So Iโ€™ve kept Guice uncoupled from my application.
...
But Uncle Bob, donโ€™t you think Dependency Injection is a good thing?

Of course I do. Dependency Injection is just a special case of Dependency Inversion. I think Dependency Inversion is so important that I want to invert the dependencies on Guice! I donโ€™t want lots of concrete Guice dependencies scattered through my code. [emph mine again -mfn]

That sounds about right, though it also seems to create a situation where you've got at least one of the "secret module" situations he was trying to avoid.

The takehome message when considering Dependency Injection? Never outsmart yourself. Or, as Zakas put it a while back, "don't be too clever".

Labels: , ,


posted by ruffin at 4/26/2016 01:33:00 PM

<< Older | Newer >>


Support freedom
All posts can be accessed here:


Just the last year o' posts:

URLs I want to remember:
* Atari 2600 programming on your Mac
* joel on software (tip pt)
* Professional links: resume, github, paltry StackOverflow * Regular Expression Introduction (copy)
* The hex editor whose name I forget
* JSONLint to pretty-ify JSON
* Using CommonDialog in VB 6 * Free zip utils
* git repo mapped drive setup * Regex Tester
* Read the bits about the zone * Find column in sql server db by name
* Giant ASCII Textifier in Stick Figures (in Ivrit) * Quick intro to Javascript
* Don't [over-]sweat "micro-optimization" * Parsing str's in VB6
* .ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture); (src) * Break on a Lenovo T430: Fn+Alt+B
email if ya gotta, RSS if ya wanna RSS, (?_?), ยข, & ? if you're keypadless


Powered by Blogger etree.org Curmudgeon Gamer badge
The postings on this site are [usually] my own and do not necessarily reflect the views of any employer, past or present, or other entity.