Chapter 1. Why Elm?
Elm is a functional language that compiles to JavaScript and is specifically for designing the frontend of your web app. One of the main design goals of Elm is to incorporate some of the advances from the last 40 years of programming design (many of which have not made the full transition from academia to common use), and to not require you to learn a bunch of jargon to benefit from those advances. The practical result is that Elm code is fast, hard to break, easily testable, and profoundly maintainable. Above all, Elm is a functional programming language for the practical frontend developer.
This report is meant for developers who are largely familiar with JavaScript and other dynamically typed, imperative languages, but who aren’t quite as familiar with static types or purely functional programming languages. If you’re an established web developer, you might feel a bit overwhelmed by trying to keep track of the recent explosion of frontend technologies—so what makes Elm fundamentally different?
Here’s quick overview of some of Elm’s best features; we’ll cover these topics in more detail later in this report.
Elm eliminates many of the most common pain points of frontend
development. That’s because many of the common issues that frontend
developers have to deal with just don’t exist in Elm. There is no
null
and no confounding errors such as undefined is not a
function
,
but that’s just the beginning. Elm really shines when we talk about the
higher-level benefits it can provide to you.
In Elm it’s extremely common to have no runtime exceptions in practice. While you technically can have a runtime error in some limited cases, it’s actually fairly difficult to accomplish. Instead of runtime exceptions, in Elm you have compile-time errors that check your work. Take a moment to think about this. You can rephrase it as, Elm ensures that errors will happen at compile time, in front of a developer, instead of runtime, in front of a user. This is fantastic! Is there any case where you’d ever want a user to receive an error instead of a developer?
Elm’s compiler is your friend and provides very specific, human-friendly compile errors as you develop. These errors generally explain why code won’t work instead of just what broke. They also tend to include hints such as links to recommended design documentation and highly accurate spelling suggestions based on what the compiler knows about your code. Features such as this go a long way toward making the Elm development experience smooth and productive.
Packages in Elm have enforced semantic versioning, meaning the version number of an Elm package will tell you whether the package API has been broken or extended, or whether this is simply a patch release fixing an internal detail. Patch changes will never break the API. This is enforced automatically on all packages, so you don’t need to worry about whether third-party developers are following semantic versioning best practices. The confidence that this builds goes both ways. As a package author, it means you won’t break your API by accident.
The reason Elm can provide all these benefits is because of how it handles types, though Elm types are likely very different from what you’re used to. They don’t require a bunch of extra work. In fact, type annotation is entirely optional because Elm can infer all the types of your program. This makes Elm types lightweight and easy to work with.
Even though type annotation is optional, Elm types are always there to provide you the benefits we’ve been talking about. These benefits aren’t something you have to activate or work hard to get right; they’re built into the language. Elm’s type system is mandatory (which is how it guarantees no runtime exceptions, superb maintainability of your code, and enforced semantic versioning) but, again, is lightweight and surprisingly conducive to productivity. Even though Elm’s type annotations are optional, you may find them incredibly useful as enforced documentation and as a powerful design tool.
Of course, having a fantastic type system doesn’t mean you don’t have to test your code. What it does mean is that you will write fewer tests, and those tests will be more meaningful and easier to write. There are many situations where you don’t need to worry about testing in Elm because of the type system. For the areas where we do need testing, Elm code is inherently easy to test because each function can be realistically tested in isolation of all others. This a somewhat subtle concept which we’ll cover later, but the gist is that Elm code is made to be easily testable.
Keep in mind that not all typed languages can give you these same benefits. Java makes you write a lot of boilerplate for your types, but will still throw runtime exceptions. TypeScript can provide incremental benefit to your JavaScript, but only so far as you’re willing to put in the work and invoke the right options; even when you do, there is no guarantee that runtime errors, enforced semantic versioning, or developer-friendly error messages won’t come up. It’s not just types that deliver these benefits, but also Elm’s design focus of leveraging types into high-level benefits for the developer.
All these practical properties make Elm code profoundly maintainable. Not just maintainable by a devoloper looking at your code five years from now, but maintainable in a way that immediately and directly affects your developer experience. You’re guaranteed that adding code to a large Elm codebase won’t break existing code. If there is something wrong, the compiler will likely tell you. The strength of Elm’s compiler leads to developers having no fear when refactoring. Old, unnecessary code can be removed with confidence. Projects can grow as they need to, and development on those projects generally doesn’t slow down significantly as they get bigger. Maintainability is Elm’s killer feature.
Elm’s emphasis on maintainability means that even after a few months, returning to a codebase to add a feature is generally trivial. It also means you don’t have to worry that beginners will silently break existing codebases. Eliminating so many of the common pain points of frontend development allows you to focus on more valuable problems such as design and business logic. (On a more subjective note, for me and many others, Elm’s maintainability and developer-friendliness has made frontend programming a blast.)
Another nifty aspect of Elm is that you can adopt it incrementally; there’s no need to rewrite your entire application in Elm to try it out. Elm compiles to JavaScript and generally renders some HTML, so integrating some Elm code into an existing project is as simple as including a JavaScript file and telling it which HTML node to render to. Existing JavaScript code can easily talk to Elm code through Elm ports.
To get started with Elm, you don’t need to know many of the things I’m going to be talking about. I highly recommend starting by writing some Elm code! You can do that by trying out the Elm online editor, or just go ahead and install the Elm platform to start developing for real. I also recommend joining the Elm Slack channel; there are many friendly developers who love helping those who are just getting started. You should also check out the Elm architecture, which is the official guide to Elm written by Evan Czaplicki, Elm’s creator.
Elm is designed to make sure you benefit from the strong design of the language without requiring you to know the theoretical underpinnings that make it strong. This report is a brief introduction to the language that focuses mostly on the benefits you can expect from Elm and what makes them possible. I’ll also compare Elm to other popular technologies to give you some perspective. Let’s jump right in.
Get Why Elm? now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.