Modern-Day Separation of Concerns

Jon Dewitt
Level Up Coding
Published in
6 min readApr 13, 2022

--

A brief overview of contemporary front-end architecture

The landscape of web development is full of sharp rocks and cliffs, making it tough to navigate. One must learn to discern good practices from the bad, taking everything with a grain of salt. Some of the most contentious issues I’ve encountered have revolved around SoC (separation of concerns.) In this article, I hope to build at least one bridge in this jagged environment, so you can spend less time deciphering these debates, and more time participating.

HTML should allow separation of content and presentation. For this reason, markup that expresses structure is usually preferred to purely presentational markup.
[…]
The article element defines an individual article, but not the details of how it is displayed.

W3C, HTML Design Principles

The excerpt above suggests that your markup should be written in a way that’s conducive to SoC. Traditionally, that means adding a <link> to your CSS and a <script> pointing to your JavaScript.

One layer labelled as HTML. The next layer labelled as CSS. The final layer labelled as JS.
Traditional SoC

But, you might say, we’ve come a long way since this documentation was written. For the most part, we no longer structure web sites with one big document, one big stylesheet, and one big script. With the rise of popular component-driven libraries like React, we tend to use tiny component scopes to combine all three languages in each one.

Three layers, each containing HTML, CSS, and JS.
SoC with components

So does that mean SoC is an outdated concept? Well, not quite, it just looks a little different. Combining languages in this way doesn’t necessarily violate the principles encouraged by the W3C, because the concept of presentation versus content transcends HTML and CSS.

Often, modern applications are structured with three layers in particular:

  1. Presentation (UI)
  2. Content (sometimes called “abstraction”)
  3. Core (API)
First layer: HTML, CSS, and JS labelled as presentation. Second layer: HTML, JS labelled as content. Final layer: JS labelled as core.
SoC with front-end architecture

Presentation

Presentation is in charge of showing content to your website’s visitors, human or otherwise.

This layer is reserved for stateless UI components, ideally without any hard-coded text at all. These components should isolate all presentation details from other layers.

There’s a lot to unpack on this subject, so it may benefit you to read more about mastering presentation components as a separate topic.

Content

The content layer can manifest in a couple different ways:

  • As higher-order components in charge of providing data (sometimes called “container” components)
  • As purely semantic components that define content (no CSS nor presentational markup such as <div> and <span>)
  • As utilities used to mediate data between the UI components and the core

At this layer, we can pull data from the core and run logic to determine what content is provided to the presentation. We can also handle events triggered by the user and send off the result to the core, (for example, form submissions.)

Core

The core of your app is in charge of running business logic, making asynchronous requests, managing state, and interacting with the content layer via internal API.

It’s especially important to decouple this layer, because it makes upgrades to your tech stack much easier when all your dependencies are neatly encapsulated in one place.

Imagine your team decides for whatever reason that Apollo GraphQL no longer fits the needs of your application. If Apollo’s useQuery hook was imported in all your components, then you’ll need to do some major rewriting across your entire codebase, and the impact scope of those changes will be massive.

Now, imagine instead that each query was contained in a function, so the only thing in your components’ scope was that function call. Now you only have to rewrite the contents of that function, rather than touch the components at all.

The Value of SoC

Although you may understand these concepts, you may be pondering whether it’s worth the effort. Is it overengineering? Is there a sufficient payoff?

“I choose a lazy person to do a hard job. Because a lazy person will find an easy way to do it. “

— Bill Gates

One thing you should understand about my approach to pretty much everything, is that I like stupid simple stuff. So why would I preach about all this complicated architecture? The answer to that lies in far-sighted visions of the future. I’m lazy, not impatient. Eventually all this discipline adds up to be less work, and if you’re business oriented, less cost.

Let’s time travel for a moment. It’s six years from now, and you’ve written the next hit mobile app. Congratulations! Your company has grown fast, and now you have to hire a team of engineers to maintain it. While you’re off making big decisions about the newest features, your team struggles to keep up. “It didn’t take me that long to write this, what’s going on?” You might think.

You open your code for the first time in several years and find that you’ve pretty much forgotten about most of it. Unfortunately, you didn’t write any documentation to help you nail it down. You sink a lot of time into searching for all the parts that have to change. Once you find them, you must then follow your code backward through the file salad until you find each dependency, and then make adjustments to all of them. You then realize the new markup you added is breaking the CSS, so you have to pinpoint the source of that style. And so this trend continues…

By the time you’ve done all that work, 8 hours came and went, so you have to return the next day… and the next… until a week has passed. You finally submit your changes, only to find they haven’t passed QA. The task has been assigned back to you, because you inadvertently caused critical defects you didn’t notice before.

Frustratingly familiar, isn’t it? Now what if you had neatly organized your concerns from the start? The same scenario looks a lot different. You documented your code well, wrote ESLint rules to keep things in order, and hired lead developers to enforce your standards.

Now, you open your code after several years, and you’re greeted with a roadmap to get where you need to go. No time spent searching. You find only one relevant area, so you can immediately start coding. Since all of your dependencies are within the scope, you don’t have to worry about hunting down side effects. Because it’s so straightforward, you easily complete your task without introducing any bugs in record time.

Okay, that’s a bit contrived and optimistic, but nevertheless, I think it effectively demonstrates the point. Practicing good SoC is like exercising — no one particularly likes doing it, but it’s hard to deny the long term benefits.

Coming full circle, we can conclude from all this that SoC is more important now than ever. Some complex systems once confined to the back-end have since moved to the front-end, and with them comes the extra responsibility to keep that code nice and tidy. You owe it to your peers, your successors, and your future self.

I intentionally kept this topic very broad to introduce the concepts at a high level. Having something like this on hand is helpful for quickly communicating these ideas across teams, and to act as supporting information for more specific and complete material.

--

--

I’m Jon! I’m the founder of Thunder Solutions, a software company in Pittsburgh. My goal is to share our open source dev tools and SaaS apps with the world!