Write to the DOM or Not: When JS Frameworks Are Necessary
Douglas Crockford, who helped develop JavaScript, created a bit of a kerfuffle over his May blog post advising developers to abandon libraries and write directly to the HTML Document Object Model (DOM) — something he’d hitherto advised against:
“My reasons were that the DOM was poorly designed, poorly implemented, and full of inconsistencies from one brand of browser to the other, and from one version to another. The DOM was a deep source of pain and misery that could be mitigated by a good library. Since then, the web standards community has, for the most part, corrected many of WC3’s failures. The DOM is much less deficient and much more portable and reliable. That is why I now recommend abandoning the libraries, which have grown into bloated platforms, and instead using the DOM and plain old JavaScript together.”
It’s an interesting recommendation, especially in light of Alex Russell’s criticism of the bloat framework libraries can add to code. But not everyone agreed when Crockford’s statement was shared via Twitter/X earlier this month.
Web developer and author Lea Verou wrote a lengthy response that, while respectful of Crockford, called his remark “a bit tone-deaf to developer needs.”
The raw DOM is fine for content-heavy sites, where JavaScript is primarily used for enhancements and that require very little DOM update code. It’s also probably fine for web apps that are fairly small and straightforward, she added.
But more complex web apps are a different story, Verou said.
“No, you should probably not build a medium or larger web app today by ‘just’ using the DOM directly or with thin abstractions like the one he proposes,” she wrote. “Either you will wind up with a tightly coupled mess of a codebase or you will re-invent a lot of the concepts libraries and frameworks have spent years perfecting.”
Her comment was liked 312 times with 52 retweets, and at least one developer responded that he’d had to practically invent a library when he tried using the DOM.
The New Stack reached out to learn more from Verou, who holds an MSc in Computer Science from MIT and is currently finalizing a Ph.D. at MIT. Professionally, she researches how to make web programming easier at MIT CSAIL, working with David Karger in the Haystack Group. She’s also the author of CSS Secrets: Better Solutions to Everyday Web Design Problems, and has been involved with designing and reviewing new web standards since 2012 and was elected as a TAG member in 2021.
There are three reasons why frameworks make it easier to develop and maintain apps, she explained.
Frameworks Are Declarative, Not Imperative
First, the framework allows specifying the UI — meaning, in this case, the output — in a declarative, reactive way. “The biggest advantage of this is that these expressions evaluate reactively,” she explained. “This means that when the data they depend on changes, anything that depends on these values also updates.”
By comparison, the DOM is imperative, which means the developer has to specify exactly how UI updates happen, she said. For example, that means creating and inserting HTML elements relative to other elements, removing HTML elements, changing HTML attribute values, setting JS properties (e.g. changing values of form controls), setting CSS properties inline, etc.
“With the DOM manipulation approach, every UI control we add comes with several lines of more event handlers to monitor changes, and every piece of data we want to output needs lines of code that have to run at the right time and re-run when their value may have changed (which we need to keep track of ourselves),” she wrote. “It quickly becomes very impractical.
Verou made two demos to show the difference in effort: A basic adding algorithm in the 1. DOM version and 2. The VueJS version.
“Notice that in one, we need to specify all the steps explicitly, and account for every possible way our state — a and b variables — may change, figure out what DOM calls are needed, and run them at the right time,” she said. “In 2, expressing our intent right in the HTML was all we needed. We specify the what and the framework takes care of the when and the how. While the difference in lines of code between the two is not groundbreaking, the difference in complexity is already apparent.”
She also referenced the difference in code between a to-do list written to the DOM and one using VueJS.
“If even a simple to-do app is this complicated to implement by using DOM methods directly, can you imagine a much more complex application, e.g. a spreadsheet app, or document editor, or drawing app?” Verou stated.
She added that this was just an exercise where she focused on keeping the code as simple as possible. A commercial web app requires much more coding to follow best practices, “such as MVC, which requires to have a data model that is the source of truth, and is kept separate from the UI,” she added. That requires even more code trying to keep the two in sync.
But the biggest advantage of frameworks is how code complexity relates to application complexity, she said.
“With the DOM manipulation approach, every UI control we add comes with several lines of more event handlers to monitor changes, and every piece of data we want to output needs lines of code that have to run at the right time and re-run when their value may have changed (which we need to keep track of ourselves),” Verou said. “It quickly becomes very impractical.”
Frameworks Support Better Modularity
Second, frameworks allow better modularity for business logic, avoiding tight couplings, she wrote. Modularity refers to the ability to program in separate, interchangeable modules.
“Modularity is achieved when we can keep functionally independent parts of code separate,” Verou explained. “The opposite of modularity is tight couplings when logically independent parts of the code need to know about each other and cannot be separated.”
She offered an example: An app state that includes two entirely different pieces of data — ”foo” and “bar” — and the developer wants to output the number of foos and bars as a tooltip on a result element (in HTML tooltips are created using the title attribute). With DOM manipulation, developers need to write the whole attribute each time either foo or bar changes, she wrote:
result.title =
${ foo } foos, ${ bar } bars
“This means that every part of your code that updates foo needs to also know about bar and vice versa The fact that they happen to be displayed together in the UI is imposing an undesirable coupling in our code,” she said.
With a reactive framework, this would be part of the HTML template, e.g.: in VueJS:
<output id="result" :title="
${ foo } foos, ${ bar } bars
">
“The code that manipulates foo and bar can remain separate, and does not have to know about how or where foo and bar is output, and what else is output next to them,” Verou explained.
With DOM manipulation, you need to write the whole attribute each time either foo or bar changes. Something like:
result.title =
${ foo } foos, ${ bar } bars
This means that every part of your code that updates foo needs to also know about bar and vice versa. The fact that they happen to be displayed together in the UI is imposing an undesirable coupling in the code, she said.
“Tight coupling is a problem because it increases cognitive overhead when working on code,” she said. “With small independent units of code, we can make changes to one logical unit in isolation, only needing to keep how that part works in mind. The more tightly coupled the codebase is, the more info we need to hold in our head to work on the code.”
That leads to the introduction of bugs as the codebase grows and becomes too complex.
Separation of Concerns
Finally, frameworks allow better separation of concerns.
“With frameworks, the code that specifies the UI template is in the HTML and entirely separate from code that specifies the business logic,” Verou said. “It’s easy to make changes to the UI without having to change any state management code or computation.”
As for the Russell’s concern about frameworks adding so much JavaScript, it affects user experience, Verou largely agrees with him but pointed out that some frameworks emphasize speed and low overhead.
“Frameworks in some cases can even improve the end-user experience, simply because they make it easier to implement high-fidelity interaction design, so you don’t have to cut corners to keep development time at bay,” she wrote.
But with all that said, there’s one thing Verou wanted to make clear: While she defended frameworks as necessary, Verou isn’t necessarily happy about the situation.
“I’m hoping that eventually, we will move towards a future where a) frameworks are less necessary because the baseline DX of the web platform is not as painful and b) frameworks will become opinionated thin abstractions over web platform primitives,” she wrote. “There is a lot of work happening in this space, especially in the Web Components communities and the CSS WG, though we are nowhere near having reactivity primitives that are native to the platform yet.”