Live data from Hacker News

Your DI framework is killing your code

blog.activelylazy.co.uk

11–20 of 59 posts

Re: Your DI framework is killing your code

#11
post #8
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…

> Which changes Email::send signature, which leads to breaking API changes and extensive manual refactoring of the entire codebase. Only if you decide to change the signature, there are other ways to achieve the same result.

For example?

Re: Your DI framework is killing your code

#12
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…

TFA actually suggests having a "RenderAsEmail" method on the "Report" object! That right there should have been a hint that this line of reasoning is flawed. It would result in things like mixing presentation logic along with business logic in the same class. The author realizes this but does not seem to see it as a red flag.

Re: Your DI framework is killing your code

#13
post #5

I can't help but disagree with so many of the things he says. I won't even go into things like "Does your customer know what an OrderPriceStrategyFactory is for? No, then it’s not a real thing. Its some bullshit you made up.", but statements like "If we change how we contact customers then only the customer needs to change, not also the ReportBuilder" sound overly simplistic to me. The whole point would be that nothi…

Every business will have an order price factory in it. Prices aren't just picked by the roll of a dice!

If you're trying to model the inner workings of a business, you probably don't want to be starting with the customer's view of it...

Re: Your DI framework is killing your code

#14
post #8

Earlier quoted context omitted.

> Which changes Email::send signature, which leads to breaking API changes and extensive manual refactoring of the entire codebase. Only if you decide to change the signature, there are other ways to achieve the same result.

For example?

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

Re: Your DI framework is killing your code

#15
post #8

Earlier quoted context omitted.

> Which changes Email::send signature, which leads to breaking API changes and extensive manual refactoring of the entire codebase. Only if you decide to change the signature, there are other ways to achieve the same result.

For example?

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

Re: Your DI framework is killing your code

#16
post #8

Earlier quoted context omitted.

> Which changes Email::send signature, which leads to breaking API changes and extensive manual refactoring of the entire codebase. Only if you decide to change the signature, there are other ways to achieve the same result.

For example?

I suppose you could add more methods, e.g sendEmailViaMailGun. But that results in the invoker having to have if-else logic (itself a code smell) for selecting which method to call, which is bad for SRP. You could try to fix that by encapsulating that logic into an EmailRouterStrategy class, but that's just another dependency you have to inject, which is not ideal according to TFA.

Re: Your DI framework is killing your code

#17
"One of the properties of good OO design is that code that operates on data is located close to the data."

Says who?

I say the point of good OO design is to have very clear focused responsibilities for classes, very clear layers of abstraction, and concretely declared dependencies.

This way I know my business logic doesn't sprawl, is discoverable, can be replaced modularly, and tested extensively and throughly.

This author sounds like he has no idea what it takes to actually build a maintainable code base of domain-driven business logic.

The fact that he actually thinks "Order.SubmitForPicking(), UserAccount.UpdatePostalAddress(), and Basket.CalculatePriceIncludingTaxes()" are examples of good OO design is LAUGHABLE. This approach couples your data layer with your business logic, negates the ability to use mocks, and makes refactoring WAY harder than it needs to be.

Re: Your DI framework is killing your code

#18

"One of the properties of good OO design is that code that operates on data is located close to the data." Says who? I say the point of good OO design is to have very clear focused responsibilities for classes, very clear layers of abstraction, and concretely declared dependencies. This way I know my business logic doesn't sprawl, is discoverable, can be replaced modularly, and tested extensively and throughly. This…

Well, encapsulation was one of the three legs of the OO stool, especially at a time when languages like C/C++ offered no protection against reading/writing memory anywhere in a program's data or code segments. Encapsulation back then literally meant keeping the representation of the data close to the code, i.e. in the same class that implemented the interface on the data or a closely-related specialty class. So I would say the author is not incorrect in looking askance at "value objects" that are passed around, from that perspective.

On the other hand, I'm not sure the perspective is quite as important as it used to be. Modern dynamic languages make it harder to do bad things in memory, and passing value objects around is pretty much the arterial life force of the entire Internet. In any case one thing is sure: the more pieces of code that know the internal structure of a bit of data the more dependencies there are, and the harder the program is to work on. So to the extent you can have that knowledge in one place - the implementation of an interface - you're better off.

Perhaps more importantly, OO purism just seems a little anachronistic to me today. I think the key things that OO had to teach us have been mostly absorbed, and we've moved on. It's still there, but now it's part of the fabric of the art and not as obtrusive as it was in the 90's.

Re: Your DI framework is killing your code

#19
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)

Re: Your DI framework is killing your code

#20
post #14

Earlier quoted context omitted.

For example?

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

Sometimes you're sending via SMTP, sometimes via MailGun. If you don't remember to call GetMailPolicySingleton()->SetSendingMechanism() before every email.send() you end up using whatever policy was set last.
Post reply on HN