I'm going to try to take the large app design questions and focus them on a
more narrow and admittedly contrived example.
Say the people doing the client coding needed to be able to take a URL
string and fetch a string via HTTP. (Yes, this is covered in the HTTL
module. Bear with me. I'm trying to keep the example simple.) Dealing with
tasks all over the place muddies up the client architecture that would
otherwise focus on commands for external operations. So, we define:
getStringCommand :
(Http.Error -> msg)
-> (String -> msg)
-> String
-> Cmd msg
This is easy to write given the standard libraries.
But now it turns out we would like to execute these one at a time. We might
generate any number of these commands during a single update call, but the
mechanics of their execution demand that we not start the HTTP fetch for
one until the HTTP fetch for the previous has finished. (I said it was
contrived. Maybe we want to automatically fail subsequent commands if the
first one fails.)
>From what I understand of effect managers, we could write an effect manager
to do this but the documentation around effect managers discourages
reaching for them as a solution. They are identified as being for library
writers and though this serialized string-fetcher seems a bit like a
library in its usage, it also feels like a chunk of general app
functionality. Or maybe the backend needs to use web sockets instead of
HTTP and we would like to use the web sockets effects manager as part of
the implementation.
One way to address this is to replace commands with requests, recognize
string fetch requests when we reach a certain point in the model hierarchy,
and process them accordingly generating commands as we move up the rest of
the hierarchy. This has been covered in previous posts to the discussion
list. The downside to this is that it doesn't interoperate well with code
that wants to speak in terms of commands. One nice thing about effects
managers is that the addressing of a command to a particular effect manager
is essentially unseen by everything that handles it until we get to the app
runner. Having lots of code need to switch from returning commands to
returning requests is a very visible consequence of using this service that
speaks via requests.
Another way to handle this is by changing update functions so that they
still speak commands, but they now have a signature like:
update : Msg -> Model -> (Model, Cmd (Wrapped Msg))
We can then watch for wrapped commands and somehow unwrap the ones that
really are looking for work by the sequencer code. That said, I'm waving my
hands somewhat fast here and while we now continue to use commands, we
don't use them in the way we're used to so I don't know that it's a big win
over the requests approach.
Is there a better way to do this that I'm not seeing? The example is
contrived but so are most examples. It feels like it gets at the sort of
problem for which there ought to be a design pattern — i.e., structure your
types and functions like this to solve this sort of problem.
Mark
--
You received this message because you are subscribed to the Google Groups "Elm
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.