Hacker News new | past | comments | ask | show | jobs | submit login
You Shouldn't Start with an SPA (simonhamp.me)
46 points by simonhamp 3 months ago | hide | past | favorite | 128 comments



>Your back-end and front-end are always coupled. So trying to split them in anything but the most extreme circumstances is an exercise in futility.

>If your back-end team want to move in one direction, they've got to align with the front-end team.

We have different backend and frontend teams and I can't agree that it's futile or hard to decouple etc. The only "coupling" which we have is the public API of the backend. Before a product or a feature is started, the teams design and agree on the API between the backend and the frontend, as part of our overall architecture design process (doesn't take more than a couple of days of 1-2 senior engineers if it's a big feature). After that, the two teams work completely in parallel. The frontend team has a framework which allows them to test the UI without the backend ready (using mock API). The backend team checks their API implementation using end-to-end tests. When the both teams are ready, we have the integration phase to see if it works together. Sure, often some edge cases are found and the API has to be changed a bit, but overall for me it has been quite a pleasant experience.


I think there are pros and cons to this. I can definitely see how, in a company with larger teams, separating the frontend and backend can help with productivity. On the other hand, I'd wager that decoupled applications are less efficient with API calls something like 90% of the time.

When I build a fully-coupled application, loading any given page after the CSS/JS files are cached requires a single HTTP request which always includes exactly the data that's required for that page. When I've built decoupled applications, I frequently end up doing 4+ HTTP requests to load various pieces of data that don't make sense to include in the same API request. In some cases these API requests will depend on data from a previous API request, which leads to multiple sequential round-trips before the page is fully usable.

I started out at my current job working on a fully coupled system that's basically as "legacy" as you can get, and eventually started modernizing it - as part of that process, we decoupled the frontend from the backend. At first it felt more productive simply because it wasn't the old system and the new frameworks actually had documentation, but once I compared it to building a coupled system with modern frameworks I realized the coupled system made me much more productive. I'm currently the only developer at my company, though, so I feel like I'm probably the perfect target audience since I don't have to worry about team coordination at all.


> When I've built decoupled applications, I frequently end up doing 4+ HTTP requests to load various pieces of data that don't make sense to include in the same API request. In some cases these API requests will depend on data from a previous API request, which leads to multiple sequential round-trips before the page is fully usable.

I'm not disagreeing with your fully-coupled approach, but you can also create a new handler to process what would otherwise be separate requests. Server-side, this new handler routes the bundled requests to existing handlers as needed and returns a single response to the client. So one trip and no duplication of logic.


This is not necessarily a good solution to duplication problem, because you're still forced to keep each endpoint isolated, and can't efficiently combine data acquisition from, say, a database. A much cleaner logic reuse is to do it in your programming language. Build an endpoint that returns exactly what's needed for this front-end view, and build another, generic API for others to consume, but reusing a lot of the logic under the hood on the backend.


Et voilà, you now have: - a public API - a purpose built API (possibly one each for iOS, Android, and your browser app!) - 1-3 UI implementations closely coupled to your per-view API

:golf-clap:


I'm honestly unclear, are you trying to say it's a bad thing? Where is the issue?


If you're building one API endpoint per frontend view to avoid doing multiple API requests, your frontend and backend aren't decoupled anymore. I personally wouldn't say it's a bad thing, but if the best way to solve the issues of a decoupled frontend is to couple it to the backend again then I don't think that counts as an argument in favor of decoupled frontends.


I'm arguing in favor of coupling. Don't think front-ends should be decoupled in most situations.

There's this notion I don't see discussed often. The more distant/unstable the link is between a caller and a callee, the more coupled they should be. The closer and more reliable the link is, the less coupled they should be.

That's why when we build interfaces in a single codebase, we can let them be minimal, and let callers use loops for batch operations. But when talking over network, we build elaborate protocols and languages (e.g. SQL) to allow for more complex operations in one roundtrip.

So if one is trying to treat their backend like it's part of their front-end's codebase, that can be fetched and looped over with little regard for the many failure modes, they're going to have a bad time. The front-end to back-end is one of the most distant and unstable links we have in computing, if not _the_ most unstable. This also applies to any intermediary back-end over network.

Minimize network interactions, and shift most work into the single backend codebase for maximum reuse and reliability.


Merely that it's an extremely expensive way to get to a tight coupling between UI and API.


Where does the "expense" come from? You either put glue code on top of existing APIs, having almost no optimization advantages, but still having to combine data (the comment I'm responding to). Or you create new endpoints, with more code reuse in them, and more optimization. How is the latter more expensive than the former?

And if you just talk about having 1 api for 3 front-ends, aren't you then forcing your front-ends to contain a ton of business logic to figure out how and what to display based on your API? You could've just given them what they need, but instead they're forced to weave together some insane tapestry from all kinds of "generic" endpoints you gave them? Isn't it expensive to maintain those front-ends?


> but still having to combine data (the comment I'm responding to).

The GP frames the problem as merely avoiding round trips. You introduced the idea of eliminating redundant database calls on the back end. In that scenario, you absolutely have the right idea.


So then, are you building your backend API directly to meet the needs of your front-end? Or are you trying to keep it generic for all needs, but also serve the front-end? Are you telling the front-end team to download multiple resources from multiple endpoints when they need to render one thing? Do you have real life other consumers of your API? Are you juggling their requirements vs internal requirements? Is your backend team telling the frontend "it's not a good API design if we give you exactly what you need, so instead please pull these multiple resources?"

Can you adequately measure your page load performance when front-end is making many parallel requests to the back-end and not all of them are required to consider the page "loaded"?

There are countless architectural downsides associated with not just giving the front-end exactly what they need, and there has to be a very good upside for doing this. Front-end freedom is not one of them, because the freedom is minimal and mostly accidental. A good upside can be: you're building specifically an API for building your kind of web application, and you want to dogfood your own work. Otherwise, it seems an incredible amount of unnecessary contention and complexity.

That said, I don't disagree that it _kind of works_ the way you describe, but it could've worked a lot better if your API could just give the front-end exactly what they need. You could've designed it with the exact same process, and they could've worked off of mocks the same way. They just would have all the data sent to them in a much more streamlined fashion.

Disclaimer: I'm the author of https://max.engineer/server-informed-ui


We have different schools of thought internally. Some prefer to tailor the backend API to the needs of the frontend, others prefer to have the backend API super generic so that changes in the frontend (say, a redesign) didn't require changing the backend. The latter is easier for backenders but harder for frontenders. It's vice versa for the former. So, the complexity stays the same, it influences which team (the frontend or the backend team) gets more complexity. However, when desiging the backend API, we always involve at least 1 frontender so that there were no "surprises".


This turns into "BFFE" (backend for frontend) in my experience, and that's not even the dumbest possible decision.


Really pleased that you've found a way to make it work.

But do you need it?


I believe this is a cultural argument mascaraing as a technical one.

The honest truth is that we have had front end and back end developers for as long as the web has been around, and before that. Your "full stack" developers are most often back end developers who begrudgingly can put together a less complex front ends with very little understanding of what makes a front end good to work with. Your "full stack" front-end preferring developers get drummed out because the back end developers conflate being good at back end concepts with being good at programming in general.

There is a definite back-end bias with developers who do not specialize in web or mobile front ends.

For some applications, that's fine. However, back end developers build the back end frameworks and do not think about what makes a great experience for developing more complicated user experiences.

In many ways, the reason front end developers moved to SPAs was that they could better control their own tooling in ways that are difficult in the traditional web application frameworks.


> In many ways, the reason front end developers moved to SPAs was that they could better control their own tooling in ways that are difficult in the traditional web application frameworks.

Partially, but let’s not pretend our field is more rigorous than it actually is. Most it was following fads: the cool kids at some big tech companies were building HUGE apps with tons of logic as SPAs and a lot of people wanted to say “us too!” without considering how similar their apps are or comparing staffing. The natural arc I’ve seen is that teams who didn’t pick an SPA for solid technical requirements end up delivering results which are no better at considerably slower speed because they’re supporting a lot of non-domain complexity and still end of changing their backends in lock-step with the front end. That tends not to leave time for things like accessibility or performance.


UI development is one of the least scalable things an individual can do with their time.


You can have great front-end experiences and great front-end-back-end developer relations without an SPA


I'm talking about a great front end developer experience.

Rails was crap. Spring * was crap. None of the back end frameworks came close to thinking in abstractions - code reusability was an afterthought at best.

Ask yourself, why was there never a Rails component library? Because Rails made abstraction difficult in the front end. Nobody did a good job here.


If you have multiple frontends seperating frontend logic from backend makes a lot of sense.

I've been building/maintaining a SPA for the past 8 years and have no regrets and am unconvinced by this article (or the one it mentions).


While the author explains that the front and backend are coupled, I think they overstate the coupling of client/API but don’t account for the numerous and disparate factors that motivated the popularity of SPAs to begin with. It’s perhaps out of scope of a comment to go into those details, but anyone who’s built and had to evolve large business applications on the web in the early 2000s is familiar with the headaches of the traditional server side techniques [sweats in server-side includes, ASP.NET form state, unnecessary db calls loading whole pages when only part has changed, etc.]. Not even getting into other benefits (API reuse and the flexibility to support multiple clients and use cases simultaneously).

In my opinion, the two major problems are tooling (which I think is more of an issue with browsers and the deficiencies of JS) and people using SPAs as an all purpose solution (does your blog or marketing homepage really need to be a SPA, really?). The former has seen steady improvements, but at any rate I’ll eat the cost of because it’s worth it for some of the larger systems I have to build and maintain. The former, well I dunno what to tell you, the cargo cult has been a fixture in this industry for a long time. I don’t think wearing a “you’re a bad person if you develop SPAs” helps (not accusing OP of this, but remarking on a general attitude) but in fact furthers the problem by pressing devs into binary thinking rather than evaluating and making decisions on their own.

So I’m with you: I won’t be shamed for having written SPAs and I’ll continue to do so as needed


No shaming intended. This is not meant to be applied retrospectively.

I believe now that an SPA is unneeded, precisely because of how far the technology has come.

And I believe that SPAs are the cause of a lot of that advancement and have pushed back-end approaches to level up to help realise some of these benefits.


Client-side rendering has a lot of benefits not mentioned in the article.

1. Adaptive design: it’s easier to adjust user experience to the client device capabilities. SPA frameworks take the job of ensuring browser compatibility, but it’s not just it.

2. Less traffic in data-rich apps (even taking into account compression, HTML is heavier than JSON and not just due to syntax overhead - consider all those page headers, footers and other common parts).

3. Better UX for slow networks: even in countries with 5G coverage there are still a lot of corners where your device will struggle to connect. SPA can auto-retry, just showing the spinning wheel longer. Browser will show the timeout page, and who knows if the backend can correctly recover on refresh.


> Less traffic in data-rich apps

Hmm. Of course it can be true in certain circumstances, but I would be surprised if on average the (compressed) size of the js bundle + subsequent JSON API request is smaller than html * the number of pages visited in a session.

Even if you are careful (and most sites are definitely not) overfetching JSON can easily happen due to API's not delivering exactly what you need etc.

Plus, in many circumstances both js bundle + json or HTML text gets dwarfed by images or other media.


Imagine rendering some complex data model to image on server vs downloading json and rendering it on client. Yes, SVG does exist, but it doesn’t cover all cases.


> Even if you are careful (and most sites are definitely not) overfetching JSON can easily happen due to API's not delivering exactly what you need etc.

I've seen the term BFFE used: Backend for Front-end, which is where the backend is a set of APIs, and for those specialised requests that the front-end makes, endpoints are created on (maybe) a new domain/machine/whatever that simply makes the correct Backend calls, aggregates and consolidates the data, and then serves it to the front-end.

It makes a lot of sense for the front-end to be able to create a single endpoint that does 4+ requests and some data manipulation rather than for front-end to wring their hands and continue making 4+ requests each time they need that specific data.


Yeah, and for a while (perhaps still?) grapqhl solved some of these issues as well. People did (do?) "schema stitching" to essentially have a BFF without really writing that much code.


I have a really bad network, SPAs are consistently worse in UX than a regular site. There are tons of SPAs that won't even show me a loading indicator when navigating, a regular site will have the browser spinner telling me to wait.


That’s not an argument against SPAs, that’s an argument for investing more time on product discovery stage to understand that this is actually a requirement. When implemented with relatively small effort, it does have better UX.


"They just haven't done SPA right enough!"


Yes. Engineers are as guilty of enshittification as managers and shareholders. If „good enough“ replaces „well-built“, no solution choice will save you. The very same engineers will build a backend that sucks.


> Better UX for slow networks

Don't you think the case can be made against SPA's w.r.t slow networks ?

Angular, react add hundreds of KB's to frontend bundle which give bad UX especially in slow networks


But then after 20s loading or whatever, it's cached and your experience every moment thereafter & if you return later is speedier.

If the app has optimistic updates, actions may even feel instant.

If your app really cares, it'll have an offline mode/be local-first. Then you you pretty much need an SPA or some kind of heavier front end.


After 20s ... you have lost 50% of your visitors, because they think the damn thing is never going to finish loading on their connection and you will have triggered connection loss anxiety on multiple levels.

Also this is assuming, that one does not want to take all the things of that website and burn them after use, which is not a safe assumption to make on most websites, considering all the ads and trackers on today's typical websites.

An offline still working app sounds great. Unfortunately very few aspire to reach that point. Most already break to various degrees when you hit the back button.


Normally I'd agree about 20s being too long.

But I'm specifically talking about users on slow links. They often know they don't have a first class connection out, and have established a different set of expectations.

If your site is actually good enough to be one the users return to (and who here wants to build a site where that's not the case?), they all appreciate the site loading very fast the next time.


Not every frontend is a marketing website where conversion is a concern. Marketing websites aren’t apps anyway, they shouldn’t have any backend - SSG is better than SSR for them.


once it's cached though, loading new pages or new data is trivial.

It really depends on the use case- if I'm navigating my banking website, I would prefer a longer load time up front if it made it navigating between accounts really fast. If I'm checking my power bill, I'm probably only going to view one page so I just want it loaded ASAP


> Less traffic in data-rich apps (even taking into account compression, HTML is heavier than JSON and not just due to syntax overhead - consider all those page headers, footers and other common parts).

This statement is way too overly broad. JSON is terrible for tabular data, since you have to include the field names in each row. HTML will be much better for data heavy sites in this case. Also, as others have mentioned, you still need to download and process the JS needed to display the data (libraries, likely styli ng, etc.).

> Better UX for slow networks: even in countries with 5G coverage there are still a lot of corners where your device will struggle to connect.

1. Offline and autoconnect are lovely ideas, but most js devs don't care enough/aren't permitted the time to write with this sort of resilency in mind. In practice it isn't really an advantage.

2. When a SPA does fail, it is often worse than a back end framework. The browser will tell you the request failed and a very general reason why. Whether it worked or not is abundantly clear. Most SPAs just sit there and silently die, while you stare at the screen waiting to see if it will actually do something.

3. Most of the mobile devices you're talking aren't that powerful, so loading them down with a bunch of JS to run, makes for a really bad for UX.


> HTML will be much better for data heavy sites in this case

I've never seen HTML be smaller than json for data representation. For any kind of data. Ever.

[Snip SPAs reasons that aren't inherent to SPA]

> Most of the mobile devices you're talking aren't that powerful, so loading them down with a bunch of JS to run, makes for a really bad for UX.

Even mobile CPUs are more powerful than your average cloud vCPU. They get refreshed much more frequently if for no other reason than the batteries give out.

That doesn't even take into consideration the fact that the server is rendering x requests vs the client's one.

Any spend on server hardware to make it fast will never make up for the network latency vs a well built SPA that can avoid refetching some data again entirely.

Page one, server render is faster. Every subsequent navigation will favor a well built SPA.


> well-built

hell of a caveat you casually slipped in there, comrade.


> JSON is terrible for tabular data

Sure. When you use API, you can design it with a domain-specific data format. When you use SSR, you stick to HTML page overhead.

>When a SPA does fail, it is often worse than a back end framework.

This is not an argument against SPA, it’s an argument to invest in UX. When done right, SPA and native clients do deliver better UX than SSR/generic browser. The effort to achieve that is not huge, in fact this behavior can be built as a reusable component.


> Sure. When you use API, you can design it with a domain-specific data format. When you use SSR, you stick to HTML page overhead.

Now you hydration, your JS to run, and a custom serialization/deserialization format (and a custom parser) to maintain.

> This is not an argument against SPA, it’s an argument to invest in UX. When done right, SPA and native clients do deliver better UX than SSR/generic browser. The effort to achieve that is not huge, in fact this behavior can be built as a reusable component.

We're well over a decade into SPAs and we're still seeing these problems/errors. I routinely see SPAs keeling over without any feedback built by large, richly resourced. The tool has something to do with it if so many different people and organizations are failing.


> This is not an argument against SPA, it’s an argument to invest in UX.

ZIRP-era thinking. Gotta get by with less of everything now, unless you're a growth/hyperscaler snowflake, in which case the advice doesn't apply to us common-or-garden engineering shops.


A lot of UX gains can be achieved in a lean way with minimal effort. It is unfortunate, that the state of the industry is such, that half of „senior“ engineers only mastered CRUD and 90% of engineering and product managers are just random people without essential knowledge or skills required for their jobs. ZIRP era thinking is to assume that money will and only money can solve the problem of building a decent product.


Time is the other variable!


> 2. Less traffic in data-rich apps (even taking into account compression, HTML is heavier than JSON and not just due to syntax overhead - consider all those page headers, footers and other common parts).

I’ve very rarely seen this not be significantly skewed in the other direction. The stuff you mentioned is tiny and compresses well, and unlike the many megabytes of JavaScript almost all SPAs ship it doesn’t block rendering.

> 3. Better UX for slow networks: even in countries with 5G coverage there are still a lot of corners where your device will struggle to connect. SPA can auto-retry,

SPAs are far less likely to get to the point where they can display that spinner on a marginal network. Any time I have had coverage, JavaScript-heavy sites are notably the worst experience especially because unlike SSR a reload only works if you have the 5% of SPA developers who correctly implemented state handling.


Amen. LCP and TTI are the only things that matter. Fix your render loops, kids.


> Less traffic in data-rich apps (even taking into account compression, HTML is heavier than JSON and not just due to syntax overhead - consider all those page headers, footers and other common parts)

> Better UX for slow networks: even in countries with 5G coverage there are still a lot of corners where your device will struggle to connect. SPA can auto-retry, just showing the spinning wheel longer. Browser will show the timeout page, and who knows if the backend can correctly recover on refresh.

It's more often the converse in my experience. If you have a slow or flaky connection, making many API requests to get all the data your SPA needs to fulfill an interaction yields worse UX than just asking a server to process it all and give back a final result for the interaction. The round trips are the killer there.


>Better UX for slow networks

Yet the reality seems to be very poor UX from SPA's on a slow or intermittent connection.


All rendering, ultimately, is client-side. That's inescapable.

So whatever mechanisms you choose to make adaptive designs, lower your throughput and account for slow networks can be done without an SPA.


I think he's fundamentally right even if he's wrong about certain details.

SPA create a polarization between devs whereby they're either front end or backend. Full stack devs are slowed down compared to tools like Hotwire/Turbo, Liveview, HTMX, etc.. Furthermore you need a huge stack of tooling to make pages work and lots of javascript code needs to be downloaded to make most standard SPAs work today. Not to mention having to render html on the backend in a slower and more complicated manner than using any of the more recent enhancements of HTML that provide caching, high speed download out of the box.


This is probably correct...for now. However, I think the next decade will see SPAs become simpler and we're already starting to see it. In some ways, I'd argue that Livewire is an example of that. I think Remix (JS) offers a full-stack experience where you just create an `action` function of what you want run on the server. Remix can be pre-rendered on the server so pages don't need to download lots of JS before stuff is displayed to the user for the initial page load.

I think WebAssembly is also going to be bringing innovations. .NET's Blazor is probably the furthest along at this point and it allows you to create an app that's rendered on the server and then WASM is downloaded in the background to enable all the interactivity. It can also operate like Livewire with websockets if you prefer. While Blazor might be here today, we'll probably see more coming. Rust's Leptos looks really cool and allows you to use its `#[server]` macro to define functions to be run on the server instead of the browser.

I think that we're going to start seeing better options for creating SPAs without needing to maintain two separate codebases.


I think that this all boils down to "The tooling sucks".

The specific SPA problems mentioned are due to the bundling, the packing, the dependencies, etc.

None of the SPA problems mentioned are specific to SPA, they're specific to current toolsets.


But there's no world where the tooling doesn't suck for an SPA.

As the application grows, the bundle is going to grow and the caching / building / splitting problems will just increase higher and higher. All those esbuild & associated tools just slightly delay the inevitable.

All the ones I worked on inevitably stumble upon this problem and the worst part is, the bigger your team is, the harder it's going to be to scale an SPA meaning that hiring more people doesn't even help here.


> But there's no world where the tooling doesn't suck for an SPA.

I dunno about that. I've seen good things with htmx. Also pretty nifty things with web components.

An SPA doesn't have to use all the most modern frameworks. SPAs were being done long before React and friends were created, long before even Jquery was popular.


Htmx isn't built with SPAs in mind. Htmx is the opposite approach to an SPA in my opinion, it's traditional views but improved. And yes, that does scale easier compared to an SPA, there's no bundling / splitting / caching complexity here.

Technologies where the frontend bundle increase with a flat or nearly flat curve as the features get added have a much much easier time to scale than the ones which do not.


What is your definition of scaling here? A large, untyped, JS-in-HTML via Htmx codebase reminds me of the jquery dark ages.


Scaling in this context means for me that features are decorrelated from the payload sent to the browser.

If they are, it's good news as more stuff gets built into the product, you have time to figure out how to continue forward and you have more resources to throw at this small problem.

If they aren't, well this is some pretty bad news since the more feature you add, the more complex the tooling is going to be to make it work, it becomes exponentially harder to maintain.

As bad as Htmx might look visually, it's going to be significantly easier to scale on a large platform since everything is decoupled apart from some common js bits you could add here and there.

On the opposite spectrum, we have a React SPA at work with a 65mb bundle which take 2GB of ram just to build, caching & splitting is obviously a nightmare. That's what happens when you have a lot of engineers working on a product and the bundle isn't decorrelated from the features.


Just like to say, you can have a pretty robust SPA tooling experience ONLY using esbuild. Yes, you give up a lot of the features provided by larger tools, but you also have less things to have to understand.

I recommend this article about a non-js savvy person: https://jvns.ca/blog/2021/11/15/esbuild-vue/


I don't know why esbuild still lacks these features over all these years. Seems like everyone is using it for various things (like vite) but no one wants to contribute to it to make it The One Tool. Is it JS/TS devs not wanting to work on a Go app? Folks not wanting to disrupt the status quo of Vite?


ESBuild already does a lot, and is already extendable via plugins https://github.com/esbuild/community-plugins. I think it's more that the maintainers of ESBuild want it to focus on doing the essentials well (which it does, IMO).


> specific SPA problems mentioned are due to the bundling, the packing, the dependencies, etc.

These are all issues, but the real issue is JavaScript itself (i.e., programming with wet noodles).


> programming with wet noodles

Very balanced mature technical argument.


It's what we technical folk refer to as spaghetti code.


I'm familiar with the term, I'm just wondering what features of JS as a language necessitates code degenerating into spaghetti. The comment I was replying to was a bit light on technical details. I'm not convinced by someone broadly gesturing at a language and saying "it's all spaghetti code". It just reeks of snark, and feels like a very shallow dismissal of a programming language.


> language necessitates code degenerating into spaghetti

I'm by no means a thoroughly vested expert, so my speculation has little merit here.

However if I had to guess code becoming spaghetti is more a symptom of collaboration between many individuals over a span of time rather than an issue with a specific programming language.

Everyone has preferences and different backgrounds, various "best practices" they've been taught or adhere to.

So when all those little differences merge together over time you get globs and hard to follow code due to changes in conventions or just being lazy when meeting a deadline.


Not sure why your comment was downvoted to death.

> However if I had to guess code becoming spaghetti is more a symptom of collaboration between many individuals over a span of time rather than an issue with a specific programming language.

That's definitely one path towards spaghetti code. An inexperienced developer can make a mess of their own codebase without contributors also though.

I do agree that it's very rarely the result of an actual defect in the chosen programming language. You can write clean code in almost any general purpose programming language, and conversely, you can write bad code in any language as well.


Made sense to me!


For what it’s worth, I started my current project with the good old Django framework. I haven’t touched it for mostly a decade and my god it’s just a pleasure. You just write your domain code and the framework handles everything else. But more importantly, Django don’t try to be original or to force you into a paradigm, it just solves and abstract away the real life problems of websites. There is basically 0 boilerplate.

Add some htmx for the few things you want dynamic and you’re done.

Now, I prefer typed languages but why haven’t we something like Django (or Rails) in typescript ?


Django in Typescript is Next.js / T3 stack which I much prefer to Django


> Django in Typescript is Next.js / T3 stack

I’m sorry but no. In Django, every parts of the framework are tightly integrated in smart ways to make you more productive.

You can write things like "redirect(entity)" to redirect your user to the view that shows your entity. Displaying a form to create/edit an entity is a few lines of code…

I understand why you would prefer something else but you can’t say that it’s Django.


> You can write things like "redirect(entity)" to redirect your user to the view that shows your entity.

You literally have a redirect() in next.js routing you to another URL

https://nextjs.org/docs/app/api-reference/functions/redirect

> Displaying a form to create/edit an entity is a few lines of code…

A form is not a particularly hard example in any sized app.

https://nextjs.org/docs/pages/building-your-application/data...

Now do Django with any sort of frontend that isn’t just html and adhoc js or htmx. DRF is very 2005 syntax “basic crud that’s it”

Then trying deploying Django, a process that will take 50x what the form will.

https://www.digitalocean.com/community/tutorials/how-to-set-...


> You literally have a redirect() in next.js routing you to another URL

I was not accurate enough. In Django you can just pass your database entity to redirect(). Since you can define directly in the models how to resolve their "Read" (as in cRud), you don’t need to build the URL each time you want to redirect.

As for the forms framework, I never implied that you can’t do this with others frameworks. As I said, I didn’t touch Django for a decade and I did mostly Typescript development for the last 6 years so I pretty much know that you can build an app with it and that there are a lot of good libs for this.

My point is not that you can’t do everything with it and that you can do more with Django, I’d even say it’s the contrary. However, if what you want to build is a classic website without a lot of real-time interaction, Django allows you to build it with way way less lines of code (and I’m not even talking about that entire cool admin you get for totally free).


Not even close.

Next is pretty barebones as a backend framework compared to mature solutions like Django, Rails, or Laravel.


You should start with an SPA if it makes sense for what you are building.


Can you give an example?


Complex admin dashboard with lots of interactions that should be low latency


Yeh I've seen some of those as SPAs... ouch

Honestly, I'd rather not be presented with an empty grid of spinners tbh

I think you can get something useful on first render and then dynamically update from there (either with polling, SSE or WebSockets) all without the added complexity of an SPA


I make mine such that the first load includes the data needed in the first load of the page. If you're going to populate a grid on the first load, just have the backend include that in the page itself inside a dynamically inserted javascript block. For something like paged search results, you can preload the first page, and preload the second page a short while after that.


You can have complex interactions with an MPA.

Regarding latency, it's mostly related to the distance between the user and the database. The routing strategy has nothing to do with that.


The routing strategy can have a significant impact on what latency the user sees.


It reads like this article's unstated premise is that it's about what you should do in situations where you aren't in control, are being paid to do the things, and working with other people in the same situation. But why write articles about what we're forced to do for money? That situation is always borked and we wouldn't be there unless we were being paid. Who wants to think about and do work during non-work free time? Yuck.

Lets see some articles about what human people, not people hired to do corporate person's bidding, should do. In this context the case for SPA is even more diffuse. In fact, all the arguments about synching frontend and backend don't even makes sense: that kind of thing is cargo culting.

Human persons when operating of their own free will working on their own projects should definitely not start with SPAs. They shouldn't even start with javascript dependent frameworks. Just put an HTML file in a directory.


I'm a freelance consultant and a human person. I advise companies, especially early-stage startups, on this stuff.

I'm writing about what I see, which is hundreds of hours being wasted on triaging bugs, meetings trying to align small teams, and decision-makers simply following trends.


I get that, you write what you know. But you're literally saying it's a thing you do because you want money to live. It's not something you're chosing to do as a human person. We're all technically human (except the corporate persons) but if you're doing something for money for companies then you're operating with those motives and preferences in mind; motives and preferences that apply to corporate persons, not human persons.

I know thinking in terms of those corporate needs is the default on HN, but it doesn't have to be, and shouldn't be. We're all human people too.


The article talks a lot about technology choice, but not about given product. I do tend to agree – that SPAs are not necessary, but I would not use this article as an argument.

And if somebody would present this article to me – I would not take it seriously. The fact that author is using very interesting language when refering to React and Angular does not help. I'd love to hear customer-centric or product-centric reasoning. * Don't use SPA because customers hate it when you change entire app on them. * Don't use SPA, because customers of our particular product require faster turn-around. * Don't use SPA, because they are harder to test in our organisation.


Thanks for the feedback. Noted


Post mentions Livewire & Hotwire but totally misses the real star (and OG) of this type of architecture: Phoenix LiveView

^ Elixir is an order of magnitude more scaleable, easier to operate and cheaper than any of these other solutions.


Only if one knows Elixir which is tiny percentage of developers.


Def use what you know. But you can learn the basics of Elixir in two weeks. The payoff is worth it.


What about DX? Would you say Phoenix is better than Laravel?


I haven’t used Laravel (I hear good things). But Phoenix is voted as most loved web framework fwiw: https://curiosum.com/blog/phoenix-framework-guide


This article (and all others like it) always ignore the fact that mobile exists. Nowadays "front end" isn't just HTML pages being rended on some browser but also entire iOS and Android apps and maybe several others. Those APIs you think are an overhead are actually necessary regardless, and after that it's your server rendered HTML that instead becomes an additional burden to maintain. A SPA with dedicated front end engineers using the same APIs as the mobile ones is the most sensible approach for most apps.


I've done this. I spent six years building and maintaining an API platform to support apps and websites.

I'm fully aware of mobile and the need for those APIs. They just weren't sufficiently overlapping to be of any use to an SPA.

You need a whole slew of separate endpoints and behaviour, so it may as well not be an API - just make it a server-rendered monolith and move along.


Why would your mobile apps and browser client be so diverging that you need a completely separate set of APIs for both?


Because they were entirely different applications. It was an API platform for a suite of applications

There was almost zero crossover in functionality


Ok sure, but 99% of applications out there do not fit this description.


If you're building an SPA that's identical to a native app, I think someone in the exec team is making poor decisions

Either make a web app or a native app... don't do both


The only difference between a browser-based (or Electron) SPA and a native app is which runtime and rendering engine you are using. Why would API calls to the backend be different in either case?


Sure. But we're talking about needing the same API for two separate clients...

That infers building both and I'm questioning why you would build both if they're identical. Just build one and get your users to use it


Look around..no one is building native clients for every desktop OS anymore. Web, iOS and Android are the way to go for modern apps.


Yeh... and if you've got iOS and Android covered, then web is a different thing. Doesn't need to be an SPA, can still use those same APIs if that makes sense for your app


In my experience spas have a much better ux. Have you guys used Jira before? It's actively painful and there even is some local interactivity. But whenever you need a page wide rerender it makes me twitch. Same thing with aws when navigating between accounts/products.

Also having a spa doesn't mean you need to have separate frontend and backend engineers.

But it does allow various value streams to leverage each other's APIs in their own front ends.


> When does an SPA make sense?

I didn't quite get the answer — if it is that an SPA makes sense when you have front-end and back-end specialists on your team, then it is surely the wrong answer. Perhaps I misunderstood.

I like Alex Russell's answer: an SPA makes sense when data about users' session depth demonstrates deep sessions. Or Jason Miller's answer: an SPA makes sense when the thing that's being built fits certain known app holotypes.


Thanks for the feedback. I will try to make this clearer in the article.

While I state later that true decoupling isn't technically possible, it really only makes sense (to me) to attempt it when you've got larger teams split down these lines.

It really comes down to where you want to create the split: in code or on the org chart?

If you've created the split in one place, it will of necessity happen in the other.

If you can avoid the split altogether, then an SPA probably doesn't ever make sense.


> It really comes down to where you want to create the split: in code or on the org chart?

Deciding on the architecture of an application based on the org chart is probably not a good idea.


And yet Conway's Law still holds up surprisingly well

One way or another, your app reflects the org chart. So either you force the split because of your architectural choice or it happens because of your org structure

One way or another it will happen


Modern frontend frameworks smear technical concepts into the presentation layer; for example, understanding of hydration becomes integral to semantic presentation of content and therefore an overriding concern; "developers aren't cheap!".

Then we are reduced to two outcomes — developers become more design-aware, or designers become more dev-aware. Both are unicorn hunts, what do?


I don't think this has anything to do with design tbh. You have developers who are comfortable with HTML/CSS/JS and those who prefer to stay clear of it.

A lot of those HTML/CSS/JS folks happen to also really enjoy (and are great at) PHP/Ruby/Python etc - not so unicorn-y


I wonder, what the best practices for supporting offline mode when the backend drives the frontend?


You can choose the routes that workbox caches, but any dynamic templates likely won't work; server-side rendering could potentially help with that, or at least help point out where it breaks.


There’s none, obviously. Offline mode excludes thin clients. You need a lot of UI, state and business logic cached locally.


You still don't need an SPA for this


It’s always amusing how people compare crappy spa vs great traditional site.

A well done spa is far superior. Offline support, caching, adaptive layout, etc. it’s not even close.

That being said, barring things like offline support the two are equivalent functionally. Use what you know.


You can get offline support without an SPA. Of course, that may mean replicating some of your back-end behaviour in JavaScript, but that doesn't necessitate building an SPA, or the whole app in JS.

Please do share which crappy SPAs you're thinking of


I feel like a lot of the commenters here have missed the point... in the title it says you shouldn't start with an SPA.

I never say "don't ever use an SPA," just that I feel—more strongly than ever—that the kinds of environments that call for a true SPA are getting further and further towards the extreme.

You should do whatever you like. As always, there are trade-offs. For me it's becoming clearer that the trade-offs are heavily stacked towards keeping my front-end and back-end more tightly coupled.


Just a nit on your article: I think you meant 'retch' not 'wretch'.


You're absolutely correct. Thanks


Two thoughts:

Firstly, when you provide a normative assertion, at least couch it in positive terms.

If you want X, then you should do Y.”

That way people at least know the tradeoffs you’re opting them into. I really can’t tell what trade offs the author is proposing are better for me.

Secondly, if you can’t build a system that actually decouples the frontend and the backend, that’s a “you” problem, not a technology problem. I have successfully designed and implemented many APIs that operated completely independently of the UI, allowing both the UI and power users to interact with our platform through a shared service.

I do get so tired of people presuming their specific issues are everyone’s issues. I have zero problem with the tooling of an SPA, my ability to customize is increased, not decreased, when I use an SPA, and when I’m working with other people, they often prefer not having to think about the whole stack, which makes them happier.

This is one of those articles you read that shows up “unplugged” from the culture in which it originated. The author demonstrates the value of talking to others in a given field, and the pitfalls that one can get trapped in when one doesn’t socialize enough professionally.


> Secondly, if you can’t build a system that actually decouples the frontend and the backend, that’s a “you” problem, not a technology problem.

You're right it's not a tech problem... it's a logistical impossibility. It is impossible to decouple a web frontend from its backend.


Building a public API and having your frontend consume it is quite easy and would result in a decoupled design.

"But then the frontend is 'coupled' to the backend!" you might say, but you would misunderstand the definition of "coupled," as both the frontend and the backend would need to be connected together for that term to apply.


How can it operate completely independently if the front end requires data in a format it understands to perform logic on.


By providing the data in a format that any consumer can understand. JSON, very often.


But your front end is still coupled to the structure of that JSON, which is often fine, but it is coupling


“Couples” means two-way. Of course your front end will depend on your backend, the problem arises when they become interdependent; when you can’t develop one without making changes to the other.

In this sense a frontend and a backend can be entirely independent, and in every sense the backend should be independent of the frontend.


It isn't entirely independent if a change in your backend can completely break your frontend.

Your using coupling as if it is a dirty word that means you've failed.


I completely disagree with any attempt to merge the front end with the back end by obscuring the boundary. It's a horrible idea and leads to security vulnerabilities.

The front end is a public resource, the back end is a private resource whose access needs to be controlled according to clear and consistent rules and with proper authentication checks.


There’s usually no problem with security in thin hypermedia apps. Backend still has full control over access, you just have an extra step of actually rendering the view with the model you’d otherwise return via API.




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

Search: