The right abstraction when bootstrapping front-ends
Picture from Samuel Lissner

Front-end bootstrapping code often turns into a big ball of mud.

There are many things to manage when you start up a complex enterprise application. However, having the wrong abstraction when starting your app may easily lead to unmaintainable code.

It is important to have a clear mental component model when starting up your app.

Steal my component structure if you struggle to separate your bootstrapping concerns:

<App />

Start your app with a thin component that handles four basic application states: Loading, Maintenance Mode, Fatal Error, Loaded

<StateContainer />

Your redux, ngrx or pinia store… or whatever state container you might use. It is very important to model the states of the following components the correct way. Apply a declarative programming paradigm to make “impossible state impossible”.

<GlobalLoading />

Show a global loading spinner or animation while your app is bootstrapping. Make sure that the global loading animation is loaded as fast as possible and is not blocking the further loading of your app.

<ConnectionCheck />

If you develop a mobile app, you could also add a connection check that asks whether your server is reachable. Usually this is resolved through polling.

<MaintenanceMode />

Usually you ask your back-end whether the app should transition into some sort of maintenance state. Maintenance mode may be necessary if you apply breaking changes to your back-end. For mobile app development you could also block older mobile clients from accessing your app if they are out of date with the back-end.

<FatalError />

Some apps require in absolute terms that the back-end sends them some data in a certain format. It may happen that the back-end violates this contract through bugs or breaking changes. Therefore, you might be forced to transition your app into a fatal error state.

<Loaded />

Your app has successfully loaded and passed the first stage of the bootstrapping.

<ServiceRegistry />

Often you have to attach all sorts of listeners. If there are just a bunch of small operations to carry out, you could bundle them in a service registry component. Or you just call different components separated by their concerns.

<Auth />

The next important step in the bootstrapping of an app is usually authentication. Let’s assume this app is an enterprise app that just serves private routes. Then you need the following:

<SingleSignOn />

This component handles everything related to single sign on. Many times, we use the redirect grant type of the OAuth 2.0 protocol. Everything related to the protocol workflow can be encapsulated in this component.

<LoggedIn />

From now on the user is successfully authenticated and known to the system. The user starts its session with a clean slate. Normally some sort of session data has been stored to the localStorage or sessionStorage

<InitialPopUps />

Often you need to receive some consent from the user, show some marketing popups or promote the next cool feature of your app. Often those popups are not bound to a specific route.

<PrivateRoutes />

From now on you can start your routing accordingly. Of course, you require more components, such as your logged in layout etc.

<LoggedOut />

If the user logs out, often you want to show some sort of “You have been logged out successfully.” screen.

That are a lot of components! It demonstrates how complex bootstrapping can get.

Make sure you get your bootstrapping abstraction straight. Avoid to drown in ugly front-end complexity.

Revealed: The software scalability game
Older post

Revealed: The software scalability game

How do the best engineers of the world scale their software? Well that's the trick: They rather don't. And you should not either, unless your business really reaches the next level in the scalability game. Let's find out why.