4 ms·
I've tried these technologies ... and for me they are less productive than the ways I know how to build API-first, JavaScript web apps I think I feel the same
by nauticacom 5y ago
I've tried these technologies ... and for me they are less productive than the ways I know how to build API-first, JavaScript web apps
I think I feel the same way you do, except the other way around. I genuinely can't understand how you build apps productively with a separate client/server model.
How do you do form validations? How about authentication and authorization? What about a consistent domain model? Is there one copy of it on the server and one on the client? Or does your client just treat everything as dumb data and make network requests for every question of business logic? What about data consistency throughout the interface—when you update e.g. Document(id=45) with new data, how does that update get propagated to every other place in the app? Does that involve a client-side identity-map? Or are you manually trying to send updated data to other places with callbacks/whatever? etc. for ever and ever.
Every time I try to build an app where the frontend and backend are split into a separate client and API, it ends up adding so many more considerations and so much more complexity than the traditional model. Mostly because now everything that just required a database query or method call before now also requires a network request, but also because data consistency in a long-running app is so hard to get right.
- nawgz 5y agoYour questions are all... contrived? > How do you do form validations? How do YOU do form validations? Is it entirely on the backend so it requires a round-trip before the user gets feedback, and additionally requires you to wire both the HTML endpoint for user feedback AND for rendering some results? For myself, I have a reusable Form component I can plug in arbitrary tests. You can run the tests when the user changes an input or on submit, with some options/conditions for when you clear the feedback. Then, of course, my API gives feedback as well; usually, it's harder / more awkward to wire the API feedback to highlight the offending Form fields, and I certainly don't see how HTMX would accomplish this, so without some machinery I already feel your side lacks QOL features like "highlight error fields" and "autofocus first offending entry". > How about authentication and authorization You are joking or what? There is no difference in how an HTMX app would authenticate to its endpoints and how an SPA would Finally, you ask a bunch of questions that clearly aren't any better in an API-endpoint-randomly-renders-HTML paradigm... > Is there one copy of it on the server and one on the client Obviously, but you load the client version from the server at API request time... just like an HTMX powered client... except an SPA keeps objects instead of a rendered representation so you can do more in-depth things without network trips... > What about data consistency throughout the interface—when you update e.g. Document(id=45) with new data, how does that update get propagated to every other place in the app? Because you use singletons like a not-crazy person... how does this happen in HTMX world where you have no data representation on the front-end? Does your form have to be manually wired to update every single present data view that is holding that document? Seems like you're worse off than me. I hold a stateful representation and update the views when that representation changes, automatically... Wow, literally no work required because it's declarative > Does that involve a client-side identity-map? Or are you manually trying to send updated data to other places with callbacks/whatever? Laughable. the HTMX paradigm is clearly worse off here > Every time I try to build an app where the frontend and backend are split into a separate client and API, it ends up adding so many more considerations and so much more complexity than the traditional model You clearly did not bother to understand how state & views relate in an SPA then. Your complaints make no sense either, this happens in HTMX world more than mine: > now everything that just required a database query or method call before now also requires a network request, but also because data consistency in a long-running app is so hard I honestly can't tell if you're trolling me. Let me break it down for you. In client/server world, client asks APIs for the data. Easy. Imagine a paradigm like GraphQL, the client literally just loads the data. It's the same as it would be on your server endpoint for HTMX, that's literally the client in your world. I hold a global singleton representation if my app is interconnected, or I load different singleton representations for unrelated subtrees if it's only partially interconnected. Next, if "collaboration"/real-time features are important, you make this data loading "aware" of when the data changed server-side, and you refresh your data. Easy as pie; you use the same function to reload. Lots of options on how to update the data, but if you correctly make your "load" function idempotent it is clear this is trivial. Finally, you write views that describe, declaratively, how to render the data. Since application state automatically re-renders these views, ideally not in their entirety if you used a good state management, you've already solved every single concern you listed about "stale data" by how you wired your data loading. So, great, in conclusion, HTMX endpoints are like a scattered version of a client that makes all nice "application" tricks virtually impossible, giving you no gains in any fashion that relates to data consistency or continuity, and requiring loads of manual wiring and awkward data-HTML manipulation in places that have no business doing it.
- nauticacom 5y agoHow do YOU do form validations? I use some server-side library to do it (take your pick for your language/framework of choice) which then sends it back to the user, in most cases automatically wiring up old field values and error messages. Checking string lengths or whatever is equally easy in both cases, but what's really difficult is the part you conveniently hand-wave away: usually, it's harder / more awkward to wire the API feedback to highlight the offending Form fields This is the entire point of validations. When I render everything on the server, I have my entire application and its associated logic to play with; can this Person access that Document? Has this Person already enabled Notifications for new Revisions on this Document? etc. Most server-side libraries make it equally easy to surface validation errors for those questions as they do questions like "Is this Password no shorter than 10 characters." Every time I've tried to do this on the client there's been no easy way or you have to wire it up manually every time. There is no difference in how an HTMX app would authenticate to its endpoints and how an SPA would I've found this not to be the case. Here are the potential options I see: - The client contains all the logic for who can view what, and redirects or shows a message appropriately using whatever mechanism is appropriate (e.g. Angular has route guards, I'm sure other routers have similar functionality). Because you want real data protection, this logic is also on the server, so now you have duplicated logic and you have to hit the server multiple times on every navigation, which is basically impractical. - The server contains all the logic for who can view what, and when the client asks the server for some data, if it responds with 403 it can show a message or redirect or whatever. This is okay, but now you have so little information on what happened on the client side that it's a much worse experience. e.g. if I try to access a document that I don't have access to on the server-side, I can redirect_back and maybe show a pretty message that says "hey you can't access that, maybe click this link to ask for permission." If I just get a 403 from the server, all I can say is "uhh I don't know, you can't do whatever you just tried to do." This is much easier if all your logic resides on the server. To check if a Person can access a Document, you just call person.owns?(document) or whatever. If they don't, you just redirect_to wherever, and since you haven't actually rendered anything yet it's all in a single HTTP request-response cycle. Obviously, but you load the client version from the server at API request time I'm not sure you understand my problem here; it seems like perhaps client-heavy people just aren't doing this anymore? Ember, Backbone, et al got this part right, and everything since then seems to have forgotten about the "M" part of MVC. What I mean is that on the server I have a Document class, a Person class, etc. and the associated business logic for dealing with it. Maybe a document has a bunch of Revisions, and they're stored in an array or something and I can get the newest revision by calling document.latest_revision, or I can get properties of the latest revision by just doing document.latest.title. Maybe when I update a field on a Document I really want to create a new Revision or something. Whatever, I'm just making stuff up here, but you get the kind of business logic I'm talking about. How do I do any of this on the client? Do I have a separate Document class that maintains all the same logic? Do I split the logic so some of it is on the client and some is on the server? Do I put it all on the client...oh but wait I can't do that because the server needs to do integrity checks or make database calls that the client simply can't do. In an ideal world, what I want is essentially like my ORM on the server-side: a cache of every instance of every model that I've loaded from the server, normalized with references to one another and an easy way to retrieve an object with its relationships either from memory or from the database (network/API). It's then easy to update Document(id=45) in one place and have it propagate to the rest of the app, and if it's referenced by any related objects to have the update propagate to them, too. This is a hell of a lot of work to create, and basically none of the modern frameworks provide anything resembling this. --- Your final few paragraphs are essentially all the rosy writing out there about client-heavy approaches: look how wonderful it is! Just fetch your data and we'll rerender it! I understand all that. And maybe it's evidence that we're just living in such different worlds that there's difficulty explaining requirements to one another. If I was creating Desmos or something, where basically every ounce of logic exists on the client, and the client's job is just to do a bunch of stuff with client-generated data and display it, then yeah I'd probably reach for a client-centric approach. But I'm not. Most of the time I'm creating GitHub or Wikipedia or Fastmail or something, where there could be some nice benefits of having a fat-client that talks to an API, but the massive complexity increase just isn't worth it.
- porker 5y ago> How do you do... Those are all questions I have, as a 2-decade "traditional web app" developer who is now doing frontend work & hybrid mobile apps. I know the backend sucks for some of them too, so this isn't a set of questions to bash with. They are the questions I'd spend money on a book or learning materials to answer. They are philosophical questions that seem overlooked. I think the answer is JS/TS on server and client-side for a lot of them, so models/classes/structs are shared; form validation rules are shared (something let's face it that "traditional" web apps suck massively at). The one Q I feel qualified to answer is: > What about data consistency throughout the interface—when you update e.g. Document(id=45) with new data, how does that update get propagated to every other place in the app? Does that involve a client-side identity-map? Or are you manually trying to send updated data to other places with callbacks/whatever? etc. for ever and ever. Assuming you're not talking realtime (because that's a problem for both) then this is why the concept of data stores (Redux, Vuex, Mobx to name a few) are so popular. Because when the data is changed, and you're using a reactive frontend framework, it updates all components that use that data. It is, frankly, magical and wonderful. But as you say, data consistency can be a problem...