Starting a Scala Project
When starting a new Scala project there are a few things that you want do get setup correctly before starting your development work. These are some of the things that I do for each new project.
Spoiler - I have created a GitHub repo basic-scala-template that contains everything that is mentioned here.
Note - Based on feedback, I have listed updates to the template at the bottom of this post.
A Note on Activator
The wonderful people at Typesafe have a project called Activator which is a nice little tool that, among other things, allows you to get started quickly by selecting a base template. While this is useful and there are some good templates, I still prefer to manage my own template. This allows me to make some additions that are missing from the Activator templates and setup my projects in a way that work best for me.
SBT
I setup all my projects as a standard SBT project (because why wouldn’t you)
so hopefully you can find this useful. The first thing I do is download the
version of SBT that I want and add the launcher and the shell script local
to my git repo. This way I always have sbt available on whatever machine
that I am working on and I am able to make per-project changes to the
launcher. If you do this as well you will have to get used to typing ./sbt
vs sbt
, but that is an easy change to make.
As of right now, my project structure looks like the following:
1
2
3
4
.
├── bin
│ └── sbt-launch.jar
└── sbt
I will note that for the actual sbt
script I usually just use one of
my own rather than the super-complex ones that ship with the SBT download. My
current sbt launch script looks like:
1
2
3
4
5
6
7
#!/bin/bash
JAVA=java
JAVA_OPTS="-Xmx512m -XX:MaxPermSize=256M"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
$JAVA $JAVA_OPTS -jar "${DIR}/bin/sbt-launch.jar"
Basic SBT Additions
Now that I have SBT setup for a project, I can start doing some basic
configurations that I figure I will need on all my projects. First I’m going
to add is the sbt-revolver. This is a very useful plugin that can run
your project in a forked JVM and reload it on a change. We can add this to
the project by adding the following to our project/plugin.sbt
:
1
addSbtPlugin("io.spray" % "sbt-revolver" % "0.7.2")
While I’m at it, I’m going to add one more plugin, sbt-idea, that can
generate IDE-specific files for IntelliJ IDE with a simple command gen-idea
:
1
addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.6.0")
Template Build File
When using SBT I opt for the full Build.scala
vs the DSL-like build.sbt
file.
I find it easier and more straight-forward to work with. I like to break my
build file into several logical sections: resolvers, dependencies, build settings,
and the application build. My typical build-file looks like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import sbt._
import Keys._
import spray.revolver.RevolverPlugin._
object Resolvers {
}
object Dependencies {
val appDependencies = Seq(
)
}
object BuildSettings {
val buildOrganization = "johnmurray.io"
val appName = "CHANGE_ME"
val buildVersion = "0.0.1-SNAPSHOT"
val buildScalaVersion = "2.10.4"
val buildScalaOptions = Seq("-unchecked", "-deprecation", "-encoding", "utf8")
import Resolvers._
import Dependencies._
val buildSettings = Defaults.defaultSettings ++ Seq(
organization := buildOrganization,
version := buildVersion,
scalaVersion := buildScalaVersion,
libraryDependencies := appDependencies,
scalacOptions := buildScalaOptions
) ++ Revolver.settings
}
object ApplicationBuild extends Build {
import BuildSettings._
lazy val main = Project(
appName,
file("."),
settings = buildSettings)
}
Even though this build file is pretty bare (at the moment) there are some key things that I like to include as part of every build configuration.
- Scala
- Aside from specifying the version that I will be using for this project, I also specify some basic compiler options to output more verbose warnings and do some extra checks for me.
- Versioning
- I like to start each project as a snapshot version (0.0.1). I can then extend the build-file later with some publishing configurations to push snapshot versions to a repo (like Sonatype) on each successful build/commit/test-run/etc.
- Revolver
-
Even though we added the
sbt-revolver
plugin to ourplugins.sbt
file earlier we still need to add the settings to our build to fully install it.
Style Checking
For me, this is a new addition but I generally like consistency in my projects (open
source and closed) when it comes to style. I’ve been playing around with various
style checkers, but I’ve settled on Scalastyle for now. I don’t have much beyond
the standard, but I’m sure it’ll evolve over time. I added the following to my
plugins.sbt
file
1
2
3
addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "0.4.0")
resolvers += "sonatype-releases" at "https://oss.sonatype.org/content/repositories/releases/"
I’ve also updated our buildSettings
in project/Build.scala
by appending the
Scalastyle settings
1
2
3
4
5
6
7
val buildSettings = Defaults.defaultSettings ++ Seq(
organization := buildOrganization,
version := buildVersion,
scalaVersion := buildScalaVersion,
libraryDependencies := appDependencies,
scalacOptions := buildScalaOptions
) ++ Revolver.settings ++ ScalastylePlugin.Settings
As far as the build configuration goes, my configuration isn’t far off the default you
get by running sbt scalastyle-generate-config
so I won’t list it here.
Testing
For testing I typically start with Specs2 and add from there. For this we add to the build file simply:
1
2
3
4
5
object Dependencies {
val appDependencies = Seq(
"org.specs2" %% "specs2" % "2.3.10" % "test"
)
}
I can easily add others in the same fashion. For example, if I were doing an Akka
project I would add the akka-testkit
for the spray-teskit
for Spray projects.
If the project I am building is open source, I have to think about CI what build
system I’m going to use. I personally prefer to use Travis-CI just because
it’s so darn simple. Since this is usually the case I add the .travis.yml
file:
1
2
3
4
5
6
7
8
9
10
11
language: scala
scala:
- 2.10.3
script:
- sbt compile test:compile
- sbt scalastyle
- sbt test
jdk:
- oraclejdk7
- openjdk7
- oraclejdk8:w
Miscellaneous
As a final note, I like to add some basic files that I put in most projects:
.gitignore
-
The baiscs for scala projects as well as IntelliJ project-files and general
files (like
.swp
files and what not) readme.md
- I like to include a readme with all of my projects (open source or not) just as a welcome and a guide for navigating and working with the project.
Done!
Now that I’m done putting together all the pieces to get started, my final directory structure is laid out in the following manner:
1
2
3
4
5
6
7
8
9
10
11
.
├── .gitignore
├── .travis.yml
├── bin
│ └── sbt-launch.jar
├── project
│ ├── Build.scala
│ └── plugins.sbt
├── readme.md
├── sbt
└── scalastyle-config.xml
As I mentioned in the spoiler up top, I have put this into a git repository for my own (and possibly your) convenience here. You can start any new project using this template simply via:
1
git clone https://github.com/JohnMurray/basic-scala-template.git YOUR_PROJECT_NAME
Or, you can clone the repository and add the scala-new
script to your path which is
located in the root of the project. With this you can simply do
1
2
3
scala-new my-new-project
cd my-new-project
# start working!
This script will take care of updating the repo, creating a directory, and copying over all the necessary files. Easy peasy.
If you find this useful (and I hope you do) then please fork my repo and customize it to suite your needs. Feel free to send pull requests if you think I am missing something awesome that you feel every Scala project should include.
Enjoy!
Update #1
Thanks to a comment by predef on reddit, I have removed the sbt-launcher jar from
my project along with my custom sbt script in favor of using the sbt-extra script
and creating a project/build.properties
file. You now must simply use the sbt script
./sbt
and the correct version of SBT will be downloaded for you.
The second suggestion was to remove the sbt-idea
plugin from the project and move it
into my global plugins (that’s a thing?!) which is a fantastic idea. So I have now created
the file ~/.sbt/0.13/plugins/intellij.sbt
that contains the addPlugin...
that we used
earlier in the plugins.sbt
file for the sbt-idea
plugin. Now the project can be more
agnostic to what editor is used. Do note that if you still want to use the IntelliJ SBT
plugin that you’ll need to add that to your global plugins as the script/template will not
handle that for you.