Skip to content
This repository has been archived by the owner on Apr 14, 2022. It is now read-only.

Basic support for Cake pattern based configuration. #17

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Basic support for Cake pattern based configuration. #17

wants to merge 1 commit into from

Conversation

hekonsek
Copy link
Contributor

@hekonsek hekonsek commented May 9, 2013

Hi,

Some people complain that using type-scafe Scala with type-unsafe Spring dependency injection makes no sense. I personally disgaree with such statements, although I think that we could add some optional type-safe checking to the project to laverage the pros of Scala. I therefore created the Cake support for Spring Scala.

Cake support for Spring Scala allows to create type-safe cake view over the entire-, or part of the-, functional application context.

I would like to elaborate a little bit on some concrete example. Imagine the part of the typical Spring application .i.e. Service and Dao.

trait Dao
class ProductionDao extends Dao
case class Service(dao: Dao)

We want to wire these two guys into Spring application context. On the same time we want to take the advantage of the cake pattern in order to:
a) get global access to the application components
b) verify at the compile time that we have provided all necessary dependencies

For this purpose we create typical cake components, but instead of specifying dependencies as T we specify them as () => T.

trait DataAccessComponent extends CakeSupport {
  val dao : () => Dao
}

trait ServiceComponent extends CakeSupport { this: DataAccessComponent =>
  val service = singleton(new Service(dao()))
}

Then we wire the dependencies into the global application context.

object MyApp extends Cake extends ServiceComponent with DataAccessComponent {
  val dao = singleton(new ProductionDao)
  // val dao = singleton(mock[Dao]) // for tests
}

We can use the CakeObject as regular Scala cake:

val dao = MyApp.dao()
val service = MyApp.service()
dao == service.dao

Under the hood, our cake hides regular Spring (functional) application context:

val context = MyApp.context
context[Service] == MyApp.service()

The magic here is the singleton method from the CakeSupport trait which registers the function defined as Cake dependency in the application context.

The nice thing in cake for Spring Scala is that you don't have to cover all your Spring dependencies with "caked" components.

object CakeObject extends Cake with FunctionalConfigurationSupport
  with ServiceComponent with DataAccessComponent {

  // Beans from this configuration will be available only for the
  // Spring application context and will not be a subject of the
  // compile time type-safe checks.
  def configurationClass = classOf[ComponentScanConfiguration]

  val dao = singleton(new ProductionDao)

}

class ComponentScanConfiguration extends FunctionalConfiguration with ContextSupport {
  componentScan("org.more.dynamic.components")
}

Using this approach you can combine the best of both worlds - type-safe cake dependencies and dynamic Spring configuration.

What do you think?

PS Scaladoc available on demand, as usually :) .

@poutsma
Copy link

poutsma commented May 13, 2013

Hey Henryk,

Once again, thanks for making another contribution to Spring Scala. It's hard for me to keep up with them all :)

I have a couple of questions/remarks:

  • I don't see how this feature is more typesafe than the existing FunctionConfiguration support we already have. Or is it simply more typesafe than Spring XML?
  • I think one of the reasons people use the Cake pattern is that they do not need an additional framework to do DI. As such, I think it will be hard to convince them to switch to the 'Spring Scala Cake' instead. And if they do switch, they will need to make some code changes in their components (switching from T to () => T and extending from a base class).
  • I think existing Spring users will feel much more at home using the FunctionalConfiguration style. It is a natural counterpart in Scala to Spring XML and Spring Javaconfig.

So overall, I am not entirely convinced we need this feature. I am just not sure who the target audience for this new feature is, who we're trying to appeal to. As I wrote above, Cake users will probably stick with Cake, and Spring users will feel more comfortable with functional configurations.

But I could be wrong, of course. Feel free to correct me :). Also, I'm interesting in hearing the opinion of other contributors: @nurkiewicz and @eugener?

@hekonsek
Copy link
Contributor Author

Hi Arjen,

I don't see how this feature is more typesafe than the existing
FunctionConfiguration support we already have

Cake is not about a type safeness itself, rather about the compiler verifying that necessary dependencies have been provided. When you compose the cake from components and compile it, the compiler will tell you what dependencies you need to provide.

object MyApp extends Cake with MyComponent1 with MyComponent2 {
  // Compiler error tells you that you need to provide missing dependencies. 
}

object MyApp extends Cake with MyComponent1 with MyComponent2 {
  // Dependencies in place. Code compiles.
  val dependency1 = new Dependnecy1()
  val dependency2 = new Dependnecy2() 
}

With FunctionConfiguration alone, you need to compile and start the Spring context to find out that you missed the dependencies (by runtime exceptions at context startup). Cake view over the FunctionalConfigApplicationContext provides you the way to verify subset of required dependencies at compile time, instead of runtime.

I think one of the reasons people use the Cake pattern is that they do not need
an additional framework to do DI. As such, I think it will be hard to convince them
to switch to the 'Spring Scala Cake' instead.

In my humble opinion "No frameworks" Scala people won't use Spring Scala anyway. I wouldn't even think about targeting them :) .

I am just not sure who the target audience for this new feature is,
who we're trying to appeal to. As I wrote above,
Cake users will probably stick with Cake, and Spring users will feel more comfortable
with functional configurations.

I'd like to target people like me :)

  • I believe that frameworks aren't evil so I would like to take the advantage of Spring.
  • On the other hand I like Scala and would like to make use of its best features.
  • I would like to use Cake for the compile time dependency checks, because if I can predict upfront that some dependencies are required, then I would like to be alarmed as soon as possible (compilation time) that I'm missing these.
  • I don't want to start the Spring context to verify that I missed required dependencies.
  • I also would like to mix required dependencies (checked at compile time) with optional dynamic dependencies (detected at runtime).

Cheers. :)

@poutsma
Copy link

poutsma commented May 14, 2013

I see, your points are valid. Especially the compile-time check, I didn't consider that before.

WIth that, I need to take another look at the code. I'll keep you informed.

Thanks!

@hekonsek
Copy link
Contributor Author

Sure, take your time. If you more information from me, just drop me a line. :)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants