Hacker Newsnew | past | comments | ask | show | jobs | submit | blakewatson's commentslogin

Related: This is a nice write-up of how to write reactive jQuery. It's presented as an alternative to jQuery spaghetti code, in the context of being in a legacy codebase where you might not have access to newer frameworks.

https://css-tricks.com/reactive-jquery-for-spaghetti-fied-le...


This brought me flashbacks of jQuery spaghetti monsters from years ago, some were Backbone related. In retrospect, over-engineered React code can be worse than decently organized jQuery code, but some jQuery mess was worse than any React code. So I guess I'm saying, React did raise the bar and standard of quality - but it can get to be too much, sometimes a judicious use of old familiar tool gets the job done.


You reminded me of a time where one of my clients asked me to add a feature on a file uploader written in react/redux. This was early 2021.

I kid you not, there were 30+ redux actions chaining in the most incomprehensible ways, the form literally had a textual input, a button to open the file explorer and a submit button.

It took few weeks one of their Romanian team to build it and apparently that team was reassigned and nobody could touch it without them.

I remember writing pages and pages of notes to understand how this all tied up in those extremely complex chains and claiming progress after few hours when I achieved to simplify the flow by removing a handful of these actions. Hooray.

Then it suddenly dawned on me that...I could just rewrite it from scratch.

Nuked the entirety of that nonsense and replaced it with a single useState in a matter of few hours also implemented the newly requested features.

The client could not believe my progress and the fact I also removed many of their previous issues.

Then I had a second realization: React was useless too and it got dropped for native HTML forms and a handful of JS callbacks.


> I kid you not, there were 30+ redux actions chaining in the most incomprehensible ways

I 100% believe this, as it describes all the redux codebases I've seen. The library seems to be an antipattern of indirection.


This sounds like an engineering quality problem rather than a tooling problem.

Well structured redux (or mobx or zustand for that matter) can be highly maintainable & performant, in comparison to a codebase with poorly thought out useState calls littered everywhere and deep levels of prop drilling.

Redux Toolkit has been a nice batteries-included way to use redux for a while now https://redux-toolkit.js.org/

But the popularity of Redux especially in the earlier days of react means there are quite a lot of redux codebases around, and by now many of them are legacy.


I took a look at the quickstart guide at https://redux-toolkit.js.org/tutorials/quick-start and to me it still seems to add a lot of indirection.


"We'll build a big centralised store and take slices out of it" still feels like something you should eventually realise your app now needs rather than a starting point, even in libraries which do it without as much ceremony and indirection as Redux.


This brought back flashbacks of a brief moment when I was left as the sole maintainer of a “soon-to-be-axed-but-currently-critical” feature in a checkout flow developed by people who A) knew redux and B) were not me. They recently implanted some state updates before departing, and the bugs for that fell to me. I think I spent a few days tracing the code and understanding how they managed their state, and I think I needed to touch about five files to fully encompass the updates for one data point - I felt nuts!

> The library seems to be an antipattern of indirection.

Auto-generated actions from slices are a codified way to do what was once considered an antipattern: Tying an action directly to a single reducer, instead of actions being an action the user could do on a page (which multiple reducers could respond to).


I really can't understand how someone would make 30 redux actions for a simple use case, as someone has implemented the exact same thing. But yes, not a fan of Redux myself


Many years ago, I used Redux to build real time streaming data processing layer. Basically I need to receive, merge, and process multiple data streams into a single realtime data pool. After that,consuming the realtime data becomes dead easy.

Even now I am not sure I could find a better tool to deal with real time data and synchronization. But for simple crud Redux is mostly overkill



True but rx was even more niche than redux. It was much easier to hire redux devs


you got to the crux of it. Redux became a trend, surfing on its popularity at a time React wasn't providing the reactive piece it needed, plus the time machine demo just amazed everyone. The author got his job at Facebook. It carried millions of developers to use that lib, the author even said it isn't necessarily the go to mechanism, but hiring manager stuck with the idea that all projects redux magicians, since all projects needed React.

For the anecdote, I remember my manager admitting we can't fix the legacy app, but we can put lipstick on the pig with React.


Have some pity for those Senior Expert Architect Full-Stack Developers (fresh out of boot camp) in urgent need of job security.


The original developers weren't bootcampers but engineering graduates.

And in the same way faang is filled with leetcode blackbelt charlatans writing slop, so is Romania apparently.


Great generalization of an entire country's sector workforce.

I'm sure you'd 100% approve of such a statement of your country when based on one anecdotal recount (even if it true).


It's not about Romania or any other country.

I was making a point that whether you graduate or not has little correlation with your capacity of handling higher abstractions and complexity, because neither bootcampers nor engineering graduates have the experience of building complex systems, let alone under time, tech leadership and management pressure.

It is likely that the original authors may have found themselves in a situation where they were tasked to build a trivial form with technologies they were not accustomed to at the request of some superior and they ended writing a soup.


I hear you saying that React raised the floor but also lowered the ceiling.


>> This brought me flashbacks of jQuery spaghetti monsters from years ago, some were Backbone related.

To be fair, jQuery was a response to the the IE and JS variant mess of the early 2000s. jQuery made development possible without debugging across three browser varients.


Standardized selectors was the big use case for me


React made complex interactive UIs a lot easier to manage than jQuery, but that resulted in many developers adding a lot more complexity just because they could.


I used this approach before and it indeed works better than the 2010-style jQuery mess. A good fit for userscripts too, where the problem you attempt to solve is fairly limited and having dependencies, especially with a build steps, is a pain. Note that you don't need jQuery for this at all, unless you are somehow stuck with ancient browser support as a requirement - querySelector, addEventListener, innerHtml - the basic building blocks of the approach - have been available and stable for a long time.


Unfortunately, nowadays writing userscripts is much harder than it used to be. Most websites are using some sort of reactive FE framework so you need to make extensive use of mutationObservers (or whatever the equivalent is in jQuery I guess).


I'm not a frontend dev but I came up with this and use it a lot in my userscripts. It's not the most efficient (it can certainly be refactored to create a MutationObserver singleton and then have each call hook into that) but it works well enough for my needs and lets me basically use an old-school to dealing with reactive sites (so long as you are fine with using async):

    function awaitElement(selector) {
        return awaitPredicate(selector, _ => true);
    }

    function awaitPredicate(selector, predicate) {
        return new Promise((resolve, _reject) => {
            for (const el of document.querySelectorAll(selector)) {
                if (predicate(el)) {
                    resolve(el);
                    return;
                }
            }

            // Create a MutationObserver to listen for changes
            const observer = new MutationObserver((_mutations, obs) => {
                // You could search just inside _mutations instead of the entire DOM.
                // Efficiency will depend primarily on how precise your selector is.
                for (const el of document.querySelectorAll(selector)) {
                    if (predicate(el)) {
                        resolve(el);
                        obs.disconnect(); // Don't forget to disconnect the observer!
                        break;
                    }
                }
            });

            // Start observing the document
            observer.observe(document.documentElement, {
                childList: true,
                subtree: true,
                attributes: false,
                characterData: false,
            });
        });
    }


It's easier to write with LLMs. One-off projects (the way I treat userscripts) is where they really shine.

Oh the horrible things I do with Instagram...


go on


I often go for `setInterval` over `MutationObserver` because it works and I don't need instant reactivity and I don't have to think too much about it.


Very true. I guess that depends on what websites you find issues with? I just checked mine and all of those are quality of life improvements for fully server rendered sites like HN or phpBB forums.


Yeah, I mostly use it for QoL improvements but for work related things. So Jira, Bitbucket, GitHub, Linear etc. basically whatever my employer uses. Back in the early 2010s most of that software was fully server rendered. Nowadays it's pretty rare for that to be the case.

I just try and get LLMs to do it for me because I'm lazy, and they like to use setInterval instead of mutationObservers and if it works, I just live with the inefficiency.


The Atlassian stack is particularly bad to extend IMHO given that there are sooooo many API endpoints that their UI calls and most of them are dog slow.


In ol'times people used BackboneJS[1] for that purpose. And surprisingly enough, it is still being actively supported[2].

If someone is still using jQuery for legacy reasons, BackboneJS might be a good intermediate step before going for a modern framework. Backbone is pretty light and pretty easy to grasp

[1]: https://backbonejs.org/

[2]: https://github.com/jashkenas/backbone/tags


There was a period where BackboneJS models were used as the datastore for React, before Redux took over. I haven't used it like this myself, but could definitely see it as a way to do an incremental rewrite.


That's a very nice pattern indeed. If you add signals, the update function even gets called automatically. That's basically what we do in [Reactive Mastro](https://mastrojs.github.io/reactive/) ;-)


The last major jquery app I wrote ended up using a similar reactive pattern. I had to shoehorn a custom search engine frontend into a Joomla CMS where I wasn’t allowed to change much. Good times!


But if you do that, you'll also find it easy to write plain JS without any libraries or frameworks. document.querySelectorAll is just slightly more verbose than $(). I have personally done this: for simple web pages, I just eschew all dependencies and write plain JS.


This is still the way - jQuery or not - for UI where you can't/don't want to use a component library. I use the same approach for my browser extensions, both for page scripts and options pages. Writing features so you update state then re-render also means you get things like automatically applying option changes live in page scripts, rather than having to reload the page, for free. Just receive the updated options and re-run everything.

Browser extension options pages are mostly a form mapped to what you have stored in the Storage API, so implementing them by handling the change event on a <form> wrapping all the options (no manual event listener boilerplate) then calling a render() function which applies classes to relevant elements (<body> classes are so good for conditionally showing/hiding things without manually touching the DOM), updates all form fields via named form.elements and re-generates any unique UI elements makes it so un-painful to change things without worrying you're missing a manual DOM update somewhere.

My options pages are Zen Garden-ing 5 different browser-specific UI themes from the same markup to match their host browsers, which is a brittle nightmare to maintain in an app which needs to change over time rather than static demo HTML, but once you've tamed the CSS, the state handling and re-rendering is so painless I'm sticking with it for a while yet, even though it would be long-term easier if I used Preact+htm for no-build option components which know what the active theme is and can generate specific UI for it.

My favourite dirty old-school knowledge is still the named global created for an element with an id, why bother selecting an element when it's right there (once you know you need to avoid global name collisions)?. I use those suckers all the time for quick fun stuff and one-off tool pages.

    <h3 id="communityNoteHeading">
      Readers added context they thought people might want to know
    </h3>
    <div>
      <textarea id="communityNote" placeholder="Note" rows="5" style="width: 400px"></textarea>
    </div>
    <button id="communityNoteCopyButton" type="button">Copy</button>
    <script>
      communityNoteCopyButton.addEventListener('click', () => {
        navigator.clipboard.writeText([
          communityNoteHeading.innerText,
          communityNote.value,
        ].join('\n\n'))
        communityNoteCopyButton.innerText = 'Copied'
        setTimeout(() => communityNoteCopyButton.innerText = 'Copy', 1000)
      })
    </script>


MobX autoruns happily call jQuery functions.


See also this lovely typeface revival. https://lineto.com/typefaces/valentine


I had a typewriter with this font. Thanks for the pointer.



Probably not too useful for many in this audience, but I wrote a web book for *absolute beginners* learning HTML. It's very much in the same spirit as the OP's post.

https://htmlforpeople.com/


You don't even need html to have a web site. You can host regular text file. For years my website was just that.


Yes, this was the one I was thinking of!


TL;DR - The ability of computers to "understand" natural language and intent has staggering implications for accessibility.


I recently hit a 10-year milestone of being employed after many years of trying and failing to get a job.


I can’t get enough of anything that helps me wrap my mind around the scale of objects and distances in the universe.

I recently discovered Epic Spaceman on YouTube, who makes incredible visual comparisons to help understand these scales. https://www.youtube.com/@EpicSpaceman

There’s also Universe Sandbox 2. But tbh this Atlas of Space is more accessible to me due to my various input limitations.

Space Engine let’s you explore the entire observable universe.


I think https://spaceengine.org/ fills part of your request. I haven't played it but I've watched videos about it and it looks like you can jump anywhere around the observable universe and look at any object you want.


This looks terrific. But it's Windows-only.


I think it's available on Steam which would mean you could theoretically use it on Linux with Steam's Proton compatibility layer.


Can that be tested before purchase?


Steam has a generous return/refund policy [0], so you could buy it, test it, and if it doesn't work request a refund.

[0]: https://store.steampowered.com/steam_refunds/


It worked for me last year, and entertained a few of us for a good while. Been meaning to revisit.

Side note: Elite Dangerous is on offer at the moment and that has been the only thing to give me that unnerving sense of scale you get when travelling between systems.


I went with "Get started already" :)


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

Search: