In Defense of the Separation of Concerns
Tags: html, css, javascript, webdev
Published: 2020-01-26 09:06:56

I'd like to make a point for the [separation of concerns](https://en.wikipedia.org/wiki/Separation_of_concerns#HTML,_CSS,_JavaScript) in web development.

HTML is a language that's been created for structuring and linking documents. CSS is for styling said documents. JS provides additional functionality. The three languages are heavily specialized to their intended use. They're also really good in what they're supposed to be doing. 

But where's light there's also shadow. Straying away from their paths means you'd have to accept (or even mitigate) some disadvantages.
Let's take a look at some of those.

## Depending on Resources
A classic request chain would go as follows:
![Waterfall diagram showing a simple request chain](https://thepracticaldev.s3.amazonaws.com/i/1bze8m6hrnvvtapqpgc2.jpg)

I've inserted a green line to mark the First Contentful Paint. Also, ignore the huge numbers. I had this on a slow 3G connection.

The document comes with the initial request. It references CSS and JS files, so they start loading as soon as the document is parsed.
Your styles are render blocking, so they are parsed next. Your JS comes in last place. The document is already [visible](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint) at this point, because we [deferred](https://www.w3schools.com/tags/att_script_defer.asp) it.
Our request chain goes from least to most complex.

HTML is pretty robust. Even if you mess up your code, your browser will probably still be able to display your content somehow. While it's easy to mess up your CSS, it's hard to mess it up so badly that your document becomes completely garbled. You can quickly implement some [severe](http://www.outlinenone.com/) [accessibility](https://www.sitepoint.com/when-and-how-to-visually-hide-content/) [issues](https://css-tricks.com/color-contrast-accessibility-tools/), though.
Javascript is arguably the most complex language out of the three. It's also the most fragile one. Mess up your main thread and the whole script stops working.

Whenever a resource after the document fails to load or parse properly, you still retain the core functionality of your page: displaying content. Everything else just adds things to make the experience of your site a bit nicer. That's the principle of [Progressive Enhancement](https://en.wikipedia.org/wiki/Progressive_enhancement).

## Rendering everything in Javascript
![Javascript all the things](https://thepracticaldev.s3.amazonaws.com/i/o9u3aaxwu09cqyv9fqzx.jpg)

There's a trend to break that principle by just rendering everything in Javascript. Angular and Vue are basically JS-in-HTML and React is HTML-in-JS. All of the big three frameworks are mixing the separation of concerns between Structure and Functionality by depending on the latter to render the former.

What the browser gets from the webserver is basically an empty document pointing to a large Javascript bundle. And that's what it's going to stay until the bundle has been loaded and processed. Until then, not only valuable time passes, you also add the risk of your site not loading at all. Remember how fragile JS is?

Until your page is rendered, the browser has to process the initial document, the framework bundle and whatever you did in that framework. That's a lot of stuff that doesn't really add anything for the user. It's just boilerplate code. Here's a diagram of what a Vue app need to do to show content:

![A performance diagram of a Vue app](https://thepracticaldev.s3.amazonaws.com/i/vyqo96vhylmc0mpepjr5.jpg)

Your bundle may also fail to load due to a flaky internet connection or a critical error in the script. HTML is forgiving in that manner and will still display whatever it can. JS not so much.

## Too much Makeup on the Markup
![Maggie Simpson with Makeup](https://thepracticaldev.s3.amazonaws.com/i/3vo3yvxw2qaujb6dh572.gif)

We can also do it the other way around and inline everything into our document. That would reduce the request chain, but at the cost of bloating up your html and binding style directly to the DOM.
Suppose you have an [Atomic CSS](https://acss.io/) framework in use and write utility classes on your elements (My example uses [tailwindcss](https://tailwindcss.com/)).
```html
<article class="mx-auto sm:my-8 md:my-12 lg:my-16 sm:p-8 sm:p-12 lg:p-16 bg-white">
    <header class="text-l lg:text-xl text-darkgrey">
        <h1>Lorem Ipsum</h1>
    </header>
    <div class="text-s lg:text-m text-black">
        <p>Dolor sit amet, consectetur...</p>
    </div>
</article>
```
You've bound your style information directly to your DOM. Now, suppose you want to add a dark theme, a printable layout, or personalized styles. Do you add even more classes? Do you accept that `text-black` doesn't mean black text in an inverted theme anymore? By writing style information directly into the DOM you lose the flexibility you gained by separating their concerns.
Also, your HTML is bloated with repeating class names now. Worse yet, those class names only describe *what* they do, not *why*.

## Complexity
![Scenes from Avril Lavignes' Complicated](https://thepracticaldev.s3.amazonaws.com/i/auw5cr39qlgjullje4qn.gif)

You can mitigate all of the aforementioned issues. You can use [SSR](https://medium.com/@baphemot/whats-server-side-rendering-and-do-i-need-it-cb42dc059b38) to deliver a functioning Document with JS frameworks. You can use [Mixins](https://sass-lang.com/documentation/at-rules/mixin) to bundle atomic CSS classes into semantic classes and keep your HTML clean. But all of that is adding complexity to your project. You'll have to keep your workarounds in mind while developing. Each one is creating mental overhead and possibly slowing down your build process. I'd argue that our current web development landscape is already complex enough.

When you're building just a small blog or a fairly static product page, why use frameworks that were meant for huge, complicated web apps in the first place? You can save yourself from working around their drawbacks by simply not using them at all, if you don't really need their functionality. Just ask yourself if you really need reactive programming for your project. Or if your CSS becomes so huge that it's impossible to maintain in semantic modules. If not, maybe just try some old fashioned DOM manipulation and [BEM](https://en.bem.info/).

Before you start choosing the right technology for your project, take a step back, take a look at the problem you're trying to solve and ask yourself if you really need the increased complexity that this fancy framework is giving you. Remember that in the end, your users don't care if you used React or jQuery.


## Buts! 🍑
> Everyone uses those frameworks, so they must be The Solution(tm)!

If it was the solution to all our web development problems, there would be no reason to write this. Even if JS-first paradigms are hot right now, they're not free from drawbacks.

> I have that super awesome SPA that relies on complex state processing and routing and...

Sure, go ahead and use frameworks where they're fit. Just be sure to have their shortcomings in mind.

> I have that really edgy edge case where I have to write inline styles

Yeah, they exist. I know. I don't want to forbid anyone to write inline styles or utility classes or anything, I just want you to be conscious about it.

> My boss told me to use React.

I don't like your boss. Show them this article.

## Homework
![A tired school kid on a desk](https://thepracticaldev.s3.amazonaws.com/i/wz99i69k49sy6vlaclkm.gif)

Here's a little exercise in mindfulness: Every once in a while: Write a small website. Don't use a framework, keep your build process as simple and straight forward as possible. Maybe don't use a build process at all?
You'd be surprised how refreshing that change in perspective is, especially if you're stuck in a big clunky web app at work.