From dependency injection to dependency rejection Mark Seemann


































































![Pure try. Accept : : Int -> (Zoned. Time -> [Reservation]) -> (Reservation -> Pure try. Accept : : Int -> (Zoned. Time -> [Reservation]) -> (Reservation ->](https://slidetodoc.com/presentation_image_h2/659392114b9a925ddabb673839862c25/image-67.jpg)
![Zoned. Time -> IO [Reservation] Reservation -> IO Int le i try. Accept. Composition Zoned. Time -> IO [Reservation] Reservation -> IO Int le i try. Accept. Composition](https://slidetodoc.com/presentation_image_h2/659392114b9a925ddabb673839862c25/image-68.jpg)















































![try. Accept : : Int -> [Reservation] -> Reservation -> Maybe Reservation try. Accept try. Accept : : Int -> [Reservation] -> Reservation -> Maybe Reservation try. Accept](https://slidetodoc.com/presentation_image_h2/659392114b9a925ddabb673839862c25/image-116.jpg)



- Slides: 119
From dependency injection to dependency rejection Mark Seemann http: //blog. ploeh. dk @ploeh
@ploeh
Object-oriented Functional ? @ploeh
Functional un No tf Dependency injection ct io na l Object-oriented Partial application Composition @ploeh
Dependency injection is “really just a pretentious way to say ‘taking an argument’” - Rúnar Bjarnason (@runarorama) @ploeh
Example Restaurant Reservation @ploeh
Restaurant Reservation Make a reservation Date Name Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2 Name Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 20 Name Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 201 Name Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 Name Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 Name Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 -1 Name Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 -12 Name Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 -12 Name Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 -12 -2 Name Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 -12 -29 Name Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 -12 -29 Name M Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 -12 -29 Name Ma Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 -12 -29 Name Mar Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 -12 -29 Name Mark Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 -12 -29 Name Mark Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 -12 -29 Name Mark S Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 -12 -29 Name Mark Se Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 -12 -29 Name Mark See Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 -12 -29 Name Mark Seem Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 -12 -29 Name Mark Seema Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 -12 -29 Name Mark Seeman Email Quantity Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 -12 -29 Name Mark Seemann Email Quantity Submit @ploeh
Restaurant Reservation Make Date Name Email Quantity a reservation 2016 -12 -29 Mark Seemann ma Submit @ploeh
Restaurant Reservation Make Date Name Email Quantity a reservation 2016 -12 -29 Mark Seemann mar Submit @ploeh
Restaurant Reservation Make Date Name Email Quantity a reservation 2016 -12 -29 Mark Seemann mark Submit @ploeh
Restaurant Reservation Make Date Name Email Quantity a reservation 2016 -12 -29 Mark Seemann mark@ Submit @ploeh
Restaurant Reservation Make Date Name Email Quantity a reservation 2016 -12 -29 Mark Seemann mark@p Submit @ploeh
Restaurant Reservation Make Date Name Email Quantity a reservation 2016 -12 -29 Mark Seemann mark@pl Submit @ploeh
Restaurant Reservation Make Date Name Email Quantity a reservation 2016 -12 -29 Mark Seemann mark@plo Submit @ploeh
Restaurant Reservation Make Date Name Email Quantity a reservation 2016 -12 -29 Mark Seemann mark@ploe Submit @ploeh
Restaurant Reservation Make Date Name Email Quantity a reservation 2016 -12 -29 Mark Seemann mark@ploeh Submit @ploeh
Restaurant Reservation Make Date Name Email Quantity a reservation 2016 -12 -29 Mark Seemann mark@ploeh. Submit @ploeh
Restaurant Reservation Make Date Name Email Quantity a reservation 2016 -12 -29 Mark Seemann mark@ploeh. d Submit @ploeh
Restaurant Reservation Make Date Name Email Quantity a reservation 2016 -12 -29 Mark Seemann mark@ploeh. dk Submit @ploeh
Restaurant Reservation Make a reservation Date 2016 -12 -29 Name Mark Seemann JSON POST Email mark@ploeh. dk Quantity 4 Submit @ploeh
Restaurant Reservation Make Date Name Email Quantity a reservation 2016 -12 -29 Mark Seemann mark@ploeh. dk 4 Submit POST JSON @ploeh
Validate Get reserved seats from DB Decide Create response Save reservation @ploeh
Object-oriented Dependency injection @ploeh
public class Reservations. Controller : Api. Controller { public Reservations. Controller(IValidator validator, IMapper mapper, IMaître. D maître. D) { this. validator = validator; POST /reservations HTTP/1. 1 this. mapper = mapper; this. maître. D = maître. D; { } "date": "2016 -12 -08", "name": "Mark Seemann", public IHttp. Action. Result Post(Reservation. Request. Dto dto) "email": "mark@ploeh. dk", { "quantity": 4 var validation. Msg = validator. Validate(dto); } if (validation. Msg != "") return this. Bad. Request(validation. Msg); var r = mapper. Map(dto); var id = maître. D. Try. Accept(r); if (id == null) return this. Status. Code(Http. Status. Code. Forbidden); return this. Ok(); } } @ploeh
public class Maître. D : IMaître. D { public Maître. D(int capacity, IReservations. Repository public interface reservations. Repository) IMaître. D { { this. capacity = capacity; int? Try. Accept(Reservation reservation); this. reservations. Repository = reservations. Repository; } } public int? Try. Accept(Reservation reservation) { var reserved. Seats = reservations. Repository. Read. Reservations(reservation. Date). Sum(r => r. Quantity); if (reserved. Seats + reservation. Quantity <= capacity) { reservation. Is. Accepted = true; return reservations. Repository. Create(reservation); } return null; } } @ploeh
How do I do dependency injection in Scala? Comic courtesy of @jrecursive and @hmemcpy You don’t, because Scala is a functional language. @ploeh
Fine, it’s functional. How do I inject dependencies? Comic courtesy of @jrecursive and @hmemcpy You use a Free Monad, which allows you to build a Monad from any Functor. @ploeh
Did you just tell me to go fuck myself? Comic courtesy of @jrecursive and @hmemcpy I believe I did, Bob. @ploeh
Partial application An attempt at dependency injection with a functional language @ploeh
Repository // int -> (Date. Time. Offset -> Reservation list) -> (Reservation -> int) -> Reservation // -> int option let try. Accept capacity read. Reservations create. Reservation reservation = let reserved. Seats = read. Reservations reservation. Date |> List. sum. By (fun x -> x. Quantity) if reserved. Seats + reservation. Quantity <= capacity then create. Reservation { reservation with Is. Accepted = true } |> Some else None @ploeh
string -> Date. Time. Offset -> Reservation list // Reservation -> int option let try. Accept. Composition reservation = let read = DB. read. Reservations connection. String @ploeh
string -> Date. Time. Offset -> Reservation list // Reservation -> int option let try. Accept. Composition reservation = let read = DB. read. Reservations connection. String @ploeh
connection. String string -> Date. Time. Offset -> Reservation list // Reservation -> int option let try. Accept. Composition reservation = let read = DB. read. Reservations connection. String @ploeh
Date. Time. Offset -> Reservation list // Reservation -> int option let try. Accept. Composition reservation = let read = DB. read. Reservations connection. String @ploeh
Reservation -> int // Reservation -> int option let try. Accept. Composition reservation = let read = DB. read. Reservations connection. String let create = DB. create. Reservation connection. String try. Accept 10 read create reservation @ploeh
// Reservation -> int option let try. Accept. Composition reservation = let read = DB. read. Reservations connection. String let create = DB. create. Reservation connection. String try. Accept 10 read create reservation @ploeh
// Reservation -> int option let try. Accept. Composition = let read = DB. read. Reservations connection. String let create = DB. create. Reservation connection. String try. Accept 10 read create @ploeh
// Reservation -> int option let try. Accept. Composition = let read = DB. read. Reservations connection. String let create = DB. create. Reservation connection. String try. Accept 10 read create @ploeh
IL @ploeh
internal class try. Accept. Composition@17 : FSharp. Func<Reservation, FSharp. Option<int>> { public int capacity; public FSharp. Func<Reservation, int> create. Reservation; public FSharp. Func<Date. Time. Offset, FSharp. List<Reservation>> read. Reservations; internal try. Accept. Composition@17( int capacity, FSharp. Func<Date. Time. Offset, FSharp. List<Reservation>> read. Reservations, FSharp. Func<Reservation, int> create. Reservation) { this. capacity = capacity; this. read. Reservations = read. Reservations; this. create. Reservation = create. Reservation; } public override FSharp. Option<int> Invoke(Reservation reservation) { return Maître. D. try. Accept<int>( this. capacity, this. read. Reservations, this. create. Reservation, reservation); } } @ploeh
Is it Functional? Partial application Dependency injection @ploeh
Same return value for same input Pure function No sideeffects @ploeh
Impure function Pure function @ploeh
Sanity check @ploeh
Pure try. Accept : : Int -> (Zoned. Time -> [Reservation]) -> (Reservation -> Int) -> Reservation -> Maybe Int try. Accept capacity read. Reservations create. Reservation reservation = let reserved. Seats = sum $ map quantity $ read. Reservations $ date reservation in if reserved. Seats + quantity reservation <= capacity then Just $ create. Reservation $ reservation { is. Accepted = True } else Nothing @ploeh
Zoned. Time -> IO [Reservation] Reservation -> IO Int le i try. Accept. Composition : : Reservation p -> IO (Maybe Int) try. Accept. Composition reservation m = o connection. String let read = DB. read. Reservations c create = DB. create. Reservation connection. String t ’ in try. Accept 10 readn create reservation s e o D Zoned. Time -> [Reservation] Reservation -> Int @ploeh
Not Functional Partial application Dependency injection @ploeh
@ploeh
Dependency injection makes everything impure @ploeh
Dependency Rejection @ploeh
Direct input Indirect input Unit Direct output Dependencies Indirect output @ploeh
Direct input Indirect input Unit Dependencies Direct output @ploeh
// int -> (Date. Time. Offset -> Reservation list) -> (Reservation -> int) -> Reservation // -> int option let try. Accept capacity read. Reservations create. Reservation reservation = @ploeh
// int -> (Date. Time. Offset -> Reservation list) -> // -> Reservation option let try. Accept capacity read. Reservations Reservation reservation = @ploeh
// int -> (Date. Time. Offset -> Reservation list) -> Reservation // -> Reservation option let try. Accept capacity read. Reservations reservation = @ploeh
// int -> (Date. Time. Offset -> Reservation list) -> Reservation option let try. Accept capacity read. Reservations reservation = @ploeh
// int -> (Date. Time. Offset -> Reservation list) -> Reservation option let try. Accept capacity read. Reservations reservation = let reserved. Seats = read. Reservations reservation. Date |> List. sum. By (fun x -> x. Quantity) if reserved. Seats + reservation. Quantity <= capacity then { reservation with Is. Accepted = true } |> Some else None @ploeh
// Reservation -> int option let try. Accept. Composition reservation = match try. Accept 10 (DB. read. Reservations connection. String) reservation with | None -> None | Some r -> (DB. create. Reservation connection. String) r |> Some @ploeh
// Reservation -> int option let try. Accept. Composition reservation = try. Accept 10 (DB. read. Reservations connection. String) reservation |> Option. map (fun r -> DB. create. Reservation connection. String r) @ploeh
// Reservation -> int option let try. Accept. Composition reservation = try. Accept 10 (DB. read. Reservations connection. String) reservation |> Option. map ( DB. create. Reservation connection. String ) @ploeh
// Reservation -> int option let try. Accept. Composition reservation = try. Accept 10 (DB. read. Reservations connection. String) reservation |> Option. map (DB. create. Reservation connection. String) @ploeh
// Reservation -> int option let try. Accept. Composition reservation = reservation |> try. Accept 10 (DB. read. Reservations connection. String) |> Option. map (DB. create. Reservation connection. String) @ploeh
Direct input Indirect input Unit Dependencies Direct output @ploeh
Direct input Unit Dependencies Direct output @ploeh
// int -> (Date. Time. Offset -> Reservation list) -> Reservation option let try. Accept capacity read. Reservations reservation = @ploeh
// int -> ( Reservation list) -> Reservation option let try. Accept capacity read. Reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity read. Reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity rad. Reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity rd. Reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity r. Reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity reservations reservation = @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity reservations reservation = let reserved. Seats = reservations |> List. sum. By (fun x -> x. Quantity) if reserved. Seats + reservation. Quantity <= capacity then { reservation with Is. Accepted = true } |> Some else None @ploeh
// int -> Reservation list -> Reservation option let try. Accept capacity reservations reservation = let reserved. Seats = reservations |> List. sum. By (fun x -> x. Quantity) if reserved. Seats + reservation. Quantity <= capacity then { reservation with Is. Accepted = true } |> Some else None @ploeh
// ('a -> 'b -> 'c) -> 'b -> 'a -> 'c let flip f x y = f y x // Reservation -> int option let try. Accept. Composition reservation = reservation. Date |> DB. read. Reservations connection. String |> fun reservations -> try. Accept 10 reservations reservation |> Option. map (DB. create. Reservation connection. String) @ploeh
// ('a -> 'b -> 'c) -> 'b -> 'a -> 'c let flip f x y = f y x // Reservation -> int option let try. Accept. Composition reservation = reservation. Date |> DB. read. Reservations connection. String |> fun reservations -> flip (try. Accept 10) reservations |> Option. map (DB. create. Reservation connection. String) @ploeh
// ('a -> 'b -> 'c) -> 'b -> 'a -> 'c let flip f x y = f y x // Reservation -> int option let try. Accept. Composition reservation = reservation. Date |> DB. read. Reservations connection. String |> -> flip (try. Accept 10) reservation |> Option. map (DB. create. Reservation connection. String) @ploeh
// ('a -> 'b -> 'c) -> 'b -> 'a -> 'c let flip f x y = f y x // Reservation -> int option let try. Accept. Composition reservation = reservation. Date |> DB. read. Reservations connection. String |> flip (try. Accept 10) reservation |> Option. map (DB. create. Reservation connection. String) @ploeh
Sanity check @ploeh
try. Accept : : Int -> [Reservation] -> Reservation -> Maybe Reservation try. Accept capacity reservations reservation = let reserved. Seats = sum $ map quantity reservations in if reserved. Seats + quantity reservation <= capacity then Just $ reservation { is. Accepted = True } else Nothing @ploeh
try. Accept. Composition : : Reservation -> IO (Maybe Int) try. Accept. Composition reservation = run. Maybe. T $ lift. IO (DB. read. Reservations connection. String $ date reservation) >>= Maybe. T. return. flip (try. Accept 10) reservation >>= lift. IO. DB. create. Reservation connection. String s le m o C i p @ploeh
Functional un No tf Dependency injection ct io na l Object-oriented Partial application Composition @ploeh
Mark Seemann http: //blog. ploeh. dk http: //bit. ly/ploehralsight @ploeh























































































































