Hacker News new | past | comments | ask | show | jobs | submit login

The big MVC frameworks are in a great position to take advantage of the move back to hypermedia as a major network model for web development. We are seeing a swing back to this model with modern hypermedia-oriented libraries like unpoly, hotwire and my own htmx, where javascript is used to augment the hypermedia model rather than replace it with a client-server RPC-style network model as with most SPAs.

These older frameworks have been honed to a razors edge for producing hypermedia (HTML) server side and delivering it to clients efficiently. As people begin to realize just how much you can achieve with this approach (and the simplicity it brings back to web development) I expect interest in these frameworks to soar.

Bullish on 2005 tech books!




To be frank, I don't really see this swing back. Maybe it's hip right now on HN to scoff at SPAs and fetishize server-rendered webpages.

Having used NoScript with temporary allowances, it's glaringly obvious how much of the web doesn't show anything without JS enabled. If there's a trend to not make everything render on the client, I'm not noticing it.

Even if there is, we may ultimately end back in the same place we were in say 2011 (or ~2014 depending on how you look at it). We could very well end up back in dumping grounds of abstraction spaghetti bad object-orientation.

The weakness of backend MVC frameworks is that it's way too easy to munge business logic with the view. Yeah, Model-View-Controller suggests a separation of those concerns, but now it's up to the human to follow that convention and... yeah...

SPAs can be just as bad in a lot of ways, but at least they are more suited to dealing with view logic and not so much of the data transaction stuff behind the scenes.

Personally, I often find frontend JavaScript projects easier to figure out, and I think that my be due to MVC being a flawed concept. It might be okay for hammering out a prototype, but in the long term so many things need to happen in order to keep it intact; Rails introduced concepts like "concerns" exactly for this purpose, because an MVC structure in a pure OO language like Ruby is very rigid.

Server frameworks should do themselves a favor and divorce themselves from ideas like MVC and find ways to create structure in ways that aren't merely meant to scratch the itch of design-pattern enthusiasts. I find it dubious that a concept of a "model" is even necessary as a thing to always think about; it's a weird implementation detail that's treated as if it's a design pattern. And when you're left with just the View-Controller part, it's dubious why they even need a formalized concept in the first place.


While MVC is certainly not perfect, I've had the opposite experience you describe: the days of the spaghetti abstraction really began with the Javascript centric approach. The emphasis changed from opinionated defaults, to completely DIY, everything's configurable, every application is a snowflake.

This doesn't seem any better to me than the Perl+CGI / PHP world that Rails replaced. And we've traded the risk of munging view and model, or breaking conventions, for no guardrails and no patterns and no conventions beyond the most popular library to show up in the last 6 months.

I've personally seen an old, terribly uncool dinosaur MVC decomposition turn into 50+ microservices, with 10+ front-end apps, each with their own toolchains, libraries, peculiarities and hidden dependencies. That doesn't seem to be a win either. It feels like we are all collectively missing a more integrated approach to development, and eventually the pendulum will swing back in the favor of more comprehensive frameworks.


But the same 'munging' of business logic and view logic happens in SPAs and related. It's just a fundamental problem with MVC that the lines are difficult to demarcate well no matter how you define your layers.

That and "model" is tricky to define well when we're talking about data backed by a relational database which can (and should be) be sliced in any number of ways. I've yet to see a good relational->UI mapping that works without badly fossilizing everything into a static and undynamic OO "model" inbetween... In fact this is made even worse in SPA-type systems by having an ORM (or similar) and a REST/GraphQL type layer inbetween the view and the DB. Layers and layers of transformation. Each stripping out the richness of the relational model.


It certainly can. In my experience, I've seen this happen to a much lesser extent, though I've not worked on as many SPAs as others of course.

> It's just a fundamental problem with MVC that the lines are difficult to demarcate well no matter how you define your layers.

Yes.

> That and "model" is tricky to define well when we're talking about data backed by a relational database

And that's why I find it nearly useless to even make it a "thing" other than perhaps for n00b coders who've yet to touch SQL or write many of their own classes/modules, or I guess just have enough experience working with data. Thinking in terms of models for data, IMO, can and I think almost always does pigeonhole data into moving and existing in ways it doesn't need to. In many cases, a formal model makes no sense for the data at hand, and if developers only think in terms of models then everything inherits a ton of complexity that may be of no benefit. It's premature optimization hidden as a convention or pattern.

> I've yet to see a good relational->UI mapping that works without badly fossilizing everything into a static and undynamic OO "model" inbetween.

At which there's no point in using strictly OO or a model paradigm. This is what happens when those highly accustomed to OO realize that their conception of OO is unsafe. Keeping data frozen, static, immutable, or whatever is right thing in more cases than is appreciated, but even when devs acutely realize it after the fact, they often resist giving up using models. If some concept of a model is more of a drawback then a benefit, just get rid of them. I don't care what framework or ORM people are using. Any developer can learn to work with data in a functional way that doesn't involve making data act as an ooey gooey object that can morph (and get messed up) and take on a taxonomy that wouldn't otherwise exist in the real world.


  > In fact this is made even worse in SPA-type systems by having an ORM (or similar) and a REST/GraphQL type layer inbetween the view and the DB. Layers and layers of transformation. Each stripping out the richness of the relational model.
What about GraphQL that is quite literally just your database structure? IE, verbatim columns and foreign key relationships.

I have this issue too -- you can make an infinite number of onion-ey layers of abstraction over your data. But at the end of the day, there's only one canonical representation of it -- in your data layer.

This is why I am against marshalling naming conventions across programming languages. If your database has snake_case columns, keep the values snake_case when working with them from API responses in your code. If you change the casing, you now have something that doesn't represent what's in your database anymore.

Want data that doesn't exist in a table? Make a view or call a function.


To be fair, I have 0 experience with GraphQL so I probably should not have mentioned it. I spent the last 10 years in pseudo-embedded land and systems programming and some purely backend high throughput systems (ad tech), not doing much 'web' related. I'd like to play with GraphQL.

That said, GraphQL is not a relational query language, and works in the world of hierarchical/graph database land. I think Date & Codd did a good job of critiquing that model and showing its faults the first time around (the 1970s).


> I have this issue too -- you can make an infinite number of onion-ey layers of abstraction over your data. But at the end of the day, there's only one canonical representation of it -- in your data layer.

Right, and the amount of effort spent by devs working within layers of abstraction can outweigh the effort they'd otherwise spend working with pure data, even if other issues arise; said issues would be faster to solve without lots of code in the way.

People forget that an abstraction doesn't make things easier to understand, but this is how many new devs are taught and think about abstraction. Abstractions are only simpler so long as you don't ever need to worry about what that abstraction is doing. As soon as an abstraction is misbehaving mysteriously, inevitably you have to open the hood and see what's up with the engine.

It doesn't even matter if the abstraction was made by really smart people with distinguished titles. At every Rails job I had, there was at least one problem with an abstraction in either ActiveRecord or other things like Rails Engines that were totally inexplicable by anything – they only were solved by hours upon hours of mid-level devs digging through framework code until they came up with a monkeypatch.

Part of this also comes from what I believe is a very misguided desire to leave the door open to switch databases. During my first two Rails jobs, senior developers resisted to use any raw SQL queries anywhere because "what if we switch to Postgres?" Never did that pan out, and in the meantime devs were forced to do weird things with ActiveRecord to make things work, often inefficiently.

I remember when I was momentarily the most senior dev at one of these jobs, once the lead had left, and I decided to just use SQL where it made sense. Not only did this cut down on lines of code and method calls, but those queries ended up being significantly faster, reducing page load time.

Sure, I didn't go through the trouble to force that raw data into an ActiveRecord model, but so what? All we wanted to do was display the data to the user. Why introduce a bunch of ORM gobbledygook for read-only? Because we might want users to edit articles in some hypothetical future where we just let any rando write stories? lol

That codebase was never great, but after some of those kinds of adjustments we somehow didn't get much if any emergency calls after hours anymore. Hmmm...

Abstractions can be great, but I've come to think they rarely have value with persistent data. In a game engine, it can make sense to have model-like objects for things that are ephemeral in gameplay but need to know about one-another, and this is usually easier to implement in a custom way because games usually aren't written like web apps.

> Want data that doesn't exist in a table? Make a view or call a function.

Yes.


> I remember when I was momentarily the most senior dev at one of these jobs, once the lead had left, and I decided to just use SQL where it made sense. Not only did this cut down on lines of code and method calls, but those queries ended up being significantly faster, reducing page load time.

That's so familiar. I've also been trough this more times than I'd like to admit. Often five or six files of ActiveRecord code that could be reduced to a View.

However I don't think it's just desire to change databases, there's also a lot of resistance against using different languages. SQL is bad, it's ugly, it's old. I see the same sentiment against Bash in younger developers too. They don't want to take the time to learn, so they just reject it.


I mean... Bash is actually bad and ugly.

And ... I'm old and that's how I learned that :-)


Bash is bad and ugly… But I just avoided a day’s worth of development of a little command line utility by adding two alias lines that go into .profile.


> I find it dubious that a concept of a "model" is even necessary as a thing to always think about; it's a weird implementation detail that's treated as if it's a design pattern.

Are you saying you find it dubious that what you're displaying should be predicated on a well-defined collection of data? Because this is what a model is.

If that's what you're saying, I'm not seeing it. Care to expand on it?


For many, the well-defined collection of data is realized in a relational database. In this case, the challenge is mapping this data onto exact requirements for specific data entry screens or reports.

With complex business rules that cannot be easily implemented via database constraints or triggers, or where the same rule is located on more than one data entry screen, then there is a justified need for an intermediate "model" layer for business logic. However, many applications out there just don't have this complexity. In these cases, having an intermediate model accessible via JSON API may be over engineering. You have to double your mappings. A new feature requires that more code be touched, in different parts of the application. For applications with simple business logic and screens that closely map the database structure, this additional layer may not be worth it.


I guess the question is: What's the alternative to defining models? Just passing around DB cursors directly or maybe pulling the results out of a cursor and storing them in a dynamic collection?

I don't disagree that models are pointless if they're not doing anything other than aping the DB. Why waste your time creating another layer of required translation if it doesn't buy you anything?

With that said, I do think there are some benefits to using statically typed models in languages line C# with larger codebases. It seems like it makes it easier to refactor the application code.


As somebody who loves databases, I think the real issue that folks are meaning to critique isn’t actually using a “model.”

It’s using an ActiveRecord-style ORM (or any ORM) without grokking what lies beneath.

A database layer IS a model. It’s just not a class or an object.

ActiveRecord is a really nice trick when it works … but it can create some really performance-killing side effects.

Ruby’s Datawrapper ORM and its siblings in other languages requires understanding both sides (the object system and RDBMS) but can let you get your class/object semantics to play nicely with your database.

And just passing around database connections and arrays of hashes can get you awfully far.

But, if you want to not think about the database layer, ActiveRecord-style ORMs are a real win for developer ergonomics.

And that’s part of the win of Rails/Django/etc. You can live in a single mental model (classes/objects with references to each other) and ignore the database layer.

Except when you can’t.

One reason (not a criticism) that NoSQL can be such a win is that the semantics are closer to class/object semantics. So you’re not trying to manipulate data with an abstraction that doesn’t quite fit.

But most of our projects aren’t Twitter or FaceBook or Google or anything else functioning at galactic scale.


> Having used NoScript with temporary allowances, it's glaringly obvious how much of the web doesn't show anything without JS enabled.

Counterpoint: I generally browse with JS disabled and there's a strong association between sites for which this is existentially problematic and sites whose content or utility are garbage.

> If there's a trend to not make everything render on the client, I'm not noticing it.

This trend is not so strong as suggested. Far from server-rendered websites being "fetishized", this remains the standard.

I recommend SPA-first development to all my competitors. Crystallising architecture around the front-end is one of those anti-patterns my grandmother warned me about. "You'll struggle to pivot," she said. "Spikes, prototypes and reimplementations are much easier to develop in proximity to business logic and persistence schema." What a wise lady. See also: nosql and microservices.


   "Having used NoScript with temporary allowances, it's glaringly obvious how much of the web doesn't show anything without JS enabled. If there's a trend to not make everything render on the client, I'm not noticing it."
You're not noticing it because JS SPA frameworks have been the new hotnessTM for ~10 years.

   "We could very well end up back in dumping grounds of abstraction spaghetti bad object-orientation.[...]it's way too easy to munge business logic with the view. Yeah, Model-View-Controller suggests a separation of those concerns, but now it's up to the human to follow that convention"
This is a problem with modeling and coupling that happens on SPA's as well, unless you've somehow solved that pesky human problem :D The fact that there's an API layer helps....sometimes...but many times your munging of business logic just ends up being in two different layers instead of one.

   "...MVC being a flawed concept. It might be okay for hammering out a prototype, but in the long term so many things need to happen in order to keep it intact; Rails introduced concepts like "concerns" exactly for this purpose, because an MVC structure in a pure OO language like Ruby is very rigid."  
Agree. IMO one of the main issues with MVC was that the layers were somewhat ambiguous, which caused bloated controllers or munged up models. In the past I found that "splitting" MVC to be more like MVVM with dedicated backend and view model layers resulted in a much cleaner separation of concerns without the need to go full SPA just for the side benefit of having an API layer.

TBH having worked on multiple high traffic, large-ish MVC apps and high traffic, large-ish react SPA's, I'm a fan of "the old way" of building apps. It felt faster, easier, and much cleaner. I can't wait until things like blazor, hotwire, and htmx help server side templating become a thing again. IMO it would help clean up the state of the web dev industry immensely. Maybe I'm looking at the past with rose colored glasses?


Since I need to actually get off HN and get something done for a change, I can't reply 100% to everything you wrote here, but I appreciate your critical response.

> TBH having worked on multiple high traffic, large-ish MVC apps and high traffic, large-ish react SPA's, I'm a fan of "the old way" of building apps. [...] Maybe I'm looking at the past with rose colored glasses?

That bias exists in all of us, but I wouldn't guess you're looking back with rose colored glasses.

I'm actually more of a fan of "the old way" than I might be letting on. My work for the last 4.5 years has been almost entirely on SPAs, so I'm part of the problem, but I think I've seen the weakness in it as well.

All in all, I'd like for us all to try and avoid complexity from the get-go. That means starting with sites that are server-rendered and to try and not immediately jump to fancy SPAs and other tools. Maybe not everything must be containerized. Maybe monoliths and relational databases are A-OK for most purposes, and scaling up in response to financial success is something that can be handled when the time comes.

At the same time, if we're going through a sanity adjustment as an industry, let's make sure we reexamine the old assumptions that we ran away from in the first place. Otherwise, it's just a pendulum swing.

My main concern about the new/coming generation of tools is whether we also see a similar brawl we witnessed at the Cambrian era of frontend frameworks. A lot of things that seemed like innovations turned out to be headaches and even universally reviled. I can just picture the blog headlines of the next 5 years: "Why we moved away from Phoneix Liveview"


I have found that all the SPA apps I have inherited (current one particularly) have way too much logic in the frontend. People complain about Django's template language being limited, but that encourages you to keep that stuff for display only.


"Way too much logic in the frontend" is entirely objective, and honestly doesn't hold much water, unless you're talking security where the logic is not mirrored in the backend. Any time performance and responsiveness matter, across the engineering board, client-side logic wins. The times that integrity matters, you still apply the logic client side and also on the server side. See the amazing Source Multiplayer Networking article for more info on where I'm coming from with respect to ultra high performance but validated architecture.

https://developer.valvesoftware.com/wiki/Source_Multiplayer_...


Nah, all he SPA apps I have worked on have had terrible performance. Way to many calls between backend and frontend. Way too much complexity. I am sure you could write them better, but server side rendering is nowhere near the bottleneck that SPA people seem to claim that it is.


counter point: Microsoft is leading the charge with Blazor, bringing full single stacks to the front-end for the first time for non JavaScript developers.

For applications its hard to see why this model wouldn't be more preferential. Most .NET applications are monolithic in nature (though you can enforce really good module separation with relatively minimal effort IME). You can look at Rust too, for its developing some Blazor-like frameworks. I could imagine for example, the next GMail being written like this, or other deeply interactive applications.

I think people want to work in a singular language / framework more than anything else. One of the reasons I think JavaScript still prevails today, is it was the first language community to largely achieve this in an accessible manner. Others are now coming forward.

I think pre-rendering is still the best approach to truly static content though, using web components to progressively enhance features of a page for light interactivity, this is one area they really shine.

I could be very wrong though!


What I've feel is ignored in the community is that actual backend development never reached a point of wide adoption with javascript/node. Certainly node and alikes are used to deliver front end code, as front end api or api layer in between. But the vast majority of backend development remained in the power of established tech. The (natural) attempt of JS tech to push into backends, led to some accidental constructs, a mix of JS and other techonologies which may act more like walls then bridges. Tech stack responsibility is blurred because of JS's omnipresence, which leads to several problems. I think some people start to realize that JS is a useful front end platform but must not be the default tool for a backend platform.


I seriously hope MSFT is committed to pushing Blazor. It's has the potential to stand above the other "unified back end front end" technologies.

Unfortunately Blazor hype has really died down the last couple of years and I'm starting to get Silverlight vibes from it, which doesn't bode well...


I think MAUI is in part built on the back of Blazor. They might converge, but I don't think its underlying model is going anywhere.

I don't work at MSFT though, so YMMV? I don't think its going to end up like Silverlight. They seem pretty committed to not back pedaling anymore like that, they know it hurt them so much, at least thats the message I been getting from MSFT developer relations, is an some admittance they really borked their DX by going through such rapid turnover of UI frameworks and such.


No it is not, MAUI is having the option to support Blazor via WebWidgets as a kind of Electron competition, which probably only the Blazor team themselves see as an advantage.

MAUI by itself is Xamarin ported to run on top of .NET Core (now .NET 5+), with WinUI as backend on Windows.

In what concerns UI Frameworks coming out of Redmond, it looks like pretty messy civil war right now.


> Blazor-like

Isn't that just "GWT-like"?


Blazor relies on dynamically generated JS Bridges and WASM, where as GWT just generated JavaScript from Java Bindings. Seems similar on the surface, however the difference being that Blazor is trying to leverage direct compilation of C# constructs directly to WASM whenever possible, and supplementing that with some JavaScript interop, as opposed to trans-piling things directly to JS itself, as with GWT.


AIUI Blazor is 2 models today

    1. As you described, compile C# to WASM, download a blob and run client side
    2. Run the C# server side, send the client a thin page and a SignalR pipe back up to the server
With 2 it's more like react SSR (as in the mode where react components run on the server, not SSG where they run on the server and just emit static HTML). When i looked through the docs, 2 was the primary mode for now.

The benefits claimed were you don't need a modern browser, i think the thin shell + signalR combo works gracefully back as far as IE9 or something silly, also you don't need much processing power on the client because the signalR pipe is just a conduit for pre-rendered HTML generated by a blazor component running server side.

The down side is that for every client, there's a websocket (or long polling connection) for every client to the server.


Isn't option 1 more like compile .NET interpreter to WASM and ship with your dlls resulting in huge download and terrible runtime performance?


There are a lot of ways to trim the size. All in sure, its 2 MB I think, for the entire .NET runtime. However there are a few mitigating steps that really do have a dramatic difference in terms of how big the WASM runtime is.

If you setup the compiler with trimming enabled[0] it gets significantly smaller. You can also lazy load assemblies by route[1] to further restrict the upfront cost.

Of course, this is not acceptable for the average web page by any means. This is really intended for behind the login type applications where you load up the initial runtime once and its cached heavily for the rest of the applications lifecycle by the user. This is really targeted at true applications-in-the-browser type situations.

Blazor server side works too, though everything then has to run via a SignalR connection and can be a bit more flaky at scale.

Runtime performance however, I actually don't find it to be a bottleneck. The apps I've built with Blazor are pretty fast. I haven't worked with it in 9 months though.

[0]: https://docs.microsoft.com/en-us/aspnet/core/blazor/host-and...

[1]: https://docs.microsoft.com/en-us/aspnet/core/blazor/webassem...


Hm, that sounds a little like meteor. Thanks for the explanation.


That makes sense. But it doesn't seem a very significant difference on the face of it. More modern implementation of same idea?


On the highest level, yeah, it really is just more modern.

In practice though, its also flexibility. GWT shoehorned you to do certain things a certain way and only that way, where as Blazor only limits you based on what calls and modules can be safely converted to run against the WASM driven runtime. Which means you aren't limited to a specific list of ways to solve a problem, its more (and increasingly so) flexible than that. So for instance, GWT has specific widgets[0] that you should use to represent the use interface, Blazor doesn't limit you to just Blazor compatible widgets (there are some though, because at some point the abstraction runs out of juice). You can use regular conventions and classes too, like the normal .NET HTTP client stack, regular data classes etc. You can also re-use Razor components, most of the time.

To be clear though, Blazor isn't a panacea, it has its own caveats and downsides, however I think its really innovative in terms of concept and execution. For anything behind a login its a pretty sensible choice IMO. I wouldn't go making your marketing / info / purely static pages with it though. server side rendering or pre-rendering is a much better choice there.

Also worth mentioning, on top of all that, is Blazor can cross compile to native applications too, like iOS and Android, with (largely) the same codebase.

[0]: https://www.gwtproject.org/doc/latest/DevGuideUiWidgets.html


For those that have integrated something like htmx/server side rendered HTML over an API into existing JSON-oriented APIs - what's the cleanest way you've found to have both formats exist together? Not that every existing API call would need to include an HTML output, but for many projects I could see there being many endpoints that would also make sense to output HTML and wouldn't deserve an entirely different API.

My first thought was to add a format/output parameter to specify the format. In that case of HTML output, you could possibly use the JSON that would normally be rendered and insert it into a jinj2 template for example.



Did you make htmx? I love that thing.


yep, glad you are finding it useful :)


I see you just about everywhere on the internet. It's nuts. Prove that you aren't a pile of ants wearing a trenchcoat.


Beats half a million ants and half collapsing star.


htmx loks really cool, a performance comparison vs the fastest SSR SPAs would be helpful




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: