Today is my 90th day working at Movio. It’s also my 90th day developing in Scala.
In my eight or so years as a software developer I had of course heard of Scala, but had never programmed in it or read any Scala code. Freshly hired as a backend developer at Movio, I was asked to learn Scala and learn it fast. Over the past few weeks, I have taken note of aspects of my learning of Scala that have stuck with me in some way which I’d like to share with you here.
Scala: A Hybrid Language
One of the first things that intrigued me when learning Scala is its position on the imperative vs functional paradigm spectrum. At first glance, Scala seems to sit at an awkward position between these two historically very different camps.
It’s not a purely functional language, such as Lisp or Haskell, and it’s certainly not a purely imperative language either. Instead, Scala has enough syntax and abstractions to fully contain both paradigms without compromise. In theory Scala programs can contain large portions of imperative code, alongside equally large portions of functional code, without conflict.
However, at Movio 99% of the code is expected to be written in a purely functional style. I found this policy very helpful as a beginner; learn to write clear and efficient code without
var or mutable data structures, and most of the time you’ll be OK. For the remaining 1%, Scala doesn’t get in the way, and lets you write concise and efficient imperative code.
Side-effects as a necessary evil
The mantra of functional programming (FP) seems to be that side-effects are evil. Pure functions, we are told, are easier to use, test, parallelize and generally reason about, and it’s difficult to disagree. But on the other hand, it would be hard to argue against the necessity of side-effects to make useful programs.
As a beginner to FP, this tension can be tricky to reconcile. You’re told to avoid side-effects at all costs, and yet you must put them somewhere. How do you decide which code should be pure and which should not? I don’t pretend to have the perfect solution on how to properly integrate side-effects in functional programs, but here are two observations.
It helps me not to think of referential transparency and purity as all-or-nothing propositions.A function that contains a `println` or a `logger.log` call, for instance, is neither pure nor referentially transparent but putting it in the same category as a function that creates a database table isn’t very helpful.
Depending on the context, side-effects such has `println` can fundamentally change the behavior of a program (e.g. CLI applications) or not at all (e.g. a web backend), which is the real concern.In that respect, I really appreciate that Scala does not force developers to label side-effecting code in the way Haskell requires it with its IO monad.
I find it helpful to distinguish between obvious and controllable side-effects from the more subtle ones Writing the result of a pure computation to an existing database table is a side-effect, but it is easily isolated in code and generally easy to control.
On the other hand, spawning a thread, creating a new file, or establishing a long-lived network connection are all examples of side-effects that can have a profound impact on the global state of the application. Controlling the modification to this global state in a safe manner is what really matters.
To solve these global state concerns, Scala’s actor model seems to be really useful but I have yet to learn about it more in depth.
Object Oriented Fu
When learning Scala, I was really surprised to see that there is very little tension between Scala’s object orientation and functional sides. Classes, interfaces, inheritance, abstract methods and polymorphism are all there and work as you expect.
When learning Scala, this familiarity is a blessing. From what I’ve seen so far the large-scale organization of a Scala program into class hierarchies and interfaces, is about the same as that of any other object-oriented language. For a newcomer to Scala who starts working in an existing codebase, this is immensely helpful.
The familiar object-oriented nature of Scala also means that it integrates quite seamlessly with third-party Java libraries. The practical usefulness of this cannot be overstated.
At Movio, we integrate a lot of Java code with Scala, and it’s almost completely transparent.
Apart from learning Haskell, I don’t remember previously having been so challenged by a new programming language, but it’s all for the best. What surprised me most about Scala is how deep the language really is.
I have now been using it daily for three months and yet I feel like I’ve only scratched the surface of the language’s complexity.
Learning Scala and returning to FP has been a great experience. I had used functional programming in research projects previously (using Haskell and a bit of ML) but, like most developers in the wild, had returned to fully imperative languages exclusively after leaving university.
At Movio, Scala and functional programming are an integral part of the engineering culture. FP has unique strengths to solve the kind of problems we solve every day (high distribution, high-availabilty, complex data processing, ...) and for us it's the best tool for the job.