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

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

Gardella_PRCampaignConclusion Pitch Letter
Gardella_PRCampaignConclusion Pitch LetterGardella_PRCampaignConclusion Pitch Letter
Gardella_PRCampaignConclusion Pitch Letter
MateoGardella
 
Making and Justifying Mathematical Decisions.pdf
Making and Justifying Mathematical Decisions.pdfMaking and Justifying Mathematical Decisions.pdf
Making and Justifying Mathematical Decisions.pdf
Chris Hunter
 
An Overview of Mutual Funds Bcom Project.pdf
An Overview of Mutual Funds Bcom Project.pdfAn Overview of Mutual Funds Bcom Project.pdf
An Overview of Mutual Funds Bcom Project.pdf
SanaAli374401
 

Recently uploaded (20)

Basic Civil Engineering first year Notes- Chapter 4 Building.pptx
Basic Civil Engineering first year Notes- Chapter 4 Building.pptxBasic Civil Engineering first year Notes- Chapter 4 Building.pptx
Basic Civil Engineering first year Notes- Chapter 4 Building.pptx
 
Unit-V; Pricing (Pharma Marketing Management).pptx
Unit-V; Pricing (Pharma Marketing Management).pptxUnit-V; Pricing (Pharma Marketing Management).pptx
Unit-V; Pricing (Pharma Marketing Management).pptx
 
Gardella_PRCampaignConclusion Pitch Letter
Gardella_PRCampaignConclusion Pitch LetterGardella_PRCampaignConclusion Pitch Letter
Gardella_PRCampaignConclusion Pitch Letter
 
Grant Readiness 101 TechSoup and Remy Consulting
Grant Readiness 101 TechSoup and Remy ConsultingGrant Readiness 101 TechSoup and Remy Consulting
Grant Readiness 101 TechSoup and Remy Consulting
 
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
 
Accessible design: Minimum effort, maximum impact
Accessible design: Minimum effort, maximum impactAccessible design: Minimum effort, maximum impact
Accessible design: Minimum effort, maximum impact
 
Ecological Succession. ( ECOSYSTEM, B. Pharmacy, 1st Year, Sem-II, Environmen...
Ecological Succession. ( ECOSYSTEM, B. Pharmacy, 1st Year, Sem-II, Environmen...Ecological Succession. ( ECOSYSTEM, B. Pharmacy, 1st Year, Sem-II, Environmen...
Ecological Succession. ( ECOSYSTEM, B. Pharmacy, 1st Year, Sem-II, Environmen...
 
Making and Justifying Mathematical Decisions.pdf
Making and Justifying Mathematical Decisions.pdfMaking and Justifying Mathematical Decisions.pdf
Making and Justifying Mathematical Decisions.pdf
 
An Overview of Mutual Funds Bcom Project.pdf
An Overview of Mutual Funds Bcom Project.pdfAn Overview of Mutual Funds Bcom Project.pdf
An Overview of Mutual Funds Bcom Project.pdf
 
Measures of Dispersion and Variability: Range, QD, AD and SD
Measures of Dispersion and Variability: Range, QD, AD and SDMeasures of Dispersion and Variability: Range, QD, AD and SD
Measures of Dispersion and Variability: Range, QD, AD and SD
 
Mehran University Newsletter Vol-X, Issue-I, 2024
Mehran University Newsletter Vol-X, Issue-I, 2024Mehran University Newsletter Vol-X, Issue-I, 2024
Mehran University Newsletter Vol-X, Issue-I, 2024
 
INDIA QUIZ 2024 RLAC DELHI UNIVERSITY.pptx
INDIA QUIZ 2024 RLAC DELHI UNIVERSITY.pptxINDIA QUIZ 2024 RLAC DELHI UNIVERSITY.pptx
INDIA QUIZ 2024 RLAC DELHI UNIVERSITY.pptx
 
Advance Mobile Application Development class 07
Advance Mobile Application Development class 07Advance Mobile Application Development class 07
Advance Mobile Application Development class 07
 
Nutritional Needs Presentation - HLTH 104
Nutritional Needs Presentation - HLTH 104Nutritional Needs Presentation - HLTH 104
Nutritional Needs Presentation - HLTH 104
 
Unit-IV; Professional Sales Representative (PSR).pptx
Unit-IV; Professional Sales Representative (PSR).pptxUnit-IV; Professional Sales Representative (PSR).pptx
Unit-IV; Professional Sales Representative (PSR).pptx
 
Holdier Curriculum Vitae (April 2024).pdf
Holdier Curriculum Vitae (April 2024).pdfHoldier Curriculum Vitae (April 2024).pdf
Holdier Curriculum Vitae (April 2024).pdf
 
ICT Role in 21st Century Education & its Challenges.pptx
ICT Role in 21st Century Education & its Challenges.pptxICT Role in 21st Century Education & its Challenges.pptx
ICT Role in 21st Century Education & its Challenges.pptx
 
Mixin Classes in Odoo 17 How to Extend Models Using Mixin Classes
Mixin Classes in Odoo 17  How to Extend Models Using Mixin ClassesMixin Classes in Odoo 17  How to Extend Models Using Mixin Classes
Mixin Classes in Odoo 17 How to Extend Models Using Mixin Classes
 
Mattingly "AI & Prompt Design: The Basics of Prompt Design"
Mattingly "AI & Prompt Design: The Basics of Prompt Design"Mattingly "AI & Prompt Design: The Basics of Prompt Design"
Mattingly "AI & Prompt Design: The Basics of Prompt Design"
 
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
 

.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