A tip for frontend apps: Develop components in isolation

It happens that some UI components of your frontend app are developed on the way as the feature is being implemented for the first time. Often it’s the case that boundaries of the components are not well defined so the business logic is being mixed with the component logic. The mixing of logic prevents us to easily pick up the existing component and reuse it in another feature.

The messy components are result of a bad development process and absence of proper development environment. Usually, what I see is that people edit “the app” as a whole and don’t work on partial solutions which can be combined together, the cycle is:

  1. start the app & go to specific state (e.g. check dashboard with a specific user role)
  2. validate the component
  3. accept or edit the component
  4. repeat if the component is not acceptable

The problem with this cycle is that running the whole app has tremendous cost meaning it consumes lots of developer time and attention. Some of the time is wasted on navigating the app, searching or focusing on the component or filtering debugging messages. The attention is wasted when the developer is distracted by updates in other parts of the app, by overflow of debugging messages or even by crashes of the app. To put simply, the developer must go through many moving parts and filter out inessential information.

The cure for this is to setup a proper development environment so we don’t have to run the whole app, and instead we can develop the parts in isolation. I believe that using proper development environment has the greatest impact on the quality and maintainability of the app. It enables one to faster produce cleaner components & easily debug them latter on.

There are multiple tools which enable you to develop in isolation. In ableneo we are using Storybook which supports all the modern frontend frameworks. I’ll omit the features and APIs of the Storybook and focus more on the benefits it brings to the table.

The main benefit of developing in isolation is that it makes you focus on the part and ignore the rest. We design each component so it lives in it’s own folder, where we have files for implementation, test and the story file. In the story file we setup static variations of the component, it enables us to render the component in browser without running the actual app.

When we run just one component, we can focus much better as we don’t see the other parts of the app, so we notice more details. This happens not only on the UI level, but also makes debugging easier — the tree of the document is flat, and our component is the actual root, so we don’t have to search for it in the DOM. Also the console is clean, as we won’t see any logs from the rest of the app. These points might seem obvious, but again and again we see a developer who “enjoys” the time traversing the DOM structure, or scrolls through hundreds of debug messages, because nobody told him that he can develop in isolation with the Storybook. Moreover as we don’t need the app running, we can also go offline because we don’t need any backend or staging environment — our stories are setup with mocked data.

Imagine you are building a library component which you can publish as a separate package. Just a glance on the dependencies of the component can tell if it’s decoupled from the rest of the app. When you want to run the component in Storybook, you don’t want it to be connected to a model or data store, because that would require some setup. From this standpoint, we are able to better split the “dumb” and “smart” parts of a component. Usually in the stories we display the “dumb” part with little or no local state.

Thus isolation leads to better public APIs of the components, which enables you to reuse the component in multiple features or screens.

Isolated components increase the developer experience (DX) of code review. While doing code reviews on the frontend, going through the changes is usually not enough because it’s important to review the user experience as well. Without Storybook, devs might be reluctant to do it, because that requires one to start the app with the necessary data setup which could take some time. In the past, to avoid running the whole app, we were attaching screenshots illustrating the changes to pull requests. It worked for smaller features, but It was not enough as we didn’t see all the details as animations or transitions in the UI. In order to improve the DX we started to deploy the storybook for each pull request. Now in just a second we can see the component running in the code review step! The instant benefit is that people use different browsers, so now some browser-specific bugs are caught in the code review step, before the QA jumps in.

The created stories are a valuable product similarly as unit tests, as you can return to them any time. This makes the app maintainable, because the stories enable us to easily check for regressions not only when the components are touched as part of a feature change but also when we are doing a larger code migration e.g. moving from Javascript to Typescript. There are other tools using the stories which can be used to catch regressions automatically. For example the Jest testing library can compare snapshots of DOM structure or Loki can compare the actual screenshots of the stories.

In summary, by developing components in isolation, we are doing bottom-up design, where we focus on one thing at a time. It leads to cleaner & decoupled component design, faster development cycle with improved developer experience and prevents regressions in the UI layer.

A tip for frontend apps: Develop components in isolation was originally published in ableneo Technology on Medium, where people are continuing the conversation by highlighting and responding to this story.