0

While building a new Playframework app I am trying to use the cake pattern.

My first understanding was to mix custom traits into the controllers and pass those provided by Play as parameter:

trait MyComponents {
   def actorSystem: ActorSystemClassic
   lazy val service  = new MyService(actorSystem)
}

class MyController(
  controllerComponents: ControllerComponents, 
  override val actorSystem: ActorSystemClassic) with MyComponents { 
  

  // ...
  // Use `service` from MyComponents
}

class MyApp extends BuiltInComponentsFromContext(context) {
  val controller = new MyController(
        controllerComponents,     // <- Provided by BuiltInComponentsFromContext
  )
}

That worked fine until I had to test MyController and tried to mock the service.

To mock the service I should be able to work with a stub of MyComponents that will provide the mock. To provide that stub I have to pass it as constructor parameter.

class MyController(
  controllerComponents: ControllerComponents,
  myComponents: MyComponents,
  override val actorSystem: ActorSystemClassic) {

  // ...
  // Use `myComponents.service`
}

Of course my controller is more complex than that and he need more than one component to work. My fear is to end with a constructor that will become hardly manageable, with a lot of parameters.

To limit the number of parameters, one idea would be to mix all of the components in one. However I am not able to mix the instance on ControllerComponents provided by the super class BuiltInComponentsFromContext with MyComponents:

class MyController(components: MyComponents with ControllerComponents)

class MyApp extends BuiltInComponentsFromContext(context) {
  val controller = new MyController(
     new MyComponents with /*instance of controllerComponents provided by BuiltInComponentsFromContext*/
  )
}

I do not want to pass the controllerComponents to MyComponents because that class provide business services, she don not care about controller components.

Can you help me to implement a real life application with the cake pattern ?

gervais.b
  • 2,294
  • 2
  • 22
  • 46
  • 1
    Cake pattern considered in Scala community as obsolete - the only recommendation - don't use it. Since you are on play you can proceed with Guice or take a look in macwire for instance, if you would like to have compile time verifications. – Ivan Kurchenko Feb 18 '21 at 11:36
  • Thanks. Do you have some materials to prove that. I am curious to know more on the reason behind that decision about the cake pattern? It is still documented without warnings in Play. – gervais.b Feb 18 '21 at 15:05
  • Well, it is what I do remember from from discussions, articles, and my current legacy project full of cake pattern - believe me, this is not a way to go with modern Scala. At least couple example problems: tests injections, interop with other DI like Guice which native for Play. – Ivan Kurchenko Feb 18 '21 at 15:08
  • Again regarding testing - mocking is complicated if possible at all. – Ivan Kurchenko Feb 18 '21 at 15:10
  • I understand your points as I am more or less in the same situation. But I believe that I was wrong with my implementation. There is nothing wrong with the cake. At this time I solved my issue by passing dependencies trough constructors instead of mixing them. There may be "a lot" of parameters but I will see. The cake is used to get the dependencies and it is quite clean (at this time). – gervais.b Feb 19 '21 at 07:21

0 Answers0