From Dependency injection to dependency rejection - Mark Seemann

preview_player
Показать описание
In object-oriented design, dependency injection is a well-known design pattern, although it's a complicated solution to the problem of decoupling. Functional programming offers a simpler way.
This talk examines dependency injection in object-oriented design, and explains how it's not required (nor desired) in functional programming. You'll also learn how a proper functional design eliminates the need for mocks and stubs in unit testing, enabling you to entirely reject the notion of dependencies.

You don't need to know Haskell or F# to attend this session; relevant syntax will be explained just-in-time. Object-oriented examples will be in C#.

NDC Conferences
Рекомендации по теме
Комментарии
Автор

Great talk. He takes a simple scenario and shows how to do it in a more robust and testable way. I really appreciated it because I made the exact mistakes he illustrated just last week in some F# code. I'm going to go refactor it now! I think where this would really shine is in a larger project.

FastFSharp
Автор

Its a marvellous presentation, reason: it is hard to make a complex topic look so simple and understandable. Great work, Mark!

iamkaransethi
Автор

OOP is totally insane, I never understood it. Functional is much cleaner

Gabriel-mfwh
Автор

Good presentation. The flip however was absolutely the sort of cleverness that you don't want to introduce. Don't try to be clever if you don't have to. A problem anyways with all applicative functional languages is exactly this, that they put a very heavy emphasis on the order of arguments. In most cases, the order of arguments does not convey meaning...

paulfrischknecht
Автор

The more I watch his talks, the more I feel the urge to pick up F# or Haskell.

PaulSebastianM
Автор

A great talk! Of course, there are several necessary simplifications to make it easier to understand, but that doesn't take away.

A very minor nitpick: He mentions "non-strict" several times when in fact he means purely functional. Strictness has nothing to do with how he rejects the dependencies of his functions.

samfischi
Автор

Replace "Not Functional" with "Not Purely Functional". Other than that, it's a great talk. The pure functional implementation is simpler. I'm all for simplicity

odytrice
Автор

all functions in Haskell are pure. <- please note the dot at the end of the sentence. in my interpretation, they are not "declared to be impure", their side effects are contained in their signatures, making them not side effects, lets say.

bocckoka
Автор

Great talk, really great examples and easy to follow

mahoneyj
Автор

The interesting part is also how this final pure functional solution would look like in C#...

pavelagarkov
Автор

The talk is good but I find it a bit misleading. The last refactoring could have been done in C# as well, with somewhat uglier syntax but the structure would be the same. Now the logic was extracted to a pure function, which is great, but we still have to perform the side effects in the consumer of the function, where we have the same problems again - how do the dependencies arrive there? How would you wire this if it's called by a web framework? These are the questions we wonder about when using FP in "real world" projects, which unfortunately were not answered here.

Basically:
1) Bottom line of the talk: Move as much logic as possible to pure functions (makes sense using a functional or OO language).
2) It was interesting, but not strictly necessary to involve functional languages. The points could have been made without.
3) With this level of understanding, one could argue that all we need is OO with "helpers" containing static methods.

ivanschuetz
Автор

BTW the Haskell example in the end can be simplified way further. Usage of transformers (T) and liftIO, code feels like someone tries to write in imperative in purely functional Haskell, for that `do` notation is used in the language. If to show the end result of functional approach, it should be cleaner representation of the language.

Generally Haskell clean code would be:
Do everything in pure functions, and find a name for that whole, aka `procReservations`.

And then 2 IO functions are needed:
1. Some function based on `fmap` (traverse, sequence, foldr)
2. Some function that outputs result into IO (printStrLn, writeToDB, etc).

So the main function would be:
```
main :: IO ()
main =
writeToDB =<< traverse procReservations takeReservations
```

antonlatukha
Автор

So, in the end we basically removed crucial business rule "Sum of quantities of all reservations shouldn't exceed the capacity SIMULTANEOUSLY". This rule was clear in the original function, because we've clearly read reservations with the date of a new reservation and sum only their quantities.

In the "refactored" function there is no explanation of what the hell "reservations" are. Maybe it's all reservations in the world, maybe reservations from a neighbor restaurant since 1970, maybe just random reservations. No one knows because now it's not in the domain/business code.

To know this business rule you need to go to the bootstrap garbage code (...Composition) where it doesn't belong. This is a design smell

leonid
Автор

If omit all stuff related to pure/impure functions which is ok, we come to "static" DB call. Which is a tight coupling and it is a reason why using DI to avoid it. We could use static calls in the very beginning code with C# controller without FP approach. I am a little bit confused with such answer.

dmytrooleinichenko
Автор

With the functional refactoring, the implementation absolutely leaks... If it turns out you don't need the whole reservation list, you can throw away your argument list...

paulfrischknecht
Автор

What tool can be used to create such a presentation?

kovolexiy
Автор

Sorry, but in a Domain Driven Design in a object oriented language, you move the "Impurities" alos to the out sind. Your Domain Model ist perfecly testable. The Database, the UI are moved to the outside of it.

RealDieselMeister
Автор

a little bit weird talk to be honest. dependency injection is a partial application, but it is not functional because his types do not align? A notion of dependency rejection is nothing more than just a composition of effectful functions. Just curious what would be the name for Kleisli's or tagless final...

thatcat
Автор

I wish F# had syntax more like that:

let tryAccept = (
capacity: int,
readReservations: (DateTimeOffset) -> List<Reservation>,
createReservation: (Reservation) -> int,
reservation: Reservation
): ?int ->
{
let reservedSeats =
|> List.sumBy(x -> x.Quantity);
if (reservedSeats + reservation.Quantity <= capacity) {
return => r.isAccepted = true)); // not sure about "With" though
}
return null;
}

nescafezos
Автор

took 40 minutes to explain "Dependency Inversion" and "Functional Core Imperative Shell". watch these instead :

driziiD