Why does Elm work in terms of commands rather than tasks? That's somewhat rhetorical, but in the case of effect managers it allows an effect manager to do things like maintain additional state, batch together operations, etc.
In the case of this system, this allows for the API service provider to again do caching and batching, to manage login status, etc.. It also allows for more general translation of the way the UI interacts with the backend service. For example, the cloud service might just communicate via a web socket connection spewing out notifications across all of the forums for which the user was a member. This isn't going to map directly to the activity that the UI is currently interested in displaying. The "problem" with commands and subscriptions is that the mapping really only applies to the tagging that happens on the way back down from the cloud (or wherever) and can't alter the commands and subscriptions on the way up to address any mismatch between the needs of the UI and the facilities provided by the backend service. Mark On Sun, Aug 28, 2016 at 7:52 PM, Erik Lott <[email protected]> wrote: > Mark, tell me about this code: > > type APICommand msg > = AddForum (Error -> msg) (ForumID -> msg) String > | DeleteForum (Error -> msg) (() -> msg) ForumID > | PostMessage (Error -> msg) (() -> msg) ForumID String > > > type APISubscription msg > = ForumList (List (ForumID, String) -> msg) > | MessageList (Array.Array String -> msg) ForumID > > > Conceptually, I appreciate what you're trying to do here (create a simple > system driven by domain messages - AddForum, DeleteForum, etc) , but the > actual implementation worries me. I'm wondering why you're not simply > creating an API module instead: > > module API exposing(addForum, deleteForum, postMessage) > > addForum: String -> Task Http.Error Forum > // code here... > > deleteForum: String -> Task Http.Error Never > // code here > > etc > > > I know that you mentioned that you have some additional complexity (task > queue, websockets,etc), but I haven't actually seen anything that would > cause me to abandon the built-in command/subscriptions system. What if you > need to do something in the page that is not necessarily domain related, > but requires a task/command - e.g. generate a random number? Are these > types of situations factored into your design? > > > > > On Saturday, August 27, 2016 at 6:14:41 PM UTC-4, Mark Hamburg wrote: > >> I'm working on some example code. I'm varying between a moderately >> fleshed out example of the plumbing but with little backing it up and a >> fully worked but trivial to the point of not being interesting example. The >> general model, however, works as follows: >> >> • We have a service model and a client model. The idea is that after >> agreeing on an API, these can then undergo independent development. >> Furthermore, we should be able to do things like mock the service rapidly >> and then fill it in with a version that talks to the web service or >> whatever is needed. Similarly, we could mock the client side quickly if we >> just wanted to test the service APIs. >> >> • The API is represented by a union type: APICommand clientMsg. A >> typical entry would be something like: >> >> | PostMessage (Error -> clientMsg) (() -> clientMsg) ForumId String >> >> >> >> • APICommand clientMsg is wrapped up inside a ClientCommand clientMsg type >> that provides standard Cmd-style functionality (batch, map). It also >> provides a way to embed non-API commands of type Cmd clientMsg. I would >> have liked to just use a different type of message within Cmd to do this >> rather than reconstructing map and batch — trivial though they may be — >> but mapping for platform commands is built around tagging results as they >> come back and we need to adjust the tagging functions on API commands >> before they get to the service. >> >> • The update function for the client has the signature: >> >> clientMsg -> clientModel -> (clientModel, ClientCommand clientMsg) >> >> This gets applied at the "root" level when processing messages destined >> for the client. On the way back, it can turn the client commands into >> platform commands of type Cmd (RootMsg serviceMsg clientMsg) where the >> RootMsg type provides for messages bound for the client, messages bound >> for the service, and API commands bound for the service. >> >> • The service processes both its own messages and API commands (in >> separate update functions in my latest code). Service updates return >> (serviceModel, >> ServiceCommand serviceMsg clientMsg) where ServiceCommand again mirrors >> Cmd in terms of providing batch and map support. (This could actually be >> represented as a Cmd (Either serviceMsg clientMsg) but I'm not sure that >> leveraging Cmd in that case provides more clarity.) >> >> • The root update function again maps the service commands appropriately >> to generate commands of type Cmd (RootMsg serviceMsg clientMsg) which >> route to the service and client as appropriate. >> >> The amount of code is actually pretty small and as discussed above, it >> provides a very nice separation of concerns between the client side and the >> server side and allows each to be coded following standard Elm architecture >> patterns with the caveat that one doesn't actually use Cmd during >> propagation. >> >> So, with that, I would be happy were it not for the fact that it's dawned >> on me that subscriptions are going to be more difficult because I can't >> simply wait for the runtime to ask the root model for subscriptions and >> then plumb it appropriately. This is because the service model will almost >> certainly need to adjust its state based on the client subscription >> requests — see some effects managers for examples — and when asked for >> subscriptions we can't update the root model. So, I will need to perform an >> internal subscription update after every client model update. This isn't >> fatal but I could imagine it being inefficient. I could also send a strobe >> to do this but that might introduce more delay than I'd like. That said, >> I've wondered whether subscriptions need lazy support akin to what we have >> for views. >> >> Mark >> >> P.S. The heart of this work was in making it possible to write an API >> like the following: >> >> type Error >> = NoPermission >> | NoConnection >> | ServiceFailure >> >> >> type ForumID = ForumID String >> >> >> type APICommand msg >> = AddForum (Error -> msg) (ForumID -> msg) String >> | DeleteForum (Error -> msg) (() -> msg) ForumID >> | PostMessage (Error -> msg) (() -> msg) ForumID String >> >> >> type APISubscription msg >> = ForumList (List (ForumID, String) -> msg) >> | MessageList (Array.Array String -> msg) ForumID >> >> Everything else was just the work to allow the client side and the >> service side to hew as closely as possible to the Elm architecture while >> getting the appropriate interaction between the two. >> >> >> >> On Fri, Aug 26, 2016 at 11:55 PM, Charles-Edouard Cady < >> [email protected]> wrote: >> >>> Would it be possible in your architecture to perform server requests at >>> the highest level of your application? You would then send a a->Msg to each >>> sub component. That way server requests would only be performed in one >>> place where you could fine-tune how you want them performed. >>> This comes from Richard's answer to a question I had on composability. >>> Components should only update their own private non-shared state that other >>> components don't need. Shared states such as your server queue are updated >>> at the highest level and each sub component merely receives a function to >>> run the update. >>> Does that make sense in your context? >>> >>> -- >>> 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.
