Greetings wonderful Elm community!
We adore Elm and want to continue using it, but our use of Elm is under “threat” from a decision maker who does not understand the many benefits and instead wants us to use the “more popular” alternative.

I’d like to respond in a different way based on what I have observed in my own work:

(1) Elm code is checked by the compiler, so that entire classes of bugs that could become evident at runtime never occur. This means (a) better user experience, (b) much less time spent finding and fixing bugs. (2) Because of the type system and compiler it is easy to refactor Elm code. Consequently (a) developers do not have to sacrifice code quality because of the risks inherent in refactoring in some other languages (b) it is far, far easier to maintain a code base over the long run.

(1) Elm code is checked by the compiler, so that entire classes of bugs that could become evident at runtime never occur.

One of the drivers behind agile methods, is that they (supposedly) help us to find bugs earlier in the development process. The argument goes that, the later in development a bug is found, the more expensive it is to fix.

The national train system in Norway is moving its entire web codebase to Elm and has largely accomplished this. See left-hand column below (screenshot from above video) – 14 apps now in Elm, 60K loc, apps running on web, ios, android, migration of front-end to Elm almost complete.

I’m curious to hear folk’s responses when contrasting Elm with React + TypeScript, or a similar situation where compiler checks are not the differentiator.

In my mind there are multiple reasons that make Elm superior to React + TypeScript. Elm does not only give you static type checking. You’re also getting:

purity - the compiler makes it impossible to write code that depends on hidden inputs / implicit state, or secretly modifies some state somewhere. You have to provide what you depend on via function arguments, and if you want to “modify” something you have to create new copy of it and return it as return value. This sounds like more work, but it makes things visible to the compiler and doing that you’re exposing more things to the compiler to check for you.

sum types (or variant types, not sure how elm community calls them now) and pattern matching. This makes it possible to model business-domain / constraints precisely and make it impossible to represent invalid states. This together with exhaustiveness checking (am I handling all cases in all places that use this data type?) eliminates significant class of bugs.

immutability - whenever you want to change something, you have to create new copy from the original that you’re changing. You can try to achieve something similar in JS too by using libraries, but there’s nobody checking for you that you (or a new colleague joining your team) is going to use that consistently across the entire code base.

The end result is that if you can say “My code compiles” you’re getting much more guarantees in Elm then in TS/React.

One argument I like, is how easy it is to refactor. So naturally, as businesses learn more about their customers and thinks more on how to serve them, projects and products need to change in unexpected and fundamental ways. Thats just life, as far as I can tell.

But suppose you have a huge React project, and one of these unexpected changes comes along. What can you do? Well, if you make a fundamental change somewhere, the only consequence is that your code is going to break in many places. Some parts of the code will be changed, but other unknown parts wont line up and youll just have errors. The only way to grow big react projects is just to burn them down and rebuild because you cant make fundamental improvements that outweigh the bugs youll be introducing.

In a big Elm project, you can change fundamental parts of you application no problem. If things dont line up, it wont compile. Like, at work our Elm code base is 80k lines, and recently I had to change some really fundamental stuff about how we were handling authentication and local storage. It was a big change that touched a lot of files, and after two days of continuous refactoring, there were no resulting errors. Merging was not only pain free, but it was so innocous no one even noticed. I didnt have to be on pager duty for when the product blows up, we didnt need extensive QA testing; none of that. It was great.

rauxyo:

I’m curious to hear folk’s responses when contrasting Elm with React + TypeScript, or a similar situation where compiler checks are not the differentiator.

Ive did one TypeScript + React / Redux project on a team with two other developers. Heres my impression of how we did TypeScript, which I think aligns well with theirs too:

It was surprisingly not that functional. We used Ramda in the project, but, the hassle of using it was pretty high.

The type system is a lot more like that of Java than that of Haskell. The TypeScript code for making the practical equivalent of a custom type in Elm, is 5x as much code, and pretty ugly.

Types arent native to JS, so all TS types are just bolted on as an after thought. That has two implications. Firstly, they arent fully reliable. Theres some JavaScript data, and people take their best guess as to how it should be typed in TypeScript, and naturally they are only 95% reliable in their typing. Secondly, the types can be enormously complicated and include tons of internal implementation details. Whenever I had a type problem with some Redux component, my terminal would just be lines and lines of red spagetti.

Yep. I’m already pushing some of those types of constraints in our TS code via TSLint. Like @Chadtech said, it is possible to enforce those things, but TS isn’t made for it. That said, I think my team wouldn’t be enthusiastic enough about Elm to deal with ports, so I’m considering Reason as a compromise.

I’ll keep playing with Elm on the side though, and maybe I’ll be able to introduce it properly at work someday.

I haven’t use Typescript in a big project, but we started our application with Flow + React. It is quite disappointing:

With Flow:

Not all libraries have definition or good ones, you end up with type black holes, places where the checker just doesn’t know what a thing is, so all the checking goes out of the window. Relay classic and Ramda are examples of this.

Some popular functional libraries are useless with Flow e.g. Ramda.js, we love it, but Flow has no clue what is happening there. Definitions for Ramda don’t work well.

Learning the Flow type system is more complex than learning the Elm one

Gradual typing is not a great thing in my opinion, because you start adding types in one side of the app, then another side of the app, but when finally you meet in the middle the types don’t match, and is a nightmare to fix all the mismatchs.

At times we had to write JS in convoluted ways just so Flow could type check something

Our code was littered with invariants (assert that something is what is supposed to be or throw an error), because Flow is just lacking

I was scared all the time to make big refactors with Flow

Elm is an entire different ball game when it comes to type safety and refactoring.

Comparing Elm Package manager vs NPM
You can be a lot more confident that the code does not do anything nasty in the background.
And semantic versioning of dependencies.

Dependencies
Since Elm does not have packages for everything, you use less time on making decisions, more time to code.
Also since there is many missing packages, you are forced to think about creating a function yourself instead of just downloading yet another dependency…
An example: I needed Oauth2 Implicit Login to access an API (Open ID).
Why would you download a dependency when all you do is make a link to an external login-site on a normal html-button. And then parse the token in url when redirected back…
If in Javascript land, you would probably not think at all and just download a dependency, instead of using 5 min coding and not adding anything to your bundle.

Any library that you use as helper logic around your app cannot do side-effects at all. The only libraries that can do sideeffects is the one that you trigger in update yourself “(model, sideeffects)”
Typically like the HTTP package.

Compare that to javascript/typescript where any of the million functions deep down in your dependencies can do whatever it wants, whenever it wants.

I guess Elms package manager has its own version of the package… Because I dont belive it is possible to remove a published package… Even if you delete your github repo, Its still available in Elm… Not 100% sure about this one, but can remember people that wanted to remove some packages a while ago.

Oh, what I meant here is that NPM allows publishing any random chunk of code, whether it’s in a repo or not. But it looks like Elm simply lets you publish a repo as a package and it pulls its copy of the package directly from that repo, rather than from some arbitrary source you have locally. Is that right?

Is that person technical or not? Could there be hidden causes, e.g. HR have a hard time finding developers, maybe because they are looking for Elm developers specifically instead of just looking for skilled people who are curious enought to learn a new language?

Network requests have to be accomplished by sending a Cmd to the Elm run-time, so any library that wants to send data to an external party has to go through you. That makes it easy to at least inspect the code that is producing the Cmd and check that it isn’t sending something malicious out.

The only exception to this is that a library can also produce HTML that can have side effects when rendered, but that is still pretty easy to inspect. You can see more here.

@sebn good question! The person who is sceptical of Elm is very much non-technical. I agree that searching for curious/creative people is a much better way of finding someone that will go beyond simply copy-pasting a superficial fix to the current problem.

tl;dr

The decision maker may have used some JQuery or installed a Wordpress Plugin but have not hand-crafted any meaningful application logic from scratch or felt the pain of maintaining something with “moving target” dependencies. Sadly, without writing any Elm code, a non-technical decision maker is unlikely to see the benefits of type-safety and refactoring confidence and friendly compiler warnings which is where Elm shines compared to other options! Furthermore if the person is only focussed on delivering the current feature set as quickly as possible, and not concerned with long-term maintenance (because they won’t have to personally maintain whatever code is written), they tend to default to “ready made” over carefully crafted solutions. vs.

We intend to cover the availability of people with existing Elm skills in the post we’re writing, and demonstrate that there are many more people available who are both capable and want to use Elm than a basic keyword search on a CV/recruitment site reveals.
The trick to finding great people is having an interesting job description, flexible working conditions (e.g: remote work) and great company culture that invites people to apply.
Sadly, most companies don’t put in the effort in any of these areas and instead want to simply hire someone for the “job to be done” with the same convenience someone with the munchies going to the corner store to buy a pack of chips.

As you say, HR only have a “hard time” finding people if they are focussed on finding the Elm keyword on a person’s CV or LinkedIn profile. Anyone hiring someone to do a technical job should focus on one thing: evidence of proactive learning.

Paul Graham described this eloquently in 2004 when comparing the search for Python (a comparatively “new” language at the time) vs. Java (established industry-leader) programmers:

“…you could get smarter programmers to work on a Python project than you could to work on a Java project.”
“It’s a lot of work to learn a new programming language. And people don’t learn Python because it will get them a job; they learn it because they genuinely like to program and aren’t satisfied with the languages they already know.”
The Python Paradox: http://www.paulgraham.com/pypar.html

At the time Java was taught in universities whereas Python was not. So the people who learned Python did so out of curiosity to try something new.

Essentially, hire people who are conscientious about learning new skills.
The chances that someone already knows how to do everything in a given app are low (unless it’s a cookie-cutter Wordpress website, Shopify store or similarly straightforward project where everything is a “solved problem” that requires limited thought…). The person’s ability to learn fast and not be overwhelmed by new challenges is far more important than existing knowledge.

One of the advantages of GitHub is that it’s easy to see if the person has a genuine curiosity for learning Elm (they have a personal project that uses it and have “starred” a few Elm repos/examples) this is a good “filter”.
e.g: https://github.com/search?q=language%3AElm

If there are a million people with coal mining skills (or something equally irrelevant to the problem you are trying to solve) what does it matter if what you need is one person with electric car battery management experience? If a decision maker uses an availability bias or have an incomplete understanding of the problem’s lifecycle to make technology decisions, they will end up hiring the wrong person to produce the wrong result.

Not saying that Elm is always the “right” choice for all web projects.
Just that in many front-end heavy web apps, it’s by far the wisest choice for both short-term delivery and long-term sustainability of the project! Decision makers who embrace Elm see huge benefits both in terms of the quality product they are building and the high calibre people they can attract to work on it.

We need to get more evidence of this so we aren’t asking anyone to have “faith”.