Using a DI framework/container may seem obvious. But when was the last time you considered *why* do you really need one? After all, "dependency injection" is just a fancy name for passing arguments to a constructor. In the talk we'll walk through some of the features of DI containers and see if we can replace them with pure Scala code. We'll start with "manual" DI, followed with using MacWire to generate the wiring code for us. Then we'll proceed to a no-framework scopes implementation (e. g. request or session), which are very useful in web applications. We will also discuss possibilities of adding interceptors using macros. And finally, we'll see how to use traits to create and compose modules (similar to the module concept known from Guice), which can be viewed as a simplified cake pattern. As MacWire heavily uses macros, as a bonus, I'll explain how Scala Macros work and when they can be useful.
6. What is DI?
class PresentPackager {!
! def wrap() {!
! ! new RibbonSelector().selectRandom()!
! ! …!
} !
}
11/12/2013 BuildStuff 2013
@adamwarski
7. What is DI?
class PresentPackager(rs: RibbonSelector) {!
! def wrap() {!
! ! rs.selectRandom()!
! ! …!
} !
}
11/12/2013 BuildStuff 2013
@adamwarski
8. Yes, DI is just using parameters
11/12/2013 BuildStuff 2013
@adamwarski
9. Why?
❖
Restrict the knowledge of the class
class PresentPackager {
class PresentPackager
! (rs: RibbonSelector) {
!
!
!
!
!
}
def wrap() {
! new RibbonSelector()
! ! .selectRandom()
! …
}
11/12/2013 BuildStuff 2013
!
!
!
!
}
def wrap() {
! rs.selectRandom()
! …
}
@adamwarski
10. But still …
❖
We need to have the news somewhere
11/12/2013 BuildStuff 2013
@adamwarski
11. Let’s create a DI container!
a.k.a. framework
11/12/2013 BuildStuff 2013
@adamwarski
12. DI in Java
❖
Many frameworks!
❖
Configuration via:!
❖
XML!
❖
annotations!
❖
Java
11/12/2013 BuildStuff 2013
@adamwarski
13. What’s wrong with that?
❖
Do I really need a DI framework?
11/12/2013 BuildStuff 2013
@adamwarski
14. Let’s go back …
❖
… and just use our host language!
❖
in this case, Scala!
❖
mapping DI framework concepts to native language
constructs
11/12/2013 BuildStuff 2013
@adamwarski
15. Manual DI!
!
object PresentWrapper extends App {!
!
!
val ribbonSelector =
! ! ! new RibbonSelector()!
!
!
val wrappingPaperFeeder =
! ! ! new WrappingPaperFeeder()!
!
!
!
!
val presentPackager =
! ! ! new PresentPackager(
! ! ! ! ribbonSelector,
! ! ! ! wrappingPaperFeeder)!
}
11/12/2013 BuildStuff 2013
@adamwarski
16. Manual DI!
!
object PresentWrapper extends App {!
!
!
lazy val ribbonSelector =
! ! ! new RibbonSelector()!
!
!
lazy val wrappingPaperFeeder =
! ! ! new WrappingPaperFeeder()!
!
!
!
!
lazy
! !
! !
! !
val presentPackager =
! new PresentPackager(
! ! ribbonSelector,
! ! wrappingPaperFeeder)!
}
11/12/2013 BuildStuff 2013
@adamwarski
27. Arbitrary scopes
object MyApp extends WebFrontEnd {
! val session: Scope =
! ! ! ! new ThreadLocalScope()!
! val filter = new ScopeFilter(session)
! // bootstrap the web server
! // using the filter
}
11/12/2013 BuildStuff 2013
@adamwarski
37. Cake Pattern
val cake = new PresentPackagerModule
! with RibbonSelectorModule
! with WrappingPaperFeederModule
! with TeddyBearProviderModule
! with ToyTrainProviderModule
! with PresentAssemblyModule
! with … { }
11/12/2013 BuildStuff 2013
@adamwarski
38. Other features
❖
Interceptors!
!
trait Chimney {!
! lazy val presentTransferer =
! ! transactional(wire[PresentTransferer])!
! def transactional: Interceptor!
}
11/12/2013 BuildStuff 2013
@adamwarski
40. Other features
❖
Instance maps!
❖
for integrating e.g. with Play!
❖
Factories!
❖
In-method wiring!
❖
More coming, someday :)
11/12/2013 BuildStuff 2013
@adamwarski
41. Summing up
❖
Reconsider using a framework!
❖
Native Scala gives a lot of power!
❖
❖
❖
use it!
wisely!
More flexibility (less constraints)
11/12/2013 BuildStuff 2013
@adamwarski