It is generally a good practice to split your project into multiple modules. A well organized project is easier to understand. The complexity of the project is broken down into separate parts, each of those parts can be studied individually. Separation also helps to reduce incremental compilation times.
We will now transform our one-module project into project with multiple modules. We will follow a pretty standard separation into Util, DAO, Services and Web modules. One extra module will be macros, because we want to ensure, that they always reside in a separate compilation unit. Here is, how we want our project to look like, once it is imported to IntelliJ:
Multi module build.sbt
Let’s take a look at the build.sbt
file, one section at a time:
We start with defining some common settings. They will be reused in all modules.
Next, we define a root aggregator project. The concept is similar to Maven’s aggregator POM. This module is not really necessary for running the application. However, it comes handy, when we want to execute the same command for all modules, e.g. clean
or test
Web module has been moved to a subdirectory. Sources are now located in modules/scalactica2d-web/app
and modules/scalactica2d-web/conf
. It depends on another sub-module: scalactica2dServices
. It is also the only module with PlayScala
plugin enabled.
Services, DAO, Util and Macros modules have a standard location of sources in src/main/scala
directories.
Note, that sbt command run
does not work anymore. There is no runnable class in the aggregator module. Instead, we will start PlayFramework server by running scalactica2dWeb/run
. It is possible to create and alias in build.sbt
:
Thin cake pattern
Now, we just need to wire everything together. For that, we will use the thin cake pattern. Let’s start from bottom up.
First of all, Macros and Util module do not expose any beans. Both contain Scala singletons (object
) or classes, that do not have state and no dependencies. A friend of mine once argued, that Util classes should be included to dependency injection too, just so that we use the same approach the same in whole project. It’s up to you, how you will decide on this.
DAO module components trait contains two beans, both implementing the same interface. It also declares a dependency on a DataSource
.
Services module components contains only one bean and one dependency:
Web module components contain router and controllers.
And finally, we mix in all components together. This is also the place, where we provide top level configuration of the whole application. In this example, we set up the datasource from configuration properties. We also choose which implementation of PlanetDAO
will be used. And we also choose, which filters will be used, while processing HTTP requests (none in this case.
Next, we will have the DAO class access a real database, but before that, you might want to check my thoughts on database access patterns