Dependency Injection in Scala - Beyond the Cake Pattern

13.395 visualizações

Publicada em

Discusses how to do dependency injection in Scala using functional programming.

Publicada em: Tecnologia
1 comentário
20 gostaram
Estatísticas
Notas
  • At slide n17 we have an 'implicit repo' at each method, why? Isnt that possible to leave only one implicit right inside TradeService trait body?

    Cheers!
       Responder 
    Tem certeza que deseja  Sim  Não
    Insira sua mensagem aqui
Sem downloads
Visualizações
Visualizações totais
13.395
No SlideShare
0
A partir de incorporações
0
Número de incorporações
68
Ações
Compartilhamentos
0
Downloads
151
Comentários
1
Gostaram
20
Incorporações 0
Nenhuma incorporação

Nenhuma nota no slide
  • Some of my coordinates ..
  • And some of my open source involvements .. Quite some bias towards Scala .. And this talk will also have quite a few Scala snippets for explaining DSL implementation ..
  • We will see an example here ..
  • Dependency Injection in Scala - Beyond the Cake Pattern

    1. 1. Dependency Injection Beyond the Cake Pattern
    2. 2. Debasish Ghosh @debasishg on twitter Code @ http://github.com/debasishg Blog @ Ruminations of a Programmer http:// debasishg.blogspot.com
    3. 3. Open Source Footprints <ul><li>Committer in Akka ( http:// akka.io ) </li></ul><ul><li>Owner/Founder of : </li></ul><ul><ul><li>sjson (JSON serialization library for Scala objects – http://github.com/debasishg/sjson ) </li></ul></ul><ul><ul><li>scala-redis (Redis client for Scala – http://github.com/debasishg/scala-redis ) </li></ul></ul><ul><ul><li>scouchdb (Scala driver for Couchdb – http:// github.com/debasishg/scouchdb ) </li></ul></ul>
    4. 4. import TradeModel._ // a Repository abstraction trait TradeRepository { def fetch(refNo: String ): Trade def update(trade: Trade ): Trade }
    5. 5. // a Trading service trait 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)} }
    6. 6. // a Trading service trait 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
    7. 7. suppose we would like to use a Redis based Repository .. 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 ..
    8. 8. 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 ) }
    9. 9. 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
    10. 10. val fetchTrade: TradeRepository => String => Trade val fetchTrade_c: String => Trade import  TradeServiceWithRedisRepo._ val  t = fetchTrade_c(&quot;ref-123&quot;) by using the appropriate module, we can switch Repository implementations ..
    11. 11. 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 binding Of functions
    12. 12. domain rule .. <ul><li>enrichment of trade is done in steps: </li></ul><ul><li>get the tax/fee ids for a trade </li></ul><ul><li>calculate tax/fee values </li></ul><ul><li>enrich trade with net cash amount </li></ul>
    13. 13. // enrichment of trade // implementation follows problem domain model 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)
    14. 14. // get the list of tax/fees for this trade val forTrade: Trade => Option [ List [ TaxFeeId ]] = {trade => // .. implementation } // all tax/fees for a specific trade val taxFeeCalculate: Trade => List [ TaxFeeId ] => List [( TaxFeeId , BigDecimal )] = {t => tids => //.. implementation } val enrichTradeWith: Trade => List [( TaxFeeId , BigDecimal )] => BigDecimal = {trade => taxes => //.. implementation }
    15. 15. 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
    16. 16. The Reader Monad <ul><li>Note how the Trade is being delayed in injection </li></ul><ul><li>How we don’t have to repeat the Trade argument in each invocation of the functions </li></ul><ul><li>This is an implementation of the Reader monad – Trade is only being read to compute all calculations </li></ul><ul><li>Partial Application is the key </li></ul>
    17. 17. 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 ..
    18. 18. 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 ..
    19. 19. import TradeService ._ import Repositories.RedisTradeRepository def run = { updateTrade(fetchTrade(&quot;r-123&quot;)) //.. }

    ×