Faking UX Race Conditions using a simple Interceptor in Angular or NestJs
Tags: angular, ux, testing, rxjs
Published: 2021-06-04 20:05:15

[see it in action - StackBlitz](https://stackblitz.com/edit/race-conditions-article)

Race conditions are easy to understand. They’re just like a high-five which depends on 2 people slapping hands at the same exact time. If one person is out of sync, the other may get a high-five to the face 🤦‍♂️. Boom! Race conditions explained!

![Do you even high-five?](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9pl4hyewv4bhz8tmfkew.gif)

In this article, we are going to talk about UX Race Conditions and using a simple interceptor to exaggerate delays from the API so that you can see if you are giving your users the best experience possible.

## UX Race Conditions
In the classic sense, race conditions can cause bugs and unintended manipulation of your data. @vsavkin shows us [an example](https://blog.nrwl.io/rxjs-advanced-techniques-testing-race-conditions-using-rxjs-marbles-53e7e789fba5) of how a user can trigger a new request before the last request had finished, causing the wrong data to be displayed.

But let's talk about the User Experience. Even if all of your data came in on time, could the User Experience also suffer from its own, sort-of, race condition? Using the image below, would the random presentation of components still convey the correct intent? 

![random-loading-site](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f9m1rg2nvp6la9ulstey.gif)

The delays in presentation would trigger a "dizzying" experience because you are shifting the user's eye-line as components are coming in. And since they have no choice to what is presented first, you could be causing the user to [context-switch](https://medium.com/helpful-human/project-fatigue-and-context-switching-bb0741e202cc) until the information they want is displayed.

## Exposing Race Conditions
Sometimes our developer machines are just so darn good that we don't notice the delays in presentation. So let's slow things down with a simple interceptor to exaggerate these delays, by a lot. 

```typescript
// Angular
@Injectable()
export class DelayInterceptor implements HttpInterceptor {
  intercept(
    httpRequest: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    const delayInMs = Math.random() * 5000; //creating a delay of up to 5 seconds.

    console.log(`DelayInterceptor: delaying for ${delayInMs}ms.`);

    return next.handle(httpRequest).pipe(delay(delayInMs));
  }
}
```

This interceptor will add a random delay of up to 5 seconds on all of your HTTP Requests for the entire application. 

By exaggerating the delay of data coming back from  your endpoints, you can now force components to be presented at different intervals, allowing you the opportunity to see if they are coming in in a strange order and if the user's experience could use a little bit of adjusting.

![2 different loading scenarios](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r1mkfh3pjq08t0z1h951.gif)

## What should you be doing?
In the [example above](https://stackblitz.com/edit/race-conditions-article?file=src%2Fapp%2Fgood-ux-container%2Fgood-ux-container.component.ts), we are using a `forkJoin` to combine all of the subscriptions so that we get all of the results back at the same time. We can now add a spinner or "loading message" to prompt the user to wait, limit the distractions and provide *you* with a "worst case scenario" if your production servers were to drag.

## What are the cool kids doing?
If you take a look at #slack or YouTube, you'll notice they add placeholders called ["skeletons"](https://css-tricks.com/building-skeleton-screens-css-custom-properties/) which lets their users know that they are going to fill a particular space. This is a neat solution to the problem because it will pre-fill the space instead and, as css-tricks states, provide the "illusion of speed." Below is an an example of that.

![skeleton](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1on8zp3yonain9uvuvrp.gif)

## Conclusion
The concept of race conditions can also be applied to the user experience. By exaggerating load times, you can simulate a slow network so that you can understand what the user sees and prepare for it. As you think about the flow of data, include "how it is presented" so that you can provide a more enjoyable user experience. Or at the least, help you find that logical race condition issue 😀. It also works for that too!


### Bonus
Below is the same interceptor for NestJs. If you are connecting to a local API, or maybe you are using React, Vue etc, you can force the same delay from your API instead.


```typescript
// Nest.js 
@Injectable()
export class DelayInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const delayInMs = Math.random() * 5000;

    console.log(`DelayInterceptor: delaying for ${delayInMs}ms.`);

    return next.handle().pipe(delay(delayInMs));
  }
}
```