A RealWorld example app version to demonstrate how to structure an Elm application using the Effect pattern.
The application is initially based on the great rtfeldman/elm-spa-example.
Introduction
Most of complex Elm application architecture examples out there use some variant of the pattern used in rtfeldman/elm-spa-example or the OutMsg pattern to have a updatable global state available in each subpage (a Session for example). The former passes the data from subpage to subpage during their initialization, so each subpage can modify it locally, the later returns an additional message from their update function handled in the top level one.
My favorite pattern to do this (and more), the Effect pattern, is most often described only in the context of tests and Cmd, for example by avh4/elm-program-test, but it can be extended to state changes and offers a clean and versatile way to handle different use cases of complex applications.
Description
The extended Effect pattern used in this application consists in definining an Effect custom type that can represent all the effects that init and update functions want to produce.
These effects can represent:
- a
Cmdvalue - a request to change the state at an upper level (for example an URL change from a subpage without an anchor)
Having a way to request an upper level state change, with or without an associated actual Cmd msg, is what lets this extended effect pattern combine the benefits of the OutMsg one with the ones from the usual effect pattern used for tests.
The init and update functions are changed to return a (Model, Effect msg), using a custom application, that will turn the Effect info actual effects through a perform function.
There are several benefits to this approach that makes it a valuable pattern for complex applications, including:
-
All the effects are defined in a single
Effectmodule, which acts as an internal API for the whole application that is guaranteed to list every possible effect. -
Effects can be inspected and tested, not like
Cmdvalues. This allows to test all the application effects, including simulated HTTP requests. -
Effects can represent a modification of top level model data, like the Session when logging in, or the current page when an URL change is wanted by a subpage
updatefunction. -
All the
updatefunctions keep a clean and conciseMsg -> Model -> ( Model, Effect Msg )signature. -
Because
Effectvalues carry the minimum information required, some parameters like theBrowser.Navigation.keyare needed only in the effectsperformfunction, which frees the developer from passing them to functions all over the application. -
A single
NoOporIgnored Stringcan be used for the whole application.
Differences with elm-spa-example
To focus on the architecture changes and to offer a different perspective, the elm-spa-example has been quite heavily reworked with the following changes:
- Refactored to use an Effect type and application
- Upgraded dependencies, including
elm/httpto 2.0 - Removed client-side fields validation to focus subpage code on effects
- Put all specific styled view code into a single
Viewmodule to declutter subpages code - Replaced slow loading detection by a simple CSS transition
- Refactored according to personal preferences
- Removed custom assets
Links
-
Testing programs with Cmds with
avh4/elm-program-test. - A service pattern: @mzero explored a variant of this pattern to implement application wide services.
- The Effect pattern: Transparent updates in Elm.
Credits
Refactoring the elm-spa-example from Richard Feldman made me realize how much work went into it.
I would most likely never had released this version without such a solid base, so thank you very much @rtfeldman.


