SlideShare a Scribd company logo
1 of 119
From dependency injection
to dependency rejection
Mark Seemann
http://blog.ploeh.dk
@ploeh
@ploeh
Object-oriented Functional
@ploeh
Object-oriented Functional
Dependency injection 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 a reservation
Date 2016-12-29
Name Mark Seemann
Email ma
Quantity
Submit
@ploeh
Restaurant Reservation
Make a reservation
Date 2016-12-29
Name Mark Seemann
Email mar
Quantity
Submit
@ploeh
Restaurant Reservation
Make a reservation
Date 2016-12-29
Name Mark Seemann
Email mark
Quantity
Submit
@ploeh
Restaurant Reservation
Make a reservation
Date 2016-12-29
Name Mark Seemann
Email mark@
Quantity
Submit
@ploeh
Restaurant Reservation
Make a reservation
Date 2016-12-29
Name Mark Seemann
Email mark@p
Quantity
Submit
@ploeh
Restaurant Reservation
Make a reservation
Date 2016-12-29
Name Mark Seemann
Email mark@pl
Quantity
Submit
@ploeh
Restaurant Reservation
Make a reservation
Date 2016-12-29
Name Mark Seemann
Email mark@plo
Quantity
Submit
@ploeh
Restaurant Reservation
Make a reservation
Date 2016-12-29
Name Mark Seemann
Email mark@ploe
Quantity
Submit
@ploeh
Restaurant Reservation
Make a reservation
Date 2016-12-29
Name Mark Seemann
Email mark@ploeh
Quantity
Submit
@ploeh
Restaurant Reservation
Make a reservation
Date 2016-12-29
Name Mark Seemann
Email mark@ploeh.
Quantity
Submit
@ploeh
Restaurant Reservation
Make a reservation
Date 2016-12-29
Name Mark Seemann
Email mark@ploeh.d
Quantity
Submit
@ploeh
Restaurant Reservation
Make a reservation
Date 2016-12-29
Name Mark Seemann
Email mark@ploeh.dk
Quantity
Submit
@ploeh
Restaurant Reservation
POST JSON
@ploeh
Make a reservation
Date 2016-12-29
Name Mark Seemann
Email mark@ploeh.dk
Quantity 4
Submit
Restaurant Reservation
POST JSON
@ploeh
Make a reservation
Date 2016-12-29
Name Mark Seemann
Email mark@ploeh.dk
Quantity 4
Submit
Validate
Get reserved
seats from
DB
Decide
Save
reservation
Create
response
@ploeh
Object-oriented
Dependency injection
@ploeh
public class ReservationsController : ApiController
{
public ReservationsController(IValidator validator, IMapper mapper, IMaîtreD maîtreD)
{
this.validator = validator;
this.mapper = mapper;
this.maîtreD = maîtreD;
}
public IHttpActionResult Post(ReservationRequestDto dto)
{
var validationMsg = validator.Validate(dto);
if (validationMsg != "")
return this.BadRequest(validationMsg);
var r = mapper.Map(dto);
var id = maîtreD.TryAccept(r);
if (id == null)
return this.StatusCode(HttpStatusCode.Forbidden);
return this.Ok();
}
}
POST /reservations HTTP/1.1
{
"date": "2016-12-08",
"name": "Mark Seemann",
"email": "mark@ploeh.dk",
"quantity": 4
}
@ploeh
public class MaîtreD : IMaîtreD
{
public MaîtreD(int capacity, IReservationsRepository reservationsRepository)
{
this.capacity = capacity;
this.reservationsRepository = reservationsRepository;
}
public int? TryAccept(Reservation reservation)
{
var reservedSeats = reservationsRepository
.ReadReservations(reservation.Date)
.Sum(r => r.Quantity);
if (reservedSeats + reservation.Quantity <= capacity)
{
reservation.IsAccepted = true;
return reservationsRepository.Create(reservation);
}
return null;
}
}
@ploeh
public interface IMaîtreD
{
int? TryAccept(Reservation reservation);
}
How do I do
dependency
injection in
Scala?
You don’t,
because Scala
is a functional
language.
Comic courtesy of
@jrecursive and @hmemcpy @ploeh
Fine, it’s functional.
How do I inject
dependencies?
You use a Free Monad,
which allows you to
build a Monad from
any Functor.
Comic courtesy of
@jrecursive and @hmemcpy @ploeh
Did you just
tell me to go
fuck myself?
I believe I
did, Bob.
Comic courtesy of
@jrecursive and @hmemcpy @ploeh
Partial application
An attempt at dependency injection with a functional language
@ploeh
// int -> (DateTimeOffset -> Reservation list) -> (Reservation -> int) -> Reservation
// -> int option
let tryAccept capacity readReservations createReservation reservation =
let reservedSeats =
readReservations reservation.Date |> List.sumBy (fun x -> x.Quantity)
if reservedSeats + reservation.Quantity <= capacity
then createReservation { reservation with IsAccepted = true } |> Some
else None
@ploeh
Repository
// Reservation -> int option
let tryAcceptComposition reservation =
let read = DB.readReservations connectionString
@ploeh
string -> DateTimeOffset -> Reservation list
// Reservation -> int option
let tryAcceptComposition reservation =
let read = DB.readReservations connectionString
@ploeh
string -> DateTimeOffset -> Reservation list
connectionString
// Reservation -> int option
let tryAcceptComposition reservation =
let read = DB.readReservations connectionString
@ploeh
string -> DateTimeOffset -> Reservation listconnectionString
// Reservation -> int option
let tryAcceptComposition reservation =
let read = DB.readReservations connectionString
@ploeh
DateTimeOffset -> Reservation list
// Reservation -> int option
let tryAcceptComposition reservation =
let read = DB.readReservations connectionString
let create = DB.createReservation connectionString
tryAccept 10 read create reservation
@ploeh
Reservation -> int
// Reservation -> int option
let tryAcceptComposition reservation =
let read = DB.readReservations connectionString
let create = DB.createReservation connectionString
tryAccept 10 read create reservation
@ploeh
// Reservation -> int option
let tryAcceptComposition =
let read = DB.readReservations connectionString
let create = DB.createReservation connectionString
tryAccept 10 read create
@ploeh
// Reservation -> int option
let tryAcceptComposition =
let read = DB.readReservations connectionString
let create = DB.createReservation connectionString
tryAccept 10 read create
@ploeh
IL
@ploeh
internal class tryAcceptComposition@17 : FSharpFunc<Reservation, FSharpOption<int>>
{
public int capacity;
public FSharpFunc<Reservation, int> createReservation;
public FSharpFunc<DateTimeOffset, FSharpList<Reservation>> readReservations;
internal tryAcceptComposition@17(
int capacity,
FSharpFunc<DateTimeOffset, FSharpList<Reservation>> readReservations,
FSharpFunc<Reservation, int> createReservation)
{
this.capacity = capacity;
this.readReservations = readReservations;
this.createReservation = createReservation;
}
public override FSharpOption<int> Invoke(Reservation reservation)
{
return MaîtreD.tryAccept<int>(
this.capacity, this.readReservations, this.createReservation, reservation);
}
}
@ploeh
Is it Functional?
Partial
application
Dependency
injection
@ploeh
Same
return
value for
same input
No side-
effects
Pure
function
@ploeh
Pure
function
Impure
function
@ploeh
Sanity check
@ploeh
tryAccept :: Int -> (ZonedTime -> [Reservation]) -> (Reservation -> Int) -> Reservation
-> Maybe Int
tryAccept capacity readReservations createReservation reservation =
let reservedSeats = sum $ map quantity $ readReservations $ date reservation
in if reservedSeats + quantity reservation <= capacity
then Just $ createReservation $ reservation { isAccepted = True }
else Nothing
@ploeh
Pure
tryAcceptComposition :: Reservation -> IO (Maybe Int)
tryAcceptComposition reservation =
let read = DB.readReservations connectionString
create = DB.createReservation connectionString
in tryAccept 10 read create reservation
@ploeh
ZonedTime -> IO [Reservation]
Reservation -> IO Int
ZonedTime -> [Reservation] Reservation -> Int
Not Functional
Partial
application
Dependency
injection
@ploeh
@ploeh
Dependency injection
makes everything impure
@ploeh
Dependency Rejection
@ploeh
Unit
Dependencies
Indirect
input
Indirect
output
Direct
input
Direct
output
@ploeh
Unit
Dependencies
Indirect
input
Direct
input
Direct
output
@ploeh
// int -> (DateTimeOffset -> Reservation list) -> (Reservation -> int) -> Reservation
// -> int option
let tryAccept capacity readReservations createReservation reservation =
@ploeh
// int -> (DateTimeOffset -> Reservation list) -> Reservation
// -> Reservation option
let tryAccept capacity readReservations reservation =
@ploeh
// int -> (DateTimeOffset -> Reservation list) -> Reservation
// -> Reservation option
let tryAccept capacity readReservations reservation =
@ploeh
// int -> (DateTimeOffset -> Reservation list) -> Reservation -> Reservation option
let tryAccept capacity readReservations reservation =
@ploeh
// int -> (DateTimeOffset -> Reservation list) -> Reservation -> Reservation option
let tryAccept capacity readReservations reservation =
let reservedSeats =
readReservations reservation.Date |> List.sumBy (fun x -> x.Quantity)
if reservedSeats + reservation.Quantity <= capacity
then { reservation with IsAccepted = true } |> Some
else None
@ploeh
// Reservation -> int option
let tryAcceptComposition reservation =
match tryAccept 10 (DB.readReservations connectionString) reservation with
| None -> None
| Some r -> (DB.createReservation connectionString) r |> Some
@ploeh
// Reservation -> int option
let tryAcceptComposition reservation =
tryAccept 10 (DB.readReservations connectionString) reservation
|> Option.map (fun r -> DB.createReservation connectionString r)
@ploeh
// Reservation -> int option
let tryAcceptComposition reservation =
tryAccept 10 (DB.readReservations connectionString) reservation
|> Option.map ( DB.createReservation connectionString )
@ploeh
// Reservation -> int option
let tryAcceptComposition reservation =
tryAccept 10 (DB.readReservations connectionString) reservation
|> Option.map (DB.createReservation connectionString)
@ploeh
// Reservation -> int option
let tryAcceptComposition reservation =
reservation
|> tryAccept 10 (DB.readReservations connectionString)
|> Option.map (DB.createReservation connectionString)
@ploeh
Unit
Dependencies
Indirect
input
Direct
input
Direct
output
@ploeh
Unit
Dependencies
Direct
input
Direct
output
@ploeh
// int -> (DateTimeOffset -> Reservation list) -> Reservation -> Reservation option
let tryAccept capacity readReservations reservation =
@ploeh
// int -> ( Reservation list) -> Reservation -> Reservation option
let tryAccept capacity readReservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity readReservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity radReservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity rdReservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity rReservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity reservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity reservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity reservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity reservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity reservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity reservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity reservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity reservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity reservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity reservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity reservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity reservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity reservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity reservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity reservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity reservations reservation =
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity reservations reservation =
let reservedSeats =
reservations |> List.sumBy (fun x -> x.Quantity)
if reservedSeats + reservation.Quantity <= capacity
then { reservation with IsAccepted = true } |> Some
else None
@ploeh
// int -> Reservation list -> Reservation -> Reservation option
let tryAccept capacity reservations reservation =
let reservedSeats = reservations |> List.sumBy (fun x -> x.Quantity)
if reservedSeats + reservation.Quantity <= capacity
then { reservation with IsAccepted = true } |> Some
else None
@ploeh
// ('a -> 'b -> 'c) -> 'b -> 'a -> 'c
let flip f x y = f y x
// Reservation -> int option
let tryAcceptComposition reservation =
reservation.Date
|> DB.readReservations connectionString
|> fun reservations -> tryAccept 10 reservations reservation
|> Option.map (DB.createReservation connectionString)
@ploeh
// ('a -> 'b -> 'c) -> 'b -> 'a -> 'c
let flip f x y = f y x
// Reservation -> int option
let tryAcceptComposition reservation =
reservation.Date
|> DB.readReservations connectionString
|> fun reservations -> flip (tryAccept 10) reservation reservations
|> Option.map (DB.createReservation connectionString)
@ploeh
// ('a -> 'b -> 'c) -> 'b -> 'a -> 'c
let flip f x y = f y x
// Reservation -> int option
let tryAcceptComposition reservation =
reservation.Date
|> DB.readReservations connectionString
|> -> flip (tryAccept 10) reservation
|> Option.map (DB.createReservation connectionString)
@ploeh
// ('a -> 'b -> 'c) -> 'b -> 'a -> 'c
let flip f x y = f y x
// Reservation -> int option
let tryAcceptComposition reservation =
reservation.Date
|> DB.readReservations connectionString
|> flip (tryAccept 10) reservation
|> Option.map (DB.createReservation connectionString)
@ploeh
Sanity check
@ploeh
tryAccept :: Int -> [Reservation] -> Reservation -> Maybe Reservation
tryAccept capacity reservations reservation =
let reservedSeats = sum $ map quantity reservations
in if reservedSeats + quantity reservation <= capacity
then Just $ reservation { isAccepted = True }
else Nothing
@ploeh
tryAcceptComposition :: Reservation -> IO (Maybe Int)
tryAcceptComposition reservation = runMaybeT $
liftIO (DB.readReservations connectionString $ date reservation)
>>= MaybeT . return . flip (tryAccept 10) reservation
>>= liftIO . DB.createReservation connectionString
@ploeh
Object-oriented Functional
Dependency injection Partial application
Composition
@ploeh
Mark Seemann
http://blog.ploeh.dk
http://bit.ly/ploehralsight
@ploeh

More Related Content

More from NETFest

.NET Fest 2019. Halil Ibrahim Kalkan. Implementing Domain Driven Design
.NET Fest 2019. Halil Ibrahim Kalkan. Implementing Domain Driven Design.NET Fest 2019. Halil Ibrahim Kalkan. Implementing Domain Driven Design
.NET Fest 2019. Halil Ibrahim Kalkan. Implementing Domain Driven DesignNETFest
 
.NET Fest 2019. Сергій Бута. Feature Toggles: Dynamic Configuration at Wirex
.NET Fest 2019. Сергій Бута. Feature Toggles: Dynamic Configuration at Wirex.NET Fest 2019. Сергій Бута. Feature Toggles: Dynamic Configuration at Wirex
.NET Fest 2019. Сергій Бута. Feature Toggles: Dynamic Configuration at WirexNETFest
 
.NET Fest 2019. Michael Staib. Hot Chocolate: GraphQL Schema Stitching with A...
.NET Fest 2019. Michael Staib. Hot Chocolate: GraphQL Schema Stitching with A....NET Fest 2019. Michael Staib. Hot Chocolate: GraphQL Schema Stitching with A...
.NET Fest 2019. Michael Staib. Hot Chocolate: GraphQL Schema Stitching with A...NETFest
 
.NET Fest 2019. Андрей Литвинов. Async lifetime tests with xUnit and AutoFixture
.NET Fest 2019. Андрей Литвинов. Async lifetime tests with xUnit and AutoFixture.NET Fest 2019. Андрей Литвинов. Async lifetime tests with xUnit and AutoFixture
.NET Fest 2019. Андрей Литвинов. Async lifetime tests with xUnit and AutoFixtureNETFest
 
.NET Fest 2019. Анатолий Колесник. Love, Death & F# Tests
.NET Fest 2019. Анатолий Колесник. Love, Death & F# Tests.NET Fest 2019. Анатолий Колесник. Love, Death & F# Tests
.NET Fest 2019. Анатолий Колесник. Love, Death & F# TestsNETFest
 
.NET Fest 2019. Алексей Голуб. Монадные парсер-комбинаторы в C# (простой спос...
.NET Fest 2019. Алексей Голуб. Монадные парсер-комбинаторы в C# (простой спос....NET Fest 2019. Алексей Голуб. Монадные парсер-комбинаторы в C# (простой спос...
.NET Fest 2019. Алексей Голуб. Монадные парсер-комбинаторы в C# (простой спос...NETFest
 
.NET Fest 2019. Roberto Freato. Azure App Service deep dive
.NET Fest 2019. Roberto Freato. Azure App Service deep dive.NET Fest 2019. Roberto Freato. Azure App Service deep dive
.NET Fest 2019. Roberto Freato. Azure App Service deep diveNETFest
 
.NET Fest 2019. Леонид Молотиевский. DotNet Core in production
.NET Fest 2019. Леонид Молотиевский. DotNet Core in production.NET Fest 2019. Леонид Молотиевский. DotNet Core in production
.NET Fest 2019. Леонид Молотиевский. DotNet Core in productionNETFest
 
.NET Fest 2019. Александр Демчук. How to measure relationships within the Com...
.NET Fest 2019. Александр Демчук. How to measure relationships within the Com....NET Fest 2019. Александр Демчук. How to measure relationships within the Com...
.NET Fest 2019. Александр Демчук. How to measure relationships within the Com...NETFest
 
.NET Fest 2019. Anna Melashkina та Philipp Bauknecht. Dragons in a Mixed Real...
.NET Fest 2019. Anna Melashkina та Philipp Bauknecht. Dragons in a Mixed Real....NET Fest 2019. Anna Melashkina та Philipp Bauknecht. Dragons in a Mixed Real...
.NET Fest 2019. Anna Melashkina та Philipp Bauknecht. Dragons in a Mixed Real...NETFest
 
.NET Fest 2019. Alex Thissen. Architecting .NET solutions in a Docker ecosystem
.NET Fest 2019. Alex Thissen. Architecting .NET solutions in a Docker ecosystem.NET Fest 2019. Alex Thissen. Architecting .NET solutions in a Docker ecosystem
.NET Fest 2019. Alex Thissen. Architecting .NET solutions in a Docker ecosystemNETFest
 
.NET Fest 2019. Stas Lebedenko. Practical serverless use cases in Azure with ...
.NET Fest 2019. Stas Lebedenko. Practical serverless use cases in Azure with ....NET Fest 2019. Stas Lebedenko. Practical serverless use cases in Azure with ...
.NET Fest 2019. Stas Lebedenko. Practical serverless use cases in Azure with ...NETFest
 
.NET Fest 2019. Сергей Медведев. How serverless makes Integration TDD a reali...
.NET Fest 2019. Сергей Медведев. How serverless makes Integration TDD a reali....NET Fest 2019. Сергей Медведев. How serverless makes Integration TDD a reali...
.NET Fest 2019. Сергей Медведев. How serverless makes Integration TDD a reali...NETFest
 
.NET Fest 2019. Сергей Корж. Natural Language Processing in .NET
.NET Fest 2019. Сергей Корж. Natural Language Processing in .NET.NET Fest 2019. Сергей Корж. Natural Language Processing in .NET
.NET Fest 2019. Сергей Корж. Natural Language Processing in .NETNETFest
 
.NET Fest 2019. Eran Stiller. Create Your Own Serverless PKI with .NET & Azur...
.NET Fest 2019. Eran Stiller. Create Your Own Serverless PKI with .NET & Azur....NET Fest 2019. Eran Stiller. Create Your Own Serverless PKI with .NET & Azur...
.NET Fest 2019. Eran Stiller. Create Your Own Serverless PKI with .NET & Azur...NETFest
 
.NET Fest 2019. Eran Stiller. 6 Lessons I Learned on My Journey from Monolith...
.NET Fest 2019. Eran Stiller. 6 Lessons I Learned on My Journey from Monolith....NET Fest 2019. Eran Stiller. 6 Lessons I Learned on My Journey from Monolith...
.NET Fest 2019. Eran Stiller. 6 Lessons I Learned on My Journey from Monolith...NETFest
 
.NET Fest 2019. Kevin Dockx. Uncovering Swagger/OpenAPI
.NET Fest 2019. Kevin Dockx. Uncovering Swagger/OpenAPI.NET Fest 2019. Kevin Dockx. Uncovering Swagger/OpenAPI
.NET Fest 2019. Kevin Dockx. Uncovering Swagger/OpenAPINETFest
 
.NET Fest 2019. Kevin Dockx. OpenID Connect In Depth
.NET Fest 2019. Kevin Dockx. OpenID Connect In Depth.NET Fest 2019. Kevin Dockx. OpenID Connect In Depth
.NET Fest 2019. Kevin Dockx. OpenID Connect In DepthNETFest
 
.NET Fest 2019. Андрей Антиликаторов. Проектирование и разработка Big Data ре...
.NET Fest 2019. Андрей Антиликаторов. Проектирование и разработка Big Data ре....NET Fest 2019. Андрей Антиликаторов. Проектирование и разработка Big Data ре...
.NET Fest 2019. Андрей Антиликаторов. Проектирование и разработка Big Data ре...NETFest
 
.NET Fest 2019. Irina Scurtu. Forget about HTTP
.NET Fest 2019. Irina Scurtu. Forget about HTTP.NET Fest 2019. Irina Scurtu. Forget about HTTP
.NET Fest 2019. Irina Scurtu. Forget about HTTPNETFest
 

More from NETFest (20)

.NET Fest 2019. Halil Ibrahim Kalkan. Implementing Domain Driven Design
.NET Fest 2019. Halil Ibrahim Kalkan. Implementing Domain Driven Design.NET Fest 2019. Halil Ibrahim Kalkan. Implementing Domain Driven Design
.NET Fest 2019. Halil Ibrahim Kalkan. Implementing Domain Driven Design
 
.NET Fest 2019. Сергій Бута. Feature Toggles: Dynamic Configuration at Wirex
.NET Fest 2019. Сергій Бута. Feature Toggles: Dynamic Configuration at Wirex.NET Fest 2019. Сергій Бута. Feature Toggles: Dynamic Configuration at Wirex
.NET Fest 2019. Сергій Бута. Feature Toggles: Dynamic Configuration at Wirex
 
.NET Fest 2019. Michael Staib. Hot Chocolate: GraphQL Schema Stitching with A...
.NET Fest 2019. Michael Staib. Hot Chocolate: GraphQL Schema Stitching with A....NET Fest 2019. Michael Staib. Hot Chocolate: GraphQL Schema Stitching with A...
.NET Fest 2019. Michael Staib. Hot Chocolate: GraphQL Schema Stitching with A...
 
.NET Fest 2019. Андрей Литвинов. Async lifetime tests with xUnit and AutoFixture
.NET Fest 2019. Андрей Литвинов. Async lifetime tests with xUnit and AutoFixture.NET Fest 2019. Андрей Литвинов. Async lifetime tests with xUnit and AutoFixture
.NET Fest 2019. Андрей Литвинов. Async lifetime tests with xUnit and AutoFixture
 
.NET Fest 2019. Анатолий Колесник. Love, Death & F# Tests
.NET Fest 2019. Анатолий Колесник. Love, Death & F# Tests.NET Fest 2019. Анатолий Колесник. Love, Death & F# Tests
.NET Fest 2019. Анатолий Колесник. Love, Death & F# Tests
 
.NET Fest 2019. Алексей Голуб. Монадные парсер-комбинаторы в C# (простой спос...
.NET Fest 2019. Алексей Голуб. Монадные парсер-комбинаторы в C# (простой спос....NET Fest 2019. Алексей Голуб. Монадные парсер-комбинаторы в C# (простой спос...
.NET Fest 2019. Алексей Голуб. Монадные парсер-комбинаторы в C# (простой спос...
 
.NET Fest 2019. Roberto Freato. Azure App Service deep dive
.NET Fest 2019. Roberto Freato. Azure App Service deep dive.NET Fest 2019. Roberto Freato. Azure App Service deep dive
.NET Fest 2019. Roberto Freato. Azure App Service deep dive
 
.NET Fest 2019. Леонид Молотиевский. DotNet Core in production
.NET Fest 2019. Леонид Молотиевский. DotNet Core in production.NET Fest 2019. Леонид Молотиевский. DotNet Core in production
.NET Fest 2019. Леонид Молотиевский. DotNet Core in production
 
.NET Fest 2019. Александр Демчук. How to measure relationships within the Com...
.NET Fest 2019. Александр Демчук. How to measure relationships within the Com....NET Fest 2019. Александр Демчук. How to measure relationships within the Com...
.NET Fest 2019. Александр Демчук. How to measure relationships within the Com...
 
.NET Fest 2019. Anna Melashkina та Philipp Bauknecht. Dragons in a Mixed Real...
.NET Fest 2019. Anna Melashkina та Philipp Bauknecht. Dragons in a Mixed Real....NET Fest 2019. Anna Melashkina та Philipp Bauknecht. Dragons in a Mixed Real...
.NET Fest 2019. Anna Melashkina та Philipp Bauknecht. Dragons in a Mixed Real...
 
.NET Fest 2019. Alex Thissen. Architecting .NET solutions in a Docker ecosystem
.NET Fest 2019. Alex Thissen. Architecting .NET solutions in a Docker ecosystem.NET Fest 2019. Alex Thissen. Architecting .NET solutions in a Docker ecosystem
.NET Fest 2019. Alex Thissen. Architecting .NET solutions in a Docker ecosystem
 
.NET Fest 2019. Stas Lebedenko. Practical serverless use cases in Azure with ...
.NET Fest 2019. Stas Lebedenko. Practical serverless use cases in Azure with ....NET Fest 2019. Stas Lebedenko. Practical serverless use cases in Azure with ...
.NET Fest 2019. Stas Lebedenko. Practical serverless use cases in Azure with ...
 
.NET Fest 2019. Сергей Медведев. How serverless makes Integration TDD a reali...
.NET Fest 2019. Сергей Медведев. How serverless makes Integration TDD a reali....NET Fest 2019. Сергей Медведев. How serverless makes Integration TDD a reali...
.NET Fest 2019. Сергей Медведев. How serverless makes Integration TDD a reali...
 
.NET Fest 2019. Сергей Корж. Natural Language Processing in .NET
.NET Fest 2019. Сергей Корж. Natural Language Processing in .NET.NET Fest 2019. Сергей Корж. Natural Language Processing in .NET
.NET Fest 2019. Сергей Корж. Natural Language Processing in .NET
 
.NET Fest 2019. Eran Stiller. Create Your Own Serverless PKI with .NET & Azur...
.NET Fest 2019. Eran Stiller. Create Your Own Serverless PKI with .NET & Azur....NET Fest 2019. Eran Stiller. Create Your Own Serverless PKI with .NET & Azur...
.NET Fest 2019. Eran Stiller. Create Your Own Serverless PKI with .NET & Azur...
 
.NET Fest 2019. Eran Stiller. 6 Lessons I Learned on My Journey from Monolith...
.NET Fest 2019. Eran Stiller. 6 Lessons I Learned on My Journey from Monolith....NET Fest 2019. Eran Stiller. 6 Lessons I Learned on My Journey from Monolith...
.NET Fest 2019. Eran Stiller. 6 Lessons I Learned on My Journey from Monolith...
 
.NET Fest 2019. Kevin Dockx. Uncovering Swagger/OpenAPI
.NET Fest 2019. Kevin Dockx. Uncovering Swagger/OpenAPI.NET Fest 2019. Kevin Dockx. Uncovering Swagger/OpenAPI
.NET Fest 2019. Kevin Dockx. Uncovering Swagger/OpenAPI
 
.NET Fest 2019. Kevin Dockx. OpenID Connect In Depth
.NET Fest 2019. Kevin Dockx. OpenID Connect In Depth.NET Fest 2019. Kevin Dockx. OpenID Connect In Depth
.NET Fest 2019. Kevin Dockx. OpenID Connect In Depth
 
.NET Fest 2019. Андрей Антиликаторов. Проектирование и разработка Big Data ре...
.NET Fest 2019. Андрей Антиликаторов. Проектирование и разработка Big Data ре....NET Fest 2019. Андрей Антиликаторов. Проектирование и разработка Big Data ре...
.NET Fest 2019. Андрей Антиликаторов. Проектирование и разработка Big Data ре...
 
.NET Fest 2019. Irina Scurtu. Forget about HTTP
.NET Fest 2019. Irina Scurtu. Forget about HTTP.NET Fest 2019. Irina Scurtu. Forget about HTTP
.NET Fest 2019. Irina Scurtu. Forget about HTTP
 

Recently uploaded

MENTAL STATUS EXAMINATION format.docx
MENTAL     STATUS EXAMINATION format.docxMENTAL     STATUS EXAMINATION format.docx
MENTAL STATUS EXAMINATION format.docxPoojaSen20
 
The Most Excellent Way | 1 Corinthians 13
The Most Excellent Way | 1 Corinthians 13The Most Excellent Way | 1 Corinthians 13
The Most Excellent Way | 1 Corinthians 13Steve Thomason
 
PSYCHIATRIC History collection FORMAT.pptx
PSYCHIATRIC   History collection FORMAT.pptxPSYCHIATRIC   History collection FORMAT.pptx
PSYCHIATRIC History collection FORMAT.pptxPoojaSen20
 
Introduction to ArtificiaI Intelligence in Higher Education
Introduction to ArtificiaI Intelligence in Higher EducationIntroduction to ArtificiaI Intelligence in Higher Education
Introduction to ArtificiaI Intelligence in Higher Educationpboyjonauth
 
Organic Name Reactions for the students and aspirants of Chemistry12th.pptx
Organic Name Reactions  for the students and aspirants of Chemistry12th.pptxOrganic Name Reactions  for the students and aspirants of Chemistry12th.pptx
Organic Name Reactions for the students and aspirants of Chemistry12th.pptxVS Mahajan Coaching Centre
 
Incoming and Outgoing Shipments in 1 STEP Using Odoo 17
Incoming and Outgoing Shipments in 1 STEP Using Odoo 17Incoming and Outgoing Shipments in 1 STEP Using Odoo 17
Incoming and Outgoing Shipments in 1 STEP Using Odoo 17Celine George
 
APM Welcome, APM North West Network Conference, Synergies Across Sectors
APM Welcome, APM North West Network Conference, Synergies Across SectorsAPM Welcome, APM North West Network Conference, Synergies Across Sectors
APM Welcome, APM North West Network Conference, Synergies Across SectorsAssociation for Project Management
 
Separation of Lanthanides/ Lanthanides and Actinides
Separation of Lanthanides/ Lanthanides and ActinidesSeparation of Lanthanides/ Lanthanides and Actinides
Separation of Lanthanides/ Lanthanides and ActinidesFatimaKhan178732
 
Q4-W6-Restating Informational Text Grade 3
Q4-W6-Restating Informational Text Grade 3Q4-W6-Restating Informational Text Grade 3
Q4-W6-Restating Informational Text Grade 3JemimahLaneBuaron
 
The basics of sentences session 2pptx copy.pptx
The basics of sentences session 2pptx copy.pptxThe basics of sentences session 2pptx copy.pptx
The basics of sentences session 2pptx copy.pptxheathfieldcps1
 
Presiding Officer Training module 2024 lok sabha elections
Presiding Officer Training module 2024 lok sabha electionsPresiding Officer Training module 2024 lok sabha elections
Presiding Officer Training module 2024 lok sabha electionsanshu789521
 
Alper Gobel In Media Res Media Component
Alper Gobel In Media Res Media ComponentAlper Gobel In Media Res Media Component
Alper Gobel In Media Res Media ComponentInMediaRes1
 
Crayon Activity Handout For the Crayon A
Crayon Activity Handout For the Crayon ACrayon Activity Handout For the Crayon A
Crayon Activity Handout For the Crayon AUnboundStockton
 
Mastering the Unannounced Regulatory Inspection
Mastering the Unannounced Regulatory InspectionMastering the Unannounced Regulatory Inspection
Mastering the Unannounced Regulatory InspectionSafetyChain Software
 
18-04-UA_REPORT_MEDIALITERAСY_INDEX-DM_23-1-final-eng.pdf
18-04-UA_REPORT_MEDIALITERAСY_INDEX-DM_23-1-final-eng.pdf18-04-UA_REPORT_MEDIALITERAСY_INDEX-DM_23-1-final-eng.pdf
18-04-UA_REPORT_MEDIALITERAСY_INDEX-DM_23-1-final-eng.pdfssuser54595a
 
How to Make a Pirate ship Primary Education.pptx
How to Make a Pirate ship Primary Education.pptxHow to Make a Pirate ship Primary Education.pptx
How to Make a Pirate ship Primary Education.pptxmanuelaromero2013
 
Accessible design: Minimum effort, maximum impact
Accessible design: Minimum effort, maximum impactAccessible design: Minimum effort, maximum impact
Accessible design: Minimum effort, maximum impactdawncurless
 
Measures of Central Tendency: Mean, Median and Mode
Measures of Central Tendency: Mean, Median and ModeMeasures of Central Tendency: Mean, Median and Mode
Measures of Central Tendency: Mean, Median and ModeThiyagu K
 
Hybridoma Technology ( Production , Purification , and Application )
Hybridoma Technology  ( Production , Purification , and Application  ) Hybridoma Technology  ( Production , Purification , and Application  )
Hybridoma Technology ( Production , Purification , and Application ) Sakshi Ghasle
 

Recently uploaded (20)

MENTAL STATUS EXAMINATION format.docx
MENTAL     STATUS EXAMINATION format.docxMENTAL     STATUS EXAMINATION format.docx
MENTAL STATUS EXAMINATION format.docx
 
The Most Excellent Way | 1 Corinthians 13
The Most Excellent Way | 1 Corinthians 13The Most Excellent Way | 1 Corinthians 13
The Most Excellent Way | 1 Corinthians 13
 
PSYCHIATRIC History collection FORMAT.pptx
PSYCHIATRIC   History collection FORMAT.pptxPSYCHIATRIC   History collection FORMAT.pptx
PSYCHIATRIC History collection FORMAT.pptx
 
Introduction to ArtificiaI Intelligence in Higher Education
Introduction to ArtificiaI Intelligence in Higher EducationIntroduction to ArtificiaI Intelligence in Higher Education
Introduction to ArtificiaI Intelligence in Higher Education
 
Organic Name Reactions for the students and aspirants of Chemistry12th.pptx
Organic Name Reactions  for the students and aspirants of Chemistry12th.pptxOrganic Name Reactions  for the students and aspirants of Chemistry12th.pptx
Organic Name Reactions for the students and aspirants of Chemistry12th.pptx
 
Incoming and Outgoing Shipments in 1 STEP Using Odoo 17
Incoming and Outgoing Shipments in 1 STEP Using Odoo 17Incoming and Outgoing Shipments in 1 STEP Using Odoo 17
Incoming and Outgoing Shipments in 1 STEP Using Odoo 17
 
Código Creativo y Arte de Software | Unidad 1
Código Creativo y Arte de Software | Unidad 1Código Creativo y Arte de Software | Unidad 1
Código Creativo y Arte de Software | Unidad 1
 
APM Welcome, APM North West Network Conference, Synergies Across Sectors
APM Welcome, APM North West Network Conference, Synergies Across SectorsAPM Welcome, APM North West Network Conference, Synergies Across Sectors
APM Welcome, APM North West Network Conference, Synergies Across Sectors
 
Separation of Lanthanides/ Lanthanides and Actinides
Separation of Lanthanides/ Lanthanides and ActinidesSeparation of Lanthanides/ Lanthanides and Actinides
Separation of Lanthanides/ Lanthanides and Actinides
 
Q4-W6-Restating Informational Text Grade 3
Q4-W6-Restating Informational Text Grade 3Q4-W6-Restating Informational Text Grade 3
Q4-W6-Restating Informational Text Grade 3
 
The basics of sentences session 2pptx copy.pptx
The basics of sentences session 2pptx copy.pptxThe basics of sentences session 2pptx copy.pptx
The basics of sentences session 2pptx copy.pptx
 
Presiding Officer Training module 2024 lok sabha elections
Presiding Officer Training module 2024 lok sabha electionsPresiding Officer Training module 2024 lok sabha elections
Presiding Officer Training module 2024 lok sabha elections
 
Alper Gobel In Media Res Media Component
Alper Gobel In Media Res Media ComponentAlper Gobel In Media Res Media Component
Alper Gobel In Media Res Media Component
 
Crayon Activity Handout For the Crayon A
Crayon Activity Handout For the Crayon ACrayon Activity Handout For the Crayon A
Crayon Activity Handout For the Crayon A
 
Mastering the Unannounced Regulatory Inspection
Mastering the Unannounced Regulatory InspectionMastering the Unannounced Regulatory Inspection
Mastering the Unannounced Regulatory Inspection
 
18-04-UA_REPORT_MEDIALITERAСY_INDEX-DM_23-1-final-eng.pdf
18-04-UA_REPORT_MEDIALITERAСY_INDEX-DM_23-1-final-eng.pdf18-04-UA_REPORT_MEDIALITERAСY_INDEX-DM_23-1-final-eng.pdf
18-04-UA_REPORT_MEDIALITERAСY_INDEX-DM_23-1-final-eng.pdf
 
How to Make a Pirate ship Primary Education.pptx
How to Make a Pirate ship Primary Education.pptxHow to Make a Pirate ship Primary Education.pptx
How to Make a Pirate ship Primary Education.pptx
 
Accessible design: Minimum effort, maximum impact
Accessible design: Minimum effort, maximum impactAccessible design: Minimum effort, maximum impact
Accessible design: Minimum effort, maximum impact
 
Measures of Central Tendency: Mean, Median and Mode
Measures of Central Tendency: Mean, Median and ModeMeasures of Central Tendency: Mean, Median and Mode
Measures of Central Tendency: Mean, Median and Mode
 
Hybridoma Technology ( Production , Purification , and Application )
Hybridoma Technology  ( Production , Purification , and Application  ) Hybridoma Technology  ( Production , Purification , and Application  )
Hybridoma Technology ( Production , Purification , and Application )
 

.NET Fest 2017. Mark Seemann. From Dependency injection to dependency rejection

  • 1. From dependency injection to dependency rejection Mark Seemann http://blog.ploeh.dk @ploeh
  • 4. Object-oriented Functional Dependency injection Partial application Composition @ploeh
  • 5. Dependency injection is “really just a pretentious way to say ‘taking an argument’” - Rúnar Bjarnason (@runarorama) @ploeh
  • 7. Restaurant Reservation Make a reservation Date Name Email Quantity Submit @ploeh
  • 8. Restaurant Reservation Make a reservation Date 2 Name Email Quantity Submit @ploeh
  • 9. Restaurant Reservation Make a reservation Date 20 Name Email Quantity Submit @ploeh
  • 10. Restaurant Reservation Make a reservation Date 201 Name Email Quantity Submit @ploeh
  • 11. Restaurant Reservation Make a reservation Date 2016 Name Email Quantity Submit @ploeh
  • 12. Restaurant Reservation Make a reservation Date 2016- Name Email Quantity Submit @ploeh
  • 13. Restaurant Reservation Make a reservation Date 2016-1 Name Email Quantity Submit @ploeh
  • 14. Restaurant Reservation Make a reservation Date 2016-12 Name Email Quantity Submit @ploeh
  • 15. Restaurant Reservation Make a reservation Date 2016-12- Name Email Quantity Submit @ploeh
  • 16. Restaurant Reservation Make a reservation Date 2016-12-2 Name Email Quantity Submit @ploeh
  • 17. Restaurant Reservation Make a reservation Date 2016-12-29 Name Email Quantity Submit @ploeh
  • 18. Restaurant Reservation Make a reservation Date 2016-12-29 Name M Email Quantity Submit @ploeh
  • 19. Restaurant Reservation Make a reservation Date 2016-12-29 Name Ma Email Quantity Submit @ploeh
  • 20. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mar Email Quantity Submit @ploeh
  • 21. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark Email Quantity Submit @ploeh
  • 22. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark Email Quantity Submit @ploeh
  • 23. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark S Email Quantity Submit @ploeh
  • 24. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark Se Email Quantity Submit @ploeh
  • 25. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark See Email Quantity Submit @ploeh
  • 26. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark Seem Email Quantity Submit @ploeh
  • 27. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark Seema Email Quantity Submit @ploeh
  • 28. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark Seeman Email Quantity Submit @ploeh
  • 29. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark Seemann Email Quantity Submit @ploeh
  • 30. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark Seemann Email ma Quantity Submit @ploeh
  • 31. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark Seemann Email mar Quantity Submit @ploeh
  • 32. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark Seemann Email mark Quantity Submit @ploeh
  • 33. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark Seemann Email mark@ Quantity Submit @ploeh
  • 34. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark Seemann Email mark@p Quantity Submit @ploeh
  • 35. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark Seemann Email mark@pl Quantity Submit @ploeh
  • 36. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark Seemann Email mark@plo Quantity Submit @ploeh
  • 37. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark Seemann Email mark@ploe Quantity Submit @ploeh
  • 38. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark Seemann Email mark@ploeh Quantity Submit @ploeh
  • 39. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark Seemann Email mark@ploeh. Quantity Submit @ploeh
  • 40. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark Seemann Email mark@ploeh.d Quantity Submit @ploeh
  • 41. Restaurant Reservation Make a reservation Date 2016-12-29 Name Mark Seemann Email mark@ploeh.dk Quantity Submit @ploeh
  • 42. Restaurant Reservation POST JSON @ploeh Make a reservation Date 2016-12-29 Name Mark Seemann Email mark@ploeh.dk Quantity 4 Submit
  • 43. Restaurant Reservation POST JSON @ploeh Make a reservation Date 2016-12-29 Name Mark Seemann Email mark@ploeh.dk Quantity 4 Submit
  • 46. public class ReservationsController : ApiController { public ReservationsController(IValidator validator, IMapper mapper, IMaîtreD maîtreD) { this.validator = validator; this.mapper = mapper; this.maîtreD = maîtreD; } public IHttpActionResult Post(ReservationRequestDto dto) { var validationMsg = validator.Validate(dto); if (validationMsg != "") return this.BadRequest(validationMsg); var r = mapper.Map(dto); var id = maîtreD.TryAccept(r); if (id == null) return this.StatusCode(HttpStatusCode.Forbidden); return this.Ok(); } } POST /reservations HTTP/1.1 { "date": "2016-12-08", "name": "Mark Seemann", "email": "mark@ploeh.dk", "quantity": 4 } @ploeh
  • 47. public class MaîtreD : IMaîtreD { public MaîtreD(int capacity, IReservationsRepository reservationsRepository) { this.capacity = capacity; this.reservationsRepository = reservationsRepository; } public int? TryAccept(Reservation reservation) { var reservedSeats = reservationsRepository .ReadReservations(reservation.Date) .Sum(r => r.Quantity); if (reservedSeats + reservation.Quantity <= capacity) { reservation.IsAccepted = true; return reservationsRepository.Create(reservation); } return null; } } @ploeh public interface IMaîtreD { int? TryAccept(Reservation reservation); }
  • 48. How do I do dependency injection in Scala? You don’t, because Scala is a functional language. Comic courtesy of @jrecursive and @hmemcpy @ploeh
  • 49. Fine, it’s functional. How do I inject dependencies? You use a Free Monad, which allows you to build a Monad from any Functor. Comic courtesy of @jrecursive and @hmemcpy @ploeh
  • 50. Did you just tell me to go fuck myself? I believe I did, Bob. Comic courtesy of @jrecursive and @hmemcpy @ploeh
  • 51. Partial application An attempt at dependency injection with a functional language @ploeh
  • 52. // int -> (DateTimeOffset -> Reservation list) -> (Reservation -> int) -> Reservation // -> int option let tryAccept capacity readReservations createReservation reservation = let reservedSeats = readReservations reservation.Date |> List.sumBy (fun x -> x.Quantity) if reservedSeats + reservation.Quantity <= capacity then createReservation { reservation with IsAccepted = true } |> Some else None @ploeh Repository
  • 53. // Reservation -> int option let tryAcceptComposition reservation = let read = DB.readReservations connectionString @ploeh string -> DateTimeOffset -> Reservation list
  • 54. // Reservation -> int option let tryAcceptComposition reservation = let read = DB.readReservations connectionString @ploeh string -> DateTimeOffset -> Reservation list connectionString
  • 55. // Reservation -> int option let tryAcceptComposition reservation = let read = DB.readReservations connectionString @ploeh string -> DateTimeOffset -> Reservation listconnectionString
  • 56. // Reservation -> int option let tryAcceptComposition reservation = let read = DB.readReservations connectionString @ploeh DateTimeOffset -> Reservation list
  • 57. // Reservation -> int option let tryAcceptComposition reservation = let read = DB.readReservations connectionString let create = DB.createReservation connectionString tryAccept 10 read create reservation @ploeh Reservation -> int
  • 58. // Reservation -> int option let tryAcceptComposition reservation = let read = DB.readReservations connectionString let create = DB.createReservation connectionString tryAccept 10 read create reservation @ploeh
  • 59. // Reservation -> int option let tryAcceptComposition = let read = DB.readReservations connectionString let create = DB.createReservation connectionString tryAccept 10 read create @ploeh
  • 60. // Reservation -> int option let tryAcceptComposition = let read = DB.readReservations connectionString let create = DB.createReservation connectionString tryAccept 10 read create @ploeh
  • 62. internal class tryAcceptComposition@17 : FSharpFunc<Reservation, FSharpOption<int>> { public int capacity; public FSharpFunc<Reservation, int> createReservation; public FSharpFunc<DateTimeOffset, FSharpList<Reservation>> readReservations; internal tryAcceptComposition@17( int capacity, FSharpFunc<DateTimeOffset, FSharpList<Reservation>> readReservations, FSharpFunc<Reservation, int> createReservation) { this.capacity = capacity; this.readReservations = readReservations; this.createReservation = createReservation; } public override FSharpOption<int> Invoke(Reservation reservation) { return MaîtreD.tryAccept<int>( this.capacity, this.readReservations, this.createReservation, reservation); } } @ploeh
  • 64. Same return value for same input No side- effects Pure function @ploeh
  • 67. tryAccept :: Int -> (ZonedTime -> [Reservation]) -> (Reservation -> Int) -> Reservation -> Maybe Int tryAccept capacity readReservations createReservation reservation = let reservedSeats = sum $ map quantity $ readReservations $ date reservation in if reservedSeats + quantity reservation <= capacity then Just $ createReservation $ reservation { isAccepted = True } else Nothing @ploeh Pure
  • 68. tryAcceptComposition :: Reservation -> IO (Maybe Int) tryAcceptComposition reservation = let read = DB.readReservations connectionString create = DB.createReservation connectionString in tryAccept 10 read create reservation @ploeh ZonedTime -> IO [Reservation] Reservation -> IO Int ZonedTime -> [Reservation] Reservation -> Int
  • 75. // int -> (DateTimeOffset -> Reservation list) -> (Reservation -> int) -> Reservation // -> int option let tryAccept capacity readReservations createReservation reservation = @ploeh
  • 76. // int -> (DateTimeOffset -> Reservation list) -> Reservation // -> Reservation option let tryAccept capacity readReservations reservation = @ploeh
  • 77. // int -> (DateTimeOffset -> Reservation list) -> Reservation // -> Reservation option let tryAccept capacity readReservations reservation = @ploeh
  • 78. // int -> (DateTimeOffset -> Reservation list) -> Reservation -> Reservation option let tryAccept capacity readReservations reservation = @ploeh
  • 79. // int -> (DateTimeOffset -> Reservation list) -> Reservation -> Reservation option let tryAccept capacity readReservations reservation = let reservedSeats = readReservations reservation.Date |> List.sumBy (fun x -> x.Quantity) if reservedSeats + reservation.Quantity <= capacity then { reservation with IsAccepted = true } |> Some else None @ploeh
  • 80. // Reservation -> int option let tryAcceptComposition reservation = match tryAccept 10 (DB.readReservations connectionString) reservation with | None -> None | Some r -> (DB.createReservation connectionString) r |> Some @ploeh
  • 81. // Reservation -> int option let tryAcceptComposition reservation = tryAccept 10 (DB.readReservations connectionString) reservation |> Option.map (fun r -> DB.createReservation connectionString r) @ploeh
  • 82. // Reservation -> int option let tryAcceptComposition reservation = tryAccept 10 (DB.readReservations connectionString) reservation |> Option.map ( DB.createReservation connectionString ) @ploeh
  • 83. // Reservation -> int option let tryAcceptComposition reservation = tryAccept 10 (DB.readReservations connectionString) reservation |> Option.map (DB.createReservation connectionString) @ploeh
  • 84. // Reservation -> int option let tryAcceptComposition reservation = reservation |> tryAccept 10 (DB.readReservations connectionString) |> Option.map (DB.createReservation connectionString) @ploeh
  • 87. // int -> (DateTimeOffset -> Reservation list) -> Reservation -> Reservation option let tryAccept capacity readReservations reservation = @ploeh
  • 88. // int -> ( Reservation list) -> Reservation -> Reservation option let tryAccept capacity readReservations reservation = @ploeh
  • 89. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity readReservations reservation = @ploeh
  • 90. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity radReservations reservation = @ploeh
  • 91. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity rdReservations reservation = @ploeh
  • 92. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity rReservations reservation = @ploeh
  • 93. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity reservations reservation = @ploeh
  • 94. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity reservations reservation = @ploeh
  • 95. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity reservations reservation = @ploeh
  • 96. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity reservations reservation = @ploeh
  • 97. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity reservations reservation = @ploeh
  • 98. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity reservations reservation = @ploeh
  • 99. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity reservations reservation = @ploeh
  • 100. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity reservations reservation = @ploeh
  • 101. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity reservations reservation = @ploeh
  • 102. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity reservations reservation = @ploeh
  • 103. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity reservations reservation = @ploeh
  • 104. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity reservations reservation = @ploeh
  • 105. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity reservations reservation = @ploeh
  • 106. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity reservations reservation = @ploeh
  • 107. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity reservations reservation = @ploeh
  • 108. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity reservations reservation = @ploeh
  • 109. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity reservations reservation = let reservedSeats = reservations |> List.sumBy (fun x -> x.Quantity) if reservedSeats + reservation.Quantity <= capacity then { reservation with IsAccepted = true } |> Some else None @ploeh
  • 110. // int -> Reservation list -> Reservation -> Reservation option let tryAccept capacity reservations reservation = let reservedSeats = reservations |> List.sumBy (fun x -> x.Quantity) if reservedSeats + reservation.Quantity <= capacity then { reservation with IsAccepted = true } |> Some else None @ploeh
  • 111. // ('a -> 'b -> 'c) -> 'b -> 'a -> 'c let flip f x y = f y x // Reservation -> int option let tryAcceptComposition reservation = reservation.Date |> DB.readReservations connectionString |> fun reservations -> tryAccept 10 reservations reservation |> Option.map (DB.createReservation connectionString) @ploeh
  • 112. // ('a -> 'b -> 'c) -> 'b -> 'a -> 'c let flip f x y = f y x // Reservation -> int option let tryAcceptComposition reservation = reservation.Date |> DB.readReservations connectionString |> fun reservations -> flip (tryAccept 10) reservation reservations |> Option.map (DB.createReservation connectionString) @ploeh
  • 113. // ('a -> 'b -> 'c) -> 'b -> 'a -> 'c let flip f x y = f y x // Reservation -> int option let tryAcceptComposition reservation = reservation.Date |> DB.readReservations connectionString |> -> flip (tryAccept 10) reservation |> Option.map (DB.createReservation connectionString) @ploeh
  • 114. // ('a -> 'b -> 'c) -> 'b -> 'a -> 'c let flip f x y = f y x // Reservation -> int option let tryAcceptComposition reservation = reservation.Date |> DB.readReservations connectionString |> flip (tryAccept 10) reservation |> Option.map (DB.createReservation connectionString) @ploeh
  • 116. tryAccept :: Int -> [Reservation] -> Reservation -> Maybe Reservation tryAccept capacity reservations reservation = let reservedSeats = sum $ map quantity reservations in if reservedSeats + quantity reservation <= capacity then Just $ reservation { isAccepted = True } else Nothing @ploeh
  • 117. tryAcceptComposition :: Reservation -> IO (Maybe Int) tryAcceptComposition reservation = runMaybeT $ liftIO (DB.readReservations connectionString $ date reservation) >>= MaybeT . return . flip (tryAccept 10) reservation >>= liftIO . DB.createReservation connectionString @ploeh
  • 118. Object-oriented Functional Dependency injection Partial application Composition @ploeh