Better Together or Better Apart?

The life-changing magic of organizing your codebase, hybrid rendering architectures, React server components, and how to draw beautiful diagrams.

Issue 9 /

Hey there,

I hope you had a fantastic week. Mine was great—I took some time off work to enjoy the beautiful California woods with my wife and kids, which was a much needed rest but also the reason there was no Frontend at Scale last weekend. I hope you didn't miss the newsletter too much 😊

Today I'm flying out to NYC for this year's React Summit US. I'm super excited to hang out with the nice folks from the React community and to give my talk, The Messy Middle, during the remote track this Wednesday. If you don't have a chance to watch it live, I'll make sure to share the recording once it's up!

This week, we'll talk about the life-changing magic of organizing your codebase, hybrid rendering architectures, React server components, and how to draw an owl beautiful diagrams. Let's jump in.


Better Together or Better Apart?

Photo by Mel Poole on Unsplash

I like to imagine Marie Kondo would be an amazing software engineer. Not necessarily because of her coding skills (which might be pretty good for all I know), but because she's really good at keeping things organized.

Some of the most challenging questions we ask ourselves when building software have to do with the way we organize our codebase:

  • Should we put this code together in a single function or split it into two smaller ones?
  • Should we put data fetching and rendering logic in the same place?
  • Should these two modules live in the same folder?

The answers to these questions will depend on a number of different factors, so there is no one-size-fits-all answer here. But a guideline that ✨sparks joy✨ for me and that I like to follow when I'm not sure how to best organize my code is to keep together things that change together.

Whenever we break down a block of code into two or more pieces, those pieces will remain coupled to each other. This is not necessarily a bad thing—some level of coupling is always expected.

But when changes to one of the parts always require changes to another, it typically means that those pieces are tightly coupled. And the more tightly things are coupled, the closer they should stay together.

Imagine you have a shared function in your codebase's common folder that is used by several different components throughout your application. This shared function might start out as a truly general-purpose utility, but as the codebase evolves, it may start to incorporate special-purpose code to support one or more specific use cases.

A "shared" utility with some special-purpose code to support only one of its users

What's problematic about this is that those two modules (the shared function and the module that uses the special-purpose functionality) are now more likely to change together, even if they live in completely separate parts of the codebase. This could result in changes to one of the parts unintentionally affecting all of the other users of the shared abstraction, causing bugs that can be really hard to track down.

What helps here is to keep the pieces that change together closer together. In our example, that means separating the special-purpose code from the general-purpose abstraction.

Two possible solutions: refactoring and duplication

The diagram above shows two possible solutions for this scenario: we could refactor the code to pull the special-purpose code out of our shared function, or we could duplicate the shared function and put it closer to the code that actually uses it.

Regardless of which option you choose, keeping related code closer together and reducing the scope of changes will always result in more organized and maintainable codebases.

For a deeper dive into this topic, I have a few books to recommend that you can check out next. If you're a frequent reader of the newsletter, you might recognize some of them from previous issues:


Hybrid Frontend Architecture with Astro and Starlight

A couple of weeks ago, Ben Holmes from the Astro team joined me on stream to do a little exercise on application design and architecture. We looked at a fictitious (but realistic) project, and we came up with an initial design and a rough prototype using Starlight, Astro’s official docs template.

Check out the latest article on the blog for a recap of our discussion and a detailed look at our project’s architecture. If you’re looking to build a similar site with Astro or Starlight, I’m sure this write-up can be of some inspiration.


Links Worth Checking Out

Speaking of Next.js, the Vercel team recently shared a sneak peek at one of the new features in Next.js 14: partial prerendering. This video walkthrough by Lee Robinson is also worth a watch.

Interesting perspective on refactoring (from a TDD perspective) as a habit worth developing. "The work is done when the code works and when we’ve made sure the changes are designed well. And to do that, we need to refactor." is one of my favorite resources for frontend-focused software design content. In addition to vanilla JS and React patterns, you'll now also find an entire section dedicated to Vue patterns.

The clarity of your architecture diagrams can make all the difference when it comes to documenting high-level decisions. This article has some great tips to help you communicate your ideas more effectively.

If Mark Dalgleish's talk below leaves you itching for more resources about how to roll your own React Server Components implementation, this detailed article has you covered.


Simplifying Server Components

I must have read dozens of articles explaining what React Server Components are at this point, and still, I can't say the concept has really clicked for me yet. Thankfully, this talk by Mark Dalgleish started to change that.

To answer the question "what are server components?", Mark goes beyond the typical answer of "they're components that run only on the server" (which, as he mentions, it's just rearranging the words in the question) to explain things from a different angle.

Mark gives us a more useful answer: server components are just virtual DOM over the network. This might not make things immediately obvious, but it can help us develop a mental model of how they differ from traditional React components.

The talk also goes through a simple implementation of server components from scratch, which not only helps us grasp the essence of server components but also clarifies which parts of this feature come from React and which from a framework like Next.js.

That’s all for today, friends! Thank you for making it all the way to the end. If you enjoyed the newsletter, it would mean the world to me if you’d share it with your friends and coworkers. (And if you didn't enjoy it, why not share it with an enemy?)

Did someone forward this to you? First of all, tell them how awesome they are, and then consider subscribing to the newsletter to get the next issue right in your inbox.

I read and reply to all of your comments. Feel free to reach out on Twitter or reply to this email directly with any feedback or questions.

Have a great week 👋

– Maxi

Is frontend architecture your cup of tea? 🍵

Level up your skills with Frontend at Scale—your friendly software design and architecture newsletter. Subscribe to get the next issue right in your inbox.

    “Maxi's newsletter is a treasure trove of wisdom for software engineers with a growth mindset. Packed with valuable insights on software design and curated resources that keep you at the forefront of the industry, it's simply a must-read. Elevate your game, one issue at a time.”

    Addy Osmani
    Addy Osmani
    Engineering Lead, Google Chrome