Elm for backend developers

Before there was the concept of frontend and backend developers, there were just developers and I was one of them. We did everything from HTML to SQL and it was not hard. Then something happened, JavaScript became popular. After years of server side rendering and thin clients, the pendulum was swinging back to fat clients again. And I was a backend developer.

Believe me, I have tried to get on the train with JavaScript and its hose of new frameworks. I took courses in JavaScript. I wrote applications using Meteor, tried Angular and React. But what I never managed to do, is liking it. There is simply to many ways of shooting yourself in the foot. And all these frameworks that come and go points to something, perhaps we are trying to fix the wrong problem. I suspect it is the foundation itself, JavaScript.

I have been a professional developer for almost 40 years now and learned more languages than I can enumerate. I prefer programming languages that have a clear idea of what it is. That is one reason why I fell in love with Elm. Loving a programming tool means that you spend a lot of your spare time with it, despite there is no connection to your day time job.  Like love, there is no learning without pain, and Elm delivers that in an exquisite way.

Out there you will find many tutorials for Elm, the official one being very good but not the only one. Plus videos from conferences and challenges. Since Elm is competing for the position as the main tool for web applications, their bias is towards people with JavaScript background. I realised that when I watched a video on introducing Elm to beginners where the advice was “do not introduce types in the beginning”. I believe a programmer with their feet deep in Java would think differently.

Elm is a strongly typed language

To me, that is good news. Strong typing reduces mistakes and enhances tool support. Elm has done this well. The language is designed to allow the compiler to infer types from context without sacrificing security. When an Elm program compiles, it works. If it does not compile, the error messages are in a new class of user friendliness. You have not seen anything remotely like it before.

Let us look at a code example. Suppose you have to handle an incoming message and wish to take action depending on which message you get. We have type “Message” and it can have a fixed set of values, representing the enumerated set of possible messages.

type Message

= Increase

| Decrease

| Reset

In Elm, this called an Union Type but in my head it is an Enum but slightly better. The best part however comes when you use it in a case statement. Here is a function named “update” that takes two parameters, “msg” and “model”.

update msg model =

case msg of

Increase ->

  model + 1

Decrease ->

  model – 1

Reset ->

  0

If you forget a branch in the case, it is a compiler error! Without the need of any tool support, we have a safe refactoring since changing the type will immediately force the change of the case statement.

HTML is a library

The strong typing is not sacrificed when describing the HTML view. Instead of having a separate HTML-file with placeholders, like you do with template solutions or mixing HTML with the language, like React, Elm has incorporated it in a type safe way using a library.

Here is a function that returns HTML:

view model =

div []

  [ button [ onClick Decrease ] [ text “-” ]

  , div [] [ text (toString model) ]

  , button [ onClick Increase ] [ text “+” ]

  , div [] [button [ onClick Reset ] [ text “Reset” ]]

  ]

Every tag follows the pattern of tag-name and two lists, the first is the attributes and the other the contents. Here we have a div tag with no attributes and contents consisting of four other elements. The first is a button which has an attribute that describes what happens when we click on it. We send the decrease message.

We also see that the second elements converts the model to a string and displays it. When the model changes, the result of the view function is changed and the Elm runtime will update the DOM. And it is fast, beating the leader React in many benchmarks.

There are CSS and SVG libraries as well, which works at the same principles as the HTML library.

Now you learned quite a few things, you know how lists and strings look like. You know that Elm gives you type-safe HTML, CSS and SVG. You know the first, but not all, about Union types. The case statement hinted about how the update works but foremost you got a first feel for how strict the language is, you can not forget a case branch.

There are no runtime exceptions in Elm

Java is strongly typed but there are still errors during runtime, most notably the infamous null pointer exception. In JavaScript the situation is worse so it is interesting to see what a new language could do about it. We still need to handle the case of no data and we still need to handle the reality of things not going according to expectations. In Java we have null and exceptions, both shoot us in the foot.

In Elm there is neither null or exceptions. In lieu with what I described above on case statements, Elm ensures that you always handle all cases. Instead of null there is Maybe which is pretty much the same as an Optional in Java, but with the compiler enforcing you to handle both cases.

case model.drag of

  Just drag ->

      — Do something

  Nothing ->

     — Handle nothing

So every time it is called upon to handle the possibility of maybe no data, you use the Maybe type which is either Nothing or Just value.

Note that Maybe is a Union type and you just learned a new thing about them, the values does not necessarily look similar to each other. Here is the Maybe type:

type Maybe value

  = Just value

  | Nothing

Did you see the type parameter, “value”, similar to generics in Java? You learned another thing about types in Elm.

Instead of exceptions we have the type Result. This gives you the compile time check for handling error cases.

type Result error value

  = Ok value

  | Err error

You may think, oops, that is like checked exceptions and we know how hard that can be. Think again, where are exceptions used? Sometimes really weird, like when a query does not return the expected number of items. Sometimes when you enter an illegal state or get malformed input. Sometimes in communication across the network. It is in the latter case, at the borders of your application, where you need to handle errors. In the former cases, it is just bad design. You should not handle a search query with exceptions and you should never end up in an illegal state. Yes, I believe some of the official Java APIs have a bad design. E.g. getSingleResult in JDBC.

Elm is a pure functional language

To a Java programmer, this is a different paradigm than the object oriented, stateful way of programming. Personally, it was not a problem since I programmed in Lisp 30 years ago, the last time functional programming was popular. You probably have no problem accepting that data is immutable. It will a bit harder to understand how to use the Module concept to accomplish encapsulation. But that you can learn later, when your application grows. You do need to forget about inheritance and mutable state.

So far, functions has had their parameter types inferred but you can annotate them with types. The benefits are better documentation and better error messages from the compiler. Type annotations are written before the function as in this example:

isNegative: Int -> Bool

isNegative num =

  num < 0

Functions are of course first class citizens and can be passed as parameters. A filter, for instance, will be familiar to the modern Java programmer.

List.filter isNegative [0, 3, -5, 8]

returns [-5]

There is a lambda notation that could replace the isNegative function above, but the readability would suffer.

The Elm architecture

Now I hope you learned enough of Elm to become curious about the language and start with a proper tutorial. One of the first thing you will learn is what is called “Elm architecture”. It is a big word for what is a message, view and model design.

An Elm program, shortly put, is a set of three functions,

  • The update function that takes the current model and a message and returns a new model.
  • The view function which takes the model and returns HTML markup and events.
  • The initialise function which initialise the model.

The runtime gives you an efficient rendering of your web application and you can really focus on the logic of your program. To quote the official guide “So the Elm Runtime is in charge of doing stuff. We just transform data.”

Tools and libraries

The eco system is of course something important. I keep using IntelliJ for programming Elm, it is a familiar tool and it works well. You do not get the same set of refactoring tools as when you program in Java, but that is expected. Do not miss elm-format so your code is always formatted according to standard. Install it as a file watcher.

There is a package system that you may recognise if ever typed “npm” at the command line, but this one is a bit better. There is meaning to the version numbers, so called semantic versioning which means that a major version is required to make breaking changes.

A twist to debugging is the time-travel debugger which logs all state changes and lets you jump back in time and look at things.

Testing is done with elm-test but you may find that the need for tests becomes less. Speaking of tests, if you like katas, there is exercism.io which give you test cases for a problem and your task is to get them all green.

There is a library elm-native for writing mobile apps but it is not mature enough for production. Personally, I have hope for browsers being enough for most apps some time in the near future.

If you like your file structure being set up for you, there is an elm-create-app which was inspired by create-react-app.

You can interop with JavaScript but since that is outside the secure world of Elm, you need to work it like communicating with an external process. That way all that comes in is thoroughly checked.

Any caveats?

The first question is usually “can it be used in production”. Apparently so, as it is already.  But that is a really low bar most things passes. With the right backing, you could get lots of stuff out in production, despite being awful in so many ways.

With that said, it feels like early days still. We have not seen version 1.0 yet. The flip side of that observation is that Elm is developing in its own pace, with each step taken carefully.

If you have a huge legacy of JavaScript, with several generations of different frameworks, is it possible to switch to Elm without a big bang? Yes, it might, if you can take a piece of the UI and rewrite it Elm. It is possible to run Elm in a div tag.

What I have found hard is the encoding and decoding of JSON. It is by its design, on purpose, a bit loose, if you see what I mean. When it comes to Java, we can use reflection and object mappers to transform JSON to Java objects. In Elm, it is more of a handmade thing. Of course it pays off to exercise your brain around how to match some JSON with Elm records, but it is not usually a core thing of my application. I just want to get the result of a REST call into something I can work with. Do not miss the decoding pipeline when you come to this.

Thanks for reading this far. Your next stop could be the official guide: https://guide.elm-lang.org/

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.