Dependency Injection in Scala - Beyond the Cake Pattern
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share

Dependency Injection in Scala - Beyond the Cake Pattern

  • 8,306 views
Uploaded on

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

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

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
  • 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!
    Are you sure you want to
    Your message goes here
No Downloads

Views

Total Views
8,306
On Slideshare
8,279
From Embeds
27
Number of Embeds
6

Actions

Shares
Downloads
93
Comments
1
Likes
10

Embeds 27

http://www.linkedin.com 18
http://twitter.com 4
https://www.linkedin.com 2
http://paper.li 1
http://www.slideshare.net 1
http://a0.twimg.com 1

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for 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 ..

Transcript

  • 1. Dependency Injection Beyond the Cake Pattern
  • 2. Debasish Ghosh @debasishg on twitter Code @ http://github.com/debasishg Blog @ Ruminations of a Programmer http:// debasishg.blogspot.com
  • 3. 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 )
  • 4. import TradeModel._ // a Repository abstraction trait TradeRepository { def fetch(refNo: String ): Trade def update(trade: Trade ): Trade }
  • 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. // 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. 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. 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. 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. 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 Repository implementations ..
  • 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. domain rule ..
    • enrichment of trade is done in steps:
    • get the tax/fee ids for a trade
    • calculate tax/fee values
    • enrich trade with net cash amount
  • 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. // 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. 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. 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
  • 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. 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. import TradeService ._ import Repositories.RedisTradeRepository def run = { updateTrade(fetchTrade(&quot;r-123&quot;)) //.. }
  • 20.