paint-brush
Front End Workflow: Re-envisionedby@mgmarlow
2,337 reads
2,337 reads

Front End Workflow: Re-envisioned

by Graham MarlowNovember 9th, 2017
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

<span>T</span>wo years ago <a href="https://reactjs.org/docs/thinking-in-react.html" target="_blank">Thinking in React</a> changed the way I design user interfaces. To put it lamely, it made designing UI more programmer-friendly: divide a chunk of UI into pieces, approach each piece individually as stateless markup, and add logic only after the whole structure is finished. The workflow of component-based design is so intuitive I often forget I am even using it.
featured image - Front End Workflow: Re-envisioned
Graham Marlow HackerNoon profile picture

As front end development embraces component-centered design, so should the approach towards constructing user interfaces.

Two years ago Thinking in React changed the way I design user interfaces. To put it lamely, it made designing UI more programmer-friendly: divide a chunk of UI into pieces, approach each piece individually as stateless markup, and add logic only after the whole structure is finished. The workflow of component-based design is so intuitive I often forget I am even using it.

Unfortunately, mapping out applications in the real world is never as simple as described in the article. Project manager needs, wants, and goals are forever in flux. Designing a user interface structure-first, logic-later, has a major pain-point: until the end of development, the code has no minimum viable product for demonstration. That means changes in scope or project direction can greatly impact work put towards development. Spending the time to structure an application is meaningless if the functionality of that application changes dramatically due to a different direction.

How can development teams provide quick, meaningful product iterations while still maintaining the advantages of component-based design? The solution is to approach development in the opposite direction of that described in Thinking in React:

  1. Begin by drawing the same map of a user interface, dividing each piece into their respective components.
  2. Instead of defining the overall structure and developing a stateless rendition, start at the smallest piece and move upwards. Take the least complex component of the application and finish it with mock data, completing a piece of the structure.
  3. Continue to move up through the map of the entire user interface, gradually implementing more complex components. These complex components will use the smaller components that were previously created.

This workflow solves the problem of the demonstrable product. With each component finished, the development team is able to show off a fully-functional application, even if it is wired up with fake data. The problem with this method lies in the development process: it is often not easy to develop an individual component in isolation without defining the rest of the application’s structure. However, there are some great tools that help us get around this issue and allow components to be developed in isolation easily and efficiently.

Sandboxing Components

When developing a full application, components should be staged and iterated upon individually. This technique is called sandboxing, or providing a complete and isolated environment for a piece of data. For modern front end frameworks, two open source sandboxing tools are Storybook and Angular Playground.

Disclaimer: I am a contributor on Angular Playground. Therefore, I will focus on Playground since it is the tool I am most familiar with.

Playground takes the components that are already written in your application code and mounts them in “scenarios”. Each scenario is a lightweight wrapper built around your component that contains only the markup that you define in that scenario. All other dependencies of the application are left out. This means you can iterate and test components without the weight of an entire application. This also means you can stage components with whatever data and dependencies you so choose, with full control over the data they provide.

Since components are created separately from scenarios in the application itself, Playground simply grabs the existing component and bootstraps it in its own environment. That means the only code you need to work on a component is its list of dependencies and its selector, e.g. <my-component>. Changes within the code base are instantly reflected in all scenarios that use that component.

These features provide developers a lot of power when constructing components.

Setting up the Playground

Angular Playground works off of an application’s existing Angular environment, so there isn’t much boilerplate to set up. Since most Angular development uses Angular CLI, I am going to begin under the assumption that your Angular application (CLI 1.2.0+) is already scaffolded. There are just a few extra metadata files that need to be added in order for Playground to hook up with your app.

If you want to skip configuration and just dive into my example project, here’s the code.

Since Playground uses dynamic import expressions to ensure sandboxed components are truly loaded in isolated chunks, make sure that the TypeScript version in your project is 2.4.0+. We also need to change a tsconfig.app.json setting to set module output to esnext.

npm install --save-dev angular-playground [email protected]

The next step is to add the code that Playground uses to bootstrap your app’s components. Within the src/ directory, add the following file: main.playground.ts

Note that my Angular apps’s name in this case is ng-app.

Next are the metadata files that Angular CLI will use to compile the Playground project. Add an extra app entry to angular-cli.json:

Now for Playground-specific configuration at the root of your project, my-app-dir/angular-playground.json. The Playground CLI tool will use this file when building your sandboxes.

Finally, add an npm script to your project’s package.json to use the Playground CLI.



"scripts": {"playground": "angular-playground"}

Run Angular Playground with npm run playground and navigate to localhost:4201.

Playground running in localhost:4201/

Creating Sandboxes

With the Playground up and running we are ready to create sandboxes for our components. Here is a simple component that we will build scenarios for:

This component allows a user to edit particular fields associated with a profile, if that user is editable. Note that this component takes in an input (@Input() user) and includes a separate component in its template, <app-details-form> (source).

We create sandboxes with the Playground API function, sandboxOf(). This function works much like Angular’s NgModule decorator in that we use it to describe the dependencies required for a particular component. Since the InfoSummaryComponent includes controls from the ReactiveFormsModule, we need to bring that module in as an import. Additionally, since the DetailsFormComponent is used within the InfoSummaryComponent’s template, Playground needs to know about it so it can properly render the entire component.

Say we want to set up two different states of this component: one with a default, editable user and one with a non-editable user. We can do this by setting up two different “scenarios” for the component, each with a different user provided to the @Input() user variable.

Sandboxing the info-summary component

Here is the respective sandbox file (info-summary.component.sandbox.ts) that stages the component with two scenarios, “Default” and “Non-editable User”.

First we instantiate the component and its dependencies with sandboxOf(InfoSummaryComponent, { /** … **/}). Then we use the .add() method to add different scenarios to the sandbox, setting up our environment. Each scenario is assigned a name and a set of options.

The only required property for the options object is template, which takes in the template that will be rendered on the page. In this simple case, we are only staging the component we care about with different types of user data. Finally, context is an optional property that provides data to the context of the component. Here we use it to provide our two different users, one editable and one not.

With this sandbox structure, we can stage many different scenarios for the components we develop, modelling all of their data requirements and uses. As components increase in complexity, the sandbox provides a great environment to help focus on the important details.

Wrapping Up

Although this is a simple example, I hope that it demonstrates the power of sandboxing components. Angular Playground works with all different types of component setups, allowing you to provide injected services, set up scenario-specific styles, and easily model both @Input() and @Output(). There are also a ton of benefits that are outside the scope of this post that can help your development team. Here are just a few:

  • Testing variations and edge-cases: by creating many scenarios for a component, every variation is easy to test and design. The worst bugs are the ones that are difficult to reproduce due to the amount of data and interaction it takes to wind up at the broken component state. Sandboxing alleviates this problem by allowing a developer to mock out the data that breaks the component and immediately start iterating on a solution.
  • Components that are single-purpose: progressing through the sandbox workflow encourages developers to build components that can easily be modeled in a scenario. This means that when the component is started, it is often broken down into smaller pieces, each one more singularly-minded. By the time the component is finished, the result is often a simple, reusable chunk of code just by following the intended workflow.
  • Easier unit tests: sandboxes are designed to be similar to unit test files, making it easy to transition into testing immediately after (or during) component development.
  • Interactive documentation: Playground scenarios can be embedded into documentation pages, allowing them to take advantage of interactive components. Since these scenarios pull from source, they are immediately updated upon component changes.

Resources