Dependency Injection in Scala - Beyond the Cake Pattern
Click here to load reader
-
Upload
debasish-ghosh -
Category
Technology
-
view
9.022 -
download
1
description
Transcript of Dependency Injection in Scala - Beyond the Cake Pattern
![Page 1: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/1.jpg)
Dependency Injection
Beyond the Cake Pattern
![Page 2: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/2.jpg)
Debasish Ghosh
@debasishg on twitter
Code @ http://github.com/debasishg
Blog @ Ruminations of a Programmerhttp://debasishg.blogspot.com
![Page 3: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/3.jpg)
Open Source Footprints
• Committer in Akka (http://akka.io)
• Owner/Founder of :– sjson (JSON serialization library for Scala
objects – http://github.com/debasishg/sjson)
– scala-redis (Redis client for Scala – http://github.com/debasishg/scala-redis)
– scouchdb (Scala driver for Couchdb – http://github.com/debasishg/scouchdb)
![Page 4: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/4.jpg)
import TradeModel._
// a Repository abstractiontrait TradeRepository { def fetch(refNo: String): Trade def update(trade: Trade): Trade}
![Page 5: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/5.jpg)
// a Trading servicetrait TradeService {
// fetches a trade based on the reference no val fetchTrade: TradeRepository => String => Trade = {repo => refNo => repo.fetch(refNo)}
// updates a trade with the given values val updateTrade: TradeRepository => Trade => Trade = {repo => trade => repo.update(trade)}
}
![Page 6: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/6.jpg)
// a Trading servicetrait TradeService {
// fetches a trade based on the reference no val fetchTrade: TradeRepository => String => Trade = {repo => refNo => repo.fetch(refNo)}
// updates a trade with the given values val updateTrade: TradeRepository => Trade => Trade = {repo => trade => repo.update(trade)}
} Repository is still abstract
![Page 7: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/7.jpg)
suppose we would like to use a Redis basedRepository ..
class RedisTradeRepository extends TradeRepository { def fetch(refNo: String): Trade = //.. Redis based implementation
def update(trade: Trade): Trade = //.. Redis based implementation}
need to indicate that to the service class ..
![Page 8: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/8.jpg)
define partial application of the service methods using the Redis based repository implementation in a separate module ..
object TradeServiceWithRedisRepo extends TradeService {
// partially applied functions val fetchTrade_c = fetchTrade(new RedisTradeRepository)
val updateTrade_c = updateTrade(new RedisTradeRepository)}
![Page 9: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/9.jpg)
define partial application of the service methods using the Redis based repository implementation in a separate module ..
object TradeServiceWithRedisRepo extends TradeService {
// partially applied functions val fetchTrade_c = fetchTrade(new RedisTradeRepository)
val updateTrade_c = updateTrade(new RedisTradeRepository)}
Concrete implementation injected
![Page 10: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/10.jpg)
val fetchTrade: TradeRepository => String => Trade
val fetchTrade_c: String => Trade
import TradeServiceWithRedisRepo._val t = fetchTrade_c("ref-123")
by using the appropriate module, we can switch Repositoryimplementations ..
![Page 11: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/11.jpg)
instead of currying individual functions, we can curry
a composed function ..
// warning: needs scalaz!val withTrade = for { t <- fetchTrade n <- updateTrade}yield(t map n)
val withTrade_c = withTrade(new RedisTradeRepository)
Monadic bindingOf functions
![Page 12: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/12.jpg)
domain rule ..
enrichment of trade is done in steps:
1. get the tax/fee ids for a trade2. calculate tax/fee values3. enrich trade with net cash amount
![Page 13: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/13.jpg)
// enrichment of trade// implementation follows problem domain modelval enrich = for { // get the tax/fee ids for a trade taxFeeIds <- forTrade
// calculate tax fee values taxFeeValues <- taxFeeCalculate
// enrich trade with net amount netAmount <- enrichTradeWith}yield((taxFeeIds map taxFeeValues) map netAmount)
![Page 14: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/14.jpg)
// get the list of tax/fees for this tradeval forTrade: Trade => Option[List[TaxFeeId]] ={trade => // .. implementation}
// all tax/fees for a specific tradeval taxFeeCalculate: Trade => List[TaxFeeId] => List[(TaxFeeId, BigDecimal)] = {t => tids => //.. implementation}
val enrichTradeWith: Trade => List[(TaxFeeId, BigDecimal)] => BigDecimal = {trade => taxes => //.. implementation}
![Page 15: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/15.jpg)
val enrich = for { // get the tax/fee ids for a trade taxFeeIds <- forTrade
// calculate tax fee values taxFeeValues <- taxFeeCalculate
// enrich trade with net amount netAmount <- enrichTradeWith}yield((taxFeeIds map taxFeeValues) map netAmount)
(TradeModel.Trade) => Option[BigDecimal]
:type enrich
![Page 16: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/16.jpg)
The Reader Monad
• Note how the Trade is being delayed in injection
• How we don’t have to repeat the Trade argument in each invocation of the functions
• This is an implementation of the Reader monad – Trade is only being read to compute all calculations
• Partial Application is the key
![Page 17: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/17.jpg)
trait TradeService { def fetchTrade(refNo: String)(implicit repo: TradeRepository) = repo.fetch(refNo)
def updateTrade(trade: Trade)(implicit repo: TradeRepository) = repo.update(trade)}
object TradeService extends TradeService
typeclass based dependency injection ..
![Page 18: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/18.jpg)
implicit object RedisTradeRepository extends TradeRepository {
def fetch(refNo: String): Trade = //.. Redis based implementation
def update(trade: Trade): Trade = //.. Redis based implementation}
typeclass instance for Redis based repository ..
![Page 19: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/19.jpg)
import TradeService._import Repositories.RedisTradeRepository
def run = { updateTrade(fetchTrade("r-123")) //..}
![Page 20: Dependency Injection in Scala - Beyond the Cake Pattern](https://reader038.fdocuments.us/reader038/viewer/2022100506/554f9de2b4c9057b298b471f/html5/thumbnails/20.jpg)