# What are your thoughts on the translator pattern for child-parent communication?

**URL:** <https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730>\
**Category:** Request Feedback\
**Created:** [March 25, 2024, 3:22pm UTC](https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730 "2024-03-25T15:22:34Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![dwayne](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dwayne/32/5478_2.png) [@dwayne](https://discourse.elm-lang.org/u/dwayne)\
**Post date:** [March 25, 2024, 3:22pm UTC](https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730/1 "2024-03-25T15:22:34Z")

</div>

I’ve been implementing [RealWorld](https://github.com/gothinkster/realworld) in Elm from scratch and one architectural design decision I made early on was adopting my own version of [the translator pattern](https://medium.com/@alex.lew/the-translator-pattern-a-model-for-child-to-parent-communication-in-elm-f4bfaa1d3f98) for [child-parent communication](https://rchavesferna.medium.com/child-parent-communication-in-elm-outmsg-vs-translator-vs-nomap-patterns-f51b2a25ecb1).

My version of the translator pattern leads to an `update` function, for the login page, that looks as follows:

```elm
type alias UpdateOptions msg =
    { ...
    , onLoggedIn : User -> msg
    , onChange : Msg -> msg
    }

type Msg
    = ...
    | SubmittedForm
    | GotLoginResponse (Result (Api.Error (List String)) User

update : UpdateOptions msg -> Msg -> Model -> ( Model, Cmd msg )
update options msg model =
    case msg of
        ...

        SubmittedForm ->
            validate model
                |> V.withValidation
                    { onSuccess =
                        \{ email, password } ->
                            ( { model | errorMessages = [], isDisabled = True }
                            --
                            -- 1. Attempt to login.
                            --
                            , Login.login
                                options.apiUrl
                                { email = email
                                , password = password
                                , onResponse = GotLoginResponse
                                }
                                |> Cmd.map options.onChange
                            )
                    , onFailure =
                        \errorMessages ->
                            ( { model | errorMessages = errorMessages }
                            , Cmd.none
                            )
                    }

        GotLoginResponse result ->
            Api.handleFormResponse
                (\user ->
                    ( init
                    --
                    -- 2. On successfully logging in you have to tell your parent, Main in this case,
                    -- so that they can do whatever they need to do on log in. As the login page
                    -- I don't care about that stuff. That's for my parent to handle.
                    -- In the case of Main, it wants to record the user's token and redirect the
                    -- user to the home page.
                    --
                    , Task.dispatch (options.onLoggedIn user)
                    )
                )
                model
                result

```

I like the solution that unfolds and I think I’m going to continue using it but there is at least one bit that maybe contentious which is the use of `Task.dispatch`.

```elm
dispatch : msg -> Cmd msg
dispatch =
    Task.succeed >> Task.perform identity

```

With `Task.dispatch` I avoid making update have the return type `( Model, msg, Cmd msg )` and instead I push the parent message into the Elm runtime which eventually finds its way back to the parent’s update function.

Here’s the relevant parts of `Main`:

```elm
updateLoginPage : LoginPage.Msg -> SuccessModel -> ( SuccessModel, Cmd Msg )
updateLoginPage pageMsg subModel =
    case subModel.page of
        Login pageModel ->
            let
                ( newPageModel, newPageCmd ) =
                    LoginPage.update
                        { apiUrl = subModel.apiUrl
                        --
                        -- 1. This is saying to notify me when you've successfully logged in via the login page.
                        --
                        , onLoggedIn = LoggedIn
                        , onChange = ChangedPage << ChangedLoginPage
                        }
                        pageMsg
                        pageModel
            in
            ( { subModel | page = Login newPageModel }
            , newPageCmd
            )

        _ ->
            ( subModel, Cmd.none )

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        ...

        LoggedIn user ->
            --
            -- 2. Handle a successful login.
            --
            loginUser user model

        ...

loginUser : User -> Model -> ( Model, Cmd Msg )
loginUser user =
    withSuccessModel
        (\subModel ->
            ( { subModel | viewer = Viewer.User user }
            , Cmd.batch
                --
                -- 3. Save the user's token and redirect to the home page.
                --
                [ Port.Action.saveToken user.token
                , Route.redirectToHome subModel.key
                ]
            )
        )

```

**N.B.** If I used `( Model, msg, Cmd msg )` then `loginUser` would be handled in the `updateLoginPage` function.

**I’d love to get feedback** on this design so I can be more objective about this architectural decision, i.e. this take on the translator pattern.

**P.S.** _I make use of this version of the translator pattern in [dwayne/elm-debouncer](https://github.com/dwayne/elm-debouncer). I liked it so much for that library that I decided to try it out in this app as well. At work we adopted a version of the `OutMsg` pattern and I didn’t much like the code it lead you to write._

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [March 25, 2024, 9:31pm UTC](https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730/2 "2024-03-25T21:31:55Z")

</div>

One thing I like about the translator pattern is that the `UpdateOptions` converts your `Msg` to an abstract `msg` for interpretation by the parent (caller). This means you can keep your `Msg` opaque.

Also if you want to pass in an event to your module, you should avoid doing so by passing a `Msg` to its `update`. Not all update-like things in Elm have to be called `update`, just make a function in the module that handles the event. No need to defunctionalize everything through an exposed `Msg` type, the `Msg` type is an internal only thing for a module, for taking care of its local side-effects only.

Here is how you can avoid the use of `dispatch`. I call this `Protocol` pattern, because that name was suggested on Slack, and it seemed ok and I could not think of a better one. So in this example I renamed your `UpdateOptions` to `Protocol`:

```auto
type alias Protocol submodel msg model =
    { toMsg : Msg -> msg

    -- Where to continue after an update.
    , onUpdate : ( submodel, Cmd msg ) -> ( model, Cmd msg )
    , onLoginOk : Credentials -> ( submodel, Cmd msg ) -> ( model, Cmd msg )
    , onLoginFail : ( submodel, Cmd msg ) -> ( model, Cmd msg )
    }

type Msg
    = ...
    | SubmittedForm
    | GotLoginResponse (Result (Api.Error (List String)) User

update : Protocol Model msg model -> Msg -> Model -> ( model, Cmd msg )
update protocol msg model =
    case msg of
        ...

        SubmittedForm ->
            processForm model -- yields a (Model, Cmd Msg)
                |> Tuple.mapSecond protocol.toMsg -- yields a (Model, Cmd msg)
                |> protocol.onUpdate -- nothing special to tell the parent about, just a normal update
  
        GotLoginResponse (Ok loggedInProps) ->
            processLoginOk loggedInProps model -- yields a (Model, Cmd Msg)
                |> Tuple.mapSecond protocol.toMsg -- yields of (Model, Cmd msg)
                |> protocol.onLoginOk loggedInProps.credentials -- tell the parent we logged in successfully

{-| Update-like function requesting an immediate log out. -}
logOut : Protocol Model msg model -> Model -> ( model, Cmd msg )
logOut protocol model =         

```

In the parent you need to build an instance of the protocol and use it whenever you call update-like things on the child:

```auto
type alias Model = 
    { child : Login.Model
    , ...
    }

childProtocol : Model -> Login.Protocol Login.Model Msg Model
childProtocol model =
    let
        setChild child =
            { model | child = child }
    in
    { toMsg = LoginMsg
    , onUpdate = U2.map setChild
    , onLoginOk = \cred -> U2.map setChild >> U2.andThen (processLogin cred)
    , onLoginFail = ...
    }

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        LoginMsg innerMsg ->
            Login.update (childProtocol model) innerMsg model.child

```

No “message” passing at all between the modules. It is all done through higher-order _functions_. Love this, because Elm is a functional language, not an actor-model language.

I like that this avoids falling into the pit of thinking of Elm as an actor-model like thing, with message passing between encapsulated components. I only create defunctionalized `Msg` types, which are opaque, and only for processing side effects.

This pattern does not require you to return a triple. The usual `(model, Cmd msg)` tuple can be used everywhere in your application without exception. This is great for railway programming based around `map`, `andThen`, `andMap` and so on over the `(model, Cmd msg)` structure. For example, I have this implementation [Update2 - elm-update-helper 2.3.0](https://package.elm-lang.org/packages/the-sett/elm-update-helper/latest/Update2) but I think there are a few others. I might now delete the Update3 module, since I no longer have any need for it and consider it bad practice. I do not need to constantly convert between U2 and U3 formats.

You can find an example of the protocol pattern I built when experiementing with it here: [GitHub - rupertlssmith/elm-protocol: Trying out the Elm config pattern with continuations.](https://github.com/rupertlssmith/elm-protocol/tree/main). Coincidentally, this is also an authentication example.

---

<div class="post-metadata">

**Author:** ![wolfadex](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/wolfadex/32/2461_2.png) [@wolfadex](https://discourse.elm-lang.org/u/wolfadex)\
**Post date:** [March 25, 2024, 10:18pm UTC](https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730/3 "2024-03-25T22:18:13Z")

</div>

We essentially use the translator pattern at work, though it’s wrapped in an opaque type so that most of our updates look like

```elm
{ model | ...changes }
    |> Page.update
    |> Page.Update.withQuery ...
    |> Page.Update.withMutation ...
    |> Page.Update.withOtherEffect ...
    |> Page.Update.mapMsg options.toMsg
    |> Page.Update.mapModel options.toModel
    |> Page.Update.withMsg (options.onLoggedIn user)

```

(not all of those are used together, just put them there as examples of some)

The wrapping in an opaque type is partially to support an Elm Spa/Elm Land like Effect module, and also makes pipeline style building easier than with tuples.

* * *

I do like the look of the protocol approach that @rupert has though. I like that it removes the `Task.dispatch` style code.

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [March 25, 2024, 10:57pm UTC](https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730/4 "2024-03-25T22:57:04Z")

</div>

One of the problems I have had with Task `dispatch`, is that in some situations it can make the UI laggy. I used ResizeObserver and wrapped it as a custom type. Then I could listen for resize events occurring when contenteditable text overflowed a div within a div that represents a sticky note on a drawing. In response to that I make the sticky note grow in size. The editor code was in a child module and the note sizing code in the parent making use of the re-usable editor module. With `dispatch` the resize would go via the Elm event queue, and miss the next animation frame. ☹ With the functional approach, it all completed within a single TEA update cycle and there was no visible lag 🍾

Of course I did not have to structure my code this way, but the intention of having re-usable editor was there before I got to the bit where it lagged.

Generally for non UI and time sensitive stuff `dispatch` will be ok. For example, dispatch after a network event - well who knows when the network is going to respond, so adding a dispatch makes no noticeable difference. Feels a bit ugly when you have to use it though!

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [April 1, 2024, 2:38pm UTC](https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730/5 "2024-04-01T14:38:25Z")

</div>

Experiencing a mouse lag on right button drag at the moment, so I started looking into what messages I have flying about, and remembered that the way this works I have 2 messages for each translated pointer event.

I used `Task.Extra.messsage` (same as `dispatch`) in my pointer package. I think if I rewrite this in the protocol pattern style, I can get rid of that. I don’t know if it will fix my mouse lag issue though…!

> <https://github.com/the-sett/elm-pointer/blob/master/src/Pointer.elm#L609>

---

<div class="post-metadata">

**Author:** ![wolfadex](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/wolfadex/32/2461_2.png) [@wolfadex](https://discourse.elm-lang.org/u/wolfadex)\
**Post date:** [April 1, 2024, 6:19pm UTC](https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730/6 "2024-04-01T18:19:07Z")

</div>

I’ve used your translator pattern, @rupert, twice in the past week to resolve circular references. I feel like it’s going to make our code easier to reason about as well.

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [April 2, 2024, 10:59am UTC](https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730/7 "2024-04-02T10:59:54Z")

</div>

I assume this is possible because the “interface” makes it possible to apply the dependency inversion principle. The interface being:

```auto
type alias Protocol submodel msg model =
    { toMsg : Msg -> msg

    -- Where to continue after an update.
    , onUpdate : ( submodel, Cmd msg ) -> ( model, Cmd msg )
    , onLoginOk : Credentials -> ( submodel, Cmd msg ) -> ( model, Cmd msg )
    , onLoginFail : ( submodel, Cmd msg ) -> ( model, Cmd msg )
    }

```

Which means that this module requires a set of follow on update functions, but that those are injected at runtime, rather than being a concrete compile time dependency.

I think if we were to also use the effect pattern in this interface, it could help greatly with module testability. Dependency injection combined with avoiding the use of opaque `Cmd`s would mean that such a module could be easily instantiated in isolation for testing purposes.

---

<div class="post-metadata">

**Author:** ![dwayne](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dwayne/32/5478_2.png) [@dwayne](https://discourse.elm-lang.org/u/dwayne)\
**Post date:** [April 4, 2024, 5:38pm UTC](https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730/8 "2024-04-04T17:38:19Z")

</div>

@rupert @wolfadex Thank you for your thoughtful comments and suggestions.

> [@rupert](#):
>
> One thing I like about the translator pattern is that the `UpdateOptions` converts your `Msg` to an abstract `msg` for interpretation by the parent (caller). This means you can keep your `Msg` opaque.

I like that too. Whenever my reusable view needs a custom `Msg` type I now always provide an `onChange : Msg -> msg` to get that benefit.

> [@rupert](#):
>
> Here is how you can avoid the use of `dispatch`. I call this `Protocol` pattern, …

I’ll keep this idea in mind but I don’t see myself ever needing or using it. On the face of it, it seems like overkill, hard to use and aesthetically displeasing. If the protocol pattern is the alternative then I’d stick with `Task.dispatch`.

> [@rupert](#):
>
> One of the problems I have had with Task `dispatch`, is that in some situations it can make the UI laggy.

I had that concern as well, but I’m yet to experience it in practice.

> [@rupert](#):
>
> Generally for non UI and time sensitive stuff `dispatch` will be ok.

Did you mean **time insensitive** stuff? Also, I was **favouring it for UI stuff** as opposed to non-UI stuff. I don’t see why I’d want to do `Task.dispatch` for non-UI stuff.

> [@rupert](#):
>
> I like that this avoids falling into the pit of thinking of Elm as an actor-model like thing, with message passing between encapsulated components.

The JavaScript DOM gives you an event-driven model for UIs. I have found that `Task.dispatch`, when needed and which isn’t often, keeps you in that mindset when writing your Elm views.

Let me try to explain with an example from [Cells](https://dwayne.github.io/elm-7guis/cells.html).

Here’s a reusable spreadsheet view: [elm-7guis/src/Task/Cells/View/Sheet.elm at f7bf120c2cb1bf0520bdf1921bd063af1aacc3b2 · dwayne/elm-7guis · GitHub](https://github.com/dwayne/elm-7guis/blob/f7bf120c2cb1bf0520bdf1921bd063af1aacc3b2/src/Task/Cells/View/Sheet.elm). You’re able to double click a cell, enter a formula, and hit `Enter`. If I didn’t need to update the internal state when the user hit `Enter` then rather than having [`enter = PressedEnter`](https://github.com/dwayne/elm-7guis/blob/f7bf120c2cb1bf0520bdf1921bd063af1aacc3b2/src/Task/Cells/View/Sheet.elm#L218) I would have had `enter = handlers.onInput edit.coord edit.rawInput`. The point is that without the internal state update the view would have been event driven so it makes sense to me to keep it event driven even with the internal state update. Otherwise, some aspects of the view would be event driven and others parts would not be.

I thought of it as follows, if it helps. If the DOM was providing me with a UI element for a spreadsheet view, then how would I interact with that element when the user pressed enter into one of its cells. It seemed to me that it’d be something like:

```html
<spreadsheet id="my-spreadsheet">...</spreadsheet>

```

```js
const spreadsheet = document.getElementById("my-spreadsheet");
spreadsheet.addEventListener("onInput", function (e) {
   // ...
   // do something with e.coord and e.rawInput
   // ...
});

```

That’s exactly what I get to achieve with `Task.dispatch` in this case, see [here](https://github.com/dwayne/elm-7guis/blob/f7bf120c2cb1bf0520bdf1921bd063af1aacc3b2/src/Task/Cells.elm#L88-L91).

I don’t feel like I lose out on testing since I prefer to make my **views very dumb** and my **data model really rich**. Just look at [the data model for Cells](https://github.com/dwayne/elm-7guis/tree/f7bf120c2cb1bf0520bdf1921bd063af1aacc3b2/src/Task/Cells/Data). And, look at [the test cases](https://github.com/dwayne/elm-7guis/tree/f7bf120c2cb1bf0520bdf1921bd063af1aacc3b2/tests/Test/Task/Cells/Data) I’m able to cover. For e.g. [this test case](https://github.com/dwayne/elm-7guis/blob/f7bf120c2cb1bf0520bdf1921bd063af1aacc3b2/tests/Test/Task/Cells/Data/Sheet.elm#L101-L150) exposes a performance issue in all the other Cells implementations I’ve tried because they don’t do proper data modeling.

> [@rupert](#):
>
> I think if I rewrite this in the protocol pattern style, I can get rid of that. I don’t know if it will fix my mouse lag issue though…

So it seems it isn’t the `dispatch` at fault here. I’d be interested to learn what was the core issue then.

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [April 8, 2024, 8:13am UTC](https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730/9 "2024-04-08T08:13:11Z")

</div>

> [@dwayne](#):
>
> > [@rupert](#):
> >
> > Generally for non UI and time sensitive stuff `dispatch` will be ok.
> 
> Did you mean **time insensitive** stuff? Also, I was **favouring it for UI stuff** as opposed to non-UI stuff. I don’t see why I’d want to do `Task.dispatch` for non-UI stuff.

I meant that to read like non (UI and time sensitive stuff). So in plain English I should probably have written non-UI and non-time sensitive stuff, or just non-UI and time insensitive stuff like you suggested.

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [April 8, 2024, 8:33am UTC](https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730/10 "2024-04-08T08:33:18Z")

</div>

> [@dwayne](#):
>
> Also, I was **favouring it for UI stuff** as opposed to non-UI stuff. I don’t see why I’d want to do `Task.dispatch` for non-UI stuff.

Here is an example of when you might use `dispatch` with the translator pattern when doing non-UI stuff.

Suppose you split off the part of your code that does auth HTTP calls, and also manages (caches) the applications current auth state. So it is not just a set of HTTP calls returning `Cmd`s, but something update-like that returns a `(model, Cmd msg)`.

Now when you get an HTTP response that puts the application into a certian state, say `Authenticated`, if you want to send an event as a msg back to the caller, you would need to use `dispatch` to do that.

In terms of performance, it is going to be fine, since the network call is always going to take a lot longer to complete anyway.

Not saying this is the best design to use, but it does illustrate where `dispatch` might be used in a non-UI situation.

---

<div class="post-metadata">

**Author:** ![dwayne](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dwayne/32/5478_2.png) [@dwayne](https://discourse.elm-lang.org/u/dwayne)\
**Post date:** [April 12, 2024, 9:46am UTC](https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730/11 "2024-04-12T09:46:00Z")

</div>

Thanks for the example. _I usually consider all that to be UI-adjacent so that’s why I didn’t consider it to be a non-UI example._

> [@rupert](#):
>
> In terms of performance, it is going to be fine, since the network call is always going to take a lot longer to complete anyway.

I’m not worried about performance. In my experience, the **dispatch pattern** seems to do fine for UI work as well. I forgot to mention that I used this pattern in:

- [dwayne/elm-2048](https://github.com/dwayne/elm-2048) for [touch control](https://github.com/dwayne/elm-2048/blob/607a1219024d8422263ed3bec5bb1b4bdc040035/src/App/View/Main.elm#L78). [Nobody complained about performance](https://discourse.elm-lang.org/t/2048-a-complete-clone-of-the-classic-game/8717/2) 🚀.
- [dwayne/elm-debouncer](https://github.com/dwayne/elm-debouncer) for debouncing and throttling. See the [trailing edge demo](https://dwayne.github.io/elm-debouncer/#trailingEdgeUseCases). In fact, `dispatch` is [central to the UX of the API](https://github.com/dwayne/elm-debouncer/blob/10ec3cccba079be678ddee508d2c3d7e62990f0c/src/Debouncer.elm#L258).

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [April 12, 2024, 2:47pm UTC](https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730/12 "2024-04-12T14:47:01Z")

</div>

One thing I have been wondering lately is should domain models built in Elm ever produce `Cmd`? Or should they be kep side effect free, and not dependant on any side effects?

I was looking at the 2024 game logic you did, Dwayne:

> **[elm-2048/src/App/Data at 607a1219024d8422263ed3bec5bb1b4bdc040035 ·...](https://github.com/dwayne/elm-2048/tree/607a1219024d8422263ed3bec5bb1b4bdc040035/src/App/Data)**
>
> A 2048 clone written in Elm. Contribute to dwayne/elm-2048 development by creating an account on GitHub.

And noticed that you have the game model and logic there “screaming” game logic. Any thoughts on how it might work out building the game model and logic but with no side effects, just pure logic and abstracting “changes” to the model out?

Reason I am thinking about this is that in current project we have domain model and logic, but also run it on front-end and on the back-end, so in the different environments different side-effects will be available. So not hard coding side effects into the highest level domain logic (high-level policy) suggests itself as a strategy for building longer-term stable domain models in Elm.

---

<div class="post-metadata">

**Author:** ![dwayne](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dwayne/32/5478_2.png) [@dwayne](https://discourse.elm-lang.org/u/dwayne)\
**Post date:** [April 12, 2024, 4:15pm UTC](https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730/13 "2024-04-12T16:15:59Z")

</div>

> [@rupert](#):
>
> Any thoughts on how it might work out building the game model and logic but with no side effects, just pure logic and abstracting “changes” to the model out?

Yes, use an `Effect` type. I made a compromise in `App.Data.Game` for practical reasons (I wasn’t going to interpret the effects in any other way) but everything else in `App.Data.*` is pure logic with no side effects.

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [April 13, 2024, 7:38pm UTC](https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730/14 "2024-04-13T19:38:17Z")

</div>

Yes, an `Effect` type will help - the same `Effect` could be interpreted differently in different environments.

I was thinking of going one step further than this though - have a domain model that consists of data models and functions to manipulate them, but that never produces any `Cmd`s or `Effect`s. Pure non side effecting code only. Then have other modules that depends on that one, that implement the various use cases.

For example, if it were a game… On the client the domain model would enforce the rules of the game and offer up all the valid next moves. Use case might be to offer the valid next moves to the player to choose from. On the server side it might check that a game replay only consists of valid moves. Use case might be checking game scores are legitimate and there was no cheating, then building a leader board.

---

<div class="post-metadata">

**Author:** ![dwayne](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dwayne/32/5478_2.png) [@dwayne](https://discourse.elm-lang.org/u/dwayne)\
**Post date:** [April 14, 2024, 11:49am UTC](https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730/15 "2024-04-14T11:49:32Z")

</div>

I think I know what you mean. I have at least two small applications written in that style and I think the approach scales to what you want.

## elm-tictactoe

The game logic is implemented and enforced in [XO.Game](https://github.com/dwayne/elm-tictactoe/blob/989891fca361d64de377ecb0ebcb1567ded21d5c/src/XO/Game.elm). It’s completely decoupled from the UI as demonstrated by these [tests](https://github.com/dwayne/elm-tictactoe/blob/989891fca361d64de377ecb0ebcb1567ded21d5c/tests/Test/XO/Game.elm).

## elm-calculator

The calculator logic is implemented and enforced in [Calculator](https://github.com/dwayne/elm-calculator/blob/09d42d31a6b197f8c9c478f39fc87c59644a0acd/src/Calculator.elm). Again, it’s completely decoupled from the UI as demonstrated by these [tests](https://github.com/dwayne/elm-calculator/blob/09d42d31a6b197f8c9c478f39fc87c59644a0acd/tests/Test/Calculator.elm).

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [April 15, 2024, 10:24am UTC](https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730/16 "2024-04-15T10:24:34Z")

</div>

Nice examples Dwayne, thanks. 👏

---

<div class="post-metadata">

**Author:** ![dwayne](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dwayne/32/5478_2.png) [@dwayne](https://discourse.elm-lang.org/u/dwayne)\
**Post date:** [April 20, 2024, 5:45pm UTC](https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730/17 "2024-04-20T17:45:41Z")

</div>

Interestingly, @RyanNHG uses the `Task.dispatch` approach via [Effect.sendMsg](https://github.com/elm-land/elm-land/blob/67489e30254db75219334a8fb5e4489dc4765810/projects/cli/src/templates/_elm-land/customizable/Effect.elm#L75-L81) in [Elm Land](https://elm.land/).

In [part 4](https://elm.land/concepts/components.html#part-4-defining-msg-and-update) of the tutorial for stateful components, `Effect.sendMsg` is used in the `SelectItem data` branch of the `update` function for the dropdown component. That’s essentially a `Task.dispatch` when you actually [perform your effects](https://github.com/elm-land/elm-land/blob/67489e30254db75219334a8fb5e4489dc4765810/projects/cli/src/templates/_elm-land/customizable/Effect.elm#L196-L197).

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [April 30, 2024, 5:45pm UTC](https://discourse.elm-lang.org/t/what-are-your-thoughts-on-the-translator-pattern-for-child-parent-communication/9730/18 "2024-04-30T17:45:45Z")

</div>

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
