Avoid Spaghetti Code using AppRun
Tags: apprun, javascript, frontend, webdev
Published: 2020-03-24 00:57:06

---
title: Avoid Spaghetti Code using AppRun
published: true
description: In the post, I will show you how AppRun can help to avoid spaghetti code
tags: #apprun #javascript #frontend #webdev
---

## Introduction

Recently I was asked to refresh an old application that has the so-called spaghetti code. There are different levels of problems. Many can be solved just refactoring to use new JavaScript language features such as using modules. However, two problems are hard to solve without the help of a framework, which I call them:

* Direct State Update
* Rendering Fragments

In the post, I will show you how [AppRun](https://apprun.js.org) can help to solve the problems. Therefore we can avoid spaghetti code.

## Example

I cannot show the real production code I am dealing with, so I made an abstracted example to demonstrate the problems. As usual, I am using a _counter_ example that has two buttons. One to increase the counter. The other one to decrease the _counter_. Also, I made it a litter complicated to show how many times each button is clicked.

![Counter](https://dev-to-uploads.s3.amazonaws.com/i/hdjy2w33ipeqdv9wxbea.png)


## Problem Code

The code below uses jQuery. jQuery is a library that provides the convenience to access and manipulation of the DOM. It does not provide any architectural guidance. jQuery code is similar to the vanilla JavaScript code that can go wild.

```javascript
$(function () {  

    // global state
    let count = 0
    let count_plus = 0
    let count_minus = 0

    function plus() {
      // state update
      count ++
      count_plus ++
      
      // rendering
      $('#total').html(count)
      $('#plus').html(`+ (${count_plus})`)
    }
    
    function minus() {
      // state update
      count --
      count_minus ++

      // rendering
      $('#total').html(count)
      $('#minus').html(`- (${count_minus})`)
    }
    
    $('#plus').on('click', plus)
    $('#minus').on('click', minus)

  })
```

You can see from the above code that event handlers _plus_ and _minus_ have the problem patterns. They update the state directly. They also render the DOM in different pieces. 

But the real problem is that there isn't a way to break them further. The state has to be shared globally. And the rendering has to be different in each click event.

In much more complicated real applications, the logic could be long and tangled even more. 

## AppRun

[AppRun](https://github.com/yysun/apprun) is the framework that can solve the two problems. 

> If you are new to AppRun, read the [AppRun Book](https://www.amazon.com/Practical-Application-Development-AppRun-High-Performance/dp/1484240685/) or visit [AppRun Docs](https://apprun.js.org).

### State Management

AppRun is a _state_ management system. It is also an event-driven system that has an event lifecycle. During an AppRun event lifecycle:

* AppRun let you update the _state_ when needed
* AppRun let you create a virtual DOM out of the _state_ when needed
* AppRun renders the virtual DOM when needed.

Sort of following the Hollywood Principle (Don't call us. We call you.) here, we provide code pieces to AppRun and wait for AppRun to call them. 

We write functions to update the _state_. AppRun gives the _current state_. We create a new _state_ based on the _current state_.

```javascript
const minus = (state) => ({ ...state,
  count: state.count - 1,
  count_minus: state.count_minus + 1
});

const plus = (state) => ({ ...state,
  count: state.count + 1,
  count_plus: state.count_plus + 1
});
```

We will be able to concentrate on the parts that are needed to update. We can spread out the rest of the _state_ using the spread operator. Also, because there is no reference to a shared global object, it is very easy to unit test the _state_ update logic.


### DOM Rendering

We also write a _view_ function that AppRun will call with the _state_ as the input parameter. We usually use JSX in the _view_ function to create a virtual DOM, which is just data structure. The _view_ function does not render the DOM. AppRun renders the DOM using a diffing algorithm. It only renders the DOM that is needed to change. Therefore, we only need one _view_ function for all events. AppRun takes care of the differential rendering accordingly.

```javascript
const view = ({ count, count_plus, count_minus }) => html`
  <h1>${count}</h1>
  <button onclick="app.run('minus')">- (${count_minus})</button>
  <button onclick="app.run('plus')">+ (${count_plus})</button>`
```

The _view_ function always returns the same result as long as the _state_ is the same. It also does not change the _state_ or anything outside the function, which means it has no side effects. We can make the _view_ function a _pure function_. There are many benefits of using _pure function_, including but not limited to the unit testing. It makes the UI code easy to unit test.
 
Using AppRun, we have a _counter_ application made from the _state, _view_, and _update_ as shown below.

```javascript
// initial state object
const state = {
  count: 0,
  count_plus: 0,
  count_minus: 0
}

// one view function to render the state, its' a pure function
const view = ({ count, count_plus, count_minus }) => html`
  <h1>${count}</h1>
  <button onclick="app.run('minus')">- (${count_minus})</button>
  <button onclick="app.run('plus')">+ (${count_plus})</button>
`

// collection of state updates, state is immutable
const plus = (state) => ({ ...state,
  count: state.count - 1,
  count_minus: state.count_minus + 1
});

const minus = (state) => ({ ...state,
  count: state.count + 1,
  count_plus: state.count_plus + 1
});

app.start(document.body, state, view, {plus, minus});
```

With the AppRun state management and DOM differential rendering in place, we no longer have the problem mixing state update with DOM rendering. 

Usually, at this moment, I will show you the live demo on glitch. This time, I will show the interactive notebook I made on observable HQ. I feel I like the notebook more and more.

https://observablehq.com/@yysun/apprun-helps-to-avoid-spaghetti-code

## Conclusion

No matter how complex the application is, we will always have three parts, the _state_, _view_, and _update_. We no longer mix the state update with DOM rendering. Because the three parts are totally decoupled, our codebase is so much easier to understand, test, and maintain.