Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Scaling] - Lenses and Submodels: MVU antipatterns? #592

Open
YkTru opened this issue Dec 31, 2023 · 5 comments
Open

[Scaling] - Lenses and Submodels: MVU antipatterns? #592

YkTru opened this issue Dec 31, 2023 · 5 comments

Comments

@YkTru
Copy link

YkTru commented Dec 31, 2023

Hi, I'm fairly new to Elm, MVU and F#, and I'm specifically limiting the scope of my questions to scaling large MVU applications.

1- Lenses: I've heard several times from Evan Czaplicki and Richard Feldman that lenses should be avoided at all costs (if possible), and that it can even be considered an MVU antipattern.
I was wondering why this sample included lenses (other than "they're ok for small projects"):


2- Submodel: Also, the use of Submodel doesn't seem to match Feldman's recommendations (which appear as recommended resources here: https://github.com/elmish/Elmish.WPF):

and @cmeeren 's similar recommendations in the comments here, even calling it an antipattern:

The main issue being an exponentially un-manageable boilerplate, and less clarity overall.


I'm quite confused on what advices should I follow when scaling huge Elmish.WPF/MVU apps, since the samples/documentation don't provide a clear explanation/comparaison of which pattern/architecture/etc. to use to scale already very large Elmish.WPF applications.

Am I misunderstanding something? everything?

I think we could all benefit from your actual take on the matter please, Thanks.

@YkTru YkTru changed the title **[Scaling]** Lenses and Submodels: MVU antipatterns? [Scaling] - Lenses and Submodels: MVU antipatterns? Dec 31, 2023
@TysonMN
Copy link
Member

TysonMN commented Dec 31, 2023

I think it is rude to @-mention so many people. I have removed all the @-mentions from the end.

It will take me some time to give you a proper answer. For now, I can start like this.

Re 1:
What is your definition of a lens?

Where in https://github.com/elmish/Elmish.WPF/blob/master/src/Samples/SubModelSeq.Core/Program.fs is a lens being used?

What do these people recommend using instead of lenses?

@YkTru
Copy link
Author

YkTru commented Dec 31, 2023

(Sorry, I didn't mean to be rude, I won't tag people like that anymore; I just thought that for newcomers, it would be important to hear what you all have to say since it's a core but really confusing/intimidating/opinionated topic).

  • For now, my naive and simplistic understanding/definition of lens would be "a way (an abstraction) to access a deeply nested data structure using get and set accessors".

  • Although I know it's not an abstraction using a "Lens" type as in Monocle.Lens, the "map get set" function in the code seems to me to resemble a lens-like structure; I suppose this is advisable for small projects, but could it cause problems if the models became more complex/nested, or had to change often?


  • Regarding the Elmish.WPF submodel samples + model and update function (and here I must be confusing several things), Richard Feldman (and Evan) seem to recommend keeping the model as flat as possible (which I suppose goes against the use of lenses and submodel), and using *extensible records for narrowing/restricting types + helper functions to reduce the complexity of the update functions (some of these recommendations actually appear in Elmish.WPF) :

"The answer is, quite simply, to scale the model/message/update/view separately, and only when needed."

However (after reading and re-reading), I still don't understand, looking at Elmish.WPF's many submodel examples, why and when "when needed" should apply. (I know every project's needs are different, but I guess there is/are idiomatic way·s to scale very large Elmish apps)

  • That said, are there one or more idiomatic samples of (eg) an Elmish.WPF master-detail application that would faithfully represent Richard Feldman's recommendations? Which sample would you recommend as actual Elmish.WPF best practices for scaling, and how do they respect/differ from Richard's approach, and what in those samples could be refined/reconsidered?

Thank you very much for your time (it's not easy coming from the OOP + MVVM)


(*someone suggested using F# anonymous records for Elm extensible records, but honestly I haven't read much about it)

@marner2
Copy link
Collaborator

marner2 commented Jan 4, 2024

@YkTru I have some very recent experience with scaling an Elmish.WPF app specifically, so I can help here. First of all I want to acknowledge that it's true that the examples are much more about showcasing specific features as they are about showing wholistic scalable examples. Perhaps that's a gap we currently have in our current sample structure.

The best techniques that we have found for scaling an Elmish.WPF app involves scaling things in a specific order. Specifically, scale the view quickly and easily depending on your immediate frontend needs, scale the model when it makes sense to group things in your store, and only scale the messages if you absolutely have to. Finally, think of the update function as the functional glue that holds everything together. We've had very good luck completely separating pure model update functions from impure message generating functions at a decent scale. The idea was always to move as much functionality over to the pure side as possible, as it made reasoning about sub-app behaviors much easier.

Something to watch out for with Elmish.WPF specifically is that "submodel" here generally refers to the view (which is exactly the "View Model" since we are interfacing with WPF's static views at that point). Generally you would break things into submodels based on your view requirements, not based on your model store, which I sense is a source of confusion here (the lower level submodel functions don't even map over the model). If you're coming from an OOP background, think of this layer in Elmish.WPF as the thing that converts Object Property setters and ICommands to Elmish messages.

Regarding lenses, it's true that they do become somewhat unwieldly in larger projects with very deep model structures, and are becoming more and more supplanted by F# 8's new features: _.Property shorthand for (fun x -> x.Property) and Nested record field copy and update. But I suspect that they still can be useful from a purely functional standpoint depending on your application needs.

@YkTru
Copy link
Author

YkTru commented Jan 10, 2024

Thank you a lot @marner2 for your insightful response, however in a more concrete way (since it remains fuzzy in my beginner's mind in terms of realization):


The best techniques that we have found for scaling an Elmish.WPF app involves scaling things in a specific order. Specifically, scale the view quickly and easily depending on your immediate frontend needs, scale the model when it makes sense to group things in your store, and only scale the messages if you absolutely have to. Finally, think of the update function as the functional glue that holds everything together. We've had very good luck completely separating pure model update functions from impure message generating functions at a decent scale. The idea was always to move as much functionality over to the pure side as possible, as it made reasoning about sub-app behaviors much easier.

1- Could you share an Elmish.WPF repos/projects where we could see actual best practices for how folder/file structure is organized + Elmish.WPF's actual best approach to MVU architecture?

2- Would you recommend following most of the practices in the [Feldman-SPA example] (https://github.com/rtfeldman/elm-spa-example), and in what aspects should the Elmish.WPF project be approached differently?

3- I know I asked it in my initial post, but it's still not clear to me what are your personnal opinions of the highly recommended Feldman video (+ Evan's one): Honnestly I'm not comfortable with the fact that it seems to date back quite a long time though (6-7 years) and that Elm "architectural/scaling philosophy" was in its early stages, but would you recommend (in general) that I follow most of that video practices, and if not which one to keep/discard considering actual Elmish.WPF best pratices?

4- And would his book Elm in Action help me better understand how I might scale Elmish. WPF, or is it too "Elm specific"?

(At this point, I'd like to point out as a newcomer that many of my difficulties in understanding the better Elmish.WPF strategies + more complex samples (SubModelSeq) come from the fact that I've had to clumsily "translate" most of the advanced documentation/tutorials that are mostly in Elm (and Elmish) to Elmish.WPF, so sorry if I sound insisting and insecure, it's easy to get lost).


Regarding lenses (...) supplanted by F# 8's new features: _.Property shorthand for (fun x -> x.Property) and Nested record field copy and update.

Great, I didn't know that! But then again, if the nesting goes too far, it could get pretty messy.

I want to acknowledge that it's true that the examples are much more about showcasing specific features as they are about showing wholistic scalable examples

5- Do you intend in the near future to add "updated" sample using F#8 new relevant features, and very explicit documentation and samples on how to scale (since for most of us it's inevitable)?


Misc question:

6- Elmish.WPF library perennity + updates: First of all, I'd like to express my great appreciation for this library and my gratitude to everyone involved in its creation and maintenance, but as I come from the very active and popular WPF+Prism+CommunityToolkit community (where there are tons of pull requests, updates, etc), and even though it's claimed that [Elmish is ready for production] (https://github.com/elmish/Elmish.WPF), as a newcomer I'm afraid it might be abandoned in the not too distant future (because I once had a very bad experience with an abandoned C# library I depended on, and mainly because I know that some early adopters/contributors no longer use it at all). I'd be happy to contribute if I ever manage to use it smoothly and competently, as I see it as a major improvement over the Prism + OOP madness.

Thank you again

@TysonMN
Copy link
Member

TysonMN commented Jan 15, 2024

@YkTru, I admire your enthusiasm. All of your questions are great.

However, you are asking for too much, especially in a single issue. Your questions suggest that you won't make a decision unless you are very confident that your decision is the best. It is not possible to be so certain about the future. You need to be more comfortable with some uncertainty.

As you say explicitly toward the end of your previous comment, I think your primary question is something like:

Should I use this library in my project at home/work?

For two years, I was the leader of a team that used Elmish.WPF. During that time, I became the lead maintainer of Elmish.WPF. Then I switched jobs. @marner2 replaced me as the leader of that team and then a bit later replaced me as the lead maintainer of Elmish.WPF. That lasted for another two years until recently when the client paused development. I won't go into the reasons why, but it wasn't due to deficiencies with Elmish.WPF. It is indeed production ready and scales well. Sure, we encountered slow performance at times, but we were always able to make the code more efficient. I expect that pattern would have continued.

I have a friend who will only use a library if it is among the most popular of options. Elmish.WPF is not very popular, so my friend would never use this library. In contrast, I decided to use this library in part because I believed that I could change it if I encountered any problem.

You won't be able to get complete or even satisfactory answers to all your questions before you have to decide if you will use Elmish.WPF.

If you decide to use Elmish.WPF, then you will likely discover the answers to your questions as you work with it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants