SlideShare ist ein Scribd-Unternehmen logo
1 von 88
Downloaden Sie, um offline zu lesen
Actually, I’m a
Spy Turtle.
Actually, I’m a
Spy Turtle.
QW
I recommend Uncle
Bob’s “The Little
Mocker” post
WS
Validate client
Authenticate user
Issue access token
clientId, clientSecret
email, password
access token
Client
User
class SignInService(clientService: ClientService,
authenticatorService: AuthentictorService,
accessTokenService: TokenService
) {
def signIn(clientId: String, clientSecret: String, email: String,
password: String): Future[AccessToken] = {
for {
client <- clientService.validateClient(clientId, clientSecret)
user <- authenticatorService.authenticateUser(email, password)
accessToken <- accessTokenService.createAccessToken(user.id,
client.id)
} yield (accessToken)
}
class SignInService(clientService: ClientService,
authenticatorService: AuthentictorService,
accessTokenService: TokenService
) {
def signIn(clientId: String, clientSecret: String, email: String,
password: String): Future[AccessToken] = {
for {
client <- clientService.validateClient(clientId, clientSecret)
user <- authenticatorService.authenticateUser(email, password)
accessToken <- accessTokenService.createAccessToken(user.id,
client.id)
} yield (accessToken)
}
class SignInService(clientService: ClientService,
authenticatorService: AuthentictorService,
accessTokenService: TokenService
) {
def signIn(clientId: String, clientSecret: String, email: String,
password: String): Future[AccessToken] = {
for {
client <- clientService.validateClient(clientId, clientSecret)
user <- authenticatorService.authenticateUser(email, password)
accessToken <- accessTokenService.createAccessToken(user.id,
client.id)
} yield (accessToken)
}
class SignInService(clientService: ClientService,
authenticatorService: AuthentictorService,
accessTokenService: TokenService
) {
def signIn(clientId: String, clientSecret: String, email: String,
password: String): Future[AccessToken] = {
for {
client <- clientService.validateClient(clientId, clientSecret)
user <- authenticatorService.authenticateUser(email, password)
accessToken <- accessTokenService.createAccessToken(user.id,
client.id)
} yield (accessToken)
}
T
class SignInService(clientService: ClientService,
authenticatorService: AuthentictorService,
accessTokenService: TokenService
) {
def signIn(clientId: String, clientSecret: String, email: String,
password: String): Future[AccessToken] = {
for {
client <- clientService.validateClient(clientId, clientSecret)
user <- authenticatorService.authenticateUser(email, password)
accessToken <- accessTokenService.createAccessToken(user.id,
client.id)
} yield (accessToken)
}
class ClientService(jsonClient: JsonClient) {
def validateClient(clientId: String, clientSecret: String):
Future[Client]={
jsonClient.getJson(
Path() / "clients" / clientId
).map {
case JsonResponse(OkStatus, json, _, _) => {
val id = (json  "id").as[Long]
val secret = (json  "secret").as[String]
if (secret != clientSecret) {
throw new Exception("Client doesn't match")
}
Client(id)
class ClientService(jsonClient: JsonClient) {
def validateClient(clientId: String, clientSecret: String):
Future[Client]={
jsonClient.getJson(
Path() / "clients" / clientId
).map {
case JsonResponse(OkStatus, json, _, _) => {
val id = (json  "id").as[Long]
val secret = (json  "secret").as[String]
if (secret != clientSecret) {
throw new Exception("Client doesn't match")
}
Client(id)
class ClientService(jsonClient: JsonClient) {
def validateClient(clientId: String, clientSecret: String):
Future[Client]={
jsonClient.getJson(
Path() / "clients" / clientId
).map {
case JsonResponse(OkStatus, json, _, _) => {
val id = (json  "id").as[Long]
val secret = (json  "secret").as[String]
if (secret != clientSecret) {
throw new Exception("Client doesn't match")
}
Client(id)
class ClientService(jsonClient: JsonClient) {
def validateClient(clientId: String, clientSecret: String):
Future[Client]={
jsonClient.getJson(
Path() / "clients" / clientId
).map {
case JsonResponse(OkStatus, json, _, _) => {
val id = (json  "id").as[Long]
val secret = (json  "secret").as[String]
if (secret != clientSecret) {
throw new Exception("Client doesn't match")
}
Client(id)
class ClientService(jsonClient: JsonClient) {
def validateClient(clientId: String, clientSecret: String):
Future[Client]={
jsonClient.getJson(
Path() / "clients" / clientId
).map {
case JsonResponse(OkStatus, json, _, _) => {
val id = (json  "id").as[Long]
val secret = (json  "secret").as[String]
if (secret != clientSecret) {
throw new Exception("Client doesn't match")
}
Client(id)
EL
class ClientService(jsonClient: JsonClient) {
def validateClient(clientId: String, clientSecret: String):
Future[Client]={
jsonClient.getJson(
Path() / "clients" / clientId
).map {
case JsonResponse(OkStatus, json, _, _) => {
val id = (json  "id").as[Long]
val secret = (json  "secret").as[String]
if (secret != clientSecret) {
throw new Exception("Client doesn't match")
}
Client(id)
"returns client if credentials match" in new Scope {
val jsonClient = mock[JsonClient]
val clientService = new ClientService(jsonClient)
val jsonResponse = JsonResponse(OkStatus, Json.fromString(...))
when(jsonClient.get(Path() / "clients" / "clientId")
.thenReturn(Future.value(jsonResponse))
clientService.validateClient("clientId", "secret")
==== Client(5)
}
"returns client if credentials match" in new Scope {
val jsonClient = mock[JsonClient]
val clientService = new ClientService(jsonClient)
val jsonResponse = JsonResponse(OkStatus,Json.fromString(...))
when(jsonClient.get(Path() / "clients" / "clientId")
.thenReturn(Future.value(jsonResponse))
clientService.validateClient("clientId", "secret")
==== Client(5)
}
"returns client if credentials match" in new Scope {
val jsonClient = mock[JsonClient]
val clientService = new ClientService(jsonClient)
val jsonResponse = JsonResponse(OkStatus, Json.fromString(...)
when(jsonClient.get(Path() / "clients" / "clientId")
.thenReturn(Future.value(jsonResponse))
clientService.validateClient("clientId", "secret")
==== Client(5)
}
"returns client if credentials match" in new Scope {
val jsonClient = mock[JsonClient]
val clientService = new ClientService(jsonClient)
val jsonResponse = JsonResponse(OkStatus,Json.fromString(...))
when(jsonClient.get(Path() / "clients" / "clientId")
.thenReturn(Future.value(jsonResponse))
clientService.validateClient("clientId", "secret")
==== Client(5)
}
"returns client if credentials match" in new Scope {
val jsonClient = mock[JsonClient]
val clientService = new ClientService(jsonClient)
val jsonResponse = JsonResponse(OkStatus,Json.fromString(...))
when(jsonClient.get(Path() / "clients" / "clientId")
.thenReturn(Future.value(jsonResponse))
clientService.validateClient("clientId", "secret")
==== Client(5)
}
"returns client if credentials match" in new Scope {
val jsonClient = mock[JsonClient]
val clientService = new ClientService(jsonClient)
val jsonResponse = JsonResponse(OkStatus,Json.fromString(...))
when(jsonClient.get(Path() / "clients" / "clientId")
.thenReturn(Future.value(jsonResponse))
clientService.validateClient("clientId", "secret")
==== Client(5)
}
B
F
class ClientService(jsonClient: JsonClient) {
def validateClient(clientId: String, clientSecret: String):
Future[Client]={
jsonClient.getJson(
Path() / "clients" / clientId
).map {
case JsonResponse(OkStatus, json, _, _) => {
val id = (json  "id").as[Long]
val secret = (json  "secret").as[String]
if (secret != clientSecret) {
throw new Exception("Client doesn't match")
}
Client(id)
class ClientService(getJson: (Path) => Future[JsonResponse]) {
def validateClient(clientId: String, clientSecret: String):
Future[Client]={
getJson(
Path() / "clients" / clientId
).map {
case JsonResponse(OkStatus, json, _, _) => {
val id = (json  "id").as[Long]
val secret = (json  "secret").as[String]
if (secret != clientSecret) {
throw new Exception("Client doesn't match")
}
Client(id)
:I
val jsonClient = JsonClient(host)
val clientService = new ClientService(jsonClient.getJson)
val jsonClient = JsonClient(host)
val clientService = new ClientService(jsonClient.getJson)
"returns client if credentials match" in new Scope {
val jsonResponse = JsonResponse(OkStatus, Json.fromString(...)
val clientService = new ClientService(_ => Future.value(jsonResponse))
clientService.validateClient("clientId", "secret") ==== Client(5)
}
"returns client if credentials match" in new Scope {
val jsonResponse = JsonResponse(OkStatus, Json.fromString(...)
val clientService = new ClientService(_ => Future.value(jsonResponse))
clientService.validateClient("clientId", "secret") ==== Client(5)
}
"returns client if credentials match" in new Scope {
val jsonResponse = JsonResponse(OkStatus, Json.fromString(...)
val clientService = new ClientService(_ => Future.value(jsonResponse))
clientService.validateClient("clientId", "secret") ==== Client(5)
}
"returns client if credentials match" in new Scope {
val jsonResponse = JsonResponse(OkStatus, Json.fromString(...)
val clientService = new ClientService(_ => Future.value(jsonResponse))
clientService.validateClient("clientId", "secret") ==== Client(5)
}
"returns client if credentials match" in new Scope {
val jsonResponse = JsonResponse(OkStatus, Json.fromString(...)
val clientService = new ClientService(_ => Future.value(jsonResponse))
clientService.validateClient("clientId", "secret") ==== Client(5)
}
!E
when(jsonClient.getJson(Path()/"clients"/"clientId")
.thenReturn(Future.value(jsonResponse))
:CA
"returns client if credentials match" in new Scope {
val jsonResponse = JsonResponse(OkStatus, Json.fromString(...)
var arg: Option[Path] = None
val getJson = (path:Path) => {
arg = Some(path)
Future.value(jsonResponse)
}
val clientService = new ClientService(getJson)
clientService.validateClient("clientId", "secret")) ==== Client(5)
arg ==== Some(Path() / "clients" / "clientId")
}
"returns client if credentials match" in new Scope {
val jsonResponse = JsonResponse(OkStatus, Json.fromString(...)
var arg: Option[Path] = None
val getJson = (path:Path) => {
arg = Some(path)
Future.value(jsonResponse)
}
val clientService = new ClientService(getJson)
clientService.validateClient("clientId", "secret")) ==== Client(5)
arg ==== Some(Path() / "clients" / "clientId")
}
:S
:MF
–Martin Fowler
http://martinfowler.com/articles/mocksArentStubs.html#TheDifferenceBetweenMocksAndStubs
~Martin Fowler
http://martinfowler.com/articles/mocksArentStubs.html#TheDifferenceBetweenMocksAndStubs
~Martin Fowler
http://martinfowler.com/articles/mocksArentStubs.html#TheDifferenceBetweenMocksAndStubs
intermediate state
~Martin Fowler
http://martinfowler.com/articles/mocksArentStubs.html#TheDifferenceBetweenMocksAndStubs
Side effects
Yay! No more
mock soup
FSB
Validate client
Authenticate user
Issue access token
clientId, clientSecret
email, password
access token
Client
User
class SignInService(
clientService: ClientService,
authenticatorService: AuthentictorService,
accessTokenService: TokenService
) {
def signIn(clientId: String, clientSecret: String, email: String,
password: String): Future[AccessToken] = {
for {
client <- clientService.validateClient(clientId, clientSecret)
user <- authenticatorService.authenticateUser(email, password)
accessToken <- accessTokenService.createAccessToken(user.id,
client.id)
} yield (accessToken)
}
class SignInService(
clientService: ClientService,
authenticatorService: AuthentictorService,
accessTokenService: TokenService
) {
def signIn(clientId: String, clientSecret: String, email: String,
password: String): Future[AccessToken] = {
for {
client <- clientService.validateClient(clientId, clientSecret)
user <- authenticatorService.authenticateUser(email, password)
accessToken <- accessTokenService.createAccessToken(user.id,
client.id)
} yield (accessToken)
}
class SignInService(
validateClient: (String, String) => Future[Client],
authenticateUser: (String, String) => Future[User],
createAccessToken: (Long, Long) => Future[AccessToken]
) {
def signIn(clientId: String, clientSecret: String, email: String,
password: String): Future[AccessToken] = {
for {
client <- validateClient(clientId, clientSecret)
user <- authenticateUser(email, password)
accessToken <- createAccessToken(user.id, client.id)
} yield (accessToken)
}
:FO
object SignIn {
def signIn(validateClient: (String, String) => Future[Client],
authenticateUser: (String, String) => Future[User],
createAccessToken: (Long, Long) => Future[AccessToken])
(clientId: String, clientSecret: String, email: String,
password: String): Future[AccessToken] = {
for {
client <- validateClient(clientId, clientSecret)
user <- authenticateUser(email, password)
accessToken <- createAccessToken(user.id, client.id)
} yield (accessToken)
}
}
object SignIn {
def signIn(validateClient: (String, String) => Future[Client],
authenticateUser: (String, String) => Future[User],
createAccessToken: (Long, Long) => Future[AccessToken])
(clientId: String, clientSecret: String, email: String,
password: String): Future[AccessToken] = {
for {
client <- validateClient(clientId, clientSecret)
user <- authenticateUser(email, password)
accessToken <- createAccessToken(user.id, client.id)
} yield (accessToken)
}
}
:C
object SignIn {
def signIn(validateClient: (String, String) => Future[Client],
authenticateUser: (String, String) => Future[User],
createAccessToken: (Long, Long) => Future[AccessToken])
(clientId: String, clientSecret: String, email: String,
password: String): Future[AccessToken] = {
for {
client <- validateClient(clientId, clientSecret)
user <- authenticateUser(email, password)
accessToken <- createAccessToken(user.id, client.id)
} yield (accessToken)
}
}
class SignInService(
validateClient: (String, String) => Future[Client],
authenticateUser: (String, String) => Future[User],
createAccessToken: (Long, Long) => Future[AccessToken]
) {
def signIn(clientId: String, clientSecret: String, email: String,
password: String): Future[AccessToken] = {
for {
client <- validateClient(clientId, clientSecret)
user <- authenticateUser(email, password)
accessToken <- createAccessToken(user.id, client.id)
} yield (accessToken)
}
:N
class SignInService(
validateClient: (String, String) => Future[Client],
authenticateUser: (String, String) => Future[User],
createAccessToken: (Long, Long) => Future[AccessToken]
) {
def signIn(clientId: String, clientSecret: String, email: String,
password: String): Future[AccessToken] = {
for {
client <- validateClient(clientId, clientSecret)
user <- authenticateUser(email, password)
accessToken <- createAccessToken(user.id, client.id)
} yield (accessToken)
}
class SignInService(
validateClient: (String, String) => Future[Client],
authenticateUser: (String, String) => Future[User],
createAccessToken: (Long, Long) => Future[AccessToken]
) {
def signIn(clientId: String, clientSecret: String, email: String,
password: String): Future[AccessToken] = {
for {
client <- validateClient(clientId, clientSecret)
user <- authenticateUser(email, password)
accessToken <- createAccessToken(user.id, client.id)
} yield (accessToken)
}
class SignInService(
validateClient: (String, String) => Future[Client],
authenticateUser: (String, String) => Future[User],
createAccessToken: (Long, Long) => Future[AccessToken]
) {
def signIn(clientId: String, clientSecret: String, email: String,
password: String): Future[AccessToken] = {
for {
client <- validateClient(clientId, clientSecret)
user <- authenticateUser(email, password)
accessToken <- createAccessToken(user.id, client.id)
} yield (accessToken)
}
:IJA
class SignInService(
validateClient: (String, String) => Future[Client],
authenticateUser: (String, String) => Future[User],
createAccessToken: (Long, Long) => Future[AccessToken]
) {
def signIn(clientId: String, clientSecret: String, email: String,
password: String): Future[AccessToken] = {
for {
client <- validateClient(clientId, clientSecret)
user <- authenticateUser(email, password)
accessToken <- createAccessToken(user.id, client.id)
} yield (accessToken)
}
class SignInService(
validateClient: (ClientId, ClientSecret) => Future[Client],
authenticateUser: (String, String) => Future[User],
createAccessToken: (Long, Long) => Future[AccessToken]
) {
def signIn(clientId: String, clientSecret: String, email: String,
password: String): Future[AccessToken] = {
for {
client <- validateClient(clientId, clientSecret)
user <- authenticateUser(email, password)
accessToken <- createAccessToken(user.id, client.id)
} yield (accessToken)
}
:W
object SignInApi extends FinagleBasedServer with AppConfigComponent{
val clientsJsonClient = JsonClient(host)
val tokensClient = JsonClient(host)
val dbClient = MySqlClient(dbconfig)
val passwordsRepo = new PasswordRepository(dbClient.prepare, dbClient.execute)
val clientService = new ClientService(clientsJsonClient.get)
val authenticatorService = new AuthentictorService(passwordsRepo.getPassword)
val tokenService = new TokenService(tokensClient.get)
val signInService = new SignInService(
clientService.validateClient,
authenticatorService.authenticateUser,
tokenService.createAccessToken
)
val signInHandler = new SignInHandler(signInService.signIn)
override def createRoutes(httpServer: HttpServer): Unit = {
httpServer.register("/sign-in", signInHandler)
}
}
MSEV
trait JsonClients {
self: ConfigComponent =>
val clientsJsonClient = JsonClient(config.clientsHost)
val tokensClient = JsonClient(config.tokensHost)
}
trait Repositories {
self: ConfigComponent =>
val dbClient = MySqlClient(config.dbHost, config.dbName, ...)
val passwordsRepo = new PasswordRepository(dbClient.prepare,
dbClient.execute)
}
trait Repositories {
self: ConfigComponent =>
val dbClient = MySqlClient(config.dbHost, config.dbName, ...)
val passwordRepo = new PasswordRepository(dbClient.prepare,
dbClient.execute)
}
trait Services extends JsonClients with Repositories {
self: ConfigComponent =>
val clientService = new ClientService(clientsJsonClient.get)
val authenticatorService = new AuthentictorService(passwordsRepo.getPassword
val tokenService = new TokenService(tokensClient.get)
val signInService = new SignInService(
clientService.validateClient,
authenticatorService.authenticateUser,
tokenService.createAccessToken
)
}
trait Services extends JsonClients with Repositories {
self: ConfigComponent =>
val clientService = new ClientService(clientsJsonClient.get)
val authenticatorService = new AuthentictorService(passwordsRepo.getPassword
val tokenService = new TokenService(tokensClient.get)
val signInService = new SignInService(
clientService.validateClient,
authenticatorService.authenticateUser,
tokenService.createAccessToken
)
}
trait Services extends JsonClients with Repositories {
self: ConfigComponent =>
val clientService = new ClientService(clientsJsonClient.get)
val authenticatorService = new AuthentictorService(passwordsRepo.getPassword
val tokenService = new TokenService(tokensClient.get)
val signInService = new SignInService(
clientService.validateClient,
authenticatorService.authenticateUser,
tokenService.createAccessToken
)
}
trait Services extends JsonClients with Repositories {
self: ConfigComponent =>
val clientService = new ClientService(clientsJsonClient.get)
val authenticatorService = new AuthentictorService(passwordsRepo.getPassword
val tokenService = new TokenService(tokensClient.get)
val signInService = new SignInService(
clientService.validateClient,
authenticatorService.authenticateUser,
tokenService.createAccessToken
)
}
object ExampleSignInApi extends FinagleBasedServer
with ConfigComponent
with Services{
val signInHandler = new SignInHandler(signInService.signIn)
override def createRoutes(httpServer: HttpServer): Unit = {
httpServer.register("/sign-in", signInHandler)
}
}
S
object ExampleSignInApi extends FinagleBasedServer
with ConfigComponent
with Services{
val signInHandler = new SignInHandler(signInService.signIn)
override def createRoutes(httpServer: HttpServer): Unit = {
httpServer.register("/sign-in", signInHandler)
}
}
S
H
●
●
●
●
E
def getUser(id: Int): Reader[DB,User]
= Reader( (db:DB) => User("duana") )
def getTracks(user: User): Reader[DB,Track]
= Reader( (db:DB) => Track(42))
val myProgram: Reader[DB,String] =
for {
user <- getUser(123)
track <- getTracks(user)
} yield track.toString
myProgram.perform(db)
●
●
●
●
TE
Manual DI Magic DI
● Requires discipline
● Static check
● No framework or fancy
language features to learn
● Boring
● Enforces consistency
● Runtime check?
● Problems can be hare-y
● Slick
U
Manual DI Magic DI (Framework)
● Requires discipline
● Static check
● No framework or fancy
language features to learn
● Boring
● Enforces consistency
● Runtime check?
● Problems can be hare-y
● Slick
Stop spreading
the news!
:L
Manual DI Magic DI (Framework)
● Requires discipline
● Static check
● No framework or fancy
language features to learn
● Boring
● Enforces consistency
● Runtime check?
● Problems can be hare-y
● Slick
Manual DI Magic DI (Framework)
● Requires discipline
● Static check
● No framework or fancy
language features to learn
● Boring
● Enforces consistency
● Runtime check?
● Problems can be hare-y
● Slick
Manual DI Magic DI (Framework)
● Requires discipline
● Static check
● No framework or fancy
language features to learn
● Boring
● Enforces consistency
● Runtime check?
● Problems can be hare-y
● Slick
:M
def makeTalk(
askChrisBerkhout: (Talk) => Better[Talk],
askAaronLevinAboutFP: (None) => Some[Idea],
askBrianGuthrieAboutClojure: (Idea) => Better[Idea]
)(ideas: Talk): Better[Talk]
makeTalk(..) was invoked by com.thoughtworks.Birgitta
@ThoughtWorks, @SoundCloudDev
@chrisberkhout, @aaronmblevin, @bguthrie, @birgitta410,
@davcamer, @rentalcustard
@theophani, @ellenkoenig, @harrydeanhudson
Questions @starkcoffee

Weitere ähnliche Inhalte

Andere mochten auch

Andere mochten auch (7)

Actividad de aprendizaje gustavo
Actividad de aprendizaje gustavoActividad de aprendizaje gustavo
Actividad de aprendizaje gustavo
 
Resume_Rajini (1)
Resume_Rajini (1)Resume_Rajini (1)
Resume_Rajini (1)
 
Contratacion electronica y contratacion informatica
Contratacion electronica y contratacion informaticaContratacion electronica y contratacion informatica
Contratacion electronica y contratacion informatica
 
IOT
IOTIOT
IOT
 
Bab 6
Bab 6Bab 6
Bab 6
 
The matrix
The matrix The matrix
The matrix
 
sanny
sannysanny
sanny
 

Ähnlich wie Dependency Injection in Functional Programming

Use Kotlin scripts and Clova SDK to build your Clova extension
Use Kotlin scripts and Clova SDK to build your Clova extensionUse Kotlin scripts and Clova SDK to build your Clova extension
Use Kotlin scripts and Clova SDK to build your Clova extensionLINE Corporation
 
The Testing Games: Mocking, yay!
The Testing Games: Mocking, yay!The Testing Games: Mocking, yay!
The Testing Games: Mocking, yay!Donny Wals
 
Azure Key Vault Integration in Scala
Azure Key Vault Integration in ScalaAzure Key Vault Integration in Scala
Azure Key Vault Integration in ScalaBraja Krishna Das
 
Monolith to Reactive Microservices
Monolith to Reactive MicroservicesMonolith to Reactive Microservices
Monolith to Reactive MicroservicesReactivesummit
 
10 Lessons Learned from using Kafka in 1000 Scala microservices - Scalar Online
10 Lessons Learned from using Kafka in 1000 Scala microservices - Scalar Online10 Lessons Learned from using Kafka in 1000 Scala microservices - Scalar Online
10 Lessons Learned from using Kafka in 1000 Scala microservices - Scalar OnlineNatan Silnitsky
 
The Ring programming language version 1.5.4 book - Part 44 of 185
The Ring programming language version 1.5.4 book - Part 44 of 185The Ring programming language version 1.5.4 book - Part 44 of 185
The Ring programming language version 1.5.4 book - Part 44 of 185Mahmoud Samir Fayed
 
つくってあそぼ Kotlin DSL 第2版
つくってあそぼ Kotlin DSL 第2版つくってあそぼ Kotlin DSL 第2版
つくってあそぼ Kotlin DSL 第2版kamedon39
 
An Introduction to Faye
An Introduction to FayeAn Introduction to Faye
An Introduction to FayeDarren Oakley
 
Kotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan SoaresKotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan SoaresiMasters
 
Websockets talk at Rubyconf Uruguay 2010
Websockets talk at Rubyconf Uruguay 2010Websockets talk at Rubyconf Uruguay 2010
Websockets talk at Rubyconf Uruguay 2010Ismael Celis
 
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代Shengyou Fan
 
AWS에서 자바스크립트 활용 - 서비스와 개발 도구 - AWS Summit Seoul 2017
AWS에서 자바스크립트 활용 - 서비스와 개발 도구 - AWS Summit Seoul 2017AWS에서 자바스크립트 활용 - 서비스와 개발 도구 - AWS Summit Seoul 2017
AWS에서 자바스크립트 활용 - 서비스와 개발 도구 - AWS Summit Seoul 2017Amazon Web Services Korea
 
Data in Motion: Streaming Static Data Efficiently
Data in Motion: Streaming Static Data EfficientlyData in Motion: Streaming Static Data Efficiently
Data in Motion: Streaming Static Data EfficientlyMartin Zapletal
 

Ähnlich wie Dependency Injection in Functional Programming (15)

Use Kotlin scripts and Clova SDK to build your Clova extension
Use Kotlin scripts and Clova SDK to build your Clova extensionUse Kotlin scripts and Clova SDK to build your Clova extension
Use Kotlin scripts and Clova SDK to build your Clova extension
 
The Testing Games: Mocking, yay!
The Testing Games: Mocking, yay!The Testing Games: Mocking, yay!
The Testing Games: Mocking, yay!
 
Azure Key Vault Integration in Scala
Azure Key Vault Integration in ScalaAzure Key Vault Integration in Scala
Azure Key Vault Integration in Scala
 
Monolith to Reactive Microservices
Monolith to Reactive MicroservicesMonolith to Reactive Microservices
Monolith to Reactive Microservices
 
10 Lessons Learned from using Kafka in 1000 Scala microservices - Scalar Online
10 Lessons Learned from using Kafka in 1000 Scala microservices - Scalar Online10 Lessons Learned from using Kafka in 1000 Scala microservices - Scalar Online
10 Lessons Learned from using Kafka in 1000 Scala microservices - Scalar Online
 
The Ring programming language version 1.5.4 book - Part 44 of 185
The Ring programming language version 1.5.4 book - Part 44 of 185The Ring programming language version 1.5.4 book - Part 44 of 185
The Ring programming language version 1.5.4 book - Part 44 of 185
 
Leveraging Symfony2 Forms
Leveraging Symfony2 FormsLeveraging Symfony2 Forms
Leveraging Symfony2 Forms
 
つくってあそぼ Kotlin DSL 第2版
つくってあそぼ Kotlin DSL 第2版つくってあそぼ Kotlin DSL 第2版
つくってあそぼ Kotlin DSL 第2版
 
An Introduction to Faye
An Introduction to FayeAn Introduction to Faye
An Introduction to Faye
 
Kotlin coroutines
Kotlin coroutines Kotlin coroutines
Kotlin coroutines
 
Kotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan SoaresKotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan Soares
 
Websockets talk at Rubyconf Uruguay 2010
Websockets talk at Rubyconf Uruguay 2010Websockets talk at Rubyconf Uruguay 2010
Websockets talk at Rubyconf Uruguay 2010
 
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
[JCConf 2020] 用 Kotlin 跨入 Serverless 世代
 
AWS에서 자바스크립트 활용 - 서비스와 개발 도구 - AWS Summit Seoul 2017
AWS에서 자바스크립트 활용 - 서비스와 개발 도구 - AWS Summit Seoul 2017AWS에서 자바스크립트 활용 - 서비스와 개발 도구 - AWS Summit Seoul 2017
AWS에서 자바스크립트 활용 - 서비스와 개발 도구 - AWS Summit Seoul 2017
 
Data in Motion: Streaming Static Data Efficiently
Data in Motion: Streaming Static Data EfficientlyData in Motion: Streaming Static Data Efficiently
Data in Motion: Streaming Static Data Efficiently
 

Kürzlich hochgeladen

The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is insideshinachiaurasa2
 
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfThe Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfayushiqss
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfproinshot.com
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...masabamasaba
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech studentsHimanshiGarg82
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...SelfMade bd
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...masabamasaba
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrandmasabamasaba
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnAmarnathKambale
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfonteinmasabamasaba
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Hararemasabamasaba
 
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburgmasabamasaba
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension AidPhilip Schwarz
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesVictorSzoltysek
 
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...masabamasaba
 
%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durbanmasabamasaba
 
Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsBert Jan Schrijver
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfkalichargn70th171
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...masabamasaba
 

Kürzlich hochgeladen (20)

The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
 
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfThe Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare
 
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
%in Lydenburg+277-882-255-28 abortion pills for sale in Lydenburg
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Vancouver Psychic Readings, Attraction spells,Br...
 
%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban
 
Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisions
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 

Dependency Injection in Functional Programming

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 9. Actually, I’m a Spy Turtle. QW I recommend Uncle Bob’s “The Little Mocker” post
  • 10.
  • 11.
  • 12.
  • 13.
  • 14. WS
  • 15. Validate client Authenticate user Issue access token clientId, clientSecret email, password access token Client User
  • 16. class SignInService(clientService: ClientService, authenticatorService: AuthentictorService, accessTokenService: TokenService ) { def signIn(clientId: String, clientSecret: String, email: String, password: String): Future[AccessToken] = { for { client <- clientService.validateClient(clientId, clientSecret) user <- authenticatorService.authenticateUser(email, password) accessToken <- accessTokenService.createAccessToken(user.id, client.id) } yield (accessToken) }
  • 17. class SignInService(clientService: ClientService, authenticatorService: AuthentictorService, accessTokenService: TokenService ) { def signIn(clientId: String, clientSecret: String, email: String, password: String): Future[AccessToken] = { for { client <- clientService.validateClient(clientId, clientSecret) user <- authenticatorService.authenticateUser(email, password) accessToken <- accessTokenService.createAccessToken(user.id, client.id) } yield (accessToken) }
  • 18. class SignInService(clientService: ClientService, authenticatorService: AuthentictorService, accessTokenService: TokenService ) { def signIn(clientId: String, clientSecret: String, email: String, password: String): Future[AccessToken] = { for { client <- clientService.validateClient(clientId, clientSecret) user <- authenticatorService.authenticateUser(email, password) accessToken <- accessTokenService.createAccessToken(user.id, client.id) } yield (accessToken) }
  • 19. class SignInService(clientService: ClientService, authenticatorService: AuthentictorService, accessTokenService: TokenService ) { def signIn(clientId: String, clientSecret: String, email: String, password: String): Future[AccessToken] = { for { client <- clientService.validateClient(clientId, clientSecret) user <- authenticatorService.authenticateUser(email, password) accessToken <- accessTokenService.createAccessToken(user.id, client.id) } yield (accessToken) } T
  • 20. class SignInService(clientService: ClientService, authenticatorService: AuthentictorService, accessTokenService: TokenService ) { def signIn(clientId: String, clientSecret: String, email: String, password: String): Future[AccessToken] = { for { client <- clientService.validateClient(clientId, clientSecret) user <- authenticatorService.authenticateUser(email, password) accessToken <- accessTokenService.createAccessToken(user.id, client.id) } yield (accessToken) }
  • 21. class ClientService(jsonClient: JsonClient) { def validateClient(clientId: String, clientSecret: String): Future[Client]={ jsonClient.getJson( Path() / "clients" / clientId ).map { case JsonResponse(OkStatus, json, _, _) => { val id = (json "id").as[Long] val secret = (json "secret").as[String] if (secret != clientSecret) { throw new Exception("Client doesn't match") } Client(id)
  • 22. class ClientService(jsonClient: JsonClient) { def validateClient(clientId: String, clientSecret: String): Future[Client]={ jsonClient.getJson( Path() / "clients" / clientId ).map { case JsonResponse(OkStatus, json, _, _) => { val id = (json "id").as[Long] val secret = (json "secret").as[String] if (secret != clientSecret) { throw new Exception("Client doesn't match") } Client(id)
  • 23. class ClientService(jsonClient: JsonClient) { def validateClient(clientId: String, clientSecret: String): Future[Client]={ jsonClient.getJson( Path() / "clients" / clientId ).map { case JsonResponse(OkStatus, json, _, _) => { val id = (json "id").as[Long] val secret = (json "secret").as[String] if (secret != clientSecret) { throw new Exception("Client doesn't match") } Client(id)
  • 24. class ClientService(jsonClient: JsonClient) { def validateClient(clientId: String, clientSecret: String): Future[Client]={ jsonClient.getJson( Path() / "clients" / clientId ).map { case JsonResponse(OkStatus, json, _, _) => { val id = (json "id").as[Long] val secret = (json "secret").as[String] if (secret != clientSecret) { throw new Exception("Client doesn't match") } Client(id)
  • 25. class ClientService(jsonClient: JsonClient) { def validateClient(clientId: String, clientSecret: String): Future[Client]={ jsonClient.getJson( Path() / "clients" / clientId ).map { case JsonResponse(OkStatus, json, _, _) => { val id = (json "id").as[Long] val secret = (json "secret").as[String] if (secret != clientSecret) { throw new Exception("Client doesn't match") } Client(id) EL
  • 26. class ClientService(jsonClient: JsonClient) { def validateClient(clientId: String, clientSecret: String): Future[Client]={ jsonClient.getJson( Path() / "clients" / clientId ).map { case JsonResponse(OkStatus, json, _, _) => { val id = (json "id").as[Long] val secret = (json "secret").as[String] if (secret != clientSecret) { throw new Exception("Client doesn't match") } Client(id)
  • 27. "returns client if credentials match" in new Scope { val jsonClient = mock[JsonClient] val clientService = new ClientService(jsonClient) val jsonResponse = JsonResponse(OkStatus, Json.fromString(...)) when(jsonClient.get(Path() / "clients" / "clientId") .thenReturn(Future.value(jsonResponse)) clientService.validateClient("clientId", "secret") ==== Client(5) }
  • 28. "returns client if credentials match" in new Scope { val jsonClient = mock[JsonClient] val clientService = new ClientService(jsonClient) val jsonResponse = JsonResponse(OkStatus,Json.fromString(...)) when(jsonClient.get(Path() / "clients" / "clientId") .thenReturn(Future.value(jsonResponse)) clientService.validateClient("clientId", "secret") ==== Client(5) }
  • 29. "returns client if credentials match" in new Scope { val jsonClient = mock[JsonClient] val clientService = new ClientService(jsonClient) val jsonResponse = JsonResponse(OkStatus, Json.fromString(...) when(jsonClient.get(Path() / "clients" / "clientId") .thenReturn(Future.value(jsonResponse)) clientService.validateClient("clientId", "secret") ==== Client(5) }
  • 30. "returns client if credentials match" in new Scope { val jsonClient = mock[JsonClient] val clientService = new ClientService(jsonClient) val jsonResponse = JsonResponse(OkStatus,Json.fromString(...)) when(jsonClient.get(Path() / "clients" / "clientId") .thenReturn(Future.value(jsonResponse)) clientService.validateClient("clientId", "secret") ==== Client(5) }
  • 31. "returns client if credentials match" in new Scope { val jsonClient = mock[JsonClient] val clientService = new ClientService(jsonClient) val jsonResponse = JsonResponse(OkStatus,Json.fromString(...)) when(jsonClient.get(Path() / "clients" / "clientId") .thenReturn(Future.value(jsonResponse)) clientService.validateClient("clientId", "secret") ==== Client(5) }
  • 32. "returns client if credentials match" in new Scope { val jsonClient = mock[JsonClient] val clientService = new ClientService(jsonClient) val jsonResponse = JsonResponse(OkStatus,Json.fromString(...)) when(jsonClient.get(Path() / "clients" / "clientId") .thenReturn(Future.value(jsonResponse)) clientService.validateClient("clientId", "secret") ==== Client(5) } B
  • 33. F
  • 34. class ClientService(jsonClient: JsonClient) { def validateClient(clientId: String, clientSecret: String): Future[Client]={ jsonClient.getJson( Path() / "clients" / clientId ).map { case JsonResponse(OkStatus, json, _, _) => { val id = (json "id").as[Long] val secret = (json "secret").as[String] if (secret != clientSecret) { throw new Exception("Client doesn't match") } Client(id)
  • 35. class ClientService(getJson: (Path) => Future[JsonResponse]) { def validateClient(clientId: String, clientSecret: String): Future[Client]={ getJson( Path() / "clients" / clientId ).map { case JsonResponse(OkStatus, json, _, _) => { val id = (json "id").as[Long] val secret = (json "secret").as[String] if (secret != clientSecret) { throw new Exception("Client doesn't match") } Client(id) :I
  • 36. val jsonClient = JsonClient(host) val clientService = new ClientService(jsonClient.getJson)
  • 37. val jsonClient = JsonClient(host) val clientService = new ClientService(jsonClient.getJson)
  • 38. "returns client if credentials match" in new Scope { val jsonResponse = JsonResponse(OkStatus, Json.fromString(...) val clientService = new ClientService(_ => Future.value(jsonResponse)) clientService.validateClient("clientId", "secret") ==== Client(5) }
  • 39. "returns client if credentials match" in new Scope { val jsonResponse = JsonResponse(OkStatus, Json.fromString(...) val clientService = new ClientService(_ => Future.value(jsonResponse)) clientService.validateClient("clientId", "secret") ==== Client(5) }
  • 40. "returns client if credentials match" in new Scope { val jsonResponse = JsonResponse(OkStatus, Json.fromString(...) val clientService = new ClientService(_ => Future.value(jsonResponse)) clientService.validateClient("clientId", "secret") ==== Client(5) }
  • 41. "returns client if credentials match" in new Scope { val jsonResponse = JsonResponse(OkStatus, Json.fromString(...) val clientService = new ClientService(_ => Future.value(jsonResponse)) clientService.validateClient("clientId", "secret") ==== Client(5) }
  • 42. "returns client if credentials match" in new Scope { val jsonResponse = JsonResponse(OkStatus, Json.fromString(...) val clientService = new ClientService(_ => Future.value(jsonResponse)) clientService.validateClient("clientId", "secret") ==== Client(5) } !E
  • 44. "returns client if credentials match" in new Scope { val jsonResponse = JsonResponse(OkStatus, Json.fromString(...) var arg: Option[Path] = None val getJson = (path:Path) => { arg = Some(path) Future.value(jsonResponse) } val clientService = new ClientService(getJson) clientService.validateClient("clientId", "secret")) ==== Client(5) arg ==== Some(Path() / "clients" / "clientId") }
  • 45. "returns client if credentials match" in new Scope { val jsonResponse = JsonResponse(OkStatus, Json.fromString(...) var arg: Option[Path] = None val getJson = (path:Path) => { arg = Some(path) Future.value(jsonResponse) } val clientService = new ClientService(getJson) clientService.validateClient("clientId", "secret")) ==== Client(5) arg ==== Some(Path() / "clients" / "clientId") } :S
  • 46. :MF
  • 51. Yay! No more mock soup FSB
  • 52. Validate client Authenticate user Issue access token clientId, clientSecret email, password access token Client User
  • 53. class SignInService( clientService: ClientService, authenticatorService: AuthentictorService, accessTokenService: TokenService ) { def signIn(clientId: String, clientSecret: String, email: String, password: String): Future[AccessToken] = { for { client <- clientService.validateClient(clientId, clientSecret) user <- authenticatorService.authenticateUser(email, password) accessToken <- accessTokenService.createAccessToken(user.id, client.id) } yield (accessToken) }
  • 54. class SignInService( clientService: ClientService, authenticatorService: AuthentictorService, accessTokenService: TokenService ) { def signIn(clientId: String, clientSecret: String, email: String, password: String): Future[AccessToken] = { for { client <- clientService.validateClient(clientId, clientSecret) user <- authenticatorService.authenticateUser(email, password) accessToken <- accessTokenService.createAccessToken(user.id, client.id) } yield (accessToken) }
  • 55. class SignInService( validateClient: (String, String) => Future[Client], authenticateUser: (String, String) => Future[User], createAccessToken: (Long, Long) => Future[AccessToken] ) { def signIn(clientId: String, clientSecret: String, email: String, password: String): Future[AccessToken] = { for { client <- validateClient(clientId, clientSecret) user <- authenticateUser(email, password) accessToken <- createAccessToken(user.id, client.id) } yield (accessToken) } :FO
  • 56. object SignIn { def signIn(validateClient: (String, String) => Future[Client], authenticateUser: (String, String) => Future[User], createAccessToken: (Long, Long) => Future[AccessToken]) (clientId: String, clientSecret: String, email: String, password: String): Future[AccessToken] = { for { client <- validateClient(clientId, clientSecret) user <- authenticateUser(email, password) accessToken <- createAccessToken(user.id, client.id) } yield (accessToken) } }
  • 57. object SignIn { def signIn(validateClient: (String, String) => Future[Client], authenticateUser: (String, String) => Future[User], createAccessToken: (Long, Long) => Future[AccessToken]) (clientId: String, clientSecret: String, email: String, password: String): Future[AccessToken] = { for { client <- validateClient(clientId, clientSecret) user <- authenticateUser(email, password) accessToken <- createAccessToken(user.id, client.id) } yield (accessToken) } }
  • 58. :C object SignIn { def signIn(validateClient: (String, String) => Future[Client], authenticateUser: (String, String) => Future[User], createAccessToken: (Long, Long) => Future[AccessToken]) (clientId: String, clientSecret: String, email: String, password: String): Future[AccessToken] = { for { client <- validateClient(clientId, clientSecret) user <- authenticateUser(email, password) accessToken <- createAccessToken(user.id, client.id) } yield (accessToken) } }
  • 59. class SignInService( validateClient: (String, String) => Future[Client], authenticateUser: (String, String) => Future[User], createAccessToken: (Long, Long) => Future[AccessToken] ) { def signIn(clientId: String, clientSecret: String, email: String, password: String): Future[AccessToken] = { for { client <- validateClient(clientId, clientSecret) user <- authenticateUser(email, password) accessToken <- createAccessToken(user.id, client.id) } yield (accessToken) } :N
  • 60. class SignInService( validateClient: (String, String) => Future[Client], authenticateUser: (String, String) => Future[User], createAccessToken: (Long, Long) => Future[AccessToken] ) { def signIn(clientId: String, clientSecret: String, email: String, password: String): Future[AccessToken] = { for { client <- validateClient(clientId, clientSecret) user <- authenticateUser(email, password) accessToken <- createAccessToken(user.id, client.id) } yield (accessToken) }
  • 61. class SignInService( validateClient: (String, String) => Future[Client], authenticateUser: (String, String) => Future[User], createAccessToken: (Long, Long) => Future[AccessToken] ) { def signIn(clientId: String, clientSecret: String, email: String, password: String): Future[AccessToken] = { for { client <- validateClient(clientId, clientSecret) user <- authenticateUser(email, password) accessToken <- createAccessToken(user.id, client.id) } yield (accessToken) }
  • 62. class SignInService( validateClient: (String, String) => Future[Client], authenticateUser: (String, String) => Future[User], createAccessToken: (Long, Long) => Future[AccessToken] ) { def signIn(clientId: String, clientSecret: String, email: String, password: String): Future[AccessToken] = { for { client <- validateClient(clientId, clientSecret) user <- authenticateUser(email, password) accessToken <- createAccessToken(user.id, client.id) } yield (accessToken) } :IJA
  • 63. class SignInService( validateClient: (String, String) => Future[Client], authenticateUser: (String, String) => Future[User], createAccessToken: (Long, Long) => Future[AccessToken] ) { def signIn(clientId: String, clientSecret: String, email: String, password: String): Future[AccessToken] = { for { client <- validateClient(clientId, clientSecret) user <- authenticateUser(email, password) accessToken <- createAccessToken(user.id, client.id) } yield (accessToken) }
  • 64. class SignInService( validateClient: (ClientId, ClientSecret) => Future[Client], authenticateUser: (String, String) => Future[User], createAccessToken: (Long, Long) => Future[AccessToken] ) { def signIn(clientId: String, clientSecret: String, email: String, password: String): Future[AccessToken] = { for { client <- validateClient(clientId, clientSecret) user <- authenticateUser(email, password) accessToken <- createAccessToken(user.id, client.id) } yield (accessToken) } :W
  • 65. object SignInApi extends FinagleBasedServer with AppConfigComponent{ val clientsJsonClient = JsonClient(host) val tokensClient = JsonClient(host) val dbClient = MySqlClient(dbconfig) val passwordsRepo = new PasswordRepository(dbClient.prepare, dbClient.execute) val clientService = new ClientService(clientsJsonClient.get) val authenticatorService = new AuthentictorService(passwordsRepo.getPassword) val tokenService = new TokenService(tokensClient.get) val signInService = new SignInService( clientService.validateClient, authenticatorService.authenticateUser, tokenService.createAccessToken ) val signInHandler = new SignInHandler(signInService.signIn) override def createRoutes(httpServer: HttpServer): Unit = { httpServer.register("/sign-in", signInHandler) } } MSEV
  • 66. trait JsonClients { self: ConfigComponent => val clientsJsonClient = JsonClient(config.clientsHost) val tokensClient = JsonClient(config.tokensHost) }
  • 67. trait Repositories { self: ConfigComponent => val dbClient = MySqlClient(config.dbHost, config.dbName, ...) val passwordsRepo = new PasswordRepository(dbClient.prepare, dbClient.execute) }
  • 68. trait Repositories { self: ConfigComponent => val dbClient = MySqlClient(config.dbHost, config.dbName, ...) val passwordRepo = new PasswordRepository(dbClient.prepare, dbClient.execute) }
  • 69. trait Services extends JsonClients with Repositories { self: ConfigComponent => val clientService = new ClientService(clientsJsonClient.get) val authenticatorService = new AuthentictorService(passwordsRepo.getPassword val tokenService = new TokenService(tokensClient.get) val signInService = new SignInService( clientService.validateClient, authenticatorService.authenticateUser, tokenService.createAccessToken ) }
  • 70. trait Services extends JsonClients with Repositories { self: ConfigComponent => val clientService = new ClientService(clientsJsonClient.get) val authenticatorService = new AuthentictorService(passwordsRepo.getPassword val tokenService = new TokenService(tokensClient.get) val signInService = new SignInService( clientService.validateClient, authenticatorService.authenticateUser, tokenService.createAccessToken ) }
  • 71. trait Services extends JsonClients with Repositories { self: ConfigComponent => val clientService = new ClientService(clientsJsonClient.get) val authenticatorService = new AuthentictorService(passwordsRepo.getPassword val tokenService = new TokenService(tokensClient.get) val signInService = new SignInService( clientService.validateClient, authenticatorService.authenticateUser, tokenService.createAccessToken ) }
  • 72. trait Services extends JsonClients with Repositories { self: ConfigComponent => val clientService = new ClientService(clientsJsonClient.get) val authenticatorService = new AuthentictorService(passwordsRepo.getPassword val tokenService = new TokenService(tokensClient.get) val signInService = new SignInService( clientService.validateClient, authenticatorService.authenticateUser, tokenService.createAccessToken ) }
  • 73. object ExampleSignInApi extends FinagleBasedServer with ConfigComponent with Services{ val signInHandler = new SignInHandler(signInService.signIn) override def createRoutes(httpServer: HttpServer): Unit = { httpServer.register("/sign-in", signInHandler) } } S
  • 74. object ExampleSignInApi extends FinagleBasedServer with ConfigComponent with Services{ val signInHandler = new SignInHandler(signInService.signIn) override def createRoutes(httpServer: HttpServer): Unit = { httpServer.register("/sign-in", signInHandler) } } S
  • 75. H
  • 77. def getUser(id: Int): Reader[DB,User] = Reader( (db:DB) => User("duana") ) def getTracks(user: User): Reader[DB,Track] = Reader( (db:DB) => Track(42)) val myProgram: Reader[DB,String] = for { user <- getUser(123) track <- getTracks(user) } yield track.toString myProgram.perform(db)
  • 79.
  • 80. TE
  • 81. Manual DI Magic DI ● Requires discipline ● Static check ● No framework or fancy language features to learn ● Boring ● Enforces consistency ● Runtime check? ● Problems can be hare-y ● Slick
  • 82. U Manual DI Magic DI (Framework) ● Requires discipline ● Static check ● No framework or fancy language features to learn ● Boring ● Enforces consistency ● Runtime check? ● Problems can be hare-y ● Slick Stop spreading the news!
  • 83. :L Manual DI Magic DI (Framework) ● Requires discipline ● Static check ● No framework or fancy language features to learn ● Boring ● Enforces consistency ● Runtime check? ● Problems can be hare-y ● Slick
  • 84. Manual DI Magic DI (Framework) ● Requires discipline ● Static check ● No framework or fancy language features to learn ● Boring ● Enforces consistency ● Runtime check? ● Problems can be hare-y ● Slick
  • 85. Manual DI Magic DI (Framework) ● Requires discipline ● Static check ● No framework or fancy language features to learn ● Boring ● Enforces consistency ● Runtime check? ● Problems can be hare-y ● Slick :M
  • 86.
  • 87. def makeTalk( askChrisBerkhout: (Talk) => Better[Talk], askAaronLevinAboutFP: (None) => Some[Idea], askBrianGuthrieAboutClojure: (Idea) => Better[Idea] )(ideas: Talk): Better[Talk] makeTalk(..) was invoked by com.thoughtworks.Birgitta
  • 88. @ThoughtWorks, @SoundCloudDev @chrisberkhout, @aaronmblevin, @bguthrie, @birgitta410, @davcamer, @rentalcustard @theophani, @ellenkoenig, @harrydeanhudson Questions @starkcoffee