Elmlightment: first impressions of Elm
I have been going back and forth with Elm for a couple of years now and never really got to test it out properly until recently when I was given the chance to write this post for our tech blog. I found this to be the perfect opportunity to provide an overview of my experience so far, some of my pain points and my journey to being “productive”.
The other day someone asked me why I’m so interested in frontend tooling when I’m mainly a backend programmer, and the answer is simple, I find frontend development to be more complex. User interactions can get extremely convoluted and unwanted side effects tend to be quite difficult to track. Therefore, it’s only natural for me to try to find a tool that helps manage my application state in a sensible manner.
I already knew some Elm syntax and constructs so I went straight to a tutorial which people within the Reddit community recommended. This tutorial explains basic Elm concepts and guides you through making a simple application.
Even if somewhat rushed I found it to be a great introduction. What I couldn’t find there I found on the official guide which goes into a bit more detail on each concept.
Upon finishing the tutorials I proceeded to create a small project on my own which you can find here.
Since the language and application architecture was new to me, in the beginning I found it really complicated and felt like dropping it altogether. It took a good two days of dedicating myself to it before it finally clicked and realized just how simple everything in Elm actually is.
Just like Haskell’s, albeit certain differences, I found Elm syntax to be really aesthetically pleasing and elegant.
To me, this function is easy to read, doesn’t have any unnecessary syntax and the signature (which is optional by the wway) only helps in the readability.
Compiler and Type system
By far Elm’s most powerful feature (and most people would agree) is its type system and its compiler errors. I’m not much of a fan of static typing but in Elm (or any ML style type system for that matter) types are so powerful and flexible that it doesn’t feel constrained at all. Contrary to most compilers I’ve encountered, Elm’s compiler messages are actually helpful when trying to find a problem. So much so, that I always found it immediately every time I got one.
Take this example from Elm’s website :
Even without knowing the language you can easily identify the problem just by reading the error message and this, to me, is a huge plus in the developer experience.
Elm is a pretty good introduction to functional programming if you ask me. Complicated functional concepts for beginners such as monads are abstracted away. I didn’t need to go out of my way to learn what they are before doing IO operations.
I didn’t experience anything that I would call a real “pain point” but people could have trouble with some concepts, especially if they don’t have a background in functional programming.
Another concept I found difficult to wrap my head around was union types and the type system in general.
Like in the example above, seeing types being used as entities by themselves without having necessarily any value associated with them was a little confusing in the beginning.
I struggled the most with how to structure my application. I had tried other tools like React and Vue before but I always followed some guidelines regarding project structure that most people seemed to accept, but in Elm, I couldn’t find such a thing. The most common answer I found on Reddit was to drop everything in a couple of files and just refactor when I felt things were getting too big which, to me, wasn’t really a satisfying answer.
It wasn’t until I watched a video where Richard Feldman, who is probably the biggest Elm promoter out there, talk (among other things) about how to organize your application logic that I started thinking that the “refactor as you move along” approach was actually not a bad idea.
As it turns out, Elm is extremely easy to refactor. There is no such thing as missing a case when doing pattern matching or forgetting to import a module during a refactor because the compiler will yell at you. I constantly read the phrase “if it compiles it probably works” when people referred to Haskell and with Elm I found that to be true as well.
All in all, it took me about 2 weeks of researching and watching tutorials to get a basic application going on my own. Therefore, I would say adoption time is pretty minimal and definitely worth it for the guarantees and productivity Elm provides.
Stay tuned for more on elm in upcoming posts.