“Scala is a creative language”. Many of us who love this tool often give this response when asked why we like using it. I’ve been hearing it from people for years, from colleagues at work, from presenters at Scala days, and from friends, etc. I have always intuitively felt the same, but have not been able to pinpoint the reason why this is so.
Then I heard Elon Musk describe First Principles Thinking, and it sounded a lot like how we use Scala. Many Scala libraries don’t give us ready made components, but they give us powerful primitive building blocks and tools that we can combine into useful pieces very fast using functional combinators. The crucial point here is that we start with primitives an we build custom components for the task at hand, as opposed to customizing or copying existing components made by others for other similar projects.
Why does this matter? Because when working with Scala we build lean lightweight solutions specifically for the task at hand. We come up with new things every single time:. We work creatively. Therefore we don’t carry around baggage from other projects, because we are not starting by copying other folks’ work.
Example: Landing page signup form
Let’s say we have a product that we have created a digital advertising campaign for, on-line. Usually, after watching an ad, the user is taken to a landing page which gives more info on the product and gives some incentives to the user to sign up for something immediately. Let’s say we are coding the signup page. How would that work?
Coding the front end the traditional way using imperative Java or Javascript:
- We would probably use a web server. If we were to use something like Node, we would probably have to deal with its myriad of dependencies. When we’re forced to upgrade one of those by a component we use, 10 other dependencies would break. We would spend much of our time keeping our dependencies under control
- node_modules would add a huge chunk to our footprint which would make deployment, and therefore the development iteration cycle slow.
- Because we used Javascript we would have to write many more tests due to the lack of a strong typing system to protect us from ourselves
- If we used Java, we would have to spend much of our time maintaining boiler plate code. Do Java beans ring bell?
That’s a lot of baggage for a single form.
Coding it using Scala and a functional Scala framework, Akka HTTP:
Scala offers a much simpler alternative by allowing us to think in terms of the low level building blocks of the HTTP protocol, which are our first principles when building HTTP endpoints. No complex web server will need to be installed. To help us work with low level constructs, Scala offers many conveniences over competing languages e. g. half of our testing will be done by the strong typing system. Without these productivity boosting features it would not be possible for us to work on a low level, on the level of our first principles, and still produce results in a reasonable timeframe.
val route =
get {
path("signup.html") {
getFromFile("signup.html")
}
} ~ post{
path("signup") {
formFieldMap { fields =>
//.. call back end to store form data ..
complete(HttpEntity(ContentTypes.`text/html(UTF-8)`,
"<h1>Thank you!</h1>"))
}
}
}
val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
Done!
The point here to notice is that Scala and Akka HTTP allowed us to build just the tiny fraction of the web server that we needed to solve our problem. We were able to construct application level functionality directly from HTTP primitives, within minutes. It is rare that tools allow us to build high level logic directly from primitives so quickly. It’s either not possible at all or it would take too long to be practical.
What did we gain? We only built what we needed, not more. So we have a slick light weight solution. Following the same line of reasoning we can ask similar questions when designing the rest of the app. For instance, what do we really need in order to save the forms? Do we really need a database, to save a couple of forms. Again the answer is that we probably don’t:
Saving the forms with Scala?
def writeObject[T <: AnyRef: Manifest](f: T): Try[Unit] =
Try(
Files.write(
Paths.get(s"${f.getClass.getSimpleName}.json"),
write[T](f).getBytes(),
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING))
Done!
So what just happened here? We achieved what we wanted. We wrote the form storage code without introducing any heavy dependency, because we coded it from low level primitives.
What are the benefits?
Cost is a big one. Reducing an app’s complexity while still delivering the functionality required is an effective way to reduce cost. If serving from the cloud, in the case of cutting out the database from the project, we are saving having to provision an extra Kubernetes pod. That’s a billable resource. Our solution will become more affordable to our clients. Everybody wins!
Without functional programming, this way of working simply would not have been practical. Scala in particular is very expressive even amongst functional programming languages, therefore it supports this way of working from primitives particularly well.
Of course let’s not re-invent the wheel if a suitable well constructed wheel actually exists! If we were to build an accounting system, we would be fools not to use a relational database, because that is precisely what they were designed for. But in those cases that are less standard, such as our simple task above was, or when the existing standard solution is suboptimal, First Principles Thinking is as useful in software as it is in any other field.