Feature based Architecture in Elm for a Better organisation
This article suppose that you’re not new to Elm, so if it’s the case, I recommend you to start with the guide of Elm-lang, or this website Beginning Elm.
Introduction
When we speak about frontend source code architecture, we refer to MVC, or MVVM. Elm’s pure approach to MVC is far from that known in ecosystems such as Angular or React. In order to dive into it, you need to separate the MVC concept and the notion of components.
But at Elm-lang, it’s stated :
What happens when Post.estimatedReadTime is used in both the update and view functions? Totally reasonable, but it does not clearly belong to one or the other. Maybe you need a Utils module? Maybe it actually is a controller kind of thing? The resulting code tends to be hard to navigate because placing each function is now an ontological question, and all of your colleagues have different theories. What is an estimatedReadTime really? What is its essence? Estimation? What would Richard think is its essence? Time?
What do we do then ?
With my colleagues, I started making an SPA, or a WebApp if you prefer. After having some views, a model with 10–20 properties and a kinda long Update, it was time to refactor. Here is born a feature based architecture.
MVC or MVVM use a structure named Component. We define for a component a model, a view and an update which is mostly independent from other components. It’s possible to do MVC with Elm, but it’s very inconvenient, and that’s why it should be avoided as far as possible.
So here comes the feature (you can add some information on the concept here).
A feature is where a small update bit and its messages live. A Msg is basically an interaction between the user and the UI. All the views are shared by all feature, so I prefer to keep them in one views folder. It’s just my preference, like this, it’s easier to go from a view to another one without searching in all folders. You could also keep them with your features, but I personally don’t recommend this.
So now, where should we put the “main” (the entrypoint of your web application) program ? And this is how it looks like:
I created a file for each part. That mean I have a Main.elm, Model.elm, Msg.elm and Update.elm (about the init, for now, I put it into the update, as it “updates” the model)
Then when I start a feature, I create a folder for it. So this folder will contain a Msg.elm and an Update.elm along side some decoder files for an http-based feature for example. But I think I forgot something, something very common in an Elm app… … …oh yes, data type of course. Where do we put them ? I created a Data folder, and put all my “type alias” into it. I put Data in its own folder in order to make it available everywhere easily. Like this, we don’t need to search through our files where they are, and it’s far more easier to import them bloc by bloc only when we need them.
Let’s see how my source code is organized at this point :
Next thing to see, the Msg part
In Elm, we can’t do ad-hoc polymorphism. But we can use union type for multiple type of msg (here we have the global one and the fetch one). So we need to map our fetch msg into a global one. To do this, we need to declare things like this :
Msg.elm
Fetch/Msg.elm
and in a view, we will only need to do :
Last thing, the update part.
At the end it’s kinda easy, as we only need to route our feature msg in the global update to the feature update like this
Great, you’re now able to make a feature based WebApp :). You will find this structure here, in a project created with create-elm-app.
Thanks to Benoit Chiquet, Théophile Kalumbu and Radwane Hassen (developer at Vente-Privee) for helping me with this article, and thanks for reading.
—
Thomas Delalonde, web developper at Abbeal