SlideShare une entreprise Scribd logo
1  sur  70
Télécharger pour lire hors ligne
Structure your Play
application with
the cake pattern
and test it
Structure a Play application like a cake
We'll build a website for

Toys Basketball Association
Architecture
Player Backend
GET http://localhost:9001/players/1
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 91
{"id":1,"name":"James P.
Sullivan","height":"34 cm","weight":"370
g","team":"Monstropolis"}
Player Backend
GET http://localhost:9001/players/1/photo
HTTP/1.1 200 OK
Last-Modified: Thu, 12 Dec 2013 13:11:02 GMT
Etag: "4911f28b55213..."
Content-Length: 1753583
Cache-Control: max-age=3600
Content-Type: image/jpeg
Date: Mon, 23 Dec 2013 10:01:15 GMT
<binary>
Video Backend
GET http://localhost:9002/videos/top
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 83
[{"id":1,"summary":"dunk","players":[1]},...]
Video Backend
GET http://localhost:9002/videos/1/stream.mp4
range: bytes=200-280
HTTP/1.1 206 Partial Content
Content-Range: bytes 200-280/2154777
Accept-Ranges: bytes
Connection: keep-alive
Content-Length: 81
Content-Type: video/mp4
http:////www.videolan.org/x264.html - options:
cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0
Let's code

•

first version
Proud of ourselves?
let's refactor
Tests with the new version?
Test pyramid
unit tests

def f(input): output
assert output
Test pyramid
component tests
Test pyramid
integration tests
Which tests are possible?
with the actual version
Component hierarchy
how to avoid that?
Introducing components

•

Live coding
Dependencies between components
Dependencies
class TopVideoService {
val videoGateway =
new VideoGateway
val playerGateway =
new PlayerGateway

trait TopVideoServiceComp
extends PlayerGatewayComp
with VideoGatewayComp {
val topVideoService =
new TopVideoService

def topVideos(): [...] = {
videoGateway.top() [...]
}

class TopVideoService {
def topVideos(): [...] = {
videoGateway.top() [...]
}
}

}

Provided service

}
Introducing components
Introducing components

✔

✔

Components expose services only to
other components
One component must depend from
another one to use the exposed service
Testing with components
unit tests
Testing with components
component
tests
Testing with components
component
tests
components as traits
✔

Components with exposed services and
dependencies

✔

Unit tests

✔

Component tests

✔

Integration tests
But...
some drawbacks
•

Testing is not optimal

•

Which dependency should be mocked?

•

The compiler can check that for us
Exposed service abstract
Dependencies
trait TopVideoServiceComp
extends PlayerGatewayComp
with VideoGatewayComp {

trait TopVideoServiceComp
extends PlayerGatewayComp
with VideoGatewayComp {

val topVideoService =
new TopVideoService

def topVideoService:
TopVideoService

[...]

[...]

}

}

Provided service
Defining the desired service
trait TopVideoServiceComp
extends PlayerGatewayComp
with VideoGatewayComp {

trait Application
extends Controller
with TopVideoServiceComp {
def index = [...]

def topVideoService: TopVideoService
}
[...]
}

object Application
extends Application
Defining the desired service
trait TopVideoServiceComp
extends PlayerGatewayComp
with VideoGatewayComp {

trait Application
extends Controller
with TopVideoServiceComp {
def index = [...]

def topVideoService: TopVideoService
}
[...]
}

ro r
r
object Applicationn e
atio
extends lApplication
pi
om
c
Defining the desired service
trait TopVideoServiceComp
extends PlayerGatewayComp
with VideoGatewayComp {

trait Application
extends Controller
with TopVideoServiceComp {
def index = [...]

def topVideoService: TopVideoService
}
[...]
}

ro r
r
object Applicationn e
atio
extends lApplication
pi
om
c
object Application
extends Application {
override val topVideoService =
new TopVideoService
}
Defining the desired service
trait TopVideoServiceComp
extends PlayerGatewayComp
with VideoGatewayComp {

trait Application
extends Controller
with TopVideoServiceComp {
def index = [...]

def topVideoService: TopVideoService
}
[...]
}

trait TopVideoServiceCompImpl
extends TopVideoServiceComp {
override val topVideoService =
new TopVideoService
}

ro r
r
object Applicationn e
atio
extends lApplication
pi
om
c
object Application
extends Application {
override val topVideoService =
new TopVideoService
}
object Application
extends Application
with TopVideoServiceCompImpl
Introducing Registry
object Application
extends Application
with PlayerGatewayCompImpl
with VideoGatewayCompImpl
with HttpClientCompImpl
with TopVideoServiceCompImpl
object Players
extends Players
with PlayerGatewayCompImpl
with VideoGatewayCompImpl
with HttpClientCompImpl
with TopVideoServiceCompImpl

trait Registry
extends HttpClientComp
with PlayerGatewayComp
with VideoGatewayComp
with TopVideoServiceComp
trait RuntimeEnvironment
extends Registry
with VideoGatewayCompImpl
with HttpClientCompImpl
with PlayerGatewayCompImpl
with TopVideoServiceCompImpl

object Application
extends Application
with RuntimeEnvironment
object Players
extends Players
with RuntimeEnvironment
Runtime and Test Registries
trait Registry
extends HttpClientComp
with PlayerGatewayComp
with VideoGatewayComp
with TopVideoServiceComp
trait RuntimeEnvironment extends Registry
with VideoGatewayCompImpl
with HttpClientCompImpl
with PlayerGatewayCompImpl
with TopVideoServiceCompImpl
trait MockEnvironment extends Registry with Mockito {
override val httpClient = mock[HttpClient]
override val playerGateway = mock[PlayerGateway]
override val videoGateway = mock[VideoGateway]
override val topVideoService = mock[TopVideoService]
}
Traits with abstract methods
✔

Components with exposed services and
dependencies

✔

Dependencies checked by compiler

✔

Unit tests

✔

Component tests

✔

Integration tests
drawback of traits inheritance
Introducing self type
Dependencies
trait TopVideoServiceComp
extends PlayerGatewayComp
with VideoGatewayComp {

trait TopVideoServiceComp {
self: PlayerGatewayComp
with VideoGatewayComp =>

def topVideoService:
TopVideoService

def topVideoService:
TopVideoService

[...]

[...]

}

}

Provided service
self type annotation

„Any concrete class that mixed in the
trait must ensure that its type conforms to
the trait's self type“
source: http://docs.scala-lang.org/glossary/#self_type
Traits with self types
✔

Components with exposed services and
only explicit dependencies

✔

Unit tests

✔

Component tests

✔

Integration tests
Parallel @Inject / traits
public class HttpClient {
...
}

trait HttpClientComp {
def httpClient: HttpClient
class HttpClient {
...
}

public class PlayerGateway {
@Inject
private HttpClient httpClient;
<use httpClient>

}
trait PlayerGatewayComp {
self: HttpClientComp =>

}

<use httpClient>

public class VideoGateway {
@Inject
private HttpClient httpClient;
<use httpClient>
}

}
trait VideoGatewayComp {
self: HttpClientComp =>
<use httpClient>
}
Dependencies Injection

•

„side effect“ of Cake pattern

•

dependencies checked by compiler
Alternatives for DI

•

Spring, Guice...

•

DI with macros: macwire
http://typesafe.com/activator/template/macwire-activator
Resolving dependencies at runtime

source: http://apmblog.compuware.com/2013/12/18/the-hidden-class-loading-performance-impact-of-the-spring-framework/
Resolving dependencies at runtime

source: http://apmblog.compuware.com/2013/12/18/the-hidden-class-loading-performance-impact-of-the-spring-framework/
Resolving dependencies at runtime

source: http://apmblog.compuware.com/2013/12/18/the-hidden-class-loading-performance-impact-of-the-spring-framework/
Resolving dependencies at runtime

source: http://apmblog.compuware.com/2013/12/18/the-hidden-class-loading-performance-impact-of-the-spring-framework/
DI with cake pattern

•

dependencies are resolved at compile time

•

no surprise at runtime
traits with self type and implementation
some drawbacks
•

mix interface / implementation

•

difficult to provide alternative runtime
implementation

•

cannot provide component dependency
only for one implementation
traits with self type and implementation
ex with top videos
traits with self type and implementation
Let's fix it
•

decouple interface / implementation
Decouple service definition / impl
trait TopVideoServiceComp {

trait TopVideoServiceComp {
def topVideoService: TopVideoService

self: PlayerGatewayComp
with VideoGatewayComp =>
def topVideoService:
TopVideoService
[impl of TopVideoService]
}

trait TopVideoService {
def topVideos(): Future[Option[Seq[TopVideo]]]
}
}
trait TopVideoServiceCompImpl
extends TopVideoServiceComp {

trait TopVideoServiceCompImpl
extends TopVideoServiceComp {

self: PlayerGatewayComp
with VideoGatewayComp =>

self: PlayerGatewayComp
with VideoGatewayComp =>

override val topVideoService =
new TopVideoServiceImpl

override val topVideoService
= new TopVideoService

class TopVideoServiceImpl
extends TopVideoService {
def topVideos(): Future[Option[Seq[TopVideo]]]
= videoGateway.top() [...]
}

}

}
Decouple service definition / impl
trait TopVideoServiceComp {
def topVideoService: TopVideoService
trait TopVideoService {
def topVideos(): Future[Option[Seq[TopVideo]]]
}
}

Provided service
definition
Dependencies
specific to impl

trait TopVideoServiceCompImpl extends TopVideoServiceComp {
self: PlayerGatewayComp with VideoGatewayComp =>
override val topVideoService = new TopVideoServiceImpl
class TopVideoServiceImpl extends TopVideoService {
def topVideos(): Future[Option[Seq[TopVideo]]] = {
videoGateway.top() [...]
}
}
}

service impl
comparison of all variants
1st version

✔
✗
✗

simple
alternative impl very difficult
forget what to override (in tests)

trait VideoGatewayComp extends HttpClientComp {
val videoGateway = new VideoGateway
sealed trait TopVideosResponse
[...]
class VideoGateway {
def top(): Future[TopVideosResponse] = [...]
}
}
comparison of all variants
2nd version

✔
✗

dependencies checked by compiler
invisible inheritance of other
dependencies

trait VideoGatewayComp extends HttpClientComp {
def videoGateway: VideoGateway
sealed trait TopVideosResponse
[...]
class VideoGateway {
def top(): Future[TopVideosResponse] = [...]
}
}
trait VideoGatewayCompImpl extends VideoGatewayComp {
override val videoGateway = new VideoGateway
}
comparison of all variants
3rd version

✔
✗
✗

explicit dependent components
no separation interface / impl
boilerplate

trait VideoGatewayComp {
self: HttpClientComp =>
def videoGateway: VideoGateway
sealed trait TopVideosResponse
[...]
class VideoGateway {
def top(): Future[TopVideosResponse] = [...]
}
}
trait VideoGatewayCompImpl extends VideoGatewayComp {
self: HttpClientComp =>
override val videoGateway = new VideoGateway
}
comparison of all variants
4th version

✔
✔

trait VideoGatewayComp {

✗

separation interface / impl
flexibility
boilerplate ++

def videoGateway: VideoGateway
sealed trait TopVideosResponse
[...]
trait VideoGateway {
def top(): Future[TopVideosResponse]
}
}
trait VideoGatewayCompImpl extends VideoGatewayComp {
self: HttpClientComp =>
override val videoGateway: VideoGateway = new VideoGatewayImpl
class VideoGatewayImpl extends VideoGateway {
def top(): Future[TopVideosResponse] = [...]
}
}
Number of traits in app

components with
abstract methods

components with
self type
annotations

components with
self type annotations
and real separation
interface /
implementation

16

16

20
Downside of Cake pattern (1)
What do you need?

•

only DI?

•

multiple alternative implementations of
same service?
Downside of Cake pattern (2)

•

compiler error

•

let's minimize it
Reducing # of compiler errors
trait RuntimeEnvironment extends Registry
with HttpClientCompImpl
with VideoGatewayCompImpl
with PlayerGatewayCompImpl
with TopVideoServiceCompImpl

class RuntimeEnvironment extends Registry
with HttpClientCompImpl
with VideoGatewayCompImpl
with PlayerGatewayCompImpl
with TopVideoServiceCompImpl
Downside of Cake pattern (3)

•

compilation speed

✔

minimize it with (abstract) class

✔

let's remove some traits
Removing some traits
class RuntimeEnvironment
extends Registry
with HttpClientCompImpl
with VideoGatewayCompImpl
with PlayerGatewayCompImpl
with TopVideoServiceCompImpl

class RuntimeEnvironment
extends Registry {
override val httpClient =
new HttpClient
override val playerGateway =
new PlayerGateway
override val videoGateway =
new VideoGateway
override val topVideoService =
new TopVideoService

trait HttpClientCompImpl
extends HttpClientComp {
override val httpClient = new HttpClient
}
trait VideoGatewayCompImpl
extends VideoGatewayComp {
self: HttpClientComp =>
override val videoGateway = new VideoGateway
}
trait PlayerGatewayCompImpl
extends PlayerGatewayComp {
[...]
}
trait TopVideoServiceCompImpl
extends TopVideoServiceComp {
[...]
}

}
Number of traits

components with
abstract methods

components with
self type
annotations

components with
self type
annotations and
real separation
interface /
implementation

16

12

20
About testing
different strategies
About testing
About testing
DI ease unit testing

Do no over-use it!
further discussion

•

make cake pattern more manageable with
https://github.com/sullivan-/congeal

trait UService extends hasDependency[URepository] {
  ...
}
Questions?
source: https://github.com/yanns/TPA/
Yann Simon
Software Engineer
Blücherstr. 22
10961 Berlin

yann.simon@leanovate.de
twitter: @simon_yann
Credits
•
•
•
•
•
•

http://www.flickr.com/photos/cefeida/2306611187/
62/366: Cake, redux (Magic Madzik)
http://www.flickr.com/photos/jason_burmeister/2125022193
Iced Tree (Jason)
http://www.flickr.com/photos/leandrociuffo/6270204821
Berlin skyline (Leandro Neumann Ciuffo)
http://www.flickr.com/photos/8047705@N02/5668841148/
Slow and steady (John Liu)
http://www.flickr.com/photos/jcapaldi/4201550567/
Bon Appetit (Jim, the Photographer)
http://www.epicfail.com/2012/07/17/about-to-fail-26/

Contenu connexe

Tendances

Getting Started With CFEngine - Updated Version
Getting Started With CFEngine - Updated VersionGetting Started With CFEngine - Updated Version
Getting Started With CFEngine - Updated VersionCFEngine
 
EWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWD
EWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWDEWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWD
EWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWDRob Tweed
 
EWD 3 Training Course Part 12: QEWD Session Timeout Control
EWD 3 Training Course Part 12: QEWD Session Timeout ControlEWD 3 Training Course Part 12: QEWD Session Timeout Control
EWD 3 Training Course Part 12: QEWD Session Timeout ControlRob Tweed
 
EWD 3 Training Course Part 5a: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5a: First Steps in Building a QEWD ApplicationEWD 3 Training Course Part 5a: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5a: First Steps in Building a QEWD ApplicationRob Tweed
 
EWD 3 Training Course Part 11: Handling Errors in QEWD
EWD 3 Training Course Part 11: Handling Errors in QEWDEWD 3 Training Course Part 11: Handling Errors in QEWD
EWD 3 Training Course Part 11: Handling Errors in QEWDRob Tweed
 
App development with quasar (pdf)
App development with quasar (pdf)App development with quasar (pdf)
App development with quasar (pdf)wonyong hwang
 
EWD 3 Training Course Part 2: EWD 3 Overview
EWD 3 Training Course Part 2: EWD 3 OverviewEWD 3 Training Course Part 2: EWD 3 Overview
EWD 3 Training Course Part 2: EWD 3 OverviewRob Tweed
 
CPAN Packager
CPAN PackagerCPAN Packager
CPAN Packagertechmemo
 
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4Rob Tweed
 
CPAN Packager
CPAN PackagerCPAN Packager
CPAN Packagertechmemo
 
EWD 3 Training Course Part 4: Installing & Configuring QEWD
EWD 3 Training Course Part 4: Installing & Configuring QEWDEWD 3 Training Course Part 4: Installing & Configuring QEWD
EWD 3 Training Course Part 4: Installing & Configuring QEWDRob Tweed
 
EWD 3 Training Course Part 29: Running QEWD as a Service
EWD 3 Training Course Part 29: Running QEWD as a ServiceEWD 3 Training Course Part 29: Running QEWD as a Service
EWD 3 Training Course Part 29: Running QEWD as a ServiceRob Tweed
 
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3Rob Tweed
 
ewd-qoper8-vistarpc: Exposing VistA's RPCs as REST Services
ewd-qoper8-vistarpc: Exposing VistA's RPCs as REST Servicesewd-qoper8-vistarpc: Exposing VistA's RPCs as REST Services
ewd-qoper8-vistarpc: Exposing VistA's RPCs as REST ServicesRob Tweed
 
EWD 3 Training Course Part 3: Summary of EWD 3 Modules
EWD 3 Training Course Part 3: Summary of EWD 3 ModulesEWD 3 Training Course Part 3: Summary of EWD 3 Modules
EWD 3 Training Course Part 3: Summary of EWD 3 ModulesRob Tweed
 
EWD 3 Training Course Part 35: QEWD Session Locking
EWD 3 Training Course Part 35: QEWD Session LockingEWD 3 Training Course Part 35: QEWD Session Locking
EWD 3 Training Course Part 35: QEWD Session LockingRob Tweed
 
Jenkins Pipeline meets Oracle
Jenkins Pipeline meets OracleJenkins Pipeline meets Oracle
Jenkins Pipeline meets OracleOliver Lemm
 
EWD 3 Training Course Part 13: Putting Everything so far into Practice using ...
EWD 3 Training Course Part 13: Putting Everything so far into Practice using ...EWD 3 Training Course Part 13: Putting Everything so far into Practice using ...
EWD 3 Training Course Part 13: Putting Everything so far into Practice using ...Rob Tweed
 

Tendances (20)

Getting Started With CFEngine - Updated Version
Getting Started With CFEngine - Updated VersionGetting Started With CFEngine - Updated Version
Getting Started With CFEngine - Updated Version
 
EWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWD
EWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWDEWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWD
EWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWD
 
Sprint 17
Sprint 17Sprint 17
Sprint 17
 
EWD 3 Training Course Part 12: QEWD Session Timeout Control
EWD 3 Training Course Part 12: QEWD Session Timeout ControlEWD 3 Training Course Part 12: QEWD Session Timeout Control
EWD 3 Training Course Part 12: QEWD Session Timeout Control
 
EWD 3 Training Course Part 5a: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5a: First Steps in Building a QEWD ApplicationEWD 3 Training Course Part 5a: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5a: First Steps in Building a QEWD Application
 
EWD 3 Training Course Part 11: Handling Errors in QEWD
EWD 3 Training Course Part 11: Handling Errors in QEWDEWD 3 Training Course Part 11: Handling Errors in QEWD
EWD 3 Training Course Part 11: Handling Errors in QEWD
 
App development with quasar (pdf)
App development with quasar (pdf)App development with quasar (pdf)
App development with quasar (pdf)
 
EWD 3 Training Course Part 2: EWD 3 Overview
EWD 3 Training Course Part 2: EWD 3 OverviewEWD 3 Training Course Part 2: EWD 3 Overview
EWD 3 Training Course Part 2: EWD 3 Overview
 
CPAN Packager
CPAN PackagerCPAN Packager
CPAN Packager
 
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4
 
CPAN Packager
CPAN PackagerCPAN Packager
CPAN Packager
 
EWD 3 Training Course Part 4: Installing & Configuring QEWD
EWD 3 Training Course Part 4: Installing & Configuring QEWDEWD 3 Training Course Part 4: Installing & Configuring QEWD
EWD 3 Training Course Part 4: Installing & Configuring QEWD
 
EWD 3 Training Course Part 29: Running QEWD as a Service
EWD 3 Training Course Part 29: Running QEWD as a ServiceEWD 3 Training Course Part 29: Running QEWD as a Service
EWD 3 Training Course Part 29: Running QEWD as a Service
 
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
 
ewd-qoper8-vistarpc: Exposing VistA's RPCs as REST Services
ewd-qoper8-vistarpc: Exposing VistA's RPCs as REST Servicesewd-qoper8-vistarpc: Exposing VistA's RPCs as REST Services
ewd-qoper8-vistarpc: Exposing VistA's RPCs as REST Services
 
EWD 3 Training Course Part 3: Summary of EWD 3 Modules
EWD 3 Training Course Part 3: Summary of EWD 3 ModulesEWD 3 Training Course Part 3: Summary of EWD 3 Modules
EWD 3 Training Course Part 3: Summary of EWD 3 Modules
 
Gradle como alternativa a maven
Gradle como alternativa a mavenGradle como alternativa a maven
Gradle como alternativa a maven
 
EWD 3 Training Course Part 35: QEWD Session Locking
EWD 3 Training Course Part 35: QEWD Session LockingEWD 3 Training Course Part 35: QEWD Session Locking
EWD 3 Training Course Part 35: QEWD Session Locking
 
Jenkins Pipeline meets Oracle
Jenkins Pipeline meets OracleJenkins Pipeline meets Oracle
Jenkins Pipeline meets Oracle
 
EWD 3 Training Course Part 13: Putting Everything so far into Practice using ...
EWD 3 Training Course Part 13: Putting Everything so far into Practice using ...EWD 3 Training Course Part 13: Putting Everything so far into Practice using ...
EWD 3 Training Course Part 13: Putting Everything so far into Practice using ...
 

Similaire à Structure your Play application with the cake pattern (and test it)

When Smalltalk Meets the Web
When Smalltalk Meets the WebWhen Smalltalk Meets the Web
When Smalltalk Meets the WebESUG
 
Microsoft Windows Server AppFabric
Microsoft Windows Server AppFabricMicrosoft Windows Server AppFabric
Microsoft Windows Server AppFabricMark Ginnebaugh
 
[rwdsummit2012] Adaptive Images in Responsive Web Design
[rwdsummit2012] Adaptive Images in Responsive Web Design[rwdsummit2012] Adaptive Images in Responsive Web Design
[rwdsummit2012] Adaptive Images in Responsive Web DesignChristopher Schmitt
 
[cssdevconf] Adaptive Images in RWD
[cssdevconf] Adaptive Images in RWD[cssdevconf] Adaptive Images in RWD
[cssdevconf] Adaptive Images in RWDChristopher Schmitt
 
[html5tx] Adaptive Images in Responsive Web Design
[html5tx] Adaptive Images in Responsive Web Design[html5tx] Adaptive Images in Responsive Web Design
[html5tx] Adaptive Images in Responsive Web DesignChristopher Schmitt
 
[convergese] Adaptive Images in Responsive Web Design
[convergese] Adaptive Images in Responsive Web Design[convergese] Adaptive Images in Responsive Web Design
[convergese] Adaptive Images in Responsive Web DesignChristopher Schmitt
 
How to ensure Presto scalability 
in multi use case
How to ensure Presto scalability 
in multi use case How to ensure Presto scalability 
in multi use case
How to ensure Presto scalability 
in multi use case Kai Sasaki
 
[HEWEBAR 2012] Adaptive Images in Responsive Web Design
[HEWEBAR 2012] Adaptive Images in Responsive Web Design[HEWEBAR 2012] Adaptive Images in Responsive Web Design
[HEWEBAR 2012] Adaptive Images in Responsive Web DesignChristopher Schmitt
 
How Bitbucket Pipelines Loads Connect UI Assets Super-fast
How Bitbucket Pipelines Loads Connect UI Assets Super-fastHow Bitbucket Pipelines Loads Connect UI Assets Super-fast
How Bitbucket Pipelines Loads Connect UI Assets Super-fastAtlassian
 
DevOps Workflow: A Tutorial on Linux Containers
DevOps Workflow: A Tutorial on Linux ContainersDevOps Workflow: A Tutorial on Linux Containers
DevOps Workflow: A Tutorial on Linux Containersinside-BigData.com
 
Remote Config REST API and Versioning
Remote Config REST API and VersioningRemote Config REST API and Versioning
Remote Config REST API and VersioningJumpei Matsuda
 
[refreshaustin] Adaptive Images in Responsive Web Design
[refreshaustin] Adaptive Images in Responsive Web Design[refreshaustin] Adaptive Images in Responsive Web Design
[refreshaustin] Adaptive Images in Responsive Web DesignChristopher Schmitt
 
High Velocity DevOps: Four Ways to Leverage CloudFront in Faster DevOps Workf...
High Velocity DevOps: Four Ways to Leverage CloudFront in Faster DevOps Workf...High Velocity DevOps: Four Ways to Leverage CloudFront in Faster DevOps Workf...
High Velocity DevOps: Four Ways to Leverage CloudFront in Faster DevOps Workf...Amazon Web Services
 
Deploying configurable frontend web application containers
Deploying configurable frontend web application containersDeploying configurable frontend web application containers
Deploying configurable frontend web application containersJosé Moreira
 
GE Predix 新手入门 赵锴 物联网_IoT
GE Predix 新手入门 赵锴 物联网_IoTGE Predix 新手入门 赵锴 物联网_IoT
GE Predix 新手入门 赵锴 物联网_IoTKai Zhao
 
Into The Box 2018 Going live with commandbox and docker
Into The Box 2018 Going live with commandbox and dockerInto The Box 2018 Going live with commandbox and docker
Into The Box 2018 Going live with commandbox and dockerOrtus Solutions, Corp
 
Going live with BommandBox and docker Into The Box 2018
Going live with BommandBox and docker Into The Box 2018Going live with BommandBox and docker Into The Box 2018
Going live with BommandBox and docker Into The Box 2018Ortus Solutions, Corp
 
Deploying Symfony | symfony.cat
Deploying Symfony | symfony.catDeploying Symfony | symfony.cat
Deploying Symfony | symfony.catPablo Godel
 
[funka] Adaptive Images in Responsive Web Design
[funka] Adaptive Images in Responsive Web Design[funka] Adaptive Images in Responsive Web Design
[funka] Adaptive Images in Responsive Web DesignChristopher Schmitt
 

Similaire à Structure your Play application with the cake pattern (and test it) (20)

When Smalltalk Meets the Web
When Smalltalk Meets the WebWhen Smalltalk Meets the Web
When Smalltalk Meets the Web
 
Microsoft Windows Server AppFabric
Microsoft Windows Server AppFabricMicrosoft Windows Server AppFabric
Microsoft Windows Server AppFabric
 
Power ai image-pipeline
Power ai image-pipelinePower ai image-pipeline
Power ai image-pipeline
 
[rwdsummit2012] Adaptive Images in Responsive Web Design
[rwdsummit2012] Adaptive Images in Responsive Web Design[rwdsummit2012] Adaptive Images in Responsive Web Design
[rwdsummit2012] Adaptive Images in Responsive Web Design
 
[cssdevconf] Adaptive Images in RWD
[cssdevconf] Adaptive Images in RWD[cssdevconf] Adaptive Images in RWD
[cssdevconf] Adaptive Images in RWD
 
[html5tx] Adaptive Images in Responsive Web Design
[html5tx] Adaptive Images in Responsive Web Design[html5tx] Adaptive Images in Responsive Web Design
[html5tx] Adaptive Images in Responsive Web Design
 
[convergese] Adaptive Images in Responsive Web Design
[convergese] Adaptive Images in Responsive Web Design[convergese] Adaptive Images in Responsive Web Design
[convergese] Adaptive Images in Responsive Web Design
 
How to ensure Presto scalability 
in multi use case
How to ensure Presto scalability 
in multi use case How to ensure Presto scalability 
in multi use case
How to ensure Presto scalability 
in multi use case
 
[HEWEBAR 2012] Adaptive Images in Responsive Web Design
[HEWEBAR 2012] Adaptive Images in Responsive Web Design[HEWEBAR 2012] Adaptive Images in Responsive Web Design
[HEWEBAR 2012] Adaptive Images in Responsive Web Design
 
How Bitbucket Pipelines Loads Connect UI Assets Super-fast
How Bitbucket Pipelines Loads Connect UI Assets Super-fastHow Bitbucket Pipelines Loads Connect UI Assets Super-fast
How Bitbucket Pipelines Loads Connect UI Assets Super-fast
 
DevOps Workflow: A Tutorial on Linux Containers
DevOps Workflow: A Tutorial on Linux ContainersDevOps Workflow: A Tutorial on Linux Containers
DevOps Workflow: A Tutorial on Linux Containers
 
Remote Config REST API and Versioning
Remote Config REST API and VersioningRemote Config REST API and Versioning
Remote Config REST API and Versioning
 
[refreshaustin] Adaptive Images in Responsive Web Design
[refreshaustin] Adaptive Images in Responsive Web Design[refreshaustin] Adaptive Images in Responsive Web Design
[refreshaustin] Adaptive Images in Responsive Web Design
 
High Velocity DevOps: Four Ways to Leverage CloudFront in Faster DevOps Workf...
High Velocity DevOps: Four Ways to Leverage CloudFront in Faster DevOps Workf...High Velocity DevOps: Four Ways to Leverage CloudFront in Faster DevOps Workf...
High Velocity DevOps: Four Ways to Leverage CloudFront in Faster DevOps Workf...
 
Deploying configurable frontend web application containers
Deploying configurable frontend web application containersDeploying configurable frontend web application containers
Deploying configurable frontend web application containers
 
GE Predix 新手入门 赵锴 物联网_IoT
GE Predix 新手入门 赵锴 物联网_IoTGE Predix 新手入门 赵锴 物联网_IoT
GE Predix 新手入门 赵锴 物联网_IoT
 
Into The Box 2018 Going live with commandbox and docker
Into The Box 2018 Going live with commandbox and dockerInto The Box 2018 Going live with commandbox and docker
Into The Box 2018 Going live with commandbox and docker
 
Going live with BommandBox and docker Into The Box 2018
Going live with BommandBox and docker Into The Box 2018Going live with BommandBox and docker Into The Box 2018
Going live with BommandBox and docker Into The Box 2018
 
Deploying Symfony | symfony.cat
Deploying Symfony | symfony.catDeploying Symfony | symfony.cat
Deploying Symfony | symfony.cat
 
[funka] Adaptive Images in Responsive Web Design
[funka] Adaptive Images in Responsive Web Design[funka] Adaptive Images in Responsive Web Design
[funka] Adaptive Images in Responsive Web Design
 

Plus de yann_s

FS2 mongo reactivestreams
FS2 mongo reactivestreamsFS2 mongo reactivestreams
FS2 mongo reactivestreamsyann_s
 
Bringing a public GraphQL API from the whiteboard to production
Bringing a public GraphQL API from the whiteboard to productionBringing a public GraphQL API from the whiteboard to production
Bringing a public GraphQL API from the whiteboard to productionyann_s
 
Bringing a public GraphQL API from beta to production ready
Bringing a public GraphQL API from beta to production readyBringing a public GraphQL API from beta to production ready
Bringing a public GraphQL API from beta to production readyyann_s
 
Introduction to rust: a low-level language with high-level abstractions
Introduction to rust: a low-level language with high-level abstractionsIntroduction to rust: a low-level language with high-level abstractions
Introduction to rust: a low-level language with high-level abstractionsyann_s
 
Performance optimisation with GraphQL
Performance optimisation with GraphQLPerformance optimisation with GraphQL
Performance optimisation with GraphQLyann_s
 
Introduction to GraphQL at API days
Introduction to GraphQL at API daysIntroduction to GraphQL at API days
Introduction to GraphQL at API daysyann_s
 
Introduction to type classes in Scala
Introduction to type classes in ScalaIntroduction to type classes in Scala
Introduction to type classes in Scalayann_s
 

Plus de yann_s (7)

FS2 mongo reactivestreams
FS2 mongo reactivestreamsFS2 mongo reactivestreams
FS2 mongo reactivestreams
 
Bringing a public GraphQL API from the whiteboard to production
Bringing a public GraphQL API from the whiteboard to productionBringing a public GraphQL API from the whiteboard to production
Bringing a public GraphQL API from the whiteboard to production
 
Bringing a public GraphQL API from beta to production ready
Bringing a public GraphQL API from beta to production readyBringing a public GraphQL API from beta to production ready
Bringing a public GraphQL API from beta to production ready
 
Introduction to rust: a low-level language with high-level abstractions
Introduction to rust: a low-level language with high-level abstractionsIntroduction to rust: a low-level language with high-level abstractions
Introduction to rust: a low-level language with high-level abstractions
 
Performance optimisation with GraphQL
Performance optimisation with GraphQLPerformance optimisation with GraphQL
Performance optimisation with GraphQL
 
Introduction to GraphQL at API days
Introduction to GraphQL at API daysIntroduction to GraphQL at API days
Introduction to GraphQL at API days
 
Introduction to type classes in Scala
Introduction to type classes in ScalaIntroduction to type classes in Scala
Introduction to type classes in Scala
 

Dernier

TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024The Digital Insurer
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxRustici Software
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vázquez
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot ModelNavi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot ModelDeepika Singh
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsNanddeep Nachan
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...apidays
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDropbox
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024The Digital Insurer
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfOverkill Security
 

Dernier (20)

TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot ModelNavi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 

Structure your Play application with the cake pattern (and test it)

  • 1. Structure your Play application with the cake pattern and test it
  • 2. Structure a Play application like a cake
  • 3. We'll build a website for Toys Basketball Association
  • 5. Player Backend GET http://localhost:9001/players/1 HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Content-Length: 91 {"id":1,"name":"James P. Sullivan","height":"34 cm","weight":"370 g","team":"Monstropolis"}
  • 6. Player Backend GET http://localhost:9001/players/1/photo HTTP/1.1 200 OK Last-Modified: Thu, 12 Dec 2013 13:11:02 GMT Etag: "4911f28b55213..." Content-Length: 1753583 Cache-Control: max-age=3600 Content-Type: image/jpeg Date: Mon, 23 Dec 2013 10:01:15 GMT <binary>
  • 7. Video Backend GET http://localhost:9002/videos/top HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Content-Length: 83 [{"id":1,"summary":"dunk","players":[1]},...]
  • 8. Video Backend GET http://localhost:9002/videos/1/stream.mp4 range: bytes=200-280 HTTP/1.1 206 Partial Content Content-Range: bytes 200-280/2154777 Accept-Ranges: bytes Connection: keep-alive Content-Length: 81 Content-Type: video/mp4 http:////www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0
  • 11. Tests with the new version?
  • 12. Test pyramid unit tests def f(input): output assert output
  • 15. Which tests are possible? with the actual version
  • 18. Dependencies between components Dependencies class TopVideoService { val videoGateway = new VideoGateway val playerGateway = new PlayerGateway trait TopVideoServiceComp extends PlayerGatewayComp with VideoGatewayComp { val topVideoService = new TopVideoService def topVideos(): [...] = { videoGateway.top() [...] } class TopVideoService { def topVideos(): [...] = { videoGateway.top() [...] } } } Provided service }
  • 20. Introducing components ✔ ✔ Components expose services only to other components One component must depend from another one to use the exposed service
  • 24. components as traits ✔ Components with exposed services and dependencies ✔ Unit tests ✔ Component tests ✔ Integration tests
  • 25. But... some drawbacks • Testing is not optimal • Which dependency should be mocked? • The compiler can check that for us
  • 26. Exposed service abstract Dependencies trait TopVideoServiceComp extends PlayerGatewayComp with VideoGatewayComp { trait TopVideoServiceComp extends PlayerGatewayComp with VideoGatewayComp { val topVideoService = new TopVideoService def topVideoService: TopVideoService [...] [...] } } Provided service
  • 27. Defining the desired service trait TopVideoServiceComp extends PlayerGatewayComp with VideoGatewayComp { trait Application extends Controller with TopVideoServiceComp { def index = [...] def topVideoService: TopVideoService } [...] } object Application extends Application
  • 28. Defining the desired service trait TopVideoServiceComp extends PlayerGatewayComp with VideoGatewayComp { trait Application extends Controller with TopVideoServiceComp { def index = [...] def topVideoService: TopVideoService } [...] } ro r r object Applicationn e atio extends lApplication pi om c
  • 29. Defining the desired service trait TopVideoServiceComp extends PlayerGatewayComp with VideoGatewayComp { trait Application extends Controller with TopVideoServiceComp { def index = [...] def topVideoService: TopVideoService } [...] } ro r r object Applicationn e atio extends lApplication pi om c object Application extends Application { override val topVideoService = new TopVideoService }
  • 30. Defining the desired service trait TopVideoServiceComp extends PlayerGatewayComp with VideoGatewayComp { trait Application extends Controller with TopVideoServiceComp { def index = [...] def topVideoService: TopVideoService } [...] } trait TopVideoServiceCompImpl extends TopVideoServiceComp { override val topVideoService = new TopVideoService } ro r r object Applicationn e atio extends lApplication pi om c object Application extends Application { override val topVideoService = new TopVideoService } object Application extends Application with TopVideoServiceCompImpl
  • 31. Introducing Registry object Application extends Application with PlayerGatewayCompImpl with VideoGatewayCompImpl with HttpClientCompImpl with TopVideoServiceCompImpl object Players extends Players with PlayerGatewayCompImpl with VideoGatewayCompImpl with HttpClientCompImpl with TopVideoServiceCompImpl trait Registry extends HttpClientComp with PlayerGatewayComp with VideoGatewayComp with TopVideoServiceComp trait RuntimeEnvironment extends Registry with VideoGatewayCompImpl with HttpClientCompImpl with PlayerGatewayCompImpl with TopVideoServiceCompImpl object Application extends Application with RuntimeEnvironment object Players extends Players with RuntimeEnvironment
  • 32. Runtime and Test Registries trait Registry extends HttpClientComp with PlayerGatewayComp with VideoGatewayComp with TopVideoServiceComp trait RuntimeEnvironment extends Registry with VideoGatewayCompImpl with HttpClientCompImpl with PlayerGatewayCompImpl with TopVideoServiceCompImpl trait MockEnvironment extends Registry with Mockito { override val httpClient = mock[HttpClient] override val playerGateway = mock[PlayerGateway] override val videoGateway = mock[VideoGateway] override val topVideoService = mock[TopVideoService] }
  • 33. Traits with abstract methods ✔ Components with exposed services and dependencies ✔ Dependencies checked by compiler ✔ Unit tests ✔ Component tests ✔ Integration tests
  • 34. drawback of traits inheritance
  • 35. Introducing self type Dependencies trait TopVideoServiceComp extends PlayerGatewayComp with VideoGatewayComp { trait TopVideoServiceComp { self: PlayerGatewayComp with VideoGatewayComp => def topVideoService: TopVideoService def topVideoService: TopVideoService [...] [...] } } Provided service
  • 36. self type annotation „Any concrete class that mixed in the trait must ensure that its type conforms to the trait's self type“ source: http://docs.scala-lang.org/glossary/#self_type
  • 37. Traits with self types ✔ Components with exposed services and only explicit dependencies ✔ Unit tests ✔ Component tests ✔ Integration tests
  • 38. Parallel @Inject / traits public class HttpClient { ... } trait HttpClientComp { def httpClient: HttpClient class HttpClient { ... } public class PlayerGateway { @Inject private HttpClient httpClient; <use httpClient> } trait PlayerGatewayComp { self: HttpClientComp => } <use httpClient> public class VideoGateway { @Inject private HttpClient httpClient; <use httpClient> } } trait VideoGatewayComp { self: HttpClientComp => <use httpClient> }
  • 39. Dependencies Injection • „side effect“ of Cake pattern • dependencies checked by compiler
  • 40. Alternatives for DI • Spring, Guice... • DI with macros: macwire http://typesafe.com/activator/template/macwire-activator
  • 41. Resolving dependencies at runtime source: http://apmblog.compuware.com/2013/12/18/the-hidden-class-loading-performance-impact-of-the-spring-framework/
  • 42. Resolving dependencies at runtime source: http://apmblog.compuware.com/2013/12/18/the-hidden-class-loading-performance-impact-of-the-spring-framework/
  • 43. Resolving dependencies at runtime source: http://apmblog.compuware.com/2013/12/18/the-hidden-class-loading-performance-impact-of-the-spring-framework/
  • 44. Resolving dependencies at runtime source: http://apmblog.compuware.com/2013/12/18/the-hidden-class-loading-performance-impact-of-the-spring-framework/
  • 45. DI with cake pattern • dependencies are resolved at compile time • no surprise at runtime
  • 46. traits with self type and implementation some drawbacks • mix interface / implementation • difficult to provide alternative runtime implementation • cannot provide component dependency only for one implementation
  • 47. traits with self type and implementation ex with top videos
  • 48. traits with self type and implementation Let's fix it • decouple interface / implementation
  • 49. Decouple service definition / impl trait TopVideoServiceComp { trait TopVideoServiceComp { def topVideoService: TopVideoService self: PlayerGatewayComp with VideoGatewayComp => def topVideoService: TopVideoService [impl of TopVideoService] } trait TopVideoService { def topVideos(): Future[Option[Seq[TopVideo]]] } } trait TopVideoServiceCompImpl extends TopVideoServiceComp { trait TopVideoServiceCompImpl extends TopVideoServiceComp { self: PlayerGatewayComp with VideoGatewayComp => self: PlayerGatewayComp with VideoGatewayComp => override val topVideoService = new TopVideoServiceImpl override val topVideoService = new TopVideoService class TopVideoServiceImpl extends TopVideoService { def topVideos(): Future[Option[Seq[TopVideo]]] = videoGateway.top() [...] } } }
  • 50. Decouple service definition / impl trait TopVideoServiceComp { def topVideoService: TopVideoService trait TopVideoService { def topVideos(): Future[Option[Seq[TopVideo]]] } } Provided service definition Dependencies specific to impl trait TopVideoServiceCompImpl extends TopVideoServiceComp { self: PlayerGatewayComp with VideoGatewayComp => override val topVideoService = new TopVideoServiceImpl class TopVideoServiceImpl extends TopVideoService { def topVideos(): Future[Option[Seq[TopVideo]]] = { videoGateway.top() [...] } } } service impl
  • 51. comparison of all variants 1st version ✔ ✗ ✗ simple alternative impl very difficult forget what to override (in tests) trait VideoGatewayComp extends HttpClientComp { val videoGateway = new VideoGateway sealed trait TopVideosResponse [...] class VideoGateway { def top(): Future[TopVideosResponse] = [...] } }
  • 52. comparison of all variants 2nd version ✔ ✗ dependencies checked by compiler invisible inheritance of other dependencies trait VideoGatewayComp extends HttpClientComp { def videoGateway: VideoGateway sealed trait TopVideosResponse [...] class VideoGateway { def top(): Future[TopVideosResponse] = [...] } } trait VideoGatewayCompImpl extends VideoGatewayComp { override val videoGateway = new VideoGateway }
  • 53. comparison of all variants 3rd version ✔ ✗ ✗ explicit dependent components no separation interface / impl boilerplate trait VideoGatewayComp { self: HttpClientComp => def videoGateway: VideoGateway sealed trait TopVideosResponse [...] class VideoGateway { def top(): Future[TopVideosResponse] = [...] } } trait VideoGatewayCompImpl extends VideoGatewayComp { self: HttpClientComp => override val videoGateway = new VideoGateway }
  • 54. comparison of all variants 4th version ✔ ✔ trait VideoGatewayComp { ✗ separation interface / impl flexibility boilerplate ++ def videoGateway: VideoGateway sealed trait TopVideosResponse [...] trait VideoGateway { def top(): Future[TopVideosResponse] } } trait VideoGatewayCompImpl extends VideoGatewayComp { self: HttpClientComp => override val videoGateway: VideoGateway = new VideoGatewayImpl class VideoGatewayImpl extends VideoGateway { def top(): Future[TopVideosResponse] = [...] } }
  • 55. Number of traits in app components with abstract methods components with self type annotations components with self type annotations and real separation interface / implementation 16 16 20
  • 56. Downside of Cake pattern (1)
  • 57. What do you need? • only DI? • multiple alternative implementations of same service?
  • 58. Downside of Cake pattern (2) • compiler error • let's minimize it
  • 59. Reducing # of compiler errors trait RuntimeEnvironment extends Registry with HttpClientCompImpl with VideoGatewayCompImpl with PlayerGatewayCompImpl with TopVideoServiceCompImpl class RuntimeEnvironment extends Registry with HttpClientCompImpl with VideoGatewayCompImpl with PlayerGatewayCompImpl with TopVideoServiceCompImpl
  • 60. Downside of Cake pattern (3) • compilation speed ✔ minimize it with (abstract) class ✔ let's remove some traits
  • 61. Removing some traits class RuntimeEnvironment extends Registry with HttpClientCompImpl with VideoGatewayCompImpl with PlayerGatewayCompImpl with TopVideoServiceCompImpl class RuntimeEnvironment extends Registry { override val httpClient = new HttpClient override val playerGateway = new PlayerGateway override val videoGateway = new VideoGateway override val topVideoService = new TopVideoService trait HttpClientCompImpl extends HttpClientComp { override val httpClient = new HttpClient } trait VideoGatewayCompImpl extends VideoGatewayComp { self: HttpClientComp => override val videoGateway = new VideoGateway } trait PlayerGatewayCompImpl extends PlayerGatewayComp { [...] } trait TopVideoServiceCompImpl extends TopVideoServiceComp { [...] } }
  • 62. Number of traits components with abstract methods components with self type annotations components with self type annotations and real separation interface / implementation 16 12 20
  • 66. DI ease unit testing Do no over-use it!
  • 67. further discussion • make cake pattern more manageable with https://github.com/sullivan-/congeal trait UService extends hasDependency[URepository] {   ... }
  • 69. Yann Simon Software Engineer Blücherstr. 22 10961 Berlin yann.simon@leanovate.de twitter: @simon_yann
  • 70. Credits • • • • • • http://www.flickr.com/photos/cefeida/2306611187/ 62/366: Cake, redux (Magic Madzik) http://www.flickr.com/photos/jason_burmeister/2125022193 Iced Tree (Jason) http://www.flickr.com/photos/leandrociuffo/6270204821 Berlin skyline (Leandro Neumann Ciuffo) http://www.flickr.com/photos/8047705@N02/5668841148/ Slow and steady (John Liu) http://www.flickr.com/photos/jcapaldi/4201550567/ Bon Appetit (Jim, the Photographer) http://www.epicfail.com/2012/07/17/about-to-fail-26/