– Let Them Eat Cake –



– Let Them Eat Cake –

0 1


iascala-cake-eater


On Github zmccoy / iascala-cake-eater

Let Them Eat Cake

Zach McCoy 
@ZachAMcCoy

Via @Bodil

Cake Pattern?

  • Implement modular abstractions
  • Usage in Dependency Injection
  • Commit at the end of the universe

Why do we care?

  • Dependency Injection
  • Modules

TRAITS and more Traits

 trait TradeRepository {    def fetch(refNo: String): Trade    def write(t: Trade): Unit}
 trait TradeRepositoryComponent {    val tradeRepo: TradeRepository       class TradeRepositoryImpl extends TradeRepository {      def fetch(refNo: String): Trade = //codes      def write(t: Trade): Unit = //codes    }}    

Our Service

trait TradeService {
  def fetchTrade(refNo: String): Trade
  def writeTrade(trade: Trade): Unit
}

trait TradeServiceComponent {
  this: TradeRepositoryComponent => //Self typing!
  val tradeService: TradeService

  class TradeServiceImpl extends TradeService {
    def fetchTrade(refNo: String) = tradeRepo.fetch(refNo)
    def writeTrade(trade: Trade) = tradeRep.write(trade)
  }
}        

Whats going on?

  • Self type annotation for TradeRepositoryComponent
  • No commitment to concrete implementation
  • No coupling to other implementation
  • Talking about traits.  
  • Abstract vals

The end of the universe

object TradeServiceAssembly extends TradeRepositoryComponent with TradeServiceComponent {
  val tradeRepo = new TradeRepositoryImpl
  val tradeService = new TradeServiceImpl
}

import TradeServiceAssembly._
val trade = tradeService.fetchTrade("2938")
tradeService.writeTrade(t)

What did we just do? 

  • Created traits with abstract  vals
  • Self typing  to require at compile time
  • Concrete Implementation at the end 

Now what?

  • Use mocks
  • Give it different impl classes
  • Mix in and layer the cake how you want

Mock that repository

      val mockTrader = new TradeRepositoryComponent with TradeServiceComponent {
        val tradeRepo = new TradeRepositoryMock
        val tradeService = new TradeServiceMock
      }

      import mockTrader._
      val trade = tradeService.fetchTrade("2983")
      tradeService.writeTrade(trade)
  

Using Scala's Type System

  • Self Type Annotations declare dependencies 
  • Abstract members allow us not to commit
  • Scala's type system is powerful.  Use it

General Pattern

  • Create trait with abstract methods you need
  • Create trait that has abstract val
  • Use self typing where needed
  • Layer your cake at the end how you need

Functional Cake Pattern

 trait TradeRepository {   def fetch(refNo: String): Trade  def update(trade: Trade): Trade  def write(trade: Trade): Unit}

Service

trait TradeService {
  val fetchTrade: TradeRepository => String => Trade = {repo =>  refNo => repo.fetch(refNo)}
  val updateTrade: TradeRepository => Trade => Trade = {repo => trade => repo.update(trade)}
  val writeTrade: TradeRepository => Trade => Unit = {repo => trade => repo.write(trade)}
}

Implementing our service type

  • Redis as storage
  • Curry our functions
    • Partial Function Application
trait TradeRepositoryRedis extends TradeRepository {
  def fetch(refNo: String): Trade = redis//...
  def update(trade: Trade): Trade = redis//...
  def write(trade: Trade): Trade = redis//...
}

The Redis Trade Service

object TradeServiceRedisContext extends TradeService {  val fetchTrade_curried = fetchTrade(new TradeRepositoryRedis)  val updateTrade_curried = updateTrade(new TradeRepositoryRedis)  val writeTrade_curried = writeTrade(new TradeRepositoryRedis)} 

Currying Review

//WAS
  val fetchTrade: TradeRepository => String => Trade = {repo => refNo => repo.fetch(refNo)}

//Curried
  val fetchTrade_curried: String => Trade = fetchTrade(new TradeRepositoryRedis)

And we get...

Information Hiding
User doesn't know implementation
    import TradeServiceRedisContext._ //Imports

    val trade = fetchTrade_curried("2983")
    writeTrade_curried(trade)

What did we obtain?

  • Information Hiding
  • Modules 
    • Top level traits
  • Explicit Dependencies 
    • Type checked

We're Hiring Scala Developers

luke.amdor@banno.com | zach.cox@banno.com