Learning Elm the Wrong Way: A Series (Probably)
Tags: elm, webdev
Published: 2022-01-15 07:33:19

Hi, I'm John, and a few months ago I decided that _I've been doing this for too long to be this bad at it_.

I've been an Elm developer since 2018, and the story is really only important to me[^1] (there's enough self-aggrandizing on the Internet[^2] these days) so I'll leave it out - but it's taken me a remarkably long time to feel as if I have any real command of the language and its tooling / ecosystem.

Some of the Best & Brightest on [the Elm Slack](https://elmlang.herokuapp.com/) have been kindly tolerating my ineptitude for some years now, and now that I know about [classList](https://package.elm-lang.org/packages/elm/html/latest/Html-Attributes#classList) and can hang out in `#beginners` and field easy questions, it's time to take the next logical step: start a dev blog.

Learning by example is well and good, but most of the truly important things I've learned have been by _counter-example_. What-to-do is nowhere near as poignant on its own, as it is when contrasted with what-not-to-do. And I'm an expert at what-not-to-do. Unfortunately, I've had to find these poignant counter-examples on my own. I'm here today to 1) confess my sins, and 2) show you how not to be like me. I've got enough sins for which to seek absolution that this will likely be a series, but let's dive in now. If you want to learn Elm the wrong way, start by following the headline-sized point below, don't read anything else, and... I'll see you in `#beginners`.

### Ignore / Fear The Runtime

So you did [https://guide.elm-lang.org/](https://guide.elm-lang.org/), and you're aware that "Elm is a functional language that transpiles to Javascript and has its own runtime". Great! Now, if you want to do things the wrong way: _never ever think about the runtime, ever again_.

To be fair, this isn't wholly advice without merit; the runtime stays out of your way. My background is in data / reporting - I thought, "Oh, good. A runtime. Like when I smash `F5` on SQL Server and it runs my query. Like dotnet. Like the JVM."

But there's a difference that wasn't apparent to me when I got started - since Elm is event-driven, you don't call the runtime; _the runtime calls YOU_. I'll say it again:

#### The runtime calls you!

Remember when you copied and pasted this block of code into `elm reactor` and fiddled with everything around it until your app compiled? I do!

```
main : Program () Model Msg
main =
    Browser.sandbox
        { init = initialModel
        , view = view
        , update = update
        }
```

"Ah. A `main` function. Seems right."

The problem with `main` is that by the numbers, it's not a function that you write often; you set it up, and it's good. The Code is Good, and you don't touch the Code when it is Good; and so you proceed to not think very hard about it for a few years.

At a high level, the difference between `public static void main()` and `main : Program () Model Msg` is that, in the case of the latter, you are telling a program that already exists which three specific functions it's going to call, to handle very specific parts of your application domain. 

Elm's `main` function has more in common with dependency injection - with `services.AddSingleton<IEmailProxy, EmailProxy>();`, than it does with `public static void main()`. Our old friend `psvm()` will execute any old code that we sling in there; in contrast, Elm's runtime only knows that it's going to get messages (from the DOM, from ports, and from HTTP responses); that it's going to render HTML; and that it's going to have to start up your application for the first time. The particulars of what it does in those situations are what the code that you are writing _actually does_, and do those things and those things only it must (no side effects, remember?). And this brings me to my next point:

#### Msgs happened in the past; getting their names right is important.

> Hardest two problems, cache invalidation, naming, blah blah blah

You've already heard the quote, you already _know that_.

But you need to realize that when you declare the variants for your `Msg` type, that every time you process a `Msg` in `update`, you are processing the output of an action that _already happened_.

Since I came from an OO / imperative / procedural background, I brought what I had with me when I started learning this language. If I was writing a Windows Forms application, and I wanted `btn_DoSomething` to do something, I'd wire its click event-handler to a function `DoSomething`, and something would be done[^3]. So in Elm:

```
button [ onClick DoSomething ] [ text "Do Something" ]
```
and
```
type Msg
    = DoSomething
```
and
```
case msg of
    DoSomething ->
        ( model, doSomething )
```

I regret to inform you that this is not the Way.

`DoSomething` means, "perform an action", and tells you nothing about how you got to the point in your program's execution where something was done. So if you choose to `DoSomething`, and something was done, what do you name your variant "for when something was done"?

Probably `DoSomethingResult`. But this is a function, in a functional language! "DoSomethingResult" is a name, a _noun_; and their kind are not welcome here[^4]. Banish from your mind any thoughts that this is a silly hill to die on; we are programmers, we are talking about a programming language, and if you don't spend quite a bit of time thinking about the structure and interpretation[^5] of the language that you speak _every day_ - you're going to have a bad time. Get interested in linguistics.

I digress. This is a functional language; custom type variants are functions that are a constructor for their custom type; we need to give them names that are verbs. What's a good verb for receiving a result from a function yclept `doSomething`? I don't know, how about, `GetDoSomethingResult`? Close, but computer says "no"[^6].

The act of receiving a `Msg` is not something that will be done by your program; it is something that _was done_, in the _past_, by the  runtime. Your `Msg` variants are event handlers for the return value of events that come _from the runtime_.

Who clicked that button? You did! (Who's a good doggy?) But the only way that the event "clicked a button" is any different from any of the other thousand events per second that you emit while using a web browser (scrolling, moving your mouse, clicking on a blank space) is that you told Elm's runtime to listen for that event, and that you could handle whatever result the runtime generated from processing that event.

So since the event that you want to handle happened in the past, and since it was done by somebody else - what should you call it? In this instance, I would call my variant `GotDoSomethingResult`. It's perfect! It tells us that the runtime already received our result from the `doSomething` function, and is ready to hand it over to us for further processing. Once you start reading packages, or other open-source projects, you'll see these patterns pop up - lots of `Got`s and `Clicked`s and `Changed`s.

Let's take what we've learned, and selectively refactor our application that we wrote earlier to use our new knowledge:

```
button [ onClick ClickedBtnDoSomething ] [ text "Do Something" ]
```
and
```
type Msg
    = ClickedBtnDoSomething
    | GotDoSomethingResult Result (Http.Error ())
```
and
```
case msg of
    ClickedBtnDoSomething ->
        ...

    GotDoSomethingResult result ->
        ...
```

When you talk about "getting" something, the Thing that you will Get is not yet in your possession, no matter how near the future may be wherein you have that Thing; but when you "Got" something, you can only ever speak of the action of your coming into its possession, in the past-tense. I brought up linguistics because when you start naming your `Msg`s (etc) in this way, it allows you to shift your thinking ever-so-slightly in a way that makes it a _lot_ easier to reason about your application, its state, and why its behavior may or may not be as expected.

In conclusion, conclusions are hard and I could spill another thousand more keystrokes without actually adding anything else of substance to this post, so I'll stop now. If you're still here: thanks for reading along. If this helped you: there's lots more where this came from. Be sure to tune in next time (probably) for (a lot) more[^7].

[^1]: The short version is, "I needed to learn Javascript but _I really didn't want to do that thing_"
[^2]: Are you supposed to capitalize "Internet"? I tried it both ways. Both feel weird.
[^3]: https://en.wikipedia.org/wiki/Politician%27s_syllogism
[^4]: https://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html (talk about an evergreen blogpost)
[^5]: The structure and interpretation of computer programs is, at its core, the structure and interpretation of _a bunch of thoughts_, both yours and those of others. Language enables thought and gives rise to consciousness; the structure and interpretation of computer programs is the structure and interpretation of _thought_, which is the structure and interpretation of _language_. Mind that I'm above my pay grade talking about these things, so whether you agree with me or not, go learn about them for yourself; and then it won't matter if I'm right - _you_ will know.
[^6]: https://www.youtube.com/watch?v=zFl6p4D59AA
[^7]: And if this made you mad, @ me in the Elm Slack. Maybe calm down a little first, though.