Why We Chose Elm for Humio’s Web UI
This blog was originally published April 13, 2021 on humio.com. Humio is a CrowdStrike Company.
Humio software engineers Thomas Anagrius and Jeroen Engels sat down to talk about why they got involved with Elm for web-based front-end programming. Humio was an early adopter of Elm, putting Elm code into production in 2016. Today, Humio has one of the largest Elm code bases in the world. Here’s what Thomas and Jeroen had to say about working with a very young programming language for a very modern new logging platform.
Q: Why did you choose Elm to build a UI for Humio’s log management platform?
Thomas:I came from a place where we had been working with Clojurescript and a Clojurescript web framework called Om for a while. In Om you had a single reference to the entire state of your application and I quickly understood the power of this. I was then introduced to Elm, where this kind of architecture was built directly into the language itself which blew me away.
Elm, the language, was made specifically for writing web applications. It is a paradigm shift compared to how you would normally think about a browser application where things like runtime-exceptions are a thing of the past. Elm is a pure functional language. It’s very focused and it’s very deliberate and it’s very opinionated in how it does things. Also it didn’t hurt that Elm is a purely functional language and we were a bunch of language nerds.
Q: What were your requirements for picking a technology?
Thomas: We wanted to build a fast interactive dashboards and fluid search experience to give users a visual representation of their log data in real-time. Dashboards sit on the walls of companies all day long, tracking systems data and applications data. Our customers want to see, for instance, how many database queries they’re running in real time. We don’t want those monitors to crash or be delayed in showing the result. It’s not okay to have a dashboard hang and think that everything is fine, when in reality your system is crashing and you don’t notice.
So in short: Speed and stability were our main requirements.
We knew we were going to be working with huge volumes of data and at the time Elm blew every other web framework out of the water in terms of performance (and still does). We wanted to represent massive amounts of log data in real time with only sub-second delay. So having as little overhead as possible was pivotal. Humio’s platform can process trillions of events a second.
We also wanted dashboards that could run for a very, very long time without crashing. Since Elm’s compiler ensures that runtime errors virtually can’t occur, we can sleep tightly at night knowing that if it compiles it runs.
Q: Why are there no runtime errors in Elm?
JS (and therefore also TS) have dynamic aspects that a static type-checker can’t validate at compile time. Elm on the other hand is a very small language with no dynamic aspects, which means that the compiler and tooling has full knowledge of possible inputs and outputs at every step, and doesn’t provide any escape hatch for circumventing the type-checking.
The compiler checks for exhaustivity and ensures that you covered all. For instance, if-expressions always have an “else” expression. You need to express what must happen when the condition is true, but the language also requires you to express what happens when the condition is false.
Q: Which other languages or frameworks did you consider?
[…] I try to write code with zero dependencies – code I wrote 25 years ago with zero dependencies still works today. Code I wrote 5 years ago with external dependencies often fails. It’s my contribution to the war on entropy. – Joe Armstrong
Q: Humio was one of the early adopters of Elm. When did you get involved? What concerns did you have about adopting a new language?
Thomas: We started working with Elm in 2016. In that first year, I kept thinking: What the [heck] were we thinking? We were worried about a bunch of problems, including how to hire Elm programmers – which turned out not to be one because learning Elm is simple. We were worried that Elm’s syntax (that most developers will find unfamiliar at first) would scare people away. We were also worried about how easy it was to debug. Since it is a compiled language you can’t see your exact code running in the browser. There were not a lot of developer tools that supported it, which was a big pain for us, and a lack of documentation. All of these turned out to be non-problems in practice.
Being an early adopter was painful at times though. When we had a problem, we were likely the first people in the world to have that exact problem. We couldn’t just look it up on StackOverflow, or find a blog that tells you how to deal with it. You can sit with a stupid little bug for weeks, trying to solve it by trial and error.
Today, the landscape is completely different. There are many examples you can use for reference, IDE support is really good and you have things like auto-suggestions for fields and type inference. The Elm community is supportive and Elm has been battle tested in production on many large projects that have had to solve similar problems to those we have encountered.
Q: Was Elm easy to learn and use? What was the learning curve like for your team?
Elm is opinionated and restrictive. At the same time, Elm is a simple language. Once you start working with it, it makes a lot of sense very quickly. Once you understand WHY things are like they are, you accept the compiler as your friend – not your enemy.
Strong types also act as a kind of documentation for other developers. Rather than writing a lot of prose, you can just annotate it with a type and the compiler will complain if something is wrong. We’re a distributed team, so we’re not sitting next to the person we’re working with, so there’s a lot of value in having types.
Jeroen: The Elm compiler is famous for its very friendly error messages which help a lot with dealing with the problems it reports and getting used to the language.
I personally find that the learning curve is not too harsh in practice. We have newcomers go through the official Elm guide, we sit down with them to answer questions and do concrete work, and after a couple of weeks, we don’t get requests for help anymore. They may not know the idiomatic Elm solutions to all problems, but they are productive fairly quickly.
Q: Are you happy with the results? Were there any “Aha!” moments, where you solved a difficult problem?
Thomas: Yes, and yes. The best thing about Elm is I am never afraid of breaking the things because of refactoring something, I have complete trust that the compiler will tell me if I did something wrong. This is a huge advantage! Elm gives you a feeling of security and confidence – for new hires this is pretty big deal. You can make big changes and do code cleanups and be confident that everything will be fine. I can’t imagine giving that up. It’s a game-changer for large code bases.
Jeroen: My “Aha!” moment was probably when I learned about data modeling. When working with Elm code, we try to prevent bad stuff from ever occurring. One of the ways we do that is by “Making Impossible States Impossible”, as we like to say (and as introduced by Richard Feldman in the talk with the same name:https://www.youtube.com/watch?v=IcgmSRJHu_8). Specifying in what states a value or a piece of the program’s state can be, and therefore preventing all the other possibilities, is an amazing tool and guarantee to have. With that in mind, you start to think about all the tools and techniques at your disposal to add new guarantees about the code across the project, so that you can stay focused on the happy paths.
Q: Is there anything you would have done differently, if you could turn back the clock, now that you have more than 4 years of insights in a production environment?
Thomas: Yes. One thing we could have done better was to make reusable components earlier in the development process. We were a startup and very focused on moving fast and making customers happy asap. I guess not making reusable enough components is not an Elm-thing, but the fact that Elm was a young technology played into it – I think. It wasn’t clear exactly how to do good reusable components in Elm – we didn’t really have any good references to get ideas from. That has since changed, and there is much more community material and examples available.