DI in scala
DI(Dependency injection)Its a popular concept for decoupling client and server implementations. DI encourages you to use the constructor patterns which means passing the target dependency as a param when the creation source object happens.
2 min readApr 21, 2020
DI in scala can be achieved by these frameworks:
- Macwire
- scaldi
- guice
- subcut
- Grafter
- Pure Scala
- Cake pattern: https://kubuszok.com/2018/cake-antipattern/
- Reader Monad
- Dependency Injection in Functional Programming
Comparison chart
Reader Monad:
Plain construction injection:
val permRepo = new PermissionRepoImpl
val repo = Repo(userRepo, permRepo)val createUserResp = UserHandlerWithConstructor.createUser(repo, User(1001, "lambda", "admin"))
Injection using monad: A type parameter, a constructor that takes an element of that type, and a flatMap method
val permRepo = new PermissionRepoImpl
val repo = Repo(userRepo, permRepo)val createUserResp = UserHandlerWithMonad.createUser(User(1001, "lambda", "admin")).run(repo)
Signature of function: def createUser(user: User): Reader[Repo, Long]
Macwire
Testing with Macwire
// main code
package shunting {
trait ShuntingModule {
lazy val pointSwitcher = wire[PointSwitcher]
lazy val trainCarCoupler = wire[TrainCarCoupler]
lazy val trainShunter = wire[TrainShunter]
}
}// test
class ShuntingModuleItTest extends FlatSpec {
it should "work" in {
// given
val mockPointSwitcher = mock[PointSwitcher]// when
val moduleToTest = new ShuntingModule {
// the mock implementation will be used to wire the graph
override lazy val pointSwitcher = mockPointSwitcher
}
moduleToTest.trainShunter.shunt()// then
verify(mockPointSwitcher).switch(...)
}
}
Summary
Compile-time dependency injection:
libraries: Macwire etc.
- pros: Can validate the presence of dependencies at compile time.
- cons: Less flexible (e.g., No dynamic type binding)
- cons: Need to enumerate all dependencies in the same scope (lengthy code).
- cons: Hard to implement life cycle management (e.g., onStart, onShutdown, etc.).
Run-time dependency injection
libraries: Google Guice, etc.
- pros: Allows dynamic type binding.
- pros: Simpler binding codes. Only need to bind direct dependencies.
- pros: inject event handler (Guice).
- cons: Missed binding founds as a runtime error.
References:
scaldi comparison score sheet Providers https://gist.github.com/gvolpe/1454db0ed9476ed0189dcc016fd758aa https://groups.google.com/forum/#!topic/scaldi/TYU36h7kGqk
P.S: Oleg Ilyenko has passed away so not sure about the maintenance of scaldi. Not to mention he was creator of sangria too :sad: