From Dependency injection to dependency rejection - Mark Seemann

  Рет қаралды 51,625

NDC Conferences

NDC Conferences

Күн бұрын

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
ndc-london.com
ndcconferences...

Пікірлер: 58
@iamkaransethi
@iamkaransethi Жыл бұрын
Its a marvellous presentation, reason: it is hard to make a complex topic look so simple and understandable. Great work, Mark!
@FastFSharp
@FastFSharp 7 жыл бұрын
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.
@PaulSebastianM
@PaulSebastianM 2 жыл бұрын
The more I watch his talks, the more I feel the urge to pick up F# or Haskell.
@40oz82
@40oz82 Жыл бұрын
Have you?
@PaulSebastianM
@PaulSebastianM Жыл бұрын
@@40oz82 playing around with F# and really loving the ideas behind it and the teachings of Scott Wlaschin on his fsharpforfunandprofit site. Can't belive more LOB aren't written in it. Especially love the idea of making error states unrepresentable!
@Brian-ro7st
@Brian-ro7st 10 ай бұрын
Clojure
@Gabriel-mf7wh
@Gabriel-mf7wh 4 жыл бұрын
OOP is totally insane, I never understood it. Functional is much cleaner
@mateusoliveira2776
@mateusoliveira2776 3 жыл бұрын
Every time you want to learn a new language in OOP you have to understand what they mean by sealed, open, closed, static, object, like... Jesus Christ, I just need my functions and lambdas lmao
@paulfrischknecht3999
@paulfrischknecht3999 3 жыл бұрын
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...
@GulshanurRahman
@GulshanurRahman 3 жыл бұрын
Although subjective, I think, lighter/cheaper or more readily available arguments should go first in the order.
@KyleLanmon
@KyleLanmon 6 ай бұрын
@@GulshanurRahmanit's interesting because my inclination is the opposite. The more essential a parameter is, the closer to the front of the argument list it goes
@mahoneyj2
@mahoneyj2 Жыл бұрын
Great talk, really great examples and easy to follow
@samfischi
@samfischi 6 жыл бұрын
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.
@odytrice
@odytrice 7 жыл бұрын
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
@bocckoka
@bocckoka 6 жыл бұрын
all functions in Haskell are pure.
@ivanschuetz9458
@ivanschuetz9458 5 жыл бұрын
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.
@swarupmahapatra1
@swarupmahapatra1 Жыл бұрын
The speaker has basically described the domain layer of DDD. Domain Layer is IO unaware and very easy to test.
@pavelagarkov2634
@pavelagarkov2634 7 жыл бұрын
The interesting part is also how this final pure functional solution would look like in C#...
@slowpnir
@slowpnir 6 жыл бұрын
Liek a piece of you know what.
@ArchiFloyd
@ArchiFloyd 5 жыл бұрын
You'll find a high level view of that in this: kzbin.info/www/bejne/fGrFq6Glo7CWbJY
@antonlatukha5845
@antonlatukha5845 Жыл бұрын
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 =
@dmytrooleinichenko9865
@dmytrooleinichenko9865 2 жыл бұрын
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.
@user-dc9zo7ek5j
@user-dc9zo7ek5j 2 жыл бұрын
DB.DoSomething is used because functions are the norm in fsharp, in OOP you would still have a class with dependencies. The topic was not about whether or not you can use static calls. The presented logic can be done in any language. The idea is, that you use concrete implementations where you need them, in C# and JAVA we're used to declaring dependencies inside the classes and have the logic mixed with the depencies, which produce side effects. This makes each unit harder to test, because you have to instantiate the class in order to test it, but you must also mock all the dependencies, and for each test, you must know which dependency to seed with data in order to reproduce the case you're trying to test. The solution that he presented is just to have 2 functions: 1 with concrete implementation, 1 with dependencies which glues the implementation with database/filesystem/responses. You can test both separately, but you must understand that what you want to do is in function 1, and what you need to do in order to compile is in function 2. The example he gave is pretty clear, we do not expect in "ReserveTable" to perform a retrieval of list of reservations, nor to see if any waiter is available, we just wanted the reservation to be created. By breaking all of the requirements into pure functions, GetIsTableReservedForToday, GetIsWaiterAvailable, CreateReservation..., the only variable that's left is the DB, which we don't need to test anyways, because we can test each one of those functions independently, and they're much simpler to reason, to the point where we don't even need to test them. In short, structure your code in such a way, that the "business" logic is pure, the way you feed the logic can be impure but don't mix them. This will result in clarity and reduced logical errors.
@victornoagbodji
@victornoagbodji 7 жыл бұрын
very interesting talk. thanks!
@paulfrischknecht3999
@paulfrischknecht3999 3 жыл бұрын
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...
2 жыл бұрын
F# has sequences, which are lazily evaluated lists (pretty similar to IEnumerable).
@leonid4416
@leonid4416 11 ай бұрын
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
@alexandrekfoury9289
@alexandrekfoury9289 2 жыл бұрын
Great blog
@KarenTazayan
@KarenTazayan 5 жыл бұрын
Great talk!
@jmazin1001
@jmazin1001 7 жыл бұрын
thx for a great talk!
@mateberes
@mateberes 7 жыл бұрын
brilliant, thank you!
@kovolexiy
@kovolexiy Жыл бұрын
What tool can be used to create such a presentation?
@RealDieselMeister
@RealDieselMeister 7 жыл бұрын
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.
@DenisG631
@DenisG631 5 жыл бұрын
So you wanna say that his OOP example is not done according to DDD rules? Wouldn't you just inject the DB or not DB related code as a repository? This way it is still abstracted
@raphaelschmitz4416
@raphaelschmitz4416 4 жыл бұрын
As far as I understand it, the difference is that in OOP, you have to inject mocks, while in FP you already have only the part you want to test.
@RealDieselMeister
@RealDieselMeister 4 жыл бұрын
@@raphaelschmitz4416 Hi. The Time I wrote my comment (3 years ago), I wasn't aware of FP and it'S principals at all. Now that I am in F# I understand this video and content much more. ;) I know what a monad is. And I love FP so much ...
@swarupmahapatra1
@swarupmahapatra1 Жыл бұрын
The speaker basically extracted the Domain layer equivalent of DDD. Nothing big deal
@thatcat3132
@thatcat3132 6 жыл бұрын
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...
@АнимусАнанимус
@АнимусАнанимус 4 жыл бұрын
Injection of impure dependencies as i see can't be used in haskell, only in f#. So if it would be real a haskell with it type strictness, i think it would be functional. But i dont see any way to do it in haskell (fix me if i wrong and show me how), because you cant apply something (a -> IO b) to function (a -> (a -> b) -> b) what is a pure function. I really tried to do this, but i didnt find any allowed monadic functions (bind, map, apply, pure, etc) combinations to get a type (a -> (a -> b) -> b) -> (a -> (a -> IO b) -> IO b)
@GeorgeTsiros
@GeorgeTsiros 3 жыл бұрын
8:25 there shouldn't be a need for a 'validator'. If the validation fails, it means the object is invalid. Which means it shouldn't exist, it shouldn't even have been created. Which means its _constructor_ , or whoever _constructed_ it, should have thrown an exception. What is shown here is _bad_ .
@nescafezos4265
@nescafezos4265 3 жыл бұрын
I wish F# had syntax more like that: let tryAccept = ( capacity: int, readReservations: (DateTimeOffset) -> List, createReservation: (Reservation) -> int, reservation: Reservation ): ?int -> { let reservedSeats = readReservations(reservation.Date) |> List.sumBy(x -> x.Quantity); if (reservedSeats + reservation.Quantity r.isAccepted = true)); // not sure about "With" though } return null; }
@malvoliosf
@malvoliosf 4 жыл бұрын
I gotta say: I disagree with almost everything in this video. First, if passing a potentially impure function into an otherwise-pure function makes the latter function impure, then map() is impure, filter() is impure. Second, what did the purification process outlined accomplish? I have moved largely trivial business logical into a pure function, but the code that I actually need, the code that gets and sets the data, is not only impure, but is strongly coupled to its dependencies.
2 жыл бұрын
Why? You are not forced to pass an impure function to map() and filter(). What you achieve with composition is getting all the dependencies, AKA impure code, together. You have to think of the composition function in the video (which is a simple example) as the equivalent of the dependency resolution in OO (the place where you couple your program with the all the specific dependencies you want, usually by using a DI framework to create a service collection).
@kenichimori8533
@kenichimori8533 7 жыл бұрын
Equal Difference.
@driziiD
@driziiD 4 жыл бұрын
took 40 minutes to explain "Dependency Inversion" and "Functional Core Imperative Shell". watch these instead : www.destroyallsoftware.com/talks/boundaries www.destroyallsoftware.com/screencasts/catalog/functional-core-imperative-shell
@kenichimori8533
@kenichimori8533 7 жыл бұрын
Compherence.
@ComprehendRealityNow
@ComprehendRealityNow 7 жыл бұрын
interesting? brilliant? great talk? You guys are crazy, he hasn't done anything except move the impure dependency injection up a layer. absolutely nothing has changed after 59 minutes of this. The new impure injection is the two DB function calls. He doesnt even mention how they get accessed. Obviously because it would show you the entire last hour of your life was wasted. There were two impure injections at the start of the example and two impure injections at the end of the example. Moving them one function to the other didn't change anything. What's worse is he's leaked the implementation details out a layer, the caller must now know we're using a DB.
@odytrice
@odytrice 7 жыл бұрын
Nope the caller now decides where to get the data. The DB is an implementation detail. I could come from a file or whatever IO device you want. Like he said, the goal is to move the impurities to the edge of your system. Impurities are what make testing difficult because you'd have to mock/stub them. So yes, It's a brilliant talk
@arnoldhau1
@arnoldhau1 7 жыл бұрын
So your dislike that there where no wonders performed. Oh surprise. And else its very well explained and to push the dependencies to the boundaries is quite a logical solution if you want to use functional programming, quite to the opposite of how you do it in OO. Both are valid, depends on what you want. So what would you do instead?
@AlexFeature
@AlexFeature 7 жыл бұрын
Agreed. Total garbage.
@odytrice
@odytrice 7 жыл бұрын
+Alexander Pavlovsky Listen to 54:50 again The idea is to isolate as much impure operations as possible from the Pure parts. This is really useful because the pure parts are easy to test without needing mocking/stubbing and the internal logic becomes simple and easy to reason about. That's how its done in Haskell
@ArwinvanArum
@ArwinvanArum 7 жыл бұрын
I agree that the talk is useful. Dependency injection still allows you to do things that you shouldn't want to do. I've seen some really weird stuff that it was being abused for, and refactored a fair bit of code in my time that brings the DI to the top level class only and passes on relevant bits from there to the proper classes, much like the io - pure - io pattern here. It's still not entirely clear to me how to cleanly do stuff like inject a centrally chosen implementation of ILogger properly into a large number of classes. Perhaps it's just a matter of writing your own local/static class that is used at the top level of a main/factory class to pass on the right interface implementations to the modules?
@expatca4444
@expatca4444 3 жыл бұрын
di sucks
@slowpnir
@slowpnir 6 жыл бұрын
54:40 GOD WHY Too bad we can't disallow him writing code in Haskell. Why can't you hide `lift`s? Is the `do`-syntax disallowed by your religion? Are you writing a piece of maintainable code or participating in obfuscation contest? And... `MaybeT`? Seriously? Good luck compiling package exporting this, lad, if your dependencies aren't covered in dust. He should pull out some free monads instead, this talk would be at least interesting in that case.
@SodAlmighty
@SodAlmighty 2 жыл бұрын
This guy has an even more condescending voice than I do, and that's saying something. Also, he talks too fast, and on a monotone. He's hard to follow.
Functional architecture - The pits of success - Mark Seemann
1:00:10
NDC Conferences
Рет қаралды 144 М.
Dependency Injection revisited - Mark Seemann
56:02
NDC Conferences
Рет қаралды 8 М.
VIP ACCESS
00:47
Natan por Aí
Рет қаралды 30 МЛН
Don’t Choose The Wrong Box 😱
00:41
Topper Guild
Рет қаралды 62 МЛН
BAYGUYSTAN | 1 СЕРИЯ | bayGUYS
36:55
bayGUYS
Рет қаралды 1,9 МЛН
Dependency Injection | Prime Reacts
28:34
ThePrimeTime
Рет қаралды 372 М.
Get value out of your monad - Mark Seemann
58:59
NDC Conferences
Рет қаралды 25 М.
Thirteen ways of looking at a Turtle -  Scott Wlaschin
1:04:42
NDC Conferences
Рет қаралды 34 М.
Dependency Injection, The Best Pattern
13:16
CodeAesthetic
Рет қаралды 920 М.
Domain Modeling Made Functional - Scott Wlaschin
51:35
NDC Conferences
Рет қаралды 29 М.
F# for C# programmers - Scott Wlaschin
1:00:01
NDC Conferences
Рет қаралды 70 М.
Demystifying Dependency Injection Containers by Kai Sassnowski
26:46
What is Dependency Injection?
6:48
Scott Bailey
Рет қаралды 120 М.
Why Isn't Functional Programming the Norm? - Richard Feldman
46:09
VIP ACCESS
00:47
Natan por Aí
Рет қаралды 30 МЛН