DEV Community

Discussion on: Immutability - something worth striving for

Collapse
 
rwoodnz profile image
Richard Wood

Hi Kasey,

My apology I didn't reply at the time as I wasn't across the OutMsg pattern and had less experience with the issues you describe. Now I re-read your comment and it makes sense to me.

I attended Elm Europe again this year and saw a couple of presentations where it came up, including an attempt to provide an actor approach to component structure and messages.

My concern with various attempts is when we get scaffolding code doing delegation and tricks that have no meaning otherwise in the application, making it an issue for future users of the code. The Elm language appears to be simply missing some useful structures built-in that would help componentise.

I agree with keeping all messages in one place. I recently did a project where I have them in the same file but broke them up by using a msg wrapper and msg types for each component. This works well for both bug finding and readability.

You can see my blog post about it here: Keeping it simple beyond a basic Elm app

Collapse
 
kspeakman profile image
Kasey Speakman • Edited

Thanks for the link to the article. We use some of those same patterns.

Lately, we have started to match both model and msg in our update function. Since messages are top level, you can technically receive a message which is not valid for the current view. This accounts for that case and also nicely unwraps the page-level model and msg all at once.

// F#, using Elmish
match model.Page, msg with
...
| CoursePage pageModel, CourseMsg pageMsg ->
    let nPageModel, effects = Course.update pageMsg pageModel
    { model with Page = CoursePage nPageModel }, effects
| CoursePage pageModel, badMsg ->
    // log?
    model, []

We handle page changes within the same structure.

match model.Page, msg with
| _, OpenCoursePage courseId ->
    let nPageModel, effects = Course.init courseId
    { model with Page = CoursePage nPageModel }, effects
...

This works with navigation. For example, it is pretty easy to parse the URL /course/abc123 into OpenCoursePage "abc123". We ended up with too many OpenXX messages, so they were organized under a wrapper message tag like OpenPage .... Then a central function is responsible for calling the correct page init.

Since these are recurring patterns, I've tried to parameterize it different ways. But that requires some extra abstraction/scaffolding. And then that abstraction must be learned by other devs (including Future Me when I've been away from the code for 6 months). The team ultimately deemed it not worth it compared to an extra line or 2 of very clear (and copy/paste-able) boilerplate.

We will continue to try different things and refine how we organize our MVU code. But this is where we are for now. We have used it for top-level pages and for 2nd level sub-pages.