Most active commenters
  • austin-cheney(8)
  • dsego(3)
  • thomasikzelf(3)

←back to thread

94 points thepianodan | 20 comments | | HN request time: 0.005s | source | bottom

I had a mind-blown-moment when I learnt that Obsidian was built without any frontend JS framework. ( https://forum.obsidian.md/t/what-framework-did-the-developer-use-to-create-obsidian-desktop-application/30724/11 )

The benefits, I can see.

    JS frameworks move really quickly, and when we're working on a large, long-term project, it sucks when big breaking changes are introduced after only a couple of years. Sticking to slow-moving web standards (which are quite mature by now) increases the longevity of a project.

    And the stability also means that more time is spent on delivering features, rather than on fixing compatibility issues.

    There is also the benefit of independence. The project's success is not tied to the framework's success. And it also makes the project more secure, from supply chain attacks and such.

    Because there is no "abstraction layer" of a framework, you also have greater control over your project, and can make performance optimizations at a lower level.

    I feel not using a framework can even make us a better developer. Because we know more of what's going on.
There are benefits to using frameworks too, I'm not here to challenge that.

But this alternative of using none... it seems rarely talked about. I want to learn more about building large (preferably web-based) software projects with few dependencies.

Do you have any suggestions on how to learn more about it? Are there any open source projects you know which are built this way? It needs to be large, complex, app-like, and browser based. I'm more interested in the frontend side.

Thank you!

1. austin-cheney ◴[] No.45615437[source]
The reasons I avoid large frameworks like React, Angular, Vue, and even jQuery is that they are aren't necessary. They are code decoration that slows things down. Here is what you can expect without these:

* greater flexibility

* faster execution, My current application produces a large single page application that fully renders visually and executes state restoration in about 105ms localhost or under 200ms across a network

* faster maintenance, I can do massive refactors that touch most files in the application in about 2 hours thanks to thorough use of TypeScript interface definitions

---

Here is how I do it:

1. Just start building your application. Realize that for any significant application the front end UI is probably only about 20% of the application code, or less.

2. Start the UI by writing static HTML. Reserve JavaScript, in the browser, only for handling events and state restoration and execute state restoration only on page load.

3. I prefer to use WebSockets over HTTP as much as possible for absolutely everything I can get away with. WebSockets are full-duplex, where HTTP is not, and have far less overhead. That will substantially reduce the complexity around messaging in and out of the web browser.

4. Everything after that is just execution, planning, refactoring, and feature addition.

5. You can do absolutely all of it in TypeScript now without any compile step. Node.js now executes TypeScript directly, but the browser does not. To solve for the web browser just include the browser code into your Node application using ES6 module import. If the imported code is a function you can convert it directly into a string for transport, and otherwise use JSON.stringify for objects/arrays.

replies(3): >>45615736 #>>45615888 #>>45615988 #
2. ramon156 ◴[] No.45615736[source]
Frameworks aren't necessary in the same way that high level languages aren't necessary. It depends, it always does

If you want to ship an MVP next week and you spend 6 days setting up your env, you've already failed. If you can get a framework with at least 80% of the features you need, suddenly you have 6.5 days left to build the product

replies(1): >>45615875 #
3. austin-cheney ◴[] No.45615875[source]
If it takes you 6 days to set up your environment there are bigger problems than framework choice at play. It does not take more than a couple hours to fully prototype some HTML and some JavaScript/TypeScript in the backend.
4. mexicocitinluez ◴[] No.45615888[source]
> and even jQuery is that they are aren't necessary.

JQuery was never considered "necessary". It's just a much prettier wrapper around the native dom apis. Arguing against adopting a more readable api (and codebase), is gonna be a tough sell.

replies(1): >>45616833 #
5. dsego ◴[] No.45615988[source]
Not sure how you avoid reinventing any of the component frameworks. Writing custom JS component backbone style seems tedious and error prone. Manually modifying the DOM on changes means writing the same logic several times, once for the initial render and then repeated in every event handler that has change the state of the UI. Alternatively, you might just be nuking your DOM with inner html and then running everything again through the initial rendering logic. But this isn't ideal, components loose focus, there can be glitches, and it can get slow. Not sure how you could make the type of complex UI heavy apps and have any greater flexibility or faster maintenance.
replies(2): >>45616544 #>>45616782 #
6. thomasikzelf ◴[] No.45616544[source]
If you are writing the same DOM update code in each event handler you can abstract it into a function.
replies(1): >>45617558 #
7. austin-cheney ◴[] No.45616782[source]
> Not sure how you avoid reinventing any of the component frameworks.

You don't do framework nonsense. That is all there is to it.

For most people writing JavaScript for employment it is absolutely impossible to imagine any universe where a couple of lines of code could be written without something that looks like a framework. That is not a limitation of the language, but rather a limitation of the given developer's imagination. The problem is thus a person problem and not a technology problem.

I do not use innerHTML because that is string parsing, and one of my critical performance steps is to avoid parsing from strings, except JSON.parse when needed.

replies(1): >>45618688 #
8. austin-cheney ◴[] No.45616833[source]
Nobody worries about fashion when buying a shovel. Your users don't care about your code fashion. These things are clear when an outside party can observe your developer habits and inform you where your priorities are as opposed to what you state they are.
replies(1): >>45617043 #
9. mexicocitinluez ◴[] No.45617043{3}[source]
> Nobody worries about fashion when buying a shovel.

Huh? Are you implying the code will never get read by another developer or possibly modified? Are you arguing there is no reason to make your code more readable?

> These things are clear when an outside party can observe your developer habits and inform you where your priorities are as opposed to what you state they are.

What?

10. dsego ◴[] No.45617558{3}[source]
What I'm saying, say you have 3 dependent dropdown pickers, selecting an item in the first one determine which of the other 2 are shown. When you have reactive interfaces like that, it's hard to extract the common "business" logic. Either you redraw everything from scratch or you do a sort of show/hide on DOM elements as in jQuery days. Not sure how you can abstract that. If you do abstract it, you end up with backbone, vue, react, or other in any case.
replies(2): >>45618211 #>>45621043 #
11. austin-cheney ◴[] No.45618211{4}[source]
You are still thinking in terms of framework goodness, which is why this is challenging for you. Don't do that. Don't redraw anything. Don't create some shallow copy, cloned node, or other insanity. You don't need any of that. You don't need to litter your code, most especially your DOM nodes, with a bunch of business logic insanity.

All you need is the event handler. The event handler can be assigned to a node's event property directly, but if this is for a commercial site with lots of third party analytics/spyware you need to use a event listener instead because those third party libraries will overwrite your event assignments. The event handler receives an event object as an argument with a reference back to the given DOM node.

All the business logic should be stored in a single location representing a given business function, typically far away from the browser logic. It makes sense when you write the code without using a framework. If you write the code and try to make it look like a framework it will look like a framework, unsurprisingly. If you don't do a bunch of framework component insanity it will not look like a framework.

This is a person problem, not a technology problem.

replies(1): >>45618393 #
12. rrgok ◴[] No.45618393{5}[source]
I did not understand the event handler part. Could you make an example?
replies(1): >>45618971 #
13. rudi-c ◴[] No.45618688{3}[source]
When you're writing only a "couple lines of code", you can do pretty much anything you want. There's no real tradeoffs to discuss except in a theoretical sense, because the stakes are so small.

If the app being built is "large" (which I understand to mean, has high essential complexity), then those tradeoffs matter a lot. If the app is built by a team instead of an individual, the people problems become significant. Those can very well be turned into a technology problem. The technology (framework in this discussion) can be used, among many other things, to establish a consistent way of solving the problems in the application, which alleviates many people problems.

replies(1): >>45619094 #
14. austin-cheney ◴[] No.45618971{6}[source]

    const myHandler = function (event) {
        console.log(event.target);
    };
    
    // this is simple and easier to troubleshoot,
    // but you can only directly assign one value to an object property
    myNode.onclick = myHandler;
    
    // for pages with JavaScript code from third party domains
    // use event listeners instead
    myNode.addEventListener("click", myHandler);
When leaving frameworks you have to stop thinking in terms of components, isolated code islands that exist only in their own isolated world. Instead think of areas of the page as parts of a larger whole. You can manage each part independently or not. You wouldn't program outside the browser using something like React, so your programming inside the browser should reflect how you would build an application if the browser weren't there.
15. austin-cheney ◴[] No.45619094{4}[source]
> When you're writing only a "couple lines of code", you can do pretty much anything you want. There's no real tradeoffs to discuss except in a theoretical sense, because the stakes are so small.

The JavaScript logic in the browser is comparatively small compared to the total application. This is absolutely more true when you remove the bloat imposed by a large framework.

Frameworks do not exist to alleviate problems for the developer. They exist to help the employer with candidate selection and training elimination to expedite hiring and firing. I can understand why a developer who is utterly reliant on the framework to do their job might think otherwise, which is a capability/dependence concern.

replies(1): >>45621736 #
16. thomasikzelf ◴[] No.45621043{4}[source]

    <select id=dropdown>
        <option value=a>a</option>
        <option value=b>b</option>
    </select>
    <select id=a style="display: none">...</select>
    <select id=b style="display: none">...</select>
    <script>
        const $ = name => document.querySelector(name)
        $('#dropdown').addEventListener('change', ev => {
            $('#a').style.display = ev.target.value == "a"? "block" : "none"
            $('#b').style.display = ev.target.value == "b"? "block" : "none"
        }
    </script>
vs

    const [showing, setShowing] = useState(null)
    const handleChange = ev => setShowing(ev.target.value)
    let other
    if(showing == "a") other = <select>...</select>
    if(showing == "b") other = <select>...</select>
    return <>
        <select onChange={handleChange}>
            <option value=a>a</option>
            <option value=b>b</option>
        </select>
        {other}
    </>
some notes:

- The complexities of both of these tiny pieces of code is similiar (I would say)

- React needs to load a big bundle

- React spits out a large stacktrace with react internals if something goes wrong

- React is slower

- React code cannot be easily stepped through with the debugger

- React needs a build step

- React performance is very unpredictable (this is more of a problem with many elements and dynamic code)

Your next question might be what you do once your form grows huge. See my other answer to @iliaznk how I handle that.

replies(1): >>45621427 #
17. dsego ◴[] No.45621427{5}[source]
Yes and then add few other pieces of state and interdependent components, the reactive code will extend, the manual patch job of connecting listeners and mutating DOM will start falling apart. The first example is okay for a one off but can't be reused as a component. It's also easy to get in a place where you have to update 3-4 different handlers to include a logic change. In a component based library/framework, you ideally update the state logic in one place and the UI just reflects that. For example, making the UI dynamic with a button that adds/removes multiple items that need this show/hide logic, you would need to attach new listeners, clean up listeners, clean up DOM items, and so on... my first example was only illustrative, but not to be taken literally. There a complex UI state in many apps, and reactivity with component based reuse is easier to manage and make sure all states are covered. Many times in my jquery years 10-15 years ago I had failed to update one piece of the DOM and there would be bugs that just aren't happening with component UIs.
replies(1): >>45622124 #
18. rudi-c ◴[] No.45621736{5}[source]
That you believe frameworks were invented to serve employers is a cynical point of view. I'm sorry for whatever bad experience you've had with the frameworks or people using them that caused you to develop this viewpoint.

A developer choosing to use a framework doesn't mean they are reliant on it, any more than choosing a particular language, library, text editor, tool, etc. It simply means they decided it was a helpful way to accomplish their goal, whether that's to save time, or establish consistency, eliminate categories of problems, avoid re-inventing the wheel, etc.

I don't know if you're aware of this, but you're coming off as incredibly arrogant with your strong claim that frameworks are used by those who don't know better. It's easy on the internet to vaguely gesture at "developers", but most of us are individual who've built software with real users among other demonstrated accomplishments. Strong claims require strong evidence, I hope you have the arguments to back it up.

replies(1): >>45622753 #
19. thomasikzelf ◴[] No.45622124{6}[source]
I agree separating your UI into components is important. If React learned us one thing it is that keeping related stuff together is the way to go. Separating into components and keeping your functions as pure as possible gives you 95% of what makes React great! You can read my answer to @iliaznk on how I do this.

cleaning up listeners or cleaning up DOM nodes is rarely needed. Just remove the component element and the browser cleans up automatically.

20. austin-cheney ◴[] No.45622753{6}[source]
I hear the exact same self absorbed reasoning on other subjects from my autistic child almost daily. The psychological term is fragile ego.

For example: It’s not that the developer reliant on the framework is less than wonderful. It’s that everyone who differs in opinion is obviously wrong and/or arrogant, because the given developer cannot fathom being less than wonderful.