Live data from Hacker News

Your DI framework is killing your code

blog.activelylazy.co.uk

31–40 of 59 posts

Re: Your DI framework is killing your code

#31
This talk might be of interest Stuart Sierra - Components Just Enough Structure https://www.youtube.com/watch?v=13cmHf_kt-Q - it is a tiny clojure framework but the ideas should be thought provoking, although granted with OO aligned type system not completely adaptable. In this example Customer could possibly just be a data-bucket/map/hashtable/Dictionary, Im not entirely sure how I'd handle reporting though as the example has put me back in OO mode, but a customer report (which knows how to organize data about a customer) shouldnt be part of customer entity (used loosely) in my opinion.

Re: Your DI framework is killing your code

#33
post #6

Yet another time it comes up. But now, after functional programming being commonplace, we at least know the answer to the "why" question. Consider the "classical OOP" method signature: email.send() vs "the anemic way" emailSender.send(message: Email) If there is only one way to send email (SMTP), things works fine. But let's assume we have to implement another way (e.g. Mailgun API). In the "anemic" case everything i…

The anemic way is modeled correctly anyway.

An email doesn't send itself nor does it interact with the transport. The transport (MUA/MTA for example) is responsible for delivering it via whatever method it happens to support. The container delivers the transport to the code. The consuming code doesn't care what the transport and method does, merely introduce the two and let them make sweet email love.

The article stinks of circa 2002 purist babble.

Re: Your DI framework is killing your code

#34
post #14

Earlier quoted context omitted.

"GetMailPolicySingleton()->SetSendingMechanism(Email::SMTP)" ;)

> Singleton What if two threads need to send mail via SMTP and Mailgun...

Singletons have nothing to do with reentrancy or lack thereof.

Re: Your DI framework is killing your code

#35
post #6

Yet another time it comes up. But now, after functional programming being commonplace, we at least know the answer to the "why" question. Consider the "classical OOP" method signature: email.send() vs "the anemic way" emailSender.send(message: Email) If there is only one way to send email (SMTP), things works fine. But let's assume we have to implement another way (e.g. Mailgun API). In the "anemic" case everything i…

Spot on. You replace your "anemic way" with first-class functions and namespacing, it ends up being the same thing. With currying, you do away with OO and parameter initialization altogether. @curry def SMTPSender(host, message): ... emailSender = SMTPSender(host='localhost') # partially evaluated fn with `host` fixed emailSender(message=message)

This is pretty much how we deal with this in a DI framework anyway. The constructor of the transport takes the host and the send method takes the message.

   emailSender = SMTPSender(host='localhost') # in container
   emailSender.send(message)                  # in implementation
The consumer of the SMTPSender only interacts with the send() method.

Re: Your DI framework is killing your code

#36

Earlier quoted context omitted.

For example?

Couldn't you just add a new SendMethod optional parameter defaulted to the method that was used prior to the refactoring? No breaking API changes, no extensive manual refactoring of the entire codebase, as far as I can tell. This is how I always did refactoring for years, it's immediately obvious to support developers wtf is going on, and there's no requirement to have any "complicated" architecture on every single o…

> Couldn't you just add a new SendMethod optional parameter

Adding an optional parameter to an already existing method is not always a backwards-compatible change. For example, in C# this will effectively change method signature and break API.

Re: Your DI framework is killing your code

#37
If I understand the argument correctly, this is a problem that some DI frameworks already address. And in others, there's an easy workaround.

Say you have a class CustomerHandler (stupid example, pseudo-C#) with a constructor like this:

     public CustomerHandler(Guid customerId, ILogger logger, ISomeExtraDependency whatever) { ... }
Now, let's say another class needs to create CustomerHandlers for specific customers, but doesn't want to care how they are created. Autofac, the .NET DI framework I'm most familiar with, let's you inject factory delegates:

    public RequestProcessor(Func
(Every type not mentioned in the Func is auto-injected.) This is very convenient because you can change the dependencies of CustomerHandler without messing up the rest of the code.

Of course, even in the absence of such an auto-factory feature, you can still create a dedicated CustomerHandlerFactory class and inject that. That's not quite as convenient, but it's still a lot better to have only one extra place that has to know CustomerHandler's dependencies than having them all over your codebase.

Re: Your DI framework is killing your code

#38
post #6

Yet another time it comes up. But now, after functional programming being commonplace, we at least know the answer to the "why" question. Consider the "classical OOP" method signature: email.send() vs "the anemic way" emailSender.send(message: Email) If there is only one way to send email (SMTP), things works fine. But let's assume we have to implement another way (e.g. Mailgun API). In the "anemic" case everything i…

Noun-verbers are also really helpful for testability, not just refactoring. Using a decent mocking framework (or just rolling some custom mocks) I can test almost all my business logic through unit tests, reducing the time that tests need to execute and increasing their reliability

Re: Your DI framework is killing your code

#39

Earlier quoted context omitted.

For example?

A 'sending mechanism' property on the email object that defaults to SMTP?

This. There may be other reasons to dislike the email.send() formulation, but it seems like the need to support other mail APIs could be handled relatively easily within this type of OO approach through the use of default values.

Re: Your DI framework is killing your code

#40
post #6

Yet another time it comes up. But now, after functional programming being commonplace, we at least know the answer to the "why" question. Consider the "classical OOP" method signature: email.send() vs "the anemic way" emailSender.send(message: Email) If there is only one way to send email (SMTP), things works fine. But let's assume we have to implement another way (e.g. Mailgun API). In the "anemic" case everything i…

Excellent summary. What an oop language like Java really needs these days are immutable value classes.
Post reply on HN