Sakalim

Sakalim

About Me

October 12, 2024

A Practical Guide to Scaling Frontend Experiences - Part 1

9 min read

    architecturereactprogramming

Before you dive into this article, I highly recommend reading Why You Should TRUST Frameworks (And What It Takes to Build One From Scratch). This series builds upon the foundation laid in that article, which explores the core challenges modern frontend frameworks face. Unisphere, the framework we’re discussing here, originated from those very concepts. In this series, we’ll outline three levels of development mastery, with the third level being where Unisphere truly shines. To fully understand the journey from basic app development to complex, scalable architectures, we encourage you to start from the frameworks article.

Many frontend developers are dealing with similar issues. The ecosystem is rich with examples, code samples, open-source projects, solutions, and ideas. However, it doesn’t always make the job easier. In fact, it can sometimes make things more challenging as you sift through endless possibilities to find what works for your specific needs.

The Developer Luck Spectrum

In this series, we’ll explore what I like to call the “Developer Luck Spectrum.” Your position on this spectrum depends on the level of freedom, complexity, and responsibility you carry as you navigate various development challenges.

  • Level I - The Luckiest Developers (Application Developers): These developers are at the "luckiest" end of the spectrum because they focus solely on a single application. They have the freedom to break APIs, tweak dependencies, and operate in a controlled environment without worrying about broader integrations. It’s a developer’s paradise—less complex, with plenty of room for experimentation.

  • Level II - The Motivated Developers (Multi-Application Developers): As you start managing features across multiple applications, you transition into the realm of scaling. You're no longer as "lucky" because you're building solutions that must work across applications, increasing complexity. However, this brings more learning opportunities and a greater sense of accomplishment.

  • Level III - The Strategic Developers (System Architects): At the highest level, you oversee integrations across multiple applications as-well-as embedding your experiences within customer applications. This requires strong architectural planning, versioning, documentations, backward compatibility, and a deep focus on developer/integrator experience. As complexity increases, so does the potential for a much broader impact.

Starting with "The Luckiest Developers (Application Developers)"

I’ll be writing an article for each level of “luckiness.” This one is tailored for “The Luckiest Developers,” and may be particularly appealing to novice developers. As we progress, the content will become more advanced, but a solid understanding of this article is essential to fully grasp the concepts in the follow-up pieces.

So, without further ado, let’s dive into what it takes to extend a single application with a feature—what we call “experiences”.

Building the Experience

To keep our focus on the underlying infrastructure, we’ll simplify the experiences by representing them as basic shapes. For instance, a simple circle will stand in for the reactions experience, and a rectangle will represent the notifications experience.

The purpose of this abstraction is to focus on building the underlying infrastructure that can be reused with any experience. It’s about a “write once, use many times” approach, allowing us focusing on the box -the structure- rather than getting caught up in the details of whatt's inside.

Let's kick things off by creating the reactions experience, which we'll represent with a simple circle. While we could easily create this using CSS, we'll wrap it in React to make it more interactive.

import React from 'react';

export const Reactions: React.FC = ({ onClick }) => {
  return (
    <div
      style={{
        width: '50px',
        height: '50px',
        borderRadius: '50%',
        backgroundColor: 'blue',
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        cursor: 'pointer',
      }}
    >
    </div>
  );
};

blue circle

The time it takes to code this isn’t the focus of this article—we're concentrating on the framework that supports it. However, to pique your curiosity, here's a glimpse of the actual experience behind the circle. As you'll see, it's much more visually engaging, but the infrastructure remains indifferent to what’s inside.

Exmaple of reactions experience


Codebase Management Strategies

This section focuses on where to code of the experience should be written

Since this is part of a single application, it’s often best to keep the code within the application’s codebase. Extracting it into a separate code base and consume it using NPM library might seem tempting, but for a feature in a single application, it raises unnecessary questions about versioning, deployment, APIs, documentation, dependencies, peer dependencies, and technology upgrades. Keeping it simple by integrating directly into the application can save time and effort.

Even for single applications, using a framework like NX can offer significant advantages in managing your codebase. While it comes with a learning curve, NX is an excellent tool for writing modular code, even within a single application. Plus, when you’re ready to explore more advanced deployment techniques, you’ll already have the infrastructure in place.


Packaging and Deployment

This section focuses on how to package and deploy the experience so it will be used in the application.

At this stage, the feature is part of the application codebase, so there’s no need to consider versioning, deployment pipelines, or public APIs as it gets automatically bundled with the application during the build process. This simplicity avoids the complexity of packaging and deployment strategies until the feature


Development Environment Tools

This section explores the tools available for developing the feature locally.

Since the feature is part of the application’s codebase, it can be served locally just like the rest of the application. For many developers, especially those working on a single app, this process is straightforward—you’re likely already serving your application locally or using tools like Storybook for isolated component development. If your feature is embedded and consumed in an iframe, you might use a playground application for developing locally. Whatever your current setup is, keep doing what works for you. For the motivated and strategic developers managing more complex setups, we’ll dive into advanced techniques in later articles.


Unit tests

This section covers when and where to focus on unit testing within your project.

Unit tests are highly valuable, yet many developers find it challenging to prioritize them due to both technical and business pressures. My rule of thumb is simple: the server should always have unit tests, while the frontend only requires them in areas with pure logic. In frontend development, automated testing, end-to-end (e2e) tests, and—if you’re using Storybook—accessibility and visual regression tests can provide significant benefits.


Documentations

This section discusses the importance of documentation and tools to consider when creating it.

Good documentation is crucial when building public APIs or products, as it helps ensure ease of use and adoption. However, documenting internal application details can be tricky and is not needed, as it can quickly become outdated and unreliable over time.

For the motivated and strategic developers managing more complex setups, we’ll dive into advanced techniques in later articles.


Core Infrastructure Feature Components

This section outlines key infrastructure components that can enhance your frontend experiences, from state management to theming.

Application State

Managing the state of your application is fundamental to building interactive experiences. You likely already have an application state library in place, so it’s usually best to continue using what works for you.

However, if you haven’t explored XState for application state management, I highly recommend checking out Rethinking State Management - Why XState is a Game-Changer for Developers. XState offers a fresh approach with its finite state machines and statecharts, providing flexibility for even the most complex state management scenarios.

Interactions with the Application

React provides all the hooks you need to manage interactions between your experience and the larger application. If you’re already using a state management solution like Mobx or Redux, you can leverage these libraries hooks to streamline communication across components.

If you’re not using an application state library, you can likely manage with React’s built-in context and providers, or even by passing props down through components (also known as prop drilling), depending on the complexity of your application.

Languages & Theming

Localization and theming are essential for any scalable application. Chances are you’re already using libraries like i18next for language management. Similarly, you’re probably relying on design systems such as Material UI, Chakra UI, Ant Design, or Tailwind CSS for theming. These libraries come with built-in hooks to help you manage languages and themes effectively.


When You Earn the Motivated Developer Badge?

At some point, you’ll find yourself working on two or more applications that need to share features between them. Your first instinct might be to start packaging shared experiences into NPM modules.

Before you rush ahead, take a moment to reconsider. Ask yourself the following question to determine if you’re ready to level up or if you can remain in the comfort zone:

Question: Are both applications managed by the same team?

Illustration about luckiest developer vs motivated fortunate developer

If the answer is yes, you’re still among the luckiest developers. There’s no need to split your codebase, and this is where NX can really save you time and effort. If you’re already using it, you can proceed with minimal hassle. If not, don’t worry—migrating to NX is a relatively simple process.

If the applications are managed by different teams, you might still benefit from using NX for its excellent Code Ownership tools. However, in many cases, you’ll likely end up managing each application in its own codebase. And with that, congratulations—you’ve officially earned the “motivated developer” badge.

What’s Next?

In the next article, we’ll shift focus to the motivated developers—those managing multiple applications and navigating the complexities of shared experiences. We’ll also dive into the world of the strategic developers, where versioning, backward compatibility, and public APIs become everyday challenges.

Even if you’re not facing those challenges yet, it’s always helpful to get a sneak peek at what’s ahead and prepare for potential future challenges.

If you’d like to be notified when the second article is released, follow me on dev.to and stay in the loop!