Something that I've often wished, as a primarily backend focused engineer, often without frontend support, is for designers or perhaps design engineers, to pretty much build Bootstrap themes. That would let me code to the Bootstrap docs (which are pretty good), while allowing us to brand or customise whatever we're working on. I've seen even contract designers push back on this idea, suggesting that doing such a thing is beneath them, and I've heard frontend engineers push back on using Bootstrap as the framework.
This has always struck me as odd. From my, admittedly naive, point of view, Bootstrap seems to be a reasonable framework for customisation. I've done this myself in personal projects. It just doesn't seem like others see it as a design system framework in that way. Few teams have capacity to develop their own design systems, but a Bootstrap theme seems to be most of the benefits with not a lot of effort. That said, I've never been particularly enthused with third party Bootstrap themes, they seem to have too much custom work and lock-in.
What am I missing? I've not used Tailwind, but it seems like perhaps the goal of Tailwind is to do something similar?
Having spent a decade in the late 90s / early aughts doing PHP web development (including Bootstrap), I can't for the life of me figure out why modern frameworks need hooks and a shadow DOM and a component model.
I dabbled for a bit about a decade ago, and the first and last JS framework I worked with was Angular2 (which was in beta); this was right about the time Typescript was getting started (in fact, I distinctly recall that a substantial number of popular JS libraries didn't even have TS bindings at that time).
I think I didn't really want to look stupid by asking in public on HN, but given recent events, I think that ship has sailed :)
Other than analytics, what in the world do we need all of this JS for? I used jQuery (sparingly I might add), and it did its job.
Most web forms don't even have that many components.
I honestly don't mean to insult anyone, and I know I must just be naive about something.
Because otherwise, HTML/CSS aren't that complicated. Messy? Sure. Large? Yup. Duplicative in areas? 100%.
So what am I missing? What exactly does React do so well that the added complexity and resulting slowdowns become an acceptable tradeoff?
You split your app into components and separate it from the backend using an API. This allows you to build a bigger development team. The result will be less efficient but more featureful, more polished, will have someone on call and a better bus factor.
> The result will be less efficient but more featureful, more polished
Not sure about polished. Just see the Atlassian wasteland: lot of features, I'm sure huge and numerous teams. Ages to load a page or anything. Multiple API documentations depending on what you need. The integration between tools is mostly random. "Simple" feature asked for a decade ago never got implemented.
I don't mean to be obtuse, so let me make sure I have this right (and please afford me some leeway on my gentle ribbing, I assure you it's all in good fun and nothing personal):
A framework will allow me to separate the app from its backend?
The web, by its very nature, runs on a client/server architecture, so it has long been possible to separate the front from the backend via an API (we can argue the level of difficulty involved, but I would say the friction was substantially reduced with the introduction of XMLHttpRequest).
So aside from separation via API, according to your list, that leaves us with (1) a bigger development team; (2) a less efficient result; (3) a potentially more polished result (I added possibly, because I'm dubious about the claim that a JS framework makes the result more polished- does it make the browser render the HTML components in a higher resolution or higher color bit-depth?); (4) someone on call (like an employee or group of employees who have to be on call at all times? or am I misunderstanding?); and (5) a better "bus factor" which is a term that I am actually unfamiliar with (is this jargon, or is it an actual technical term/concept?).
Which of these are technical in nature, or rather I should say, which of these factors has anything to do with software (in the abstract) or actual code or markup (in the concrete)?
Now for my more serious follow up: just level with me; is this all bs? Do people use these frameworks because they don't know any other way to do it? Is it a code / organizational issue? Did people take the "separate all code from all HTML/CSS" advice too far and adopt it as dogma? Do people find the event model in JS to be too complex or unreliable? Is it an issue of people getting hooked on frameworks while JS was in flux so they needed the polyfills? Is it that people fell in love with TS, which naturally led to framework-itis?
I feel kind of like I went to the future, and everybody rides exercise bikes everywhere they go to stay in shape, but since exercise bikes don't go anywhere, they have to be put in the bed of a pickup truck first, you know, to actually go places, but then there was a gas shortage, so it was decided to save gas we'd all carpool by putting 5 pickup trucks on a single semi-truck flatbed. Because that's just how things evolved.
So now you're explaining to me why I see people riding exercise bikes on top of pickup trucks that are themselves being pulled 5 at a time on the back of a semi truck, and you're looking at me like I'm out of touch because I can't figure out why you guys can't just walk the 250 feet to the store across the street.
Hilarious analogy that honestly doesn’t seem that far off. But in that reality, you probably wouldn’t be able to walk to the store, much less anywhere else, because there would be all these semi trucks driving everywhere and a road-dominated country. That’s basically a dev trying to get a job today, which means they’re just gonna focus on learning that whether it’s the best solution or not.
Most devs don’t use React because it’s the best tool for the job, they use it because it’s the best tool for getting a paycheck.
Well we can all relate to that. We've all got to eat (and stay warm & dry).
I think I'm just getting to the "old man yells at cloud" stage of my career.
I think of all of the things that we could have built over the years, and understand, I say this not to detract from all of the great software that has been built, but to lament the fact that devs spend so much time spinning their wheels these days (when not reinventing them, or trying to fit a square one on a race car) that we have spent so much opportunity cost that could have been the next big thing or the better version of an old thing.
I would just implore people to go back and look at the history of computing, and the things we had back then (even if they were research demos or ahead-of-their-time pipe dreams), and remember that we have 100,000-1,000,000x the compute (or more) than we had when these older things were built. We can do better.
And remember, not every abstraction is a useful one, not every appeal from authority should be taken as gospel, that creating software can be one of the most creative and expressive endeavors one can undertake, that there is no greater joy than seeing people use the things you build (or help build), and that there's no such thing as perfect software (but we should always strive to get as close as reasonably possible).
would it be OK for me to steal your analogy? It's great!
In the team I'm currently leading, we have made the same observation, with stuff getting more complicated without anything substantial to show for it. In a way we're having a harder time getting out features than twenty years ago, but somehow that's "progress".
As an experiment, I had one of my juniors rewrite a (admittedly small) frontend with Go templates and HTMX, and not only did they have a blast doing it, they were surprised at how simple everything suddenly was. Give that one a try, it's worth it!
That said, there are frontends with requirements that actually do need all that framework crap. Once you want 3D stuff that a user can move around with the mouse, you pretty much have no other choice. While those special cases are rare, people prefer to learn one framework and use it for every nail they see lying around instead of looking at all the other tools in their shed...
Hey I'm not saying it's always a better way or that all apps should be developed in a certain way. But it's a trend, people are doing it for a reason and I think I understand why.
You asked whether some of the reasons are technical. Not in the sense that you can't do it in a simpler way, no.
Look at it from the perspective of a company that has a product and a few developers working on it. It's successful. Now a lot of requests pops up. Some are small, some are related to an obscure integration, maybe a few custom development requests from important customers, bug fixes... The company can now either say no to a big chunk of them (a fine choice), or, if it has money, it can hire more people.
Now, with more people, for them to be somehow effective, you need to create internal APIs and narrow down the focus areas of your teams. Backend/frontend is a separation layer, you're right. But I'd argue it's not that useful for this problem. If the backend emits HTML, what's the frontend work then? Styling? On the other hand, running a thick client in the browser that consumes an API makes it possible to decouple even the release cycle of the frontend from the backend.
Mind you, there are companies that are/were successful with a small team. But most often, the success is supported by large teams at the cost of technical perfection.
"bus factor" is just a side benefit of having a larger dev team. The idea is if someone gets run over by a bus then you still have someone who "knows" the code to train the replacement.
More exactly, the bus factor = number of people who'd have to be hit by a bus to stop development. So the bigger your bus factor, the more secure your dev.
One thing that I've learned over time is that if I can't understand why people are taking some particularly obtuse or circuitous route, then that's probably because I don't yet understand what they're doing properly. I never really understood why people would use terminal-based text editors until I tried it out for myself, and while I still have my doubts, I understand the tradeoffs much better now. If frontend development feels as insane to you as the analogy you're describing, and yet it's one of the largest sectors of the software industry, then it seems likely that you're missing something, rather than everyone else going mad.
As you say, it has always been possible to build things where the browser-based client is separated from the backend via an explicit API. Consider an application that shows you a list of flights coming into an airport. You want it to automatically update whenever new flights come in, so you need some polling to fetch that data, and some Javascript to clone elements, fill in the details of the new flights, and insert them into the DOM. But you also want sort functionality, so you need to be able to rearrange all the elements as well. And you want to filter, so you need to be able to store all the flight information internally as state, even if those flights aren't currently being shown. And your can click on each flight to expand it and view more details about that flight, so while you're rearranging and rewriting all your flights, you also need to be keeping track of which ones are currently open or not.
This was the exact application where I first realised that all the jQuery-based DOM manipulation techniques I'd learned were not going to be enough, and that there was a lot of value in having a tool that manages keeping the DOM in sync with the application state, allowing you to focus on keeping track of that state.
There are other approaches, but in my experience, they mostly come down to building your own framework, one way or another. They don't have to be as complicated as React, or as heavyweight as Angular, but you need some system in place to help you sync your state to the DOM.
I'm not establishing here that all web development needs to take this approach, just that there are a lot of situations where it is very useful. I've ended up building and maintaining variants in the above filter/sort/details/live updates system three or four times in different contexts and with different parameters, to say nothing of other, similarly complex web apps where the system works have been unmanageable without some sort of frontend framework.
Once this starts, though, you end up with frontend developers who specialise in this kind of development, and I suspect this results in a kind of siloisation, splitting web development into frontend teams and backend teams, who can each specialise further. Backend developers no longer need to worry about that occasional time where they need to tweak some CSS or JS, and frontend developers don't need to understand databases. This in turn develops into frontend developers using their tools in a wider variety of situations, because it turns out they make a lot of web development a lot easier, not just complex state management. It's a bit like how people use git to track their dotfiles. Even though git is designed to coordinate between multiple people syncing complex branches and forks together, it turns out it also works well as a simple backup and rollback mechanism.
The result is that tools like React are probably somewhat overused, but that allows developers to specialise into broad fields like "frontend" or "backend", while also remaining very general within those fields (because most work that is frontend will use similar sorts of tools and layouts, just like how MVC will apply to most backend development, regardless of language or framework). And this also isn't universal - there are still plenty of smaller, more boutique design operations that will build websites in the more traditional way.
I hope you understand that a fair bit of my second post was tongue-in-cheek.
I appreciate the concrete examples, and yes, that makes perfect sense when you start getting into data-heavy frontend applications. I do remember jQuery being useful for AJAX and for DOM selection primarily, so I get it.
And of course I knew I was missing something, that's why I asked lol, the question was serious and I knew HN wouldn't let me down.
I'm still a bit mystified about the necessity of a shadow DOM, it just seems counterintuitive to me, but perhaps it's because I'm not familiar with browsers' DOM handling conventions. Perhaps me gaining some insight there would make the purpose of a shadow DOM more clear.
Honestly, I really did figure that it had something to do with the event model (not the DOM or shadow DOM). Something about providing a more consistent apparatus for wiring and handling events.
I still think there's a lot of unnecessary spinning of the wheels on the front end, but that gets beat to death around here, so I'll let it be.
By shadow DOM do you mean the virtual DOM? The shadow DOM is also a thing, but it's largely unrelated to web frameworks.
The idea behind the virtual DOM is that it's usually easier to render everything in a functional sort of way. You treat rendering like a function that takes state as an argument, and returns your desired UI. Every time an event handler fires and changes some state somewhere, you rerun all the functions with the new state and that produces a (potentially different) UI.
For various reasons, it's not practical for these functions to actually return a new DOM every time the state changes, so instead they return the VDOM, which is a description of what the DOM should look like, and React diffs the real DOM against the VDOM and updates it if there are any changes. This way, if you've got an input that the user is typing in, it doesn't get replaced completely every time the component updates, but React might update properties on it as they change.
Originally the React team talked about how the VDOM made React faster, and this claim got stuck in everyone's heads, but it's not really true. The VDOM allows React to separate the rendering phase (i.e. when all the component render functions are called) and the DOM update phase, which can have some performance improvements against more naive approaches, but if you could optimally update the DOM directly whenever state changes, then this would still always be quicker. (And a lot of frameworks are moving towards this model, and away from the more React-like VDOM approach.) The main benefit of the VDOM is that it simplifies the programming model: it allows the "UI as a function of state" concept, and makes it easier to reason about what's happening while a render function is being executed.
A lot of more modern frameworks are moving away from VDOM-based approaches, although React is staying very much where it is. Like I said, there are faster approaches, but these arguably come with tradeoffs about complexity. Personally, I tend to avoid React because of the VDOM approach, in large part because it's a layer of abstraction that I don't really need.
I'm a BE dev that has do to some FE work now and again, but IIRC the shadow DOM thing is about performance: it is in theory more performant to modify the shadow tree and then send it to the browser for rendering in one go than to manipulate individual elements and have the updates render immediately.
Back in the day I had to use an escape hatch in Vue 2 (which does not have shadow DOM) to work with the DOM directly to render a fast changing component (a structured log browser window with live logs flowing in rapidly). No idea if React would have worked better though. :)
In my experience, a lot of developers have a very limited grasp of what the browser can do for you without React. If all you know is React, everything looks like a single-page application.
I have a very good grasp on jQuery and a good grasp on SPA frameworks, and as soon as you cross that barrier into a complex application, jQuery is completely unsuitable in maintaining a clean state.
My career started in the transition period between jQuery everywhere and frameworks everywhere. Much of my work throughout the years was picking up after others who left/were fired.
Main difference that I noticed between that time and the present day is that you hardly ever see unfixable monstrosities made by a lone-wolf one-man-army developer any more - at least in the Angular space, where as long as you're familiar with the convention, you'll manage. Much of that is thanks to TypeScript and the possibility to communicate to future maintainers what was your intention without writing paragraphs upon paragraphs of documentation.
Of course the tradeoff is that it's all pretty heavy right now, but that's what frameworks like Svelte or SolidJS and generally the concept of Signals try to address.
My take is that the moment we get Signals into the JS standard, this will all neatly fold like rows in Tetris.
Just being a webmaster integrating a simple design could be done by "anyone" so not paying so well anymore. So came the idea: now we're not doing websites, we're doing webapps. Suddenly fresh-out-of-school engineers can try to implement GUI concepts they vastly misunderstood, but in javascript and limited by the DOM. So that's years of work to maybe get a tenth of the performances of desktop apps: javascript interpreters to optimize, browsers, frameworks and then the apps themselves.
Add the rise of smartphone apps and you even get the excuse of "we made an API for the apps, so why not use it for the frontend".
The real reason is because it’s faster (or was in 2014) to diff 2 versions of an optimized in-memory tree than it is to use the dom API to diff live html (where any change might trigger the browser’s layout and rendering pipeline)
That’s why react opted for a virtual dom. Many frameworks followed suit.
We’re a decade on at this point and JavaScript runtimes are much faster
You're not missing anything, companies like mine have done just this.
We supported a messy situation of 7 webapps using different technologies looking 7 different ways. Once we got them to use Bootstrap, was a cinch to consolidate to a single company brand.
The "big reskin" UX was gearing up for was as simple as a new theme, and was done without any drama. They were almost disappointed it was so easy, ha.
I like Tailwind, but it's a rotten fit for reskinning (not just changing font or colors). I'd much rather have a single .card class, vs "p-3 border-1 shadow-sm rounded-2" or whatever. Not all of us have have the luxury of a single modern app all using the same React components.
Indeed, the reasoning I've read falls close to the last paragraph of your previous comment. Components will consistently apply "atomic styles" everywhere and so are thought to be a replacement for "semantic styling" (sprinkling in some quotes because I don't know the exact terminology).
Yeah it's one of those things I just don't agree with them from practical experience. No beef against utility classes in general just not for everything. In fact I really like Bootstrap's which are just enough to help, but are still themeable: https://getbootstrap.com/docs/5.3/utilities/api/
I've seen both sides of this idea many times, and from my personal experience, this idea looks good on paper, but usually implodes in practice. Bootstrap gives you a baseline quickly, but what pretty much universally happens is that at one point a feature requires you to venture outside of its constraints and that's when the trouble starts. Overrides and extensions, then something changes in the underlying theme or you update Bootstrap for some adjacent reason, that means more changes to the custom logic and eventually it's a big ball of yarn. Since you're working within the confines of Bootstrap and what it does and doesn't let you customize, you're never in a position where you can refactor all of it to make complete sense. In my opinion, if you're already working with a designer, it's way easier to build what they delivered from scratch, rather than try to bend Bootstrap over backwards to fit over it.
Can you give any more insight as to why? Designers always seem to want to build design libraries, I don't understand why they wouldn't want to use a common API as the basis for that so that there's a contract of sorts with developers.
I would assume their thought is, that it limits their creative spirit and in general is too technical. But they start (as 2 people teams) on figma a complete own design lib with a lot of variables and custom components which look the same like any other lib.
Things like Tailwind take the core concepts of bootstrap and build and improve on it on a grand scale. It is like comparing jQuery (bootstrap), to React (tailwind).
People really do sell Tailwind as if it’s a Bootstrap-like framework. I think that’s why so many sites (see: most startups) have a very similar “Tailwind look” now - everybody wants to use Tailwind because it’s hip, but nobody actually wants to write styles if they can help it, so they just copy-paste a very basic rounded-border-plus-shadow style onto all their components and call it a day. It’s a little better than the “Bootstrap look” because at least it doesn’t come with a default accent color that nobody will ever change, but man, it’s not that much better.
> I've not used Tailwind, but it seems like perhaps the goal of Tailwind is to do something similar?
I'd say that's the opposite of the goal of Tailwind.
Tailwind is not like Bootstrap, Tailwind is to build your own design system component library. Tailwind makes it easy to build unique designs at the cost of having to make the design yourself. Bootstrap makes it easy to build a website with a premade design, at the cost of having the same design as your neighbour.
As someone who used Bootstrap / Semantic UI a lot in the past, I've finally concluded I won't be using them anymore: they ALWAYS end up being too rigid for what I want to do. It also invariably ends up breaking things in minor updates. Tailwind is freeing in comparison.
Functionally no companies have a team building component libraries.
Tech companies with >100 employees might be more likely to, but that leaves most companies without that team, where they may still benefit from using Bootstrap as the basis for it.
Every bootstrap site looks the same no matter how you customize it. Designers quite often focus on the details. They're the type of person who gets offended if the icon is off by 1 pixel. It is fine for most of us with no artistry brain, but may be boring to see the same bootstrap theme for them. Anecdotally, it is like clothing choice in different gender. Majority of men are fine wearing the same tee everyday, but most women prefer to wear different styles of clothes on each day.
> Every bootstrap site looks the same no matter how you customize it.
How would you recognize a bootstrap site if this is false though? Sounds like confirmation bias, that is, "all sites that I can recognize as using Bootstrap use Bootstrap"
I hear ya, but it is CSS so the target doesn't move, Codeberg is using it for their docs [1], and it is easy enough to paper over any problems you might find. Good enough for me. Some might even say the more relaxed release cadence is a feature not a bug.
To be fair, a lot of people miss that Bootstrap is themeable, and what you are complaining about is just the default theme. E.g. check out https://bootswatch.com for examples, many aren't flatsville.
I've had confused conversations with UX, etc over the years when they say "We can't use Bootstrap - our colors are totally different!", etc.
This has always struck me as odd. From my, admittedly naive, point of view, Bootstrap seems to be a reasonable framework for customisation. I've done this myself in personal projects. It just doesn't seem like others see it as a design system framework in that way. Few teams have capacity to develop their own design systems, but a Bootstrap theme seems to be most of the benefits with not a lot of effort. That said, I've never been particularly enthused with third party Bootstrap themes, they seem to have too much custom work and lock-in.
What am I missing? I've not used Tailwind, but it seems like perhaps the goal of Tailwind is to do something similar?