3 ms·
Author here. You're right, there was a line missing. That's now fixed. Thanks for spotting that. To address your other points: in just about every Elm applicat
by yakshaving_jgt 6y ago
Author here. You're right, there was a line missing. That's now fixed. Thanks for spotting that.
To address your other points: in just about every Elm application I've ever worked on, there was an initial ambition to separate and encapsulate things nicely, for reasons of safety or Clean Code or some other philosophical ideal.
Then requirements change (which is normal and good — businesses change and evolve, and the product should mirror that). Then you discover that oh, you need a bit of state from one page in another. Oh, and modifying the state of something on one page should affect this other page. Hmm… Why does this view function now take seven arguments?
Your final paragraph hints at the kind of engineering that inevitably begins to appear as a workaround to solving the wrong problem in the first place. All of it is extra complexity that doesn't need to exist at all.
> The author's approach has data for every page of your app stored in the model at once, and available to every other page. Also, any page can edit the data for any other page and send messages to any other page. That makes me nervous.
Why exactly this emotional reaction specifically? Does prior experience with bad surprises in Elm give you this intuition? Or is it from experience from a language like JavaScript where global mutable state is indeed something to be wary of?
- philh 6y ago> Your final paragraph hints at the kind of engineering that inevitably begins to appear as a workaround to solving the wrong problem in the first place. All of it is extra complexity that doesn't need to exist at all. I agree it's extra complexity, and it's not strictly necessary. But it's not that much extra, and it doesn't affect pages that don't need it, which in the app I work on, most don't. (Whereas if all your pages take a top-level model, and return a top-level message, they all need to deal with that even if they don't need it.) > Does prior experience with bad surprises in Elm give you this intuition? Or is it from experience from a language like JavaScript where global mutable state is indeed something to be wary of? Not specifically Elm, I've only written it in one app. But I'm imagining bugs where a page mutates its state in ways that satisfy some invariant, and then that invariant is violated and no one can work out how it happens. Turns out some other page is editing its state, in ways that probably made sense at the time. (Granted the debugger will probably help, but... I dunno, I'd rather just not have to.) I'm not convinced large Elm apps don't have problems like this. And saying "no, if you want to communicate with another page, you have to do it through this specific mechanism" seems like a fine way of avoiding it.
- pyrale 6y ago> Turns out some other page is editing its state The solution to this particular problem is to stop thinking in terms of page. Which page you're on is only a matter of view, and maybe a minimal amount of view-related model. Most of your model data should be related to your application logic, not to a specific page or component. Separating your model logic and your view logic helps a lot to avoid having this problem, because your model logic becomes agnostic to what page modifies it.
- philh 6y agoI've never tried it your way, so maybe I'm missing something here. But thinking in terms of pages seems like a very useful abstraction to me. I can't keep the whole application state in my head at once, so I want to be able to look at a small part of the app and know that I don't need to think about anything else right now. (It maybe won't be "literally just this page", but "this page plus a small number of well defined mechanisms for bringing data in and out of it".) I wouldn't want to give that up, and I don't know how I'd split the state if not by page (or at least something similar, like "groups of closely related pages"). If my model logic is happy to be modified by any page, and if there's a bug in my model logic, then I have no idea where to look.
- yakshaving_jgt 6y ago> If my model logic is happy to be modified by any page, and if there's a bug in my model logic, then I have no idea where to look. I don't mean this sarcastically (hard to convey tone in written form), but is this genuinely something you have encountered with Elm in practice? Even with the time-travelling debugger?
- philh 6y agoNo. Like I said, I've only worked on one Elm app, and that one doesn't let model logic be modified by any page (with some well-defined exceptions). But it's what I'd expect to sneak in if we hadn't architectured it to forbid that kind of thing. I agree that the time-travel debugger would help, but... I guess, even if that makes it less costly, I'm not seeing the benefits.
- philh 6y agoThe new type signature is updatePersonalInformation : PersonalInformationMsg -> Model -> (PersonalInformationModel, Cmd PersonalInformationMsg) -> (Model, Cmd Msg) I know the point was "this is a bad type signature", but I guess I'm still confused. I can't think what problems someone is trying to solve by writing a function like this. I can maybe see why it might have both `Model` and `PersonalInformationModel`: the author doesn't want to prefix everything with `model.personalInformation` so they pass both `model` and `model.personalInformation` to it. (Maybe they forget that they can start the function with `let personalInformation = model.personalInformation`?) So I can maybe guess why `PersonalInformationModel` might be there, and if my guess is right I agree it's silly. But I have no idea what the `Cmd PersonalInformationMsg` is doing, and it makes me think I don't understand the `PersonalInformationModel` either. Where does that input come from, and what does the function do with it?
- yakshaving_jgt 6y agoIf it seems confusing, it's because it is. That's the point I'm trying to make. I have seen — several times across a number of projects — people writing code with a philosophical ideal along the lines of "well, this page should only know about the state (a subset of the model) that it is responsible for, so I won't give it the whole model. Also it will only send the messages related to just this page. Oh, requirements changed. No problem, I'll just add another part of the global state as an argument. Oh, requirements changed again, and I need to send a global message. Hmm… I'll just… etc" Furthermore, I've observed over a few years the behaviour in which developers with significant JavaScript ecosystem experience will impose these philosophical ideals far too early in an Elm application's design because they aren't familiar with Elm's refactoring story and are justifiably wary of a codebase growing to the size and level of complexity that is beyond saving. I understand and agree with the idea of generally narrowing types to simplify APIs, but in my experience, the typical "page" in a multi-step webform actually contains too many cross-cutting concerns for this approach to remain frictionless as business needs change (and if your business/product needs don't change, then I would like to buy whichever crystal ball you're in possession of).
- 6y ago