Dependency Injection Beyond the Cake Pattern
Debasish Ghosh @debasishg on twitter Code @  http://github.com/debasishg   Blog @  Ruminations of a Programmer http:// deb...
Open Source Footprints <ul><li>Committer in Akka ( http:// akka.io )  </li></ul><ul><li>Owner/Founder of : </li></ul><ul><...
import  TradeModel._ // a Repository abstraction trait   TradeRepository  { def  fetch(refNo:  String ):  Trade def  updat...
// a Trading service trait   TradeService  { // fetches a trade based on the reference no val  fetchTrade:  TradeRepositor...
// a Trading service trait TradeService { // fetches a trade based on the reference no val fetchTrade:  TradeRepository  =...
suppose we would like to use a  Redis based Repository  .. class   RedisTradeRepository   extends   TradeRepository  { def...
define  partial application  of the service methods  using the Redis based repository implementation in a  separate module...
define  partial application  of the service methods  using the Redis based repository implementation in a  separate module...
val  fetchTrade:  TradeRepository  =>  String  =>  Trade val  fetchTrade_c:  String  =>  Trade import  TradeServiceWithRed...
instead of currying individual functions, we can curry a  composed function  ..  // warning: needs scalaz! val  withTrade ...
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>...
// enrichment of trade // implementation follows problem domain model val  enrich =  for  { // get the tax/fee ids for a t...
// get the list of tax/fees for this trade val  forTrade:  Trade  =>  Option [ List [ TaxFeeId ]] = {trade =>  // .. imple...
val  enrich =  for  { // get the tax/fee ids for a trade taxFeeIds  <- forTrade  // calculate tax fee values taxFeeValues ...
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 th...
trait   TradeService  { def  fetchTrade(refNo:  String )( implicit  repo:  TradeRepository ) = repo.fetch(refNo) def  upda...
implicit   object   RedisTradeRepository   extends   TradeRepository  { def  fetch(refNo:  String ):  Trade  = //.. Redis ...
import  TradeService ._ import  Repositories.RedisTradeRepository def  run = { updateTrade(fetchTrade(&quot;r-123&quot;)) ...
 
Prochain SlideShare
Chargement dans…5
×

Dependency Injection in Scala - Beyond the Cake Pattern

13 113 vues

Publié le

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

Publié dans : Technologie
1 commentaire
20 j’aime
Statistiques
Remarques
  • 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!
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
Aucun téléchargement
Vues
Nombre de vues
13 113
Sur SlideShare
0
Issues des intégrations
0
Intégrations
68
Actions
Partages
0
Téléchargements
151
Commentaires
1
J’aime
20
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive
  • 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;)) //.. }

    ×