I agree with Mark. In addition, to avoid circular dependencies it means you have to put your top-level Msg type in a separate module with no dependencies on the module where your update is defined. I strongly prefer to have the Msg type next to the update. Ok, the compiler will still save you wherever it is, but there is something to be said for having the possible values right there in front of you.
Also thanks Mark for the clearest explanation I have seen of 'what happened to classic TEA' and 'is it ever useful'. Here's my stab at it. IMO it's a perfectly fine tool for encapsulating pages of an app, or other "places it makes sense to break ones app apart". It's not as nice for reusable bits of UI, because it forces dealing with nested messages in your view and update at every call site. Injecting generic message types and tagger functions (e.g. `String -> msg`) into the view gets rid of this boilerplate. At the same time, if your child module deals with a lot of different messages, and you're only using it one place, it's sometimes less work to nest, rather than inject into the view stuff like `Child.view ClickChildMsg onInputDoSomething SaveMsg model.child` or `Child.view massiveConfig model.child`. I think it has caused a bit of confusion to remove classic TEA documentation, but I don't know which confusion is worse -- thinking it's the only way to do things, or not realizing it's even an option :) On Thursday, March 30, 2017 at 11:51:17 AM UTC-4, Mark Hamburg wrote: > > As I said, in your small example it probably doesn't matter. But I've also > seen larger examples with more fields in the top level model. My point is > that if there are any cross-field validity constraints, then it's probably > a bad idea to have lots of code that is not only able to but expected to > produce new models. Classic TEA allows one to have the page handler code > handle pages — keeping the top level model ignorant of the details and > unable to muck with the page model — while the top level code handles and > enforces the constraints for the top level model. > > Export as little as possible. If you have constraints on how pieces > interact and you can't just make the type system enforce them, then make > sure there is only one module that can modify those pieces. Reduce the > surface area in case you have to go hunting for bugs. > > Mark > > On Wed, Mar 29, 2017 at 5:57 PM Witold Szczerba <[email protected] > <javascript:>> wrote: > >> I'm not really sure what are you suggesting, Mark. Is it's all really >> about that CSRF token, then OK, I could have hide it behind opaque type and >> expose just the bare minimum, so noone could tinker with it's value. Or I >> could turn the simple architecture into more complicated (extra mappings of >> models and commands?) just in the name of... what would that be? And what >> if all that barriers and safety guards turns against me by being too >> restrictive? >> >> Just because you can change that token, does it mean you could do it by >> mistake? I don't really think that would the case. And if you have to, you >> could just do it, without developing circles around all those "safety" >> guards, I guess... >> >> 30.03.2017 1:36 AM "Mark Hamburg" <[email protected] <javascript:>> >> napisał(a): >> >>> While it cuts down on the boilerplate, it seems like this creates a fair >>> amount of exposure for what might otherwise be internal structures. For >>> example, if the page update functions all get and produce full models, then >>> each of the modules implementing those update functions becomes a place >>> where any cross-field invariants have to be maintained. Now, if you can >>> build your model in such a way that all representable states are also >>> considered legal — the corollary to making illegal states impossible — then >>> you don't have a problem. But if you can't arrange this, then you've taken >>> a validity concern and spread it through your codebase. Functional >>> programming protects you from a particular data instance being modified but >>> you still need to figure out how you guarantee that all data instances that >>> get produced are valid. In your little example — which probably is small >>> enough not to trigger a problem — would you consider it acceptable for a >>> page update to change the CSRF token? If not, then the page update should >>> not produce a new Model. >>> >>> Mark >>> >>> On Wed, Mar 29, 2017 at 3:29 PM, Witold Szczerba <[email protected] >>> <javascript:>> wrote: >>> >>>> The best solution to deal with your problems is to use Swiss knife of >>>> functional programming, i.e.* function composition*. You would be >>>> surprised how about anything could be handled by this *simple* >>>> technique. >>>> >>>> Few weeks ago there was a question asked on Reddit about nesting data >>>> in a model. It was actually more about structuring the application, so I >>>> think your questions are related. I have answered providing a little >>>> example of the structure of my own application. I think you could be >>>> interested, so please take a look: >>>> >>>> >>>> https://www.reddit.com/r/elm/comments/5wikog/easy_questions_beginners_thread_week_of_20170227/deeptz3/ >>>> >>>> In my opinion (yes, I am repeating myself) the most simple layout of >>>> all the "modules" is to have an update functions like this: >>>> >>>> *update: XyzMsg -> Model -> ( Model, Cmd Msg )* >>>> >>>> Where XyzMsg is the module's message, Model is top level model and Msg >>>> is top level message. The main update function just delegates to the >>>> update >>>> functions of each module, so it looks like a table of contents of possible >>>> actions and the main model looks like a table of contents of the possible >>>> states. It really makes working with the application a pleasure :) Every >>>> time I go back to the other app written in AngularJS, I feel like I am >>>> lost >>>> in a thick fog. >>>> >>>> I hope it helps! >>>> >>>> Regards, >>>> Witold Szczerba >>>> >>>> P.S. >>>> My application has grown a little bit since then, the main model is now >>>> a little bit different: >>>> >>>> type Page >>>> = NoPage >>>> | AnnouncementListPage (WebData (List Announcement)) >>>> | AnnouncementItemPage (WebData AnnouncementForm) >>>> | PayoutCancelledListPage (WebData PayoutListForm) >>>> >>>> >>>> type alias Model = >>>> { page : Page >>>> , csrfToken : String >>>> } >>>> >>>> As you can see, now I am able to keep a `csrfToken` independent of the >>>> current page. Now I can add even more things not related to the actual >>>> page, like e.g. logged in user. >>>> >>>> >>>> On Wed, Mar 29, 2017 at 11:29 PM, Juan Ibiapina <[email protected] >>>> <javascript:>> wrote: >>>> >>>>> Thanks for the explanation. >>>>> >>>>> I understand the choices made so far, but I still haven't been able to >>>>> find good solutions for some simple problems: >>>>> >>>>> 1. I don't want to have every single possible message handled in the >>>>> same place. It gets too big. >>>>> >>>>> 2. My global update function deals with everything in the app, >>>>> including a message to update the value of the e-mail input field when >>>>> the >>>>> user is typing. This seems like a small concern that should be handled by >>>>> the login page (or a component?). I don't want to clutter my model with >>>>> temporary data. >>>>> >>>>> 3. On my User info page, my model is the same as other pages, so it >>>>> has Maybe User. Since I have authorization, I *know* that there will >>>>> always >>>>> be a user when I go to the user info page. I want this to be reflected on >>>>> the code, so I never have to check if there is a user. >>>>> >>>>> So far these issues are pointing me towards some sort of page >>>>> separation, but I haven't been able to come up with something I like yet. >>>>> >>>>> On Wed, Mar 29, 2017 at 9:54 PM, Mark Hamburg <[email protected] >>>>> <javascript:>> wrote: >>>>> >>>>>> The config approach pops up various places — e.g., elm-sortable-table >>>>>> — but isn't as well specified anywhere that I've seen because it doesn't >>>>>> have as clear a pattern to specify. >>>>>> >>>>>> Cmd.map (and Html,map) come out of what could be called Classic TEA. >>>>>> The classic Elm architecture was built to allow decomposition by using >>>>>> tagged messages to route through the compound model. For example, if you >>>>>> wanted to have a number of pages, you could have a top level model that >>>>>> served as a page switcher and it would use tagged messages to route to >>>>>> the >>>>>> current page (or to discard messages if they weren't bound for the >>>>>> current >>>>>> page). This worked well though I know programmers who grouse at the >>>>>> amount >>>>>> of message routing boilerplate one has to write. >>>>>> >>>>>> But then people started trying to build React style component models >>>>>> with this and had trouble. At which point, various people in the Elm >>>>>> community decided that nesting was a bad idea and advocated strongly for >>>>>> flatness with functions being the only decomposition mechanism and those >>>>>> without much in the way of architectural guidance. Basically, this was a >>>>>> case of the pendulum swinging wildly and the architecture for building >>>>>> complex applications seemingly getting cast aside without a replacement. >>>>>> >>>>>> My advice would be to use the message routing patterns from classic >>>>>> TEA in the places it makes sense to break ones app apart — just know >>>>>> that >>>>>> it isn't particularly well suited to building components. >>>>>> >>>>>> For example, our codebase contains a module providing a model and >>>>>> corresponding messages and update function for managing the sign up/sign >>>>>> in >>>>>> process. It knows how to talk to our server. It knows what validation to >>>>>> do. It understands the errors coming back from the server. It knows >>>>>> nothing >>>>>> about how to display the data and instead provides a function to fill in >>>>>> a >>>>>> ViewData structure that contains the information needed by the view >>>>>> code. >>>>>> We can now reuse this logic in a variety of places where we need SUSI >>>>>> logic. Each of those hosting cases then routes messages to and from the >>>>>> logic using a message case of the form `ToLogic Logic.Msg` and using >>>>>> `Cmd.map ToLogic` to promote logic layer messages to view layer messages. >>>>>> >>>>>> Mark >>>>>> >>>>>> On Wed, Mar 29, 2017 at 11:50 AM, Juan Ibiapina <[email protected] >>>>>> <javascript:>> wrote: >>>>>> >>>>>>> Where can I find more information about that Config approach? I'm >>>>>>> not able to find a way to organise multiple page applications that I >>>>>>> like. >>>>>>> >>>>>>> On Wed, Mar 29, 2017 at 6:24 AM, Peter Damoc <[email protected] >>>>>>> <javascript:>> wrote: >>>>>>> >>>>>>>> If you have a series of pages that each has Cmds and you have these >>>>>>>> pages unified under one app, you need to lift each page Cmd to become >>>>>>>> an >>>>>>>> app Cmd. >>>>>>>> >>>>>>>> There used to be a nesting architecture where this was demonstrated >>>>>>>> but now that's been dropped in favor of the Config approach. >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> On Wed, Mar 29, 2017 at 1:09 AM, Brian Marick <[email protected] >>>>>>>> <javascript:>> wrote: >>>>>>>> >>>>>>>>> I’m having trouble thinking of a scenario in which you’d use >>>>>>>>> `Cmd.map`. >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> Is it for a case where you create a `Cmd a` where `a` is something >>>>>>>>> different than the usual `Msg`, then transform it into a `Msg`? (When >>>>>>>>> would >>>>>>>>> you do such a thing?) >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> Or for a case where you want to change the `Msg` constructor that >>>>>>>>> `Cmd` “wraps”? (Ditto.) >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> -- >>>>>>>>> >>>>>>>>> >>>>>>>>> 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] <javascript:>. >>>>>>>>> >>>>>>>>> >>>>>>>>> For more options, visit https://groups.google.com/d/optout. >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> -- >>>>>>>> There is NO FATE, we are the creators. >>>>>>>> blog: http://damoc.ro/ >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> -- >>>>>>>> >>>>>>>> >>>>>>>> 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] <javascript:>. >>>>>>>> >>>>>>>> >>>>>>>> For more options, visit https://groups.google.com/d/optout. >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>> >>>>>>> >>>>>>> -- >>>>>>> Juan >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> -- >>>>>>> >>>>>>> >>>>>>> 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] <javascript:>. >>>>>>> >>>>>>> >>>>>>> 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] <javascript:>. >>>>>> >>>>>> >>>>>> For more options, visit https://groups.google.com/d/optout. >>>>>> >>>>>> >>>>>> >>>>> >>>>> >>>>> -- >>>>> Juan >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> -- >>>>> >>>>> >>>>> 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] <javascript:>. >>>>> >>>>> >>>>> 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] <javascript:>. >>>> >>>> >>>> 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] <javascript:>. >>> >>> >>> 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] <javascript:>. >> >> >> 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.
