Modules

    Elm modules work best when you define them around a central type. Like how the module is all about the List type. So say we want to build a module around a Post type for a blogging website. We can create something like this:

    The only new syntax here is that module Post exposing (..) line at the very top. That means the module is known as Post and only certain values are available to outsiders. As written, the wordCount function is only available within the Post module. Hiding functions like this is one of the most important techniques in Elm!

    As your application gets more complex, you will end up adding things to your modules. It is normal for Elm modules to be in the 400 to 1000 line range, as I explain in The Life of a File. But when you have multiple modules, how do you decide where to add new code?

    I try to use the following heuristics when code is:

    • Similar — Say we want to show Post previews on the home page and on the author pages. On the home page, we want to emphasize the interesting content, so we want longer snippets. But on the author page, we want to emphasize the breadth of content, so we want to focus on titles. These cases are similar, not the same, so we go back to the unique heuristic. Just write the logic separately.

    These heuristics are all about making helper functions within a single file. You only want to create a new module when a bunch of these helper functions all center around a specific custom type. For example, you start by creating a Page.Author module, and do not create a Post module until the helper functions start piling up. At that point, creating a new module should make your code feel easier to navigate and understand. If it does not, go back to the version that was clearer. More modules is not more better! Take the path that keeps the code simple and clear.

    Note: One of the most common ways to get tripped up with modules is when something that was once the same becomes similar later on. Very common, especially in user interfaces! Folks will often try to create a Frankenstein function that handles all the different cases. Adding more arguments. Adding more complex arguments. The better path is to accept that you now have two unique situations and copy the code into both places. Customize it exactly how you need. Then see if any of the resulting logic is the same. If so, move it out into helpers. Your long functions should split into multiple smaller functions, not grow longer and more complex!

    It is customary in Elm for all of your code to live in the src/ directory. That is the default for even. So our module would need to live in a file named src/Post.elm. From there, we can import a module and use its exposed values. There are four ways to do that:

    I recommend using exposing pretty rarely. Ideally on zero or one of your imports. Otherwise, it can start getting hard to figure out where things came from when reading though. “Wait, where is filterPostBy from again? What arguments does it take?” It gets harder and harder to read through code as you add more exposing. I tend to use it for import Html exposing (..) but not on anything else. For everything else, I recommend using the standard and maybe using as if you have a particularly long module name!