I was recently looking through our various open-source Scala projects and I think a common theme emerges: enabling using simple code and simple APIs to solve common tasks. To be more specific, let me call out three of them:
- quicklens: modifying deeply nested case classes
- macwire: automatic generation of constructors when using manual dependency injection
- sttp: a programmer-friendly http client, with easy request templating, an uri interpolator and exchangeable backends
The use-cases for the above mentioned projects aren’t particularily exciting or novel; however, they solve practical, “everyday” problems. It’s not Machine Learning or Fast Data, but I think it’s still worth exploring how to simplify the more mundane parts of code. In the long run, this will allow us to spend less time writing and reading these “simple” parts, leaving more mental space for the complex code solving complex problems.
As far as Scala is concerned, it’s sometimes easy to loose focus on solving simple problems using simple code. The Scala language offers a number of features; while each of them is relatively straightforward, it’s their interaction where the language gets its expressive power. This, in turn, can lead to complex code; but certainly doesn’t have to. We just need to keep in mind, what kind of problem are we solving (see also the Principle of Least Power by Li Haoyi).
This potential complexity might be seen as an argument against using Scala at all: maybe using a more basic language will save us, at least partially, from writing complex code? I don’t think so; as competent, responsible software engineers, we are more than capable to choose how to best solve a specific problem. I don’t believe that using crippled tools (i.e. languages with fewer features) and taking away some of the freedom that we have in Scala is the way to go. Here, competent and responsible means that we must resist the temptation to over-engineer (and this temptation is no way unique to the Scala ecosystem), and carefully consider the balance between the complexity of language features used and the problems at hand.
On the contrary, I think that there’s yet another opportunity for Scala to shine over Java, Kotlin or Go. Apart from being a great language for building big data and distributed systems, Scala can have a huge role in offering simpler solutions to every-day problems than their current Java counterparts. These solutions might be not as attractive, with less “magic”, but in effect make the code better. As a specific example, consider the usage of annotations in Java.
Note that „simple” is definitely subjective; in the context of Scala, it might as well mean using features that are considered to be more “advanced”, such as implicit parameters, higher kinded type constructors or macros. Language features are just a tool to achieve our goals:
- code which clearly separates business logic and infrastructure concerns
- explorable and readable both by current and future developers of the system
- striking a balance between terseness and using basic, familiar constructs
Scala gives us a rich toolset: object oriented programming, functional programming, immutability, implicits, macros… But remember that object-oriented doesn’t need to mean inheritance, or functional doesn’t need to mean type-level programming. Let’s use the more intricate language feature combinations for the complex problems. And let’s build a simple Scala stack for the simple ones.
I’m sure that the three projects mentioned at the beginning are just the tip of the iceberg; there’s certainly many more areas in the Scala ecosystem that could use simpler or better thought-through APIs. What would you improve?What are the use-cases for which you think a simpler approach should exist in Scala? Let us know! Maybe this will be an inspiration to existing or aspiring open-source developers.