Hacker News new | ask | show | jobs
by projectileboy 629 days ago
OMG it feels so good to not be the lone voice in the woods. I would say about 3/4 of my frustrations as a user are from sites that should have simply been built with HTML + CSS and minimal Javascript. The front end community most days feels like a jobs program.
4 comments

You aren't alone, I'm a technical director and even I can't win this battle. We have a ton of complexity on what could be a simple SSR site, but frontend devs don't like writing anything but SPAs, so it's hard to change.
My constant battle in the last 15 years (of 30 years of development) has been the unending torrent of completely unneccesary complexity that teams inflict on themselves. I feel it's often just to pad their CVs or because the current *perfectly usable* stack is boring.

Limiting complexity to where it's *really* needed is the hidden magic of a great leader in my opinion. A great engineer knows how to wall that complexity off from the rest of the system as well because complexity spreads like cancer through a codebase.

I've never been a TD but I can imagine your pain.

Everybody is incentived to use the tools FAANG+ are using even if completely unnecessary, ie follow fashion. Developers for Resume Driven Development, and execs because it reassure investors and is good for marketing. The industry doesn’t reward smart engineering choices.
Hey, at least I managed to consolidate all our services into a monolith, which developers ended up really liking, and it works well for us.

One battle at a time, I guess, but the "let's simplify the frontend" effort is meeting much more resistance from people who are interested in the frontend having a lot of state.

Part of the issue in the complexity battle is competition and levels of expectations from features. Non technical decision makers (and there are lots of them, I’d say most of them) see services from Facebook, Google, etc. and have the same level of feature expectations in their one off small app. They have no clue how much effort exists behind it to maintain what seems simple and now even standard (across large services).

Ultimately they come up with ideas and write feature requirements (indirectly) based around this premise with their shoestring budget and ad hoc team. And we end up in a world with not so well developed applications attempting to create similar features to competitors in budget which leads to a lot of corner cutting and barely working implementations with no thought towards long term maintenance requirements. At least, this has been mostly my experience.

There are of course those out there simply bored with life who want to build unnecessary complexity because they have to be doing something (heaven forbid there be idle time in any work environment either from their own pressure and/or internal organizational pressures) and they start trying to be clever or skill up to some wider marketable skillset (e.g. react).

It’s really business environments that create this sort of complexity requirement from needless feature requests to wide adoption of specific trendy skills in their stack to make hiring easier/cheaper, etc.

> could be a simple SSR site, but frontend devs don't like writing anything but SPAs

It might be worth asking why that is.

I used to write a ton of SSR'ed pages back when that was really the only option we had (before people introduced jQuery and AJAX), then I wrote SPAs (mostly Angular & React), then again SSR'ed websites (Java/Spring/JSP with a ton of more-or-less vanilla JavaScript) and now I've been on a Vue-based stack (w/ Astro/Vite for SSR) for a number of years. And these were all applications with dozens of teams working on them in parallel and a corresponding number of components & LoC.

Personally, I wouldn't want to go back to traditional SSR stacks (Spring/JSP, vanilla PHP, or Python w/ Django or Flask) ever. People often vastly underestimate the complexity of good UIs. They might start simple ("could be a simple SSR site", as you say) and, before long, the wheels come off the bus and they look at a big unmaintainable ball of vanilla JS on top of HTML templates that are directly coupled to the database schema, with global CSS styles permeating (infecting) the entire code base.

In my experience, there is a certain amount complexity that is inherent to a good UI. It doesn't matter whether you use classic SSR, or modern frontend frameworks like Angular/React/Vue/Svelte/SolidJS, or new kids on the block like HTMX/Turbo/… — that complexity will still be there. However, with modern frameworks you've at least got a chance to tame that beast.

More specifically, what modern frontend frameworks give us is: 1) Modularization into components, 2) scoping of styles, 3) type-safety, 4) unit-testability of components, 5) component-local state management (≠ insanities like Redux), 6) clear separation between view/UI logic and business logic.

If you can replicate these features using a bespoke version of JSP or HTMX or whatever, great! But if you can't, I'd personally rather pick a well-established frontend framework like React or Vue. Yes, your developers might still mess that up and produce shitty code, but the chances of them messing up in a classic SSR stack (without the aforementioned features) are so much greater.

You're arguing against something different, though: I agree you shouldn't do components with CSS/jQuery, components should be self-contained. I'm arguing against SPAs, where the state of the user's browsing is replicated on the frontend as well, with all the complexity this entails.

Isn't there a good component framework we can use, and that's it? I want to be able to say <carousel></carousel> and have it work, without having to have a whole SPA attached to my components library, with routing, state, and all the rest. Doesn't that exist?

> I'm arguing against SPAs, where the state of the user's browsing is replicated on the frontend as well

What state exactly are you referring to? I'm not trying to play dumb, I'm genuinely curious because in my experience there can be "good" and "bad" state in the frontend (where "good" roughly translates to "inherent to the problem").

> I want to be able to say <carousel></carousel> and have it work, without having to have a whole SPA attached to my components library

A carousel sounds like a great example for something that could be standalone. However, what if 1) the data shown in the carousel needs to be loaded lazily (e.g. because the carousel is near the end of the page and loading the data is expensive), and 2) the carousel's display settings (e.g. how many items are shown at once) depend on the content being shown? I recently had to work on exactly this case. Suddenly, your once static carousel component isn't so static anymore and you have to add a bunch of JavaScript, and also state.

> without having to have a whole SPA attached to my components library, with routing, state

Maybe I'm missing something here but pure React/Vue doesn't require your page to be an SPA or to have any routing mechanism at all?

> where "good" roughly translates to "inherent to the problem"

I don't mean per-page state (that one is inherent to the problem, as you say), but cross-page state (the one typically handled by backends, such as authentication, account info, stuff you've done in your current session, etc).

> Suddenly, your once static carousel component isn't so static anymore and you have to add a bunch of JavaScript, and also state.

You're right, all of this is inherent to the problem as well, and you do need state. Generally, however, I haven't found a need for state to cross pages, which is a really good reducer of complexity (things are easier to reason about if every page load starts with a known state).

> Maybe I'm missing something here but pure React/Vue doesn't require your page to be an SPA or to have any routing mechanism at all?

They don't require it, but they make it easy, and that's the default that all frontend development pretty much starts with. Nobody says "hey, do we really need routing?". They start from "the way you make an app is with routing", and now you have a SPA where you just needed components. That's the big problem, and we've had a fair amount of issues with this...

> cross-page state (the one typically handled by backends, such as authentication, account info, stuff you've done in your current session, etc).

Yeah, that one is a different beast. We've been trying to keep it very simple in our SPAs lately: Account information & other backend data get retrieved from the backend upon page load (its all one big GraphQL query) and then it ends up in the GraphQL cache. If we then do a SPA-like soft page switch, that cache will speed up the next page's page load. However, the next page's GraphQL query will still be fired (it will likely need some other data that's not in the cache yet, anyway) which ensures the UI stays consistent with the backend state. In other words: The client-side cache is merely a mirror of the backend state and its presence or absence only affects loading behavior. There is no cross-page state beyond that (almost, see below).

> Generally, however, I haven't found a need for state to cross pages, which is a really good reducer of complexity (things are easier to reason about if every page load starts with a known state).

Agreed! If I do have a bit of client-only state which I'd like to persist (e.g. some kind of user selection / filter / …), then I simply encode it in the URL. Components then don't keep their own (mutable) copy of that state but simply mutate the URL to modify state. In that way, I end up with a one-to-one correspondence between URLs and UI states.

I get it. And to be clear, I have seen SPAs that justified their existence. I just feel very strongly that for most of the apps I use on a regular, daily basis (email, messaging, newspapers, bank, etc), SPAs are just totally unnecessary.

A hill I will die on: the users NEVER asked for them. The UI community likes to pretend otherwise, but the users never asked for SPAs. What users want is the simplest, clearest and fastest possible experience, that changes only gradually and only when necessary. SPAs often stumble on simple and clear, and straight up explode on fast.

Things like Livewire, and alpine.js are showing simpler ways.

You can build a SPA SSR as well.

Our frontend is a bunch of barely working wonky react-soup, and we really need to rewrite it. It's mostly a "tables and forms"-type frontend with a lot of complexity in the backend: it's a great use case for htmx (or even vanilla/jQuery).

But I'm not really sure how we're going to handle that or who we'll hire for it, because I fear we'll end up with another react-soup. My current strategy is to make a MVP in my spare time to show it can be done and that it'll be quite nice.

The main part is to avoid holding state in two places (frontend and backend) if you can do with holding state in only one (either frontend or backend).
Unless you're building an app that holds data locally, for most web apps, you should be pushing state down into the backend. Fat models should be your single source of truth, skinny controllers, and service functions in order to separate data from code for testability.

Avoid caching as much as possible until you absolutely need to. As soon as you introduce caching you now have multiple sources of truth instead of one.

or be stateless… ;)
after you re-write it (either immediately or with time) you will end up with the same thing, just a different kind of soup. using vanilla-whatever you will eventually notice you are doing “X” over and over again and then you’ll start writing small libraries (or even worse, some internal “framework”) which over time will get stale or will get bunch of features from devs that need “just that plus a few more things..” ad infinitum…
This is simply not true, and has never been true anywhere I've worked. We can do everything with a much better UX in about 2,000 to 3,000 lines of code, instead of ~25,000 (and almost 2,000 dependencies).

It's a boring tedious "true-ism" that keeps getting pounded. I don't really know what else to say, but it's simply just not true.

What is the longest you have ever worked on a single piece of software? If you are in some sort of consultancy or jump jobs every 2-3 years it most definitely won't be true. You stay with a product for 5+ years it is bound to happen unless your dev shop is like 10 people. If you think this is not true AND have spent 5+ years with the same piece of software you are an outlier...
And it doesn't help when the Browser, the Web Spec and front end dev are all aligned into making SPAs with JS.

I really wish something like HTMX is built into the browser or part of HTML5 spec.

There’s a draft proposal to get some of HTMX in the browser: https://github.com/alexpetros/triptych
Hope next.js 14 isn’t the framework behind the “simple SSR site”
It's Django. Next.js fails the "simple" part.
An SSR site needs to have full stack devs, not front end devs.

Else you will have exactly this problem

An SSR site needs a frontend dev to produce the HTML/CSS/JS and a backend dev to provide the template variables. You don't need a developer to do both when the interface is so small.
Nah that's crazy man
Then why hire front end devs for a project that doesn't need one?

Probably 80% of websites could do with a good designer that knows how to get their designs from concept to CSS and a good backend engineer that know how to output decent markup.

Because someone needs to turn the concept to browser-ready, responsive, cross-browser, lightweight markup, and that person is a developer who specializes in the frontend, ie a frontend developer.
> I can't win this battle

You are fighting the wrong battle. You harp on the technology used rather than the specific functionality you desire.

The bad way to do it: "You made a single page app with PHP and {other tech} and {database}! I hate those! Don't you read (reddit, twitter, hacker news)? Best practices say..."

The good way to do it: "Our users often share links within the application with each other to navigate and the new single page app you demoed doesn't allow that."

Or: "While the page load times look great on the metrics in your power point, as everything is lazy loaded it takes 10 seconds for the page to actual become usable, the old site loaded in under a second why are we regressing the user experience here?"

Or the evergreen: "What does that buy us?"

This is fairly basic advice, and it feels a bit insulting to assume I'm just hating on some tech. Obviously, if things were as easy as "here's the immediate and unambiguous problem with this approach", I would have gone that way.

Things would be great if the risks were as simple as this. The actual problem is "six years later, the frontend is a ball of spaghetti code and it takes you two sprints to change a component".

How many developers do you think heed those warnings?

> heed those warnings

It's not a warning. It's a functional requirement that you put into the ticket. The project isn't done if the rewritten page takes longer to load than the old one did. Don't ship it, don't pay bonuses based on shipping it.

Please read my comment more carefully, you're being patronizing. I can't put "I want feature development on this codebase to be faster than two sprints in six years" in the requirements.
Sounds like you should talk to the person who is actually in charge then.
Not enough. But they will scoff at other technologies old and new.
It seems that the pendulum of public opinion is swinging back towards simple, mostly HTML-based solutions, with the rise of intermediate solutions like htmx.
Same here as developer, I only put up with SPAs at work, because job title isn't doing fronted stuff.

However on side projects it is pretty much vanilla.js without any kind of SPA related stuff.

I don’t make sites like gov.uk or any random-user facing sites, but they are fast, frustrationless and “frontend”. I use them myself. Coming from desktop UIs (from most of them, and they are like 100x superior), writing 1.0 websites is a sort of bdsm to me. I actually avoided web programming before 2.0 became a thing.

I’m sure, and it will be hard to convince me otherwise, that it’s NOT a client model (thin client, thick client, mixed approaches) that is a source of your frustrations, but the amount of bullshit that “frontend developers” tend to serve to everyone including themselves and at the same time leave ends loose by e.g. never checking for errors or assuming incorrect lifetimes or phases of page loading.

If you just write a regular non-wEbApp app with js as a scripting lang and dom as a poor man’s ui lib, it works like any other ui app. All problems arise from trying to jump over the head to render empty frames 200ms faster out of total 12 seconds of loading.

My “stack” is mithril.js, bootstrap.css and just js runtime for “state”, for those curious. Yes, I manage “state” by storing it in js objects and transform it via assignment operators (shocking I know).

I started avoiding web programming after 2.0 became a thing, because it turned into an unmanageable time sink and usability nightmare, and it still is.
And I remember when 1.0 sites erased most of the form on an apparent mistake on my part and took ages to load aspx. There are facets in each version of web that we tend to see or ignore, but it’s clear that the common facet is poor and/or overcomplicated programming, not a paradigm itself.