Long time ago the recommended way of doing full stack apps in .NET was WebForms. I am old enough to remember the pain of maintaining large WebForms apps so I thought I'll provoke a discussion.
I'd like Blazor to succeed and minimize the need for using JS/TS for full stack development, however in order to commit to it as technology of choice, I need to be sure that Blazor is not going to repeat WebForms mistakes.
WebForms core element was a component, that had both a codebehind part (C#) and webforms view part (pre razor view engine). In addition to that the codebehind was split into autogenerated part with subcomponent initialization (as in winforms) and the custom part (using partial keyword in C#).
Some people used MVP pattern to scale webforms using Presenters, but it didn't really promote unidirectional flow and stateless components, so state management gravitated towards a mess, with ViewState, special events, concerns were mixed, etc. etc. Lack of guidance made larger projects a mess.
Blazor views resemble some of the bad practices that webforms allowed. It is perhaps the legacy of razor
, but maybe there's a different way to write views and their logic without mixing everything together in one file?
There's now one tag "@functions" where anything can be put. State, props, events, etc. What's more all those parameters go at the bottom, even though the render that is written above them, is a result of them (perhaps it's just the convention that can be changed, but maybe it should?).
Nowadays I work quite a bit with React and Flux, which reminds me of windows message loop, winforms and webforms but where more guidance is provided to keep the components as thin as possible. At the same time, testing a component is easy (in contrast to a webforms component tree), so view logic can finally be nicely tested in code without a lot of work. Reducers allow composing components+logic with great flexibility, which was hard to obtain in webforms, because the framework would not guide on how to do it without shooting yourself in the foot. React also has a render method, but it is much nicer to use composition there thanks to TSX, nicer syntax and because it's in JS (so you don't have to jump to hoops to ensure some JS is called as part of render).
What I would like to see is for Blazor to learn lessons from WebForms and Razor failures and React wins, perhaps taking a bit more from React/Flux by being a bit more opinionated with regard to target application architecture.
Several ideas (taken from post-webforms world):
I think immutability by default (props) is the way to go to ensure scalable full stack development. State should be minimized, kept only where necessary, moved to reducer/ store.
Nowadays, C# viewmodels are often parsed to generate typings in TS for use in frontend. Blazor should integrate such viewmodels (immutable if possible) seamlessly.
Is there a larger sample planned that would cover full stack development with a larger component tree on the frontend and some non-trivial backend logic?
Blazor should direct people towards recommended way of structuring view-related logic. Perhaps blazor-redux is the way to go? Or maybe it isn't? Or maybe there are two approaches?
Styling should be addressed separately not as simple strings. CSS should be strongly typed according to the standard. There should be a recommendation on how to manage CSS in a way that does not work against existing best practices, allow styles to be separate from component code if necessary with proper namespacing, nesting ,etc.
Most components should be pure (be just functions). That's part of the incentive system to reduce state in the architecture. It would be nice if Blazor encouraged use of pure functions, perhaps by promising better performance, etc.
This is react weak point - performing animation that cannot be done using CSS is a pain - you need to update state or hack your way out of react and work on DOM. Perhaps Blazor can be better in this regard? How could animations work in Blazor
There are many more ideas that could be borrowed and improved from react/flux. I am a big proponent of unidirectional flow in large scale apps after being bitten by bidirectional databindings many times in different frameworks.
What's the direction for Blazor?
I've seen blazor redux before, definitely a step in the right direction but the problems with current blazor and razor syntax and other outlined by me persist.
Moreover blazor-redux is a non-Microsoft experiment on top of blazor that's already an experiment. Without serious backing as 'the right way', blazor-redux will not become the go to method for structuring large apps.
If blazor embraces flux as the recommended architecture then situation may improve.
Immutability by default (props)
No. Just no.
This is cargo-cult design. The only real benefit of immutability--guaranteed thread safety--does not apply in a single-threaded, Web-workers-but-shared-nothing browser environment, so you end up with all of the many drawbacks of immutability (copying everywhere and keeping track of copies, increased complexity, increased GC pressure, decreased performance) all for nothing.
You can use F# if you want immutability since that is a core rule on the language and is supported in .NET, I'd say that it's better to make Blazor flexible and lean rather than binding those rules directly onto the framework. The solution to make it a separate package like how Blazor-Redux is made is better overall as it gives flexibiltiy than constricting developers of choice.
This also applies to react wherein Redux is a separate package so that devs can either use React with Redux or barebones React.
Please read the documentation and at least be accurate with what you are saying before you start making statements like "Blazor views resemble some of the bad practices that webforms allowed."
If you need a framework for Blazor that will tell you how you should do things, I am sure that someone will create one for you (just give it time). Blazor is a platform that third parties will, I am sure, create all sorts of addons and workflows for,
I for one do not want them baked in and I definitely do not want to HAVE to use redux with the overhead that will bring, I do not want Immutability by default, You can share models between the server and the client and surely the view model is only needed on the client. Also you can have the C# in a separate file and not in the the same file as the Markup if that is what you want.
Just because in some cases something is good, does not mean it suits all cases and it definitely does not need to inflicted on all of us.
I disagree.
Immutability by default helps reasoning about dependencies between system components and limit state. It doesn't really matter whether I am using a single thread or not.
Immutability does not mean that you always have to copy. It just limits the programmer on when he can mutate variables and when not (for example when you mutate a variable, some side effects should be performed, so mutating variable directly is a bad idea). Copying can be avoided, leave it to the platform and the compiler. There is a very good reason why you are going to have ref readonly in C# soon, and why C++ had const& for ages.
Furthermore, you shouldn't look at immutability as only going on at the client. When I look at full stack development, I may create some objects on the server only to be displayed on the client. Immutability (via read only properties) will prevent others from mutating the variables on the frontend and wondering what should happen next - should the server do something then, or maybe it doesn't work?
I agree that in small, either in scope, time period, team size, lack of maintenance (one-off projects) it can be an overkill. What I care about is large scale development, only addressing its needs Blazor can succeed. After all, you can use React without Redux.
EDIT - please also see my previous comment. I'm not saying redux must be a part of blazor. All I recommend for is to select one pattern as the suggested one for large scale development.
I added the links earlier to suggest that there is already community activity related to _extending_ Blazor. I disagree with Blazor taking any kind of opinionated design stance. Design patterns will change as time moves forward. Blazor should be a platform for extension so communities can build what they want to make it more to their liking or style or needs. Blazor should serve the sophisticated developer and the beginner. Blazor should work to be a platform for building and changing with the times.
reasoning about dependencies
limit state
side effects
This vocabulary sounds like you come from a functional background and are trying to bring FP's dogma to Blazor. Please don't. Most of us are just trying to get stuff done, and would greatly prefer to not have our attempts at productivity shoehorned into a model that is a very poor fit for Web development.
Well, thanks for your comments so far about one of my suggestions, even though I find them a little bit too focused on my persona and not on the proposals. I can see that our experience is completely different with regard to immutability and web development to say the least ;)
Since you are already engaged in this discussion, do you mind commenting on other parts of my suggestion @masonwheeler ?
You should create separate issues for each topics.
I'm a huge fan of Functional Programming in C#. With that said, I feel that it's something that should not be forced on developers, but should be opted into.
Making immutability the default is going to cause more harm than good. C# for all intents and purposes is OOP. The people that enjoy FP (myself included) are the minority. For Blazor to gain ground it has to be accessible and relateable to the majority.
@EdCharbeneau F# is a viable option for people who would love a Functional programming focused language in .NET since it's the .NET language for FP while C# leans more on OOP.
So overall as long as it's supported by .NET standard (F# is supported), then developers do have a choice (Although Razor syntax is limited to C# sadly, you must use a code behind .fs file that inherits the component).
@RyoukoKonpaku yes, I think we're on the same page.
@voltcode
I can see that our experience is completely different with regard to immutability and web development to say the least ;)
If I'm right, you also like the unidirectional dataflow (like react.js)? (the reason for your immutability-proposal?)
Interesting discussion! I too have history with both WebForms and more recent technologies including React, Angular, and Vue. Architecturally, Blazor is much closer to React/Vue than to WebForms. In general we certainly are trying to learn the lessons of more recent frameworks, both where they succeed and where they are failing.
Closing as this isn't an active work item but please feel free to continue the discussion!
@SteveSandersonMS I'm not really sure if anyone will take part in discussion under a closed ticket, especially people that have never seen it. I'm not sure what's Blazor's intended place for discussion, I thought it was the issues. Closing it means you consider the discussion as done. So this is more of an organizational question to you.
I can split this large topic into several ones (immutability separate, CSS separate, etc.) but only if this is what you recommend and if they won't get shut down after a couple of days like this one.
@voltcode Wasn’t trying to stop discussion. We try to use this issue tracker for managing the work pipeline, so that’s what the “open” flag means to us - some work to be planned.
Since you’ve asked I’ll reopen this for now but will want to close maybe at the end of the week to keep things organised. We don’t have a particular place for indefinite open-ended discussions but this will have to do for now.
@DNF-SaS I prefer to use unidirectional dataflow as the overarching architectural principle, but I understand that some things are very hard/cumbersome to do it this way. When I use bidirectional flow, I try to contain it, so it doesn't pollute/leak and change entire architecture to spaghetti.
I think I am a bit misunderstood by some people in this discussion, I am not trying to exclude mutability here, just make immutability the starting option, for example by using private setters in examples if possible (I haven't tested if they work in blazor yet). One of the problems I have with MVC viewmodels that they cannot have private setters because of their serialization (JSON.NET can handle private setters no problem).
I'd like others to comment whether they see other points I raised as important for solving in blazor (either as core blazor or as a plugin).
@voltcode I partially agree with you and I would like to see "larger, non-trivial fullstack sample". Blazor can be used to create an order entry system. The idea is simple and everybody can understand it. The solution should have the following functionality:
In my opinion this is the minimal real world sample application. I hope sooner or later we will be able to create it in Blazor.
Looks like this discussion has wound up so to keep the issues list tidier I'll flag it as closed. As mentioned before, people are still welcome to continue discussing here for as long as anyone wants :)
Most helpful comment
Please read the documentation and at least be accurate with what you are saying before you start making statements like "Blazor views resemble some of the bad practices that webforms allowed."
If you need a framework for Blazor that will tell you how you should do things, I am sure that someone will create one for you (just give it time). Blazor is a platform that third parties will, I am sure, create all sorts of addons and workflows for,
I for one do not want them baked in and I definitely do not want to HAVE to use redux with the overhead that will bring, I do not want Immutability by default, You can share models between the server and the client and surely the view model is only needed on the client. Also you can have the C# in a separate file and not in the the same file as the Markup if that is what you want.
Just because in some cases something is good, does not mean it suits all cases and it definitely does not need to inflicted on all of us.