Advanced Elm

What Fits in Our Heads

Richard Feldman

Richard Feldman

Vendr, Inc.
Advanced Elm

Check out a free preview of the full Advanced Elm course

The "What Fits in Our Heads" Lesson is part of the full, Advanced Elm course featured in this preview video. Here's what you'd learn in this lesson:

Richard discusses the fundamental challenge of scaling: what happens when the codebase gets too big to fit in our heads?


Transcript from the "What Fits in Our Heads" Lesson

>> Richard Feldman: So in the topic of scaling, we're gonna talk about a couple of things here. One is what fits in our heads as developers, we'll talk about narrowing types. We're gonna talk about enforcement arguments. And finally, we're gonna talk about using modules for modularity. This is one of the three sections in the workshop in which we go immediately, to the code!

All right, so we're gonna be talking about the code with no assistance from slides. All right, so what fits in our heads? Let's start with that. So here in the sidebar, we can see the entire code base of elm-spa-example. We're gonna ignore the assets directory, because there's no actual code in there.

But if I expand out all of these directories, and sub-directories, and so forth, you end up with quite a good bit of stuff in here. Ignoring tests altogether, we have a large number of modules, reasonably sized number of folders, and quite a bit of, thousands of lines of code across all of these.

Now there comes a point in every application, if it gets sufficiently large, that it's not just enough to say that if I look at this one particular module, I can keep it all in my head. But when we start off small and the whole application sort of fits in our head, we outgrow that eventually.

And maybe in some cases, we outgrow it even at the module level. We have a particular module where it's like, there's just so much logic going on in here that I can't keep this whole thing in my head. The article editor in particular, 600-some-odd lines of code, there's a lot of stuff going on there.

I can't necessarily just read this whole thing, load it all into my head and be like, yep, I could answer a question about any part of this, at any time. Because I just understand it all so well, it all fits in my head. I mean as humans, we're limited by sort of the notion of what fits in our heads.

But we're also limited by the realities of working on a collaborative team. So even if I did get something like this loaded into my head, and I'm like yeah, I have perfect knowledge of this. I completely understand what's going on. If I have a big enough team, by the time I finish that sentence, someone's already made a pull request that changes the code.

And now it's no longer true, even though it was true when I started off saying the sentence. Now, I don't work at a company that's big enough for that to be true. But there are companies out there where you really can get, even if you have a perfect piece of knowledge about some particular piece of code, that can be invalidated by somebody else before you even finish what you're working on.

So this is sort of a general problem in software. This is not something Elm specific, but Elm does have certain techniques that we can use to make this problem at least more tractable. So in general, what we're going to try and do here, is we're going to try and slice things up, so that there are parts of the code that we could load into our heads, that will fit into our heads.

And where we can actually work just in terms of that subset of the code, without having to load the rest into our heads to be productive, or to avoid shooting ourselves in the foot or causing problems. And as has been a recurring theme in here, what we're going to be doing to do this is to leverage the compiler more.

So it is entirely possible to write an Elm program in which all of our types are sort of as broad as possible. So let's look at, for example, the Model type. Every page that we have in here has its own Model. Model has typically at least a couple of things going on here.

This particular Model doesn't actually have that much going on in it, because it only has Session and Status. But if you look at Status, there's actually quite a bit going on inside Status. There's a bunch of different incremental states that we could be in with this article editing page.

So just to walk through them, we could say, okay, we might be editing an article. In which case, we have this set of possibilities. Or we could be working on a New Article. Both of those are sorta dynamically determined on the page, based on how you arrived at the page.

And there's a lot in common between those two, but they do have some differences. For example, on the New Article, there's nothing to load. The Edit Article, we have to load the existing article, load the data. You might also be in the process of saving it. Whereas with the New Article, once you're done with your stuff, you're then transitioning to the creating state.

And once that's finished, it's actually gonna redirect to a different page immediately. And if you are editing it, there might be some problems. Or you could be editing a new one, there might also be some problems. There's gonna be a form. So there's all these different states, and we're trying to sorta keep all of these in our head whenever we're working with this code.

Now if every function I wrote that had to do with our state accepted Model, that's gonna mean we have to keep the Session in our heads. We have to keep the Status in our heads. And there's sort of a transitive dependency there. Which is to say, if I'm keeping the Model in my head, that implies that I also need to keep the Status in my head, because the Status is in the Model.

So if all of that's potentially fair game, that's what I need to be keeping in my head to work with any function that accepts Model as an argument. Now, why does that matter? Let's suppose that I'm trying to track down a bug. I've got some issue with this page and there's some problem with the form.

I'm like, yeah, in some combination of things, I've got some bug. And the symptoms are some part of the form just isn't quite working right. Something's getting cleared out when it shouldn't, or maybe it's displaying the wrong thing. Whatever the case maybe, it's very form specific. Any function that accepts the Model is potentially doing something with the form's information.

If there is a problem with the form, that function is potentially affected by that problem. Depending on the symptoms, it might be that something is wrong with the logic of how we are updating the form. So in that case, it would only matter if the particular function returned a Model.

In other words, it's to say it's modifying the Model. Then we'd have to worry about it as a potential culprit.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now