Three tools to improve your Scala workflow
A programming language itself, while being definitely in the centre of interest, is only one of the components of a programming ecosystem. Another crucial component is tooling - and even given the best programming language out there, productivity might be poor if the tooling isn’t right.
Luckily enough, Scala is not only a great programming language but a significant investment is done in the tooling area. There are a couple of tools that I find especially useful in my day-to-day work. And while I might be biased, as apart from commercial projects I only work a lot on open-source ones such as tapir, hopefully, you’ll find the below useful in your everyday work.
First and foremost comes scalafmt. Scala, being a flexible language, gives you a number of possibilities to pick from when creating abstractions, choosing either a more object-oriented or a more function-oriented approach, but it also allows for a great deal of flexibility when it comes to syntax.
While the discussions on which programming construct to choose to create an abstraction are good to have, as they directly impact future extensibility, maintainability, and readability of the code, code-formatting discussions are almost entirely bikeshedding. Scalafmt removes all that.
All of the open-source projects that I work on (and most closed-source ones) use scalafmt for formatting. Personally, I use format-on-save in my editor, but when you do the formatting, it is, of course, up to you. The important requirement is that you format before pushing to version control. Not only does it remove needles discussions, but it also causes diffs to contain less noise - no more “artificial” changes because someone added indentation or removed a newline.
Nicely formatted source code using scalafmt
Scalafmt can be configured itself, and its configuration might be a source of pointless debates as well. That’s why I simply use the default configuration, it’s good enough and again, ends any discussions on the subject before they even start. Well, to be honest, I do have one configuration override - max line length. Here’s the
.scalafmt.conf file that configures the formatting:
version = 3.4.3 maxColumn = 140
If there’s one thing I might wish for in scalafmt, it’s that it would always create the same “canonical” version of the source code on reformat, regardless of the newlines you add manually. That’s not always the case currently - scalafmt allows some of your syntax-related inventions to be preserved. Maybe in a future release? :)
Docs aren’t the most exciting thing to work on in a project, but they are a necessity. One of the reasons we don’t like working on documentation is because it gets outdated so quickly. But there’s a tool for that: mdoc. It’s a markdown pre-processor that type-checks and optionally runs any code snippets that you embed in your code.
Not only are you sure that any code examples in the documentation are up-to-date; it also forces you to put all the necessary imports next to the code. While imports aren’t the most exciting thing in a code example, they are a saviour for the consumer of your docs. They remove a possible source of confusion (and make “copy-paste programming” even easier! :) ).
It’s all type-checked!
You might think that this is mostly useful for open-source projects, but in any larger commercial project or organisation, you’ll end up with internal libraries. They need documentation - sorry, compiled documentation - as well!
Being up to date
A typical project will have tens (if not more!) direct and transitive dependencies. It’s most often hard to keep track of all the new releases; if we’re not actively working on staying up-to-date, you’ll soon find yourself doing a painful upgrade spanning multiple minor or major versions of a dependency, with a number of breaking changes that have been introduced along the way.
Scala Steward is quite smart when it comes to integrating with sbt and correctly finding what you depend on, what can be updated, and where to update the version number (it works great if you store dependency version number in constants as well!). Assuming your CI kicks in when a new pull request/merge request is created, staying up-to-date with the ecosystem will become a breeze.
Creating the PRs is only a first step; you’ll soon find manually merging them to be tedious and boring work. That’s when tools such as mergify come to the scene: they allow you to automatically merge a pull request if certain conditions are met. For example, you might say that if a PR from Scala Steward affects only the
build.sbt, and the CI passes, the PR should be merged.
Scala Steward at work
You can use the as-a-service Scala Steward for publicly accessible projects, or you can set up your own instance for your closed work. The latter requires a bit more work, but well - nothing comes for free.
When dependencies are involved, there are always security considerations at play. On one hand, your organisation might require that only verified releases of libraries are used. On the other, using outdated dependencies is a risk in itself. Auditing every release of every open-source library that a project uses is virtually impossible, so you’ll have to either go with using an audited, but probably significantly out-of-date set of dependencies; or staying up-to-date with the latest releases, which means having access to the latest features, security fixes but also … to probable new bugs that might be introduced.
We’ve only scratched the surface of the tooling in Scala that is in use every day. One of the core tools is sbt, which despite its weaknesses and complexity, is still one of the best build tools out there. There’s the upcoming scala-cli, which aims to improve the command-line Scala experience. There’s sbt-release and numerous other sbt plugins (our favourites are bundled in a sbt-softwaremill meta-plugin) which automate many rather boring everyday tasks (that’s what computers are for!).
It would be great to see continued investment in the Scala toolchain. It might not seem to be the most exciting thing to work on, but given its direct impact on the productivity of Scala programmers, maybe it is?
What’s your favourite Scala tool? :)