At Codacy, we use Scala for all our core, complemented by Play Framework and built with sbt.
sbt is a great open-source build tool. It is used for Scala and Java projects, similar to Java’s Maven and Ant. specially if you want to focus more on coding than compiling :D.
Earlier this month we decided to do a complete separation of our application.
Although we already had several different sbt sub-projects we had to define some structure and rules to keep them in sync.
With all the simplification and ease of creating a project comes great responsibility, we want our build to be kept simple and easy to maintain.
Growing the project
As soon as our project started growing we found ourselves splitting it into multiples sub-projects and even completely breaking it in several completely different projects.
When we split our monolithic app (one app with several sub-projects) in several completely different projects we thought we could just duplicate all the sbt configs and all would be fine.
But obviously when you go easy on something you will end up suffering :(.
How to keep it clean
Bellow I will describe the most important lessons we learned in this process and why they matter to keep your projects maintainable and in sync.
Before we start you can apply this steps for both sbt sub-projects and completely separated sbt project.
If you have sub-project you should create objects in your project/ folder for example Common.scala and Dependencies.scala.
if you are sharing the settings between projects you can use a sbt plugin to import all the settings.
- Common settingsRefactor your configurations into a Common object.
- Each sbt project needs to have multiple settings and most of them can/must be shared between projects.
Our base settings contains mainly the scalaVersion, the compiler flags:
- We also have other configurations that are specific for our play applications:
- Common resolverssbt supports Ivy and also Maven style repositories. Since Scala can use Java libraries it is very common to depend on lots of libraries.
To always have the right resolvers you should define them like the common settings:
- Unified dependenciesWhen you have lots of dependencies you do not want to write them all in your projects. Not only because it is a lot of text but also because you should keep versions in sync on your sub-projects.
- To solve this you should use a object where you define all of them and then you just have to write the value in the project build definition.
- Plugins are your friendssbt might not be as mature as Maven, but there are plenty of plugins that will help you focus more on project development and not maintaining the build configuration.
- One of the most recent additions to Codacy is the `sbt-native-packager` which allows us to package our application in many different formats, more precisely a docker.
- You just need to add the plugin and configure the docker settings:
- In the beginning you just need to setup your application and with half a dozen of lines you can have your Scala / Java code compiling, running and being distributed in multiple different formats.
During my research for this post I found a great presentation from Josh Suereth that has all this aspects and even more tricks you can use on your Scala projects.
Now that you have your sbt project setup lets focus on code again and use Codacy to keep it clean.
Do you have any other recommendations that we might have missed? Let me know in the comments below.
Edit: We just published an ebook: “The Ultimate Guide to Code Review” based on a survey of 680+ developers. Enjoy!
Codacy is used by thousands of developers to analyze billions of lines of code every day!
Getting started is easy – and free! Just use your GitHub, Bitbucket or Google account to sign up.