Yes, a command queue is the obvious implementation for what I identified as a 
contrived example. The core problem, however, is how items get into the command 
queue through the normal command routing mechanisms.

Mark

On Aug 25, 2016, at 8:18 PM, Nick H <[email protected]> wrote:

>> 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.
> 
> One solution that comes to mind is adding a command queue to your model. 
> Something along these lines:
> 
> type alias Model =
>   { pendingFetches : List (Cmd msg) }
> 
> update action model =
>   case action of
>     HTTPResponse value ->
>       let
>         newModel = processResponse value model
>       in
>         case newModel.pendingFetches of
>           head :: tail ->
>             ( { newModel | pendingFetches = tail }, head )
> 
>           [] ->
>             ( newModel, Cmd.none )
> 
>> On Thu, Aug 25, 2016 at 5:51 PM, Mark Hamburg <[email protected]> wrote:
>> 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.
> 
> -- 
> 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.

-- 
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.

Reply via email to