dependency injection in scala

33
DEPENDENCY INJECTION IN SCALA ... ESPECIALLY WITH PLAY! By / Michal Bigos @teliatko

Upload: michal-bigos

Post on 03-Sep-2014

3.476 views

Category:

Technology


0 download

DESCRIPTION

Evaluation of DI frameworks in context of using them with Play!

TRANSCRIPT

Page 1: Dependency injection in scala

DEPENDENCY INJECTIONIN SCALA

... ESPECIALLY WITH PLAY!By /

Michal Bigos @teliatko

Page 2: Dependency injection in scala

AGENDA1. Introduction2. Evaluation criteria3. Covered approaches/frameworks

SpringSpring-ScalaCDIGuiceSubCutCake

4. Recommendations

Page 3: Dependency injection in scala

INTRODUCTIONCATEGORIZATION OF APPROACHES

Pure Scala approaches: Subcut, Cake

Mixed Java/Scala approaches: Spring-Scala, Guice

Pure Java aproaches: Spring, CDI

Page 4: Dependency injection in scala

INTRODUCTIONWHY JAVA DI FRAMEWORKS AT ALL

Reason 1: Important for existing Java-based projects, whenyou need to mix Java and Scala

Reason 2: Mature, proven solutions

Page 5: Dependency injection in scala

EVALUATION CRITERIA1. As much as possible idiomatic approach

minimal usage of: vars, annotations, specialconfiguration filesideal case pure Scala

2. Simple testingIntegration testingUnit testing too

3. Good fit with Play!4. No steep learning curve

Page 6: Dependency injection in scala

EVALUATION CRITERIASymbols used in evaluation

(+) pros

(-) cons

(±) it depends

Page 7: Dependency injection in scala

EXAMPLE APPLICATION

Page 8: Dependency injection in scala

SPRING1. Relies heavily on annotations (-)2. External configuration file is needed (-)3. Differences are minimal in relation to Java (±)4. Immutability possible via constructor injection (+)5. Setter injection requires additional work in Scala (±)6. Popular well-designed Java framework (+)7. More than just DI (±)8. Various testing possibilities (±)

Page 9: Dependency injection in scala

SPRING SPECIALSSETTER INJECTION

or

@org.springframework.stereotype.Controllerclass Translate extends Controller {

@BeanProperty @(Autowired @beanSetter) var translator: Translator = _

...}

@org.springframework.stereotype.Controllerclass Translate extends Controller {

private var translator: Translator = _

@Autowired def setTranslator(translator: Translator): Unit = this.translator = translator

...}

Page 10: Dependency injection in scala
Page 11: Dependency injection in scala

SPRING-SCALA1. No annotations (+)2. Wiring in code, no external configuration file (+)3. Work in progress (-)4. Immutability via contructor injection (+)5. Spring under the hood (+)6. Provides DSL to use Spring templates (±)7. Various testing possibilities (±)

Page 12: Dependency injection in scala

SPRING-SCALA SPECIALSTEMPLATES

Improvements: functions, Options, manifests

ConnectionFactory connectionFactory = ...JmsTemplate template = new JmsTemplate(connectionFactory);

template.send("queue", new MessageCreator() { public Message createMessage(Session session) throws JMSException { return session.createTextMessage("Hello World"); }});

val connectionFactory : ConnectionFactory = ...val template = new JmsTemplate(connectionFactory)

template.send("queue") { session: Session => session.createTextMessage("Hello World")}

Page 13: Dependency injection in scala

SPRING-SCALA SPECIALSXML CONFIGURATION

class Person(val firstName: String, val lastName: String) { ... }

<beans> <bean id="firstName" class="java.lang.String"> <constructor-arg value="John"/> </bean> <bean id="lastName" class="java.lang.String"> <constructor-arg value="Doe"/> </bean></beans>

class PersonConfiguration extends FunctionalConfiguration { importXml("classpath:/names.xml")

val john = bean() { new Person(getBean("firstName"), getBean("lastName")) }}

Page 14: Dependency injection in scala

SPRING-SCALA SPECIALSCONFIGURATION COMPOSITION

You can use also traits for composition

abstract class PersonConfiguration extends FunctionalConfiguration { val firstName: String val lastName: String bean() { new Person(firstName, lastName) }}

class JohnDoeConfiguration extends PersonConfiguration { val firstName = singleton() { "John" } val lastName = singleton() { "Doe" }}

Page 15: Dependency injection in scala

SPRING-SCALA SPECIALSPROFILES, INIT AND DESTROY

class DataSourceConfiguration extends FunctionalConfiguration { profile("dev") { bean("dataSource") { new BasicDataSource() } init { // Set up properties } destroy { _.close() } } profile("prod") { bean("dataSource") { val dataSource = new OracleDataSource() // Set up properties dataSource } }}

Page 16: Dependency injection in scala

CDITHE ONLY SOLUTION I DIDN'T TRY BECAUSE OF ITS LIMITS

1. Java EE Standard (JSR-299), part of every JEE6 compiliantcontainer (±)

2. Relies heavily on annotations (-)3. Only Singleton and Dependent scoped beans are injected

as direct dependecies (-)4. Proxy and ThreadLocal magic behind, doesn't work well

with actors (-)5. Mulitple implementations (±)6. Various testing possibilities (±)

Page 17: Dependency injection in scala

CDILIMITS

Various scopes: singleton, prototype (dependent), session,request, applicationOnly singleton and dependent are injected directlyOther scopes use proxies and thread localsRestriction on proxied classes:

1. Default constructor => no immutablity2. No final classes and methods => Scala uses some in

beckground implicitly

Page 18: Dependency injection in scala

GOOGLE GUICE1. Few annotations needed (±)2. Only DI nothing else, leaner, easier (+)3. Wiring in code, no external configuration file (+)4. Immutability via contructor injection (+)5. Scala DSL for bindings (+)6. Easy testing (+)

Page 19: Dependency injection in scala

GOOGLE GUICE SPECIALSPLAIN VANILLA GUICE

Scala DSLs remove unnecessary classOf calls

SBT dependencies

class TranslationModule extends AbstractModule { def configure() { bind( classOf[Translator] ).to( classOf[FrenchTranslator] ) }}

// Two options"com.tzavellas" % "sse-guice" % "0.7.1""net.codingwell" %% "scala-guice" % "3.0.2"

Page 20: Dependency injection in scala

GOOGLE GUICE SPECIALSINJECTION AND TESTING

Anytime you can inject members using any arbitrary module.Relevant for setter injection.

It is possible to override production module with anothermodule in tests. Use ` instead of '

val runner = ...injector.injectMembers(runner)

val m = Modules 'override' new ProductionModule 'with' new TestModuleval injector = Guice createInjector m

Page 21: Dependency injection in scala

SUBCUT1. No annotations (+)2. Wiring in code, no external configuration file (+)3. Pure Scala library (+)4. Intrusive code (-)5. Actually service locator pattern and not DI (-)6. Limited testing (-)

Page 22: Dependency injection in scala

SUBCUTBINDING OPTIONS

Example directly from SubCut website

object SomeConfigurationModule extends NewBindingModule (module => { import module._ // optional but convenient - allows use of bind instead of module.bind

bind [X] toSingle Y bind [Z] toProvider { codeToGetInstanceOfZ() } bind [A] toProvider { implicit module => new AnotherInjectedClass(param1, param2) } // module singleton bind [B] to newInstanceOf [Fred] // create a new instance of Fred every time - Fred require injection bind [C] to moduleInstanceOf [Jane] // create a module scoped singleton Jane that will be used bind [Int] idBy PoolSize to 3 // bind an Int identified by PoolSize to constant 3 bind [String] idBy ServerURL to "http://escalatesoft.com"})

Page 23: Dependency injection in scala

SUBCUTLESS INTRUSIVE OPTION

Normal definition of component

Using AutoInjectable

Sad news, it needs compiler plugin (macros in next versions)

class SomeServiceOrClass(param1: String, param2: Int) (implicit val bindingModule: BindingModule) extends SomeTrait with Injectable { ...}

class SomeServiceOrClass(param1: String, param2: Int) extends SomeTrait with AutoInjectable { ...}

Page 24: Dependency injection in scala

CAKE PATTERN1. Dependencies are checked in compile time, statically

typed, immutable (+)2. No library needed, uses only Scala language features (+)3. Wiring in code, no external configuration file (+)4. Uses advanced features of Scala, not easy to grasp (-)5. Easy testing (+)

Page 25: Dependency injection in scala

CAKE PATTERNEXPLANATION

Definition of module/component

// Module or Componenttrait Translation { // Services it provides

def translator: Translator

// Service interface with multiple implementations trait Translator { def translate(what: String): String }}

Page 26: Dependency injection in scala

CAKE PATTERNEXPLANATION

Implementation of component, relies on inharitance

trait FrenchTranslation extends Translation { // Singleton instance override val translator = new FrenchTranslator

// Implementation of service class FrenchTranslator extends Translator { def translate(what: String): String = {...} }}

Page 27: Dependency injection in scala

CAKE PATTERNEXPLANATION

Expressing dependency and usage, relies on self-typeannotations

trait Translate extends Controller { this: Translation => // Dependency

def greet(name: String) = Action { // Usage of service Ok(views.html.greet(translator.translate(s"Hello $name!"))) }}

Page 28: Dependency injection in scala

CAKE PATTERNEXPLANATION

Binding, relies on mixins of traits

object Translate extends Translate with FrenchTranslation

Page 29: Dependency injection in scala

RECOMMENDATIONSWHEN TO USE (JAVA FRAMEWORKS)

Spring (definitely w/ Spring-Scala)

1. When you need more than DI2. When you need to intergate with Java code3. When you know Spring well

CDI

1. Only in JEE compiliant container, when your code dependson container services

Guice

1. When you want to do only DI and do it well2. When you need to integrate with Java code

Page 30: Dependency injection in scala

RECOMMENDATIONSWHEN TO USE (SCALA DI)

SubCut

1. When you want to be hipster and rant with a new library2. When you want pure Scala solution

Cake

1. Wnen you need additional type safety2. When you want pure Scala solution3. When you want very cohesive components/modules

Page 31: Dependency injection in scala

RECOMMENDATIONSUSAGE EXAMPLES

Java/Scala mixed project => Spring or Guice

Scala standalone project => Guice or Cake

Play! project => Guice or Cake

Domain or algorithm => Cake

Page 32: Dependency injection in scala

RECOMMENDATIONSVERY SUBJECTIVE RANKING

Category Spring CDI Guice SubCut CakeIdiomatic ** * ** *** ***Simple testing *** * *** * ***Good fit with Play! *** * *** ** ***No steep learning curve ** ** *** *** *Java integration *** *** *** n/a n/a

Page 33: Dependency injection in scala

THANKS FOR YOUR ATTENTION