Scala

Handling exceptions in Scala with monad transformers

A very common characteristic of Scala code is a large number of for expressions (also known as for comprehensions). And for a good reason: for expressions are straightforward to read and relatively easy to write as they usually boil down to only two methods - map and flatMap.

For example, this is a very typical Scala code that first grabs the ID of a user from one server, and then uses this ID to query additional data from another endpoint.

for {
  user <- getCurrentUserData()
  employment <- getUserEmployment(user.id)
} yield UserEmploymentInfo(user.name, employment.employer)

This code is so simple that even a person unfamiliar with programming (let alone Scala) will immediately guess what's going on here.

However, there is an important assumption that the above code makes. In order for "for expressions" to work, both functions must return monadic-like structures (you can read about it in detail here), which basically means that these structures must have correctly-defined methods `map` and `flatMap`. This is usually not a problem in Scala, as many useful types such as `Option`, `Try`, `Either`, `Future` have these methods.

However, what will happen if the result type of a little more complicated, say, Future[Try[_]]? In this case, the simple "for expression" will not work as it can only extract the outer-most value.

It turns out, however, that this use case is so common and there are generic solutions as well. Several functional Scala libraries such Cats and ScalaZ expose these solutions as so-called monad transformers.

However, if you're only using monadic structures from the standard library, there is an easier way - a small library called Scala Hamsters:

val result = for {
  user <- FutureTry(getCurrentUserData())
  employment <- FutureTry(getUserEmployment(user.id))
} yield UserEmploymentInfo(user.name, employment.employer)
result.wrapped

The only noticeable difference is that now end up with an instance of `FutureTry` and therefore, we must unwrap it at the very end.

The technology balance

When it comes to choosing technology for a new project, it is often tempting to choose the latest and the brightest stack. On the other hand, many businesses tend to fall back to something proven, well-known and usually outdated. In my opinion, neither approach is perfect and as engineers we always need to find the perfect balance between innovation and stability.

To illustrate the point, let's think about hardware. If you look at the price range of the latest CPUs, you'll notice that once you get to high-end selection the price starts to increase exponentially. The actual processing speed gets better as well, but only gradually. This makes perfect sense, because the technological process of manufacturing new chips is not yet established and production lines don't work as efficient. Inevitably, after several years, as manufacturers discover new (cheaper) ways to increase the output efficiency, the price of high-end models drops dramatically.

A similar thing happens in the software industry, but there is an important difference. Whereas a high-end CPU is definitely better than its cheaper counterparts, "new and shiny" technologies are routinely proven as anti-patterns only months (sometimes years) after the initial craze is subsided.

It is especially true on the frontend where new stuff gets released almost every day and deemed outdated or "wrong" just as quickly. A good example of this phenomenon is CoffeeScript, which came out several years ago and tried to fix some of the bad parts of JavaScript while introducing some novel features along the way. In 2018, it's not even considered a viable choice anymore and it makes certain big projects (such as Atom), which doubled down on CoffeeScript a while back, pretty awkward.

In this day and age, it is surprisingly easy to end up with a legacy frontend application even before it's finished. One European bank, for example, recently finished revamping its UI using AngularJS only to realize that Google already deprecated it and the new version of the framework is a complete rewrite. Ouch.

This logically brings us to the question of outsourcing. Can you outsource the creation of a Web-site? Absolutely, and as long as you are perfectly happy with mostly static content on the home page and the simplicity of overall design, the WordPress-based site will work perfectly well. The same reasoning can be applied to so-called "throwaway prototyping", a phrase coined by Fred Brooks in his well-known book "The Mythical Man-Month". However, there is an important caveat. As Fred Brooks himself admitted recently, the idea of creating something with the intention of throwing it away is wrong, because it's overly simplistic. And indeed, in this scenario, you run the risk of creating a completely dysfunctional system that doesn't present much opportunity to learn anything from it. As a result, as Ward Cunningham suggests here, you'll have to build the prototype twice, probably with disastrous consequences for the business.

What should we do then? In my opinion, we should try to create a reasonably flexible system that works well under a reasonable load. This flexibility will enable us to adopt it to future changes while serving perfectly well the current need of the business and its customers. For many startups, the reasonable load could be just about 10,000 concurrent connection and, quite honestly, with modern hardware, this is pretty easy to handle.

This is one of the reasons I like Scala and React. These technologies are relatively stable and give the developers an enormous amount of flexibility. Scala, in particular, is a very good choice for a backend language as it allows programmers to move very quickly while preserving type information and keeping accidental complexity to almost zero. The Play framework makes a great choice as a foundation for a backend stack as it has a ready-to-use solution for pretty much any problem out of the box. While Java is making a good progress at becoming a more productive language, Scala is still miles ahead which is well illustrated here.

Similarly, React is a very capable library and, unlike some other frontend solutions, its API has been stable almost since the inception. The ecosystem is also quite enormous and there are usually several good choices for any task. And the final argument is React's great support for server-side rendering, which we successfully employed in our projects (one such example can seen here).