5 reasons to avoid imperative code
Tags: rxjs, angular
Published: 2022-11-28 10:30:03

---
title: 5 reasons to avoid imperative code
published: true
description: 5 reasons to avoid imperative code that are consequences of how imperative code violates separation of concerns 
tags: rxjs,angular
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bi7az7n6vfl9l3a03wm9.png
# Use a ratio of 100:42 for best results.
# published_at: 2022-11-16 04:52 +0000
--- 

[YouTube](https://www.youtube.com/watch?v=s0iKhOrtUdE)

## 1. Inconsistent state

In an imperative app, events trigger event handlers, which are containers of imperative code. This imperative code is burdened with the responsibility of understanding and controlling features that often have nothing to do with the original event. Imperative code is written outside the context of the state it's controlling and all the other code that controls that state, which is scattered across other event handlers. This often results in naive update logic that fails to consider the whole picture or account for other downstream effects. This usually causes bugs from inconsistent state. 

For example: This is a movies app with a search bar in the header. When you enter a search in, it calls an API and takes you to a page with the search results returned from the API.

![Search Results](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b1ril2rb3ae2x9176ecu.png)

Many of you are already in the habit of programming this reactively: Just change the URL and let the search results page contain its own logic that reacts to the URL by fetching the search results requested. 

But this feature was structured more imperatively, with the search submit handler being responsible for both fetching the results and redirecting.

This caused a bug where if you were on the search results page and refreshed, there would be no search results, because that feature was unable to react to the URL correctly by itself. 

![inconsistent-state-imperative](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9rrreax2x4oezmzzckfc.png)

**Imperative code is buggy by default**: If any unforeseen event triggers a state change, downstream state will remain stale and inconsistent.

On the other hand, when downstream state is reactive, it doesn't matter what caused the state change above it. It will always react.

![inconsistent-state-reactive](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vk9t9332f3d9656te2ne.png)

If you think setting the URL first and handling the API request on the route page is a special case, you simply haven't noticed yet that imperative code is the cause of almost all inconsistent state. Hunt down the origin of every bug and you'll find that imperative code can account for as much as 40% of the bugs.

## 2. State elevation

The movie search feature illustrates another problem with imperative code: State has to be elevated to a level where the imperative code from other features can control it. If event handlers need access to state from other features, that state cannot be local; it has to be global.

![State Elevation—Imperative](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t3e8o4ailsm1unae0vf0.png)

This is where the original developer used NgRx/Component-Store. He created a global service/store that movie search submit handler could access and store the results of the API call. 

The first issue with this is that it decoupled the search results state from the lifecycle of the component. If the search results observable was only used in the component that needed to react to it with the `async` pipe, it would have unsubscribed from that observable when navigating away. This would have either canceled the API request, or when revisiting the route it would have created a new request. 

![State Elevation—Reactive](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8vge5oj0dz36dx8p1ybp.png)

Instead, there had to be extra logic to reset the search results, and in-flight requests were just left un-cancelled.

The second issue with this is that state accessible to every feature is potentially being changed by every feature, and you won't know until you check. 

## 3. Large bundles

The rule of reactivity is that everything that can be downstream should be downstream. This is naturally lazy behavior. 

The only framework I know of that makes taking advantage of this easy is [Qwik](https://qwik.builder.io/). But even in Angular, it's easy to take advantage of code that's reactive to URL changes, because routes are very easy to lazy-load. 

Unless you're using Qwik, every lazy-loaded code bundle probably contains the code of all of its event handlers. Since event handlers are often busy referencing and changing other features, this means those other features need to be included in this bundle too.

![Bundle Sizes Imperative](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/utjvr7t32knlipmy4l79.png)

So, if you can, try to have event handlers change the URL and have everything else react to that. 

![Bundle Sizes Reactive](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cjh5evq38bjf09ytqcw6.png)

## 4. Unnecessary complexity

State that's controlled externally by callback functions relies on those functions to control it in every scenario. This decentralization of control creates duplicated control. In this diagram from earlier, you can see that every new event will require 2 more arrows:

![inconsistent-state-imperative](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9rrreax2x4oezmzzckfc.png)

Every arrow that causes `State Change 1` must be duplicated for `State Change 2`. This bloats the codebase.

But does the imperative code really have to be this way? Maybe we can improve it. Let's look at an example and try to make it DRY. 

In this example, we'll have `carModel` as our `State 1`, and various derived states. We could create a central function for updating `carModel` called `changeCarModel` that includes an update to the derived states.

```tsx
  changeCarModel(newCarModel: CarModel) {
    this.carModel = newCarModel;
    this.zeroToSixtyTime = this.zeroToSixtyTimes[newCarModel];
    this.price = this.prices[newCarModel];
    this.electricRange = this.ranges[newCarModel];
    this.canDriveLaToFresno = this.electricRange > 270 ? 'Yes' : 'No';
  }
```

One of the benefits of reactive code is that the update logic is next to the state it's relevant to. Can we achieve this with imperative code too? We already have a function for changing `carModel` right next to it, so can't we just extract the downstream state change logic to individual functions that live next to those other states themselves too? Then we can just invoke those functions from the end of `changeCarModel`. Let's define the update functions as arrow functions so we can put them right next to their states:

```tsx
  carModel = 'Chevy Volt' as CarModel;
  changeCarModel = (newCarModel: CarModel) => {
    this.carModel = newCarModel;
    this.changeZeroToSixtyTime(newCarModel);
    this.changePrice(newCarModel);
    this.changeElectricRange(newCarModel);
  };

  changeZeroToSixtyTime = (newCarModel: CarModel) => {
    this.zeroToSixtyTime = this.zeroToSixtyTimes[newCarModel];
  };
  zeroToSixtyTime = this.zeroToSixtyTimes[this.carModel];

  changePrice = (newCarModel: CarModel) => {
    this.price = this.prices[newCarModel];
  };
  price = this.prices[this.carModel];

  changeElectricRange = (newCarModel: CarModel) => {
    const newElectricRange = this.ranges[newCarModel];
    this.electricRange = newElectricRange;
    this.changeCanDriveLaToFresno(newElectricRange);
  };
  electricRange = this.ranges[this.carModel];

  changeCanDriveLaToFresno = (newElectricRange: number) => {
    this.canDriveLaToFresno = newElectricRange > 270 ? 'Yes' : 'No';
  };
  canDriveLaToFresno = this.electricRange > 270 ? 'Yes' : 'No';
```

Look at that! `changeCarModel` no longer needs to worry about `canDriveLaToFresno`, because `changeElectricRange` calls that update function on its own! And this is all imperative code! Everything follows this pattern:

```tsx
updateDerivedState = (aboveState: AboveState) => {
  // Update this.derivedState
  // Call update functions for states that derive from this state
}
derivedState = initialDerivedState;
```

But you know what, there's sort of a circular dependency going on here. The derived state has to know about the state it's derived from, because it wouldn't exist in the first place if it weren't for the state it uses to derive itself. But the top-level state function needs to know about and directly call the derived state update functions below. What can we do about this? 

Derived state knowing about state it's derived from reflects the natural relationship between the state and derived state.  It's similar to how vanilla JavaScript works when you declare initial values for variables:

```tsx
const a = 5;
const b = a * 10;
// Notice that `a`'s declaration includes nothing about `b`.
```

So it seems like the odd part of the circular dependency we've created is that our top-level state has to reference the state change functions below it. Can we get rid of that?

What if we came up with a generic mechanism the top-level state could use to update its derived states without actually referencing them? We could define an empty array that derived states can add their update functions to. The central `changeCarModel` function could just loop through the array, calling each function with its new value for `carModel`. This would allow any derived state to just add its update function to that array and have it get called whenever `changeCarModel` runs. Here's what that looks like:

```tsx
  carModel = 'Chevy Volt' as CarModel;
  carModelUpdates = [] as ((newCarModel: CarModel) => void)[];
  changeCarModel = (newCarModel: CarModel) => {
    this.carModel = newCarModel;
    this.carModelUpdates.forEach((update) => update(newCarModel));
  };

 // Assign dummy property just so we can run this code here
  dummyProp1 = this.carModelUpdates.push((newCarModel: CarModel) => {
    this.zeroToSixtyTime = this.zeroToSixtyTimes[newCarModel];
  });
  zeroToSixtyTime = this.zeroToSixtyTimes[this.carModel];

  // etc...
```

Guess what? We basically just invented observables. Those update functions are like observers in RxJS.

Let's refactor completely to observables and compare it with what we just came up with:

![Imperative to RxJS Diff](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zt6ts7ng3025ufzm60r1.png)

Pretty similar, but RxJS abstracted away the subscription mechanisms so all that's left is our business logic. And it's even more DRY now that initial values aren't treated as a special case.

So how did we get here?

1. Make imperative code more DRY by centralizing state change code next to state
2. Achieve the same thing for derived state while also improving separation of concerns, by moving derived state's update logic next to the derived state 
3. Remove pseudo-circular dependencies between state and derived state and improve separation of concerns further by making state agnostic about state that is derived from it
4. Make code even more DRY by using RxJS

Every step that improves imperative code moves it closer to reactivity. This means the only way to fundamentally improve imperative code is to have less of it. 

Let's review the basic rule of reactivity again: Everything that can be downstream should be downstream. This goal is the exact same as that 4-step process we just went through, and it is the best way to get as minimal and simple state management as possible. Downstreaming improves code at every stage.

![inconsistent-state-reactive](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vk9t9332f3d9656te2ne.png)

And since reactive code is located next to the feature it controls, logically similar code will be grouped together, so it's easy to find opportunities to condense repeated logic. This is much harder with scattered, imperative code. In the app I refactored, the first event handler had these two imperative commands next to each other in an event handler:

```tsx
    this.store.switchFlag(false);
    this.router.navigate(['/']);
```

At first I had no way of knowing that `switchFlag` was only ever called at the same time. 

After I had refactored to reactivity, it became obvious that `store.flag` was downstream from the app's URL; it was a flag to determine whether the app was supposed to be on a certain route. You might think this is a ridiculous example, but it's real code that was written, and I really couldn't see how to simplify it until I made it reactive.

Clean code is reactive code.

---

[Here's the repository](https://github.com/mfp22/good-imperative-code2) for the example in this section. And for fun, here's the diff when I convert the RxJS version to [StateAdapt](https://github.com/state-adapt/state-adapt), the state management library I created:

![RxJS vs StateAdapt](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iz2cfch7ptb1l2wtou2x.png)

## Bad function names

Functions are things that do stuff. That's what they are. So their names should reflect that, right? But if you saw this in a template, could you tell me what it does?

```html
(click)="onClick()"
```

No. Rather than being named for what it *is*, this event handler, like most tend to be, is named for how or when it is called. 

I know this is extremely common, so at this point I'll cite an authority that might trump tradition. From the classic and extremely authoritative book Clean Code:

> Methods should have verb or verb phrase names like `postPayment`, `deletePage` or `save`. 

Is `onClick` a verb? Does it describe what the function *is* or *does*? No. It describes an instance in time, when a thing is clicked. All you know when you see a function called `onClick` is that it is called... on click. 

Wouldn't a function name like this be easier to understand?

```html
(click)="refreshData()"
```

Hopefully you agree with me that that is a better name than `onClick`. 

Alright. Can you help me come up with a better name for this function than `onSubmit`?

![onSubmit function](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5n0i31a44h6zhkxc571f.png)

This is color-coded according to what state is being affected. 

Can you come up with a single name that describes what this function does? Here's my best attempt:

```tsx
ifValidDeleteMoviesFetchAndSaveMoviesAndSaveSearchHeaderFlagAndNavigateElseShowAlert() {
  // ...
}
```

That is a function name that almost describes everything happening in the function. But it's long. Maybe we can shorten it by extracting commonality from multiple steps and describing the common effect instead of every detail:

```tsx
validateAndClearSearchAndSaveNewSearchDataAndNavigate() {
  // ...
}
```

Now we could become philosophers and eventually come up with something that describes the overall *essence* of what's happening, but that would take a lot of time. So it's easy to understand why we're always naming event handlers by when they get called instead of by what they do. 

Another technique I've seen is to just pick our favorite behavior from the function and simply ignore everything else:

```tsx
  navigateBack() {
    this.store.deleteMovies();
    this.store.switchFlag(false);
    this.router.navigate(['/']);
  }
```

`navigateBack`? There seems to be more going on there. 

Again, this isn't the original developer's fault.

The problem is that all these things need to be done, but they have little in common with each other.

The problem is imperative code.

In an imperative app, events trigger event handlers, which are containers of imperative code. This imperative code is burdened with the responsibility of understanding and controlling features that often have nothing to do with the original event. The event handler requires an umbrella name that covers everything inside it. This can be so difficult that the best name for the function truly is something hollow, like `onSubmit`. 

Reactive code doesn't have this problem. 

I refactored that `onSubmit` code to be reactive and here is what some of the code became:

![URL Observable](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/09md9xu21e0wubinxc34.png)

Do you know how hard it was to come up with the name `url$`? Not hard at all. Because that's what it *is*. It might change over time, and it might be derived using other observables, but it still is just an observable of the URL. 

Reactive code is declarative, meaning, it declares all its own behavior instead of relying on other code to control it. When no code is reliant on other code to control it, everything can just be concerned with itself only. Nothing is burdened with downstream effects or concerns, so you never have to come up with names that include downstream effects or concerns.

# Conclusion

There are many reasons to program reactively. This is why the history of web development has followed an overall trend towards more and more reactivity. 

But it's taking a long time. Most developers are still confused about what reactivity even is. Some think that synchronous reactivity covers reactivity completely, forgetting that asynchronous code can also be reactive with tools like RxJS and React Query. 

So why is it taking developers so long to get on board with fully reactive programming?

I think it's because JavaScript developers are trained to code with an imperative mindset, because JavaScript 101 includes almost exclusively imperative APIs. I used to think all new developers should start with JavaScript 101, but I'm having second thoughts about that... What would a reactivity-first tutorial look like?

I also think it's hard to stray too far from the dominant style in the ecosystem you work in. For example, if you're using Angular Material and you notice that RxJS is tricky to work with whenever you use a dialog component, you might mistakenly blame RxJS for the bad experience instead of the [outdated API](https://dev.to/this-is-angular/wrapping-imperative-apis-in-angular-550b) for `MatDialog`.

For most developers, programming reactively will require a big shift in mindset. It will also require some tools and wrapper components.

But every feature I've refactored to reactivity has become simpler, less buggy and more performant.

So I think it's worth it.