# What is Ferp

Summary of what ferp is, and why you would want to use it.

## tl;dr

Simply put, [Ferp](https://github.com/ferp-js/ferp) is a Javascript library to functionally manage your application's state. The main attraction of Ferp is that side-effects and subscriptions take a front-row seat. Ferp also has no opinion on your end-interface, be it a command line application, server, desktop application, or front-end web application.

## Project Goals

#### Every interaction outside of your application is a side effect

Does your app generate a random number, get the current timestamp, or handle user input? If so, you are relying on side-effects. Side-effects, or simply effects, aren't bad at all, but they can make testing and logic hard. Ferp's update loop puts the power of controlled effects into the hands of every developer.

#### Effects should be composable

In most cases, effects cause other effects. For example, to add a notification in the browser, you must first ask permission. These are two separate side effects that should be able to be composed, something like `notifyPermit(notifySend('Holy notification, Batman!'))`. This pattern can prevent unnecessary update calls, and keeps side-effect producing code out of your state.

#### State has nothing to do with presentation

Much like many state management libraries that have come before, ferp has no preconceived notion of how you want to present your app. Use your favourite front-end or back-end library, or your custom one-of-a-kind solution. I would even argue that presentation is a form of a side-effect, since it often times modifies state outside of your applications control.

## Is Ferp Right for Your Project?

Ferp solves a certain combination of problems, but it does not claim to be the most correct way to solve these problems. The following table compares some of the key features of ferp to other popular libraries.

| Feature              | Ferp      | Redux         | Mobx          |
| -------------------- | --------- | ------------- | ------------- |
| State is...          | immutable | immutable     | mutable       |
| Update mechanism     | effects   | actions       | observables   |
| Number of stores     | single    | single        | multiple      |
| Side-effect support  | built-in  | plugins       | built-in      |
| Subscription support | functions | *redux-saga?* | *observables* |

Consider the problems your application is going to face, and evaluate all your options. This includes considering the libraries you may import, the existing code you have, and of course, the features you need.

## Links

* Check out the code over at [github.com/ferp-js/ferp](https://github.com/ferp-js/ferp)
* Learn more about me at my website, [mrbarry.com](https://mrbarry.com)


# Installing Ferp in Your Application

## Installing

Depending on your project, needs, and target audience, there are a number of ways to get up and running with Ferp within seconds.

### Installing from npm or yarn

You know the drill!

```bash
npm install --save ferp@^2
# OR
yarn add ferp@^2
```

And import Ferp into your code-base:

{% tabs %}
{% tab title="From es6/babel" %}

```javascript
import { app, effects } from 'ferp';
```

{% endtab %}

{% tab title="From NodeJS" %}
{% code title="index.js" %}

```javascript
const { app, effects } = require('ferp');
```

{% endcode %}
{% endtab %}
{% endtabs %}

If you are targeting a web browser, you may need to bundle or build your scripts, with something like [rollup](https://rollupjs.org/), [webpack](https://webpack.js.org/), or [parcel](https://parceljs.org/).

### Using a CDN

Of course, you don't need to install anything at all. Content delivery networks (CDNs) like unpkg work great!

{% tabs %}
{% tab title="Standard es5 javascript" %}
{% code title="index.html" %}

```markup
<script src="https://unpkg.com/ferp@2"></script>
```

{% endcode %}

```bash
const { app, effects } = window.ferp;
```

{% endtab %}

{% tab title="Modern Browsers" %}

```markup
<script type="module">
  import { app, effects, util } from 'https://unpkg.com/ferp?module=1';
</script>
```

{% endtab %}
{% endtabs %}

With a CDN, there is no install needed to get going. Of course, you may want to look into [Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers) if you want to support your application while offline.


# What Does Ferp Provide

An overview of exports in ferp

## app()

This is the entry point to your application. An application can be describe in three pieces, `init`, `subscribe`, and `observe`. Init is a **required** tuple of your initial data in the form of `[initialState, initialEffect]`. Subscribe is an **optional** function with the signature `(state) => [sub1, sub2, ...]`. Observe is an **optional** function with the signature `([currentState, currentEffect], action) => {}` and is used for debugging. These pieces all exist inside an object, and all together, they may look something like this:

{% code title="example.js" %}

```javascript
import { app, effects } from 'ferp';



const initialState = 1;

const Add = state => [state + 1, effects.none()];

const addSubcription = (dispatch, intervalInMs) => {
  const handle = setInterval(dispatch, intervalInMs, effects.act(Add));
  
  return () => {
    clearInterval(handle);
  };
};

const dispatch = app({
  init: [
    initialState,
    effects.none(),
  ],

  subscribe: (state) => [
    state < 10 && [addSubscription, 1000],
  ],
});
```

{% endcode %}

Don't worry if this looks scary, this guide will step you through each piece, and explain how they work.

Your call to app will also return a copy of dispatch. This is meant to be an escape hatch, but in all likelihood, you will never need it. If you're not sure if you need it, check out the [What is a Ferp Subscription?](/understanding-subscriptions-in-ferp/what-is-a-ferp-subscription) which covers 99% of the cases when you think you may need the app global dispatch method. The last 1% is probably for end-to-end testing of your application

## effects {}

Ferp, inspired by the likes of Elm's Cmd, exports a set of core effects that can be combined and composed to build powerful pieces of logic. Getting comfortable and familiar with these effects will enable you to use Ferp effectively.

Effects are a way to encapsulate code that affects out-of-app state. These are things like getting the system time, requesting permissions, accessing the file system, or handling user interaction.

There are a set of core effects that Ferp exposes as the effects object:

```javascript
import { effects } from 'ferp';

console.log(effects);
/*
{ none: [Function: none],
  batch: [Function: p],
  defer: [Function: q],
  thunk: [Function: r],
  act: [Function: s] }
*/
```

There are some other effects in that object, but we're not going to dive into those as much right here. Check out the [core effects](/understanding-effects-in-ferp/core-effects) documentation for more information!


# The Boilerplate

### Application Anatomy

Every ferp application uses the `app` function, and must have `init`, which declares your applications initial state, and any initial side effect. In the helloWorld example, there is no state, `null`, and a custom side effect that adds text to the html page or console, `writeEffect`.

#### init: \[state, effect]

```javascript
import { app, effects } from 'ferp';

const INITIAL_STATE = { counter: 1 };

app({ init: [INITIAL_STATE, effects.none()] });
```

The init key holds a special structure that is used everywhere in ferp. The state-effect tuple tells ferp what the next state should look like, and if there are any effects that need to be ran. The state can take on whatever shape you need it to, but it is pretty common to have large nested objects. This, however, will depend on what you need your application to do, and the data sources it uses. The second part of this tuple is the effect. You can read more about effects in the [Core Effects](/understanding-effects-in-ferp/core-effects) section. In this example, there's an effect that adds text to an HTML document, but more importantly, returns `effects.none()`, which tells ferp that we're done doing work until some other event triggers our application later.

#### subscribe: (state) => \[]

```javascript
import { app, effects } from 'ferp';

import mySubscription from './mySubscription.js';

const INITIAL_STATE = { counter: 1 };

app({
  init: [INITIAL_STATE, effects.none()],
  
  subscribe: (state) => [mySubscription, state.counter < 10]
});
```

This method lets you run subscriptions, which are long-running effects that react to state by starting, restarting, or stopping. Subscriptions are great ways to interact with third-party objects, like websockets, dom watching mechanisms, or other event-based long-running tasks. You can read more about them in the [What is a Ferp Subscription?](/understanding-subscriptions-in-ferp/what-is-a-ferp-subscription) section.

#### observe: (\[currentState, currentEffect], actionAnnotation) => {}

```javascript
import { app, effects } from 'ferp';

const INITIAL_STATE = { counter: 1 };

const incrementCounter = (state) => [
  { counter: state.counter + 1 },
  effects.none(),
];

app({
  init: [INITIAL_STATE, effects.act(incrementCounter)],
  
  observe: ([state, effect], annotation) => {
    console.groupCollapsed(annotation, state);
    console.log(effect);
    console.groupEnd();
  }
});
```

Observe is an optional app property that lets you see the current state and effect being ran, as well as the action that triggered it (if available). This can be a great way to react to every state change, and not just the changes a subscription would see. For example, if you write a canvas application that must draw after every state update, putting the draw logic in observe may be what you're looking for. Another example would be for an application debug tool, where you output the current state, action, and effects being ran.

#### const dispatch = app({ ... })

```javascript
import { app, effects } from 'ferp';

const INITIAL_STATE = { counter: 1 };

// Action
const incrementCounter = (state) => [
  { counter: state.counter + 1 },
  effects.none(),
];

// Action-creator
const incrementCounterBy = (amount) => (state) => [
  { counter: state.counter + amount },
  state.none();
];

const dispatch = app({
  init: [INITIAL_STATE, effects.none()],
});

dispatch(incrementCounter); // Dispatch an action
dispatch(incrementBy(5), 'incrementBy'); // Dispatch an action creator, with an annotation
```

Dispatch is how you run new actions to update your state and run additional side effects, and allows subscriptions to react to your state changes. You can call dispatch from anywhere with any action-function. Dispatch can take an action or an action creator, and an optional action annotation. Annotations can be handle for action creators, which don't have function names by default.

## The Counter App

{% tabs %}
{% tab title="counter.browser.js" %}

```javascript
import { app, effects } from 'https://unpkg.com/ferp?module=1';

const createElement = (tag, id, text) => {
  const element = document.createElement(tag);
  element.id = id;
  element.innerText = text;
  return element;
};

document.body.appendChild(createElement('h1', 'value', '0'));
document.body.appendChild(createElement('button', 'incr', '+1'));
document.body.appendChild(createElement('button', 'decr', '-1'));

const elementSetTextEffect = (elementId, text) => effects.thunk(() => {
  const element = document.getElementById(elementId);
  if (element) {
    element.innerText = text.toString();
  }
  
  return effects.none();
});
const elementSetText = (elementId) => function elementSetTextAction(state) { return [
  state,
  elementSetTextEffect(elementId, state.toString()),
]; };

const Incr = (state) => [state + 1, effects.act(elementSetText('value'))];
const Decr = (state) => [state - 1, effects.act(elementSetText('value'))];

const elementClickSubscription = (dispatch, elementId, clickAction) => {
  const callback = (event) => {
    dispatch(clickAction, `click:${elementId}`);
  };
  
  const element = document.getElementById(elementId);
  element.addEventListener('click', callback);
  
  return () => {
    element.removeEventListener('click', callback);
  };
};

const initialState = 0;

app({
  init: [
    initialState,
    effects.act(elementSetText('value'))
  ],
  
  subscribe: () => [
    [elementClickSubscription, 'incr', Incr],
    [elementClickSubscription, 'decr', Decr],
  ],
});
```

{% endtab %}

{% tab title="counter.cli.js" %}

```javascript
import { app, effects } from 'ferp';

const writeEffect = (value) => effects.thunk(() => {
  console.log(value);
  return effects.none();
});

const delayEffect = (milliseconds, nextEffect) => effects.thunk(() => (
  effects.defer(new Promise((resolve) => {
    setTimeout(resolve, milliseconds, nextEffect);
  }))
));

const Tick = (state) => {
  const times = state.times - 1;
  const value = state.value + state.changeBy;
  
  return [
    { ...state, times, value },
    effects.batch([
      writeEffect(value),
      times > 0
        ? delayEffect(state.delay, effects.act(Tick))
        : effects.none(),
    ]),
  ];
};

const initialState = {
  value: 0,
  changeBy: 1,
  times: 10,
  delay: 30,
};

const dispatch = app({
  init: [initialState, effects.none()],
});

dispatch(Tick);

/*
// Could also be written as:

app({
  init: [initialState, effects.act(Tick)],
});
*/
```

{% endtab %}
{% endtabs %}


# What is a Ferp Effect?

## Effects

A side-effect, or simply effect, is a way of talking the world outside of your Ferp application. Effects will always be a composition of the [Core Effects](/understanding-effects-in-ferp/core-effects).

You effects may look something like:

{% code title="effectExamples.js" %}

```javascript
import { effects } from 'ferp';

const MyAction = (state) => [state, effects.none()];

const exampleEffects = {
  effect1: effects.thunk(() => effects.none()),
  effect2: effects.defer(1234),
  effect3: effects.act(MyAction),
};
```

{% endcode %}

Ultimately, you will want to compose your effects to be consistent, meaningful, and easy to use.

### The Inside World

When we talk about your application, there are essentially two contexts, or worlds. The first is the inside world. This is anything that lives inside of your application state. To be even more strict, it's anything in your application state that can also be serialized. This doesn't mean that your state has to be capable of being serialized to JSON or similar, but that pieces that are serializable are the inside world parts of your application. Things in the inside world are easily used, manipulated, and tested through actions.

### The Outside World

&#x20;There are some things that are obviously the outside world, and some that are less obvious; we should probably discuss what belongs in an effect.

Some obvious examples of the outside world are external servers and processes. To talk to them, maybe you use fetch, a file, or an IPC channel. There is a very clear boundary between your Ferp application and another application or server. Some less obvious examples are local files, accessing the system clock, generating a random number. More strictly, even modules you import in your files are in some sense a side-effect.

## Talk to the Outside World in Isolation

While in some sense, the outside world is a scary place, filled with uncertainty and chaos, using Ferp's [Core Effects](/understanding-effects-in-ferp/core-effects) forces these communication channels to be isolated from harming our precious application.


# Core Effects

The basic effects that Ferp provides to help you build better software

### effects.none()

The none effect is very simple, there is no effect. Use this effect to tell your app there is nothing to do after an update. All arguments passed to it are ignored, and your update function will not be called.

### effects.defer(promiseLike)

A deferred promise is a great way to connect things like timers, http requests, and other asynchronous code to your update loop. There is a hitch, though - deferred effects should **never** throw an error. This means that if your effect has the chance of causing a run-time error, it **must** be caught inside your `effects.defer` call, and an alternative effect should be returned. Here is an example of a bad deferred effect:

{% code title="badDeferredEffect.js" %}

```javascript
import { effects } from 'ferp';

const fetchEffect = (url, options, okEffect) => effects.defer(
  fetch(url, options)
    .then(response => response.json())
    .then(okEffect)
);

// Usage:

fetchEffect(
  'https://jsonplaceholder.typicode.com/posts',
  undefined,
  (json) => ({ type: 'httpSuccess', json }),
);
```

{% endcode %}

What happens if this fetch fails? It will throw an exception, and crash your app. To counter-act this, provide an explicit error effect:

{% code title="goodDeferredEffect.js" %}

```javascript
import { effects } from 'ferp';

const fetchEffect = (url, options, okEffect, errorEffect = effects.none) => effects.defer(
  fetch(url, options)
    .then(response => response.json())
    .then(okEffect)
    .catch(errorEffect)
);


// Usage:

fetchEffect(
  'https://jsonplaceholder.typicode.com/posts',
  undefined,
  json => ({ type: 'httpSuccess', json }),
  error => ({ type: 'httpFailure', error }),
);

```

{% endcode %}

This provides your app with a reasonable way to manage the error without being opinionated.

The `defer` effect can also be used to wait a single tick, so something like `defer(act(YourAction))`will allow the application to finish it's current tick and other queued work.

And one last ease of use, you can pass a Promise constructor function directly, like `defer((resolve, reject) => {})` to avoid the overly verbose `defer(new Promise((resolve, reject) => {}))` version, but both are valid.

### effects.thunk(() => effect)

Thunks are a way to prevent side-effect code from running until the effects manager processes the effect. This is great for isolating your effects, like a call to `console.log` , but can also be used to defer a promise or a desired synchronous batch behavior. A great example use case for a thunk is chaining a series of timeouts. Consider the following example:

{% code title="badDelayEffect.js" %}

```javascript
import { effects } from 'ferp';

const delay = (milliseconds, effect) => effects.defer(new Promise((resolve) => {
  setTimeout(() => resolve(effect()), milliseconds);
}));

delay(1000, () => effects.batch([
  'first timer done',
  delay(1000, () => 'second timer done'),
]));
```

{% endcode %}

You might expect something like `/* wait 1 second */, 'first timer done', /* wait 1 second */, 'second timer done'`, but in reality, it will be `/* wait 1 second */, 'first timer done', 'second timer done'`. This is because the promises are kicked off immediately, before the effect manager handles them. In some cases, like non-dependent http requests, this is great, but for chaining timers, it is not. The solution, as you might have guessed, is wrapping our delay effect in a thunk, just like this:

{% code title="goodDelayEffect.js" %}

```javascript
import { effects } from 'ferp';

const delay = (milliseconds, effect) => effects.thunk(() => effects.defer(new Promise((resolve) => {
  setTimeout(() => resolve(effect()), milliseconds);
})));

delay(1000, () => effects.batch([
  'first timer done',
  delay(1000, () => 'second timer done'),
]));
```

{% endcode %}

Now each delay waits until it is called, with a 1 second timeout before each message. Thunks are a great tool for effect flow control.

### effects.batch(arrayOfEffects)

Batch is the other powerful flow control tool for effects. Often times, an update will only need to do a single effect, but this is not the only case. Batching effects gives you the opportunity to run multiple side effects from a single action or dispatch, and in order.

### effects.act(actionFunction, alias)

Sometimes as a result of an action, or inside another effect, you'll want to invoke an action to update the state. Actions can take two basic forms, and as a result, `effects.act` has two ways of being called.

The first form of an action is one that purely uses state. That means it takes no values from any other place, and should always be a pure function. Let's take a look:

```javascript
import { effects } from 'ferp';

const PureStateActionIncrementState = (state) => [state + 1, effects.none()];

effects.act(PureStateActionIncrementState);
```

These may be effects that are constant, such as the `+ 1` implementation seen above.

The second form of action takes values from another source. For instance, you may use these to bring information from the outside work (an effect) into your application state. These types actions look like this:

```javascript
import { effects } from 'ferp';

const ValueActionIncrementState = (amount) => (state) => [state + amount, effects.none()];

effects.act(ValueActionIncrementState(1), 'ValueActionIncrementState');
```

While these two examples achieve the same result, the second example is able to use outside world information to update your application.


# Composing Custom Effects

### Being composable

Use the core effects is meant to be easy. That's because they are composable, which means you could nest the effects inside each other. For example, if you want to run an action through a thunk and promise, you could easily write:

```javascript
effects.thunk(() => (
  effects.defer((resolve) => {
    resolve(effects.act((state) => [state, effects.none()]);
  })
))
```

Of course, if you do this frequently, it's probably a good time to wrap up the common pattern in a custom effect.

## Composing Complex Effects

Let's start off with a larger effect, one that I actually wrote for a demo project, and we'll go through the refactoring steps I had to making this two composable and powerful effects.

{% code title="noncomposableNotificationEffect.js" %}

```javascript
import { effects } from 'ferp';

export const notificationEffect = (title, body) => effects.defer(
  Notification.requestPermission()
    .then((result) => {
      if (result === 'granted') {
        const notification = new Notification(title, { body });
      }
    })
    .catch(() => {})
    .then(() => {
      return effects.none();
    });
);

// usage: notificationEffect('Ferp.JS', 'Hello world!');
```

{% endcode %}

This is not awful, but it's also not great. There is no way to react to different permission settings, and the permission request is locked to showing individual notifications. My first refactor was to separate out the permission request from the actual notification:

{% code title="notificationEffects.js" %}

```javascript
import { effects } from 'ferp'

export const notificationPermissionEffect = (
  grantEffect,
  denyEffect = effects.none,
  dismissEffect = effects.none,
  errorEffect = effects.none
) => effects.defer(
  Notification.requestPermission()
    .then((result) => {
      switch (result) {
        case 'granted':
          return grantEffect();
        case 'denied':
          return denyEffect();
        default:
          return dismissEffect();
      }
    })
    .catch(errorEffect)
);

export const notificationEffect = (title, body) => notificationPermissionEffect(
  () => effects.none(new Notification(title, { body })),
);

// usage: notificationEffect('Ferp.JS', 'Hello world');
```

{% endcode %}

That feels better and keeps the same signature as the first, but the notification effect will eat permission denied, dismissed and error, and it's limited in how I can react to the notification further. Let's explore an alternative composition:

{% code title="composableNotificationEffects.js" %}

```javascript
import { effects } from 'ferp'

export const notificationPermissionEffect = (
  grantEffect,
  denyEffect = effects.none,
  dismissEffect = effects.none,
  errorEffect = effects.none
) => effects.defer(
  Notification.requestPermission()
    .then((result) => {
      switch (result) {
        case 'granted':
          return grantEffect();
        case 'denied':
          return denyEffect();
        default:
          return dismissEffect();
      }
    })
    .catch(errorEffect)
);

export const notificationEffect = (title, options = {}, resultEffect = effects.none) => effects.thunk(() =>
  resultEffect(new Notification(title, options))
);

// Usage:
// notifiationPermissionEffect(notificationEffect('Ferp.JS', { body: 'Hello world!' }))
```

{% endcode %}

This is a little more dense, but it offers the greatest flexibility. It would be easy to compose a message effect to store the notification in the state to react to it's events in a subscription. That could look like this:

{% code title="notificationExample.js" %}

```javascript
import { app, effects, sub } from 'ferp';
import { notificationPermissionEffect, notificationEffect } from './composableNotificationEffects.js';

const INITIAL_STATE = {
  notifications: [],
};

const NotificationAdd = (notification) => (state) => [
  { ...state, notifications: state.notifications.concat(notification) },
  effects.none(),
];

const NotificationRemove = (notification) => (state) => [
  { ...state, notifications: state.notifications((n) => n !== notification) },
  effects.none(),
];

const NotificationCreate = (title) => (state) => [
  state,
  notificationEffect(title, undefined, (notification) => effects.act(NotificationAdd, notification)),
];

const delayEffect = (timeout, nextEffect) effects.thunk(() => effects.defer((resolve) => {
  setTimeout(resolve, timeout, nextEffect);
});

const notificationSubscription = (notification, onInteract) => (dispatch) => {
  const onClose = (event) => {
    dispatch(onInteract(notification));
  };
  
  const onClick = (event) => {
    dispatch(onInteract(notification));
  };
  
  notification.addEventListener('click', onClick);
  notification.addEventListener('close', onClose);
  
  return () => {
    notification.removeEventListener('click', onClick);
    notification.removeEventListener('close', onClose);
  };
};


app({
  init: [
    INITIAL_STATE,
    effects.batch([
      notifyEffect('First Notification'),
      delayEffect(1000, () => effects.batch([
        notifyEffect('Second Notification')),
        delayEffect(3000, () => notifyEffect('Third Notification')),
      ]),
    ]),
  ],
  subscribe: (state) => [
    ...state.notifications.map(notification => sub(
      notificationSubscription,
      notification,
      NotificationRemove,
    )),
  ],
});
```

{% endcode %}


# Testing Your Effects

## The Problem

The problem you will initially run into is this: I just want to test an effect, but I don't know how to run the effect on its own. Well, maybe you don't need to run the effect in isolation, and run it through a test app. This will keep your test reflecting the reality of how it is used, while also helping you isolate how the effect affects the state.

## The Solution: End to End

Let's take the Custom Effects section example of notificationPermission and notification effects.

{% code title="notificationEffects.js" %}

```javascript
import { effects } from 'ferp'

export const notificationPermissionEffect = (
  grantEffect,
  denyEffect = effects.none,
  dismissEffect = effects.none,
  errorEffect = effects.none
) => effects.defer(
  Notification.requestPermission()
    .then((result) => {
      switch (result) {
        case 'granted':
          return grantEffect();
        case 'denied':
          return denyEffect();
        default:
          return dismissEffect();
      }
    })
    .catch(errorEffect)
);

export const notificationEffect = (title, options = {}, resultEffect = effects.none) => effects.thunk(() =>
  resultEffect(new Notification(title, options))
);
```

{% endcode %}

In this case, we have some browser specific code (ie the Notification class), so we'll just make a global/controllable mock for it. If you are building a browser-based ferp app, you may want to look into a modern browser based test framework. Let's set up a test using describe/it blocks, similar to what you'd seen in mocha or jest:

{% code title="notificationEffects.test.js" %}

```javascript
import { app, effects } from 'ferp';
import { notificationPermissionEffect, notificationEffect } from './notificationEffects.js';

describe('Notification effects', () => {
  describe('notificationPermissionEffect', () => {
    const injectNotificationClass = (permissionResponse) => {
      global.Notification = class {
        static requestPermission() {
          return permissionResponse;
        }
      }
    };
    
    afterEach(() => {
      delete global.Notification;
    });
    
    const createTestApp = (onComplete) => {
      const setterEffect = (value) => () => value;
      const detach = app({
        init: [
          null,
          notificationPermissionEffect(
            setterEffect('grantEffect'),
            setterEffect('denyEffect'),
            setterEffect('dismissEffect'),
            setterEffect('errorEffect'),
          ),
        ],
        update: (message, state) => {
          onComplete(message);
          detach();
          return [state, effects.none()];
        },
      });
      
    };
    
    it('calls the grantEffect', (done) => {
      injectNotificationClass(Promise.resolve('grant'));
      createTestApp((whichEffect) => {
        expect(whichEffect).toBe('grantEffect');
        done();
      });
    });

    it('calls the denyEffect', (done) => {
      injectNotificationClass(Promise.resolve('deny'));
      createTestApp((whichEffect) => {
        expect(whichEffect).toBe('denyEffect');
        done();
      });
    });

    it('calls the dismissEffect', (done) => {
      injectNotificationClass(Promise.resolve('dismiss'));
      createTestApp((whichEffect) => {
        expect(whichEffect).toBe('dismissEffect');
        done();
      });
    });

    it('calls the errorEffect', (done) => {
      injectNotificationClass(Promise.reject());
      createTestApp((whichEffect) => {
        expect(whichEffect).toBe('errorEffect');
        done();
      });
    });
  });

  describe('notificationEffect', () => {
    const injectNotificationClass = () => {
      global.Notification = class {
        constructor(title, options) {
          this.constructorArgs = [title, options];
        }
      }
    };
    
    afterEach(() => {
      delete global.Notification;
    });
    
    const createTestApp = (title, options, onComplete) => {
      app({
        init: [
          null,
          notificationEffect(title, options, onComplete),
        ],
      });
      
    };
    
    it('creates a notification', (done) => {
      injectNotificationClass();
      createTestApp('Hello world', { body: 'From Ferp.JS' }, (notification) => {
        expect(notification).toBeInstanceOf(Notification);
        expect(notification.constructorArgs).toEqual(['Hellow world', { body: 'From Ferp.JS' }]);
        done();
        return effects.none();
      });
    });
  });
});
```

{% endcode %}


# What is a Ferp Action?

## Actions

Actions are the only way to initiate new state changes and side-effects in Ferp. State changes must be complete and immutable, and side effects must always be declared, even if there are no side-effects. Actions are always pure functions that return `[state, sideEffect]`, and pure meaning it does not use any data not immediately accessible to the action. On the contrary, an invalid action would use things like `Math.random()` or `Date.now()`, which are external to the action function.

## Types of Actions

### Naked Action

Plain, or naked, actions are actions that need no parameters. For instance, a naked action could be something that only updates a single state property by incrementing it by 1. Let's see what that looks like:

```javascript
import { effects } from 'ferp';

const IncrementCounterByOne = (state) => [
  { ...state, counter: state.counter + 1 },
  effects.none(),
];
```

Depending on the shape of your state, you may find naked actions to be very fitting.

There are two ways to call an action, and here they are:

```javascript
import { app, effects } from 'ferp';

const IncrementCounterByOne = (state) => [
  { ...state, counter: state.counter + 1 },
  effects.none(),
];

const dispatch = app({
  init: [
    { counter: 0 },
    effects.act(IncrementCounterByOne), // run an action via effect
  ],
});

dispatch(IncrementCounterByOne); // run an action via dispatch
```

### Action Builder

Action builders are actions that can take parameters. This may mean a value can be passed from user input, or from some other external side-effect. Using the previous counter example, here's what it would look like if it took external input for the increment amount:

```javascript
import { effects } from 'ferp';

const IncrementCounterByN = (n) => (state) => [
  { ...state, counter: state.counter + n },
  effects.none(),
];
```

Similar to naked actions, there are two ways to run this action in your application:

```javascript
import { app, effects } from 'ferp';

const IncrementCounterByN = (n) => (state) => [
  { ...state, counter: state.counter + n },
  effects.none(),
];

const dispatch = app({
  init: [
    { counter: 0 },
    effects.act(IncrementCounterByN(10)), // run a builder action via effect
  ],
});

dispatch(IncrementCounterByN(999)); // run a builder action via dispatch
```

If you're not sure how the builder works, this is just a function that returns a function. Here's probably a more familiar version to read:

```javascript
import { effects } from 'ferp';

function IncrementCounterByNBuilder(n) {
  return function IncrementCounterByNAction(state) {
    return [
      { ...state, counter: state.counter + n },
      effects.none(),
    ];
  };
};
```

This is called a closure, and it's used in Javascript to encapsulate a scope. For instance, the variable `n` is available in the inner function (`IncrementCounterByNAction`), but `n` is not available outside of this closure (`IncrementCounterByNBuilder`).

To make this easier to understand, once we have this builder that returns an action, internally, Ferp does something like this:

```javascript
// You call...
dispatch(IncrementCounterByNBuilder, 999);

// Ferp does...
const yourAction = IncrementByNBuilder(999);
dispatch(yourAction);
```


# Writing Your Own Actions

Actions are absolutely tied to your application, but good news, they are just basic functions, so they are easy to write. Check out this very simple action:

```javascript
const SimpleAction = (state) => [state, effects.none()];
```

Sure, it doesn't do anything, but it's an action!

## Actions with Side-Effects

{% hint style="info" %}
If you haven't already read about [Composing Custom Effects](/understanding-effects-in-ferp/custom-effects), go check out that section before continuing.
{% endhint %}

Up until this point, we've mostly dealt with basic actions that have no side-effects. More good news, actions always return a state and a **single** (side) effect. Yes, a valid side effect is `effects.none()`, meaning no side effect.

As you would expect from the examples so far, writing an effect into an action is simple:

```javascript
import { effects } from 'ferp';

const MyEffect = (text) => effects.thunk(() => {
  console.log('MyEffect', text);
  return effects.none();
});

const IncrementCounterAndPrint = (state) => [
  { ...state, counter: state.counter + 1 },
  MyEffect('incremented'),
];
```

## Best Practices

### Actions import Effects, Effects accept Action parameters

One thing I found immediately while writing state management with actions and effects is it is incredibly easy to have issues with circular dependencies.  For instance, often times actions can trigger effects, and those effects may trigger more actions. If your actions and effects are in separate files, how do you import things to prevent Node from having a circular dependency? The formula that works for me is letting my actions module import any and all effect modules, but forcing effect methods to have actions passed to them. Here's an example of how that can look:

{% tabs %}
{% tab title="actions.js" %}

```javascript
import { effects } from 'ferp';
import * as todoFx from './todoFx.js';

export const AddTodo = (todo) => (state) => [
  { ...state, todos: state.todos.concat(todo) },
  effects.none(),
];

export const RequestTodo = (todoId) => (state) => [
  state,
  todoApi.getTodo(state.external.fetch, todoId, AddTodo),
];
```

{% endtab %}

{% tab title="todoFx.js" %}

```javascript
import { effects } from 'ferp';

export const getTodo = (fetchFn, id, onSuccess, onFailure) => effects.defer(
  fetchFn(`https://jsonplaceholder.typicode.com/todos/${id}`)
    .then(response => response.json())
    .then(data => effects.act(onSuccess(data)))
    .catch((err) => (
      onFailure
        ? effects.act(onFailure(err))
        : effects.none()
    ))
);
```

{% endtab %}
{% endtabs %}


# Testing Actions

## State Change

Testing for a state change is easy, and you can just run your action like a function.

```javascript
import { effects } from 'ferp';

const IncrementCounter = state => [
  { ...state, counter: state.counter + 1 },
  effects.none(),
];

describe('IncremenetCounter', () => {
  it('increments the counter state variable', () => {
    const initialState = { counter: 0 };
    
    const [state, _effect] = IncrementCounter(initialState);
    
    expect(state).toDeepEqual({
      counter: 1,
    });
  });
});
```

Testing action builders is very similar, too:

```javascript
import { effects } from 'ferp';

const IncrementCounterByN = n => state => [
  { ...state, counter: state.counter + n },
  effects.none(),
];

describe('IncremenetCounterByN', () => {
  it('increments the counter state variable using the provided value', () => {
    const initialState = { counter: 0 };
    
    const [state, _effect] = IncrementCounterByN(999)(initialState);
    
    expect(state).toDeepEqual({
      counter: 999,
    });
  });
});
```

## Result of Side-Effects

Testing that the correct side effects can be a little more tricky. The problem is that effects touch the outside world that is not controlled by Ferp. Running these end-to-end just like the effect testing is likely your best bet.

{% tabs %}
{% tab title="actions.spec.js" %}

```javascript
import * as sinon from 'sinon';
import { app } from 'ferp';

import * as actions from './actions.js';

describe('RequestTodo', () => {
  it('does not modify the state', () => {
    const initialState = { todos: [], externals: { fetch: window.fetch } };
    
    const [state] = actions.RequestTodo(1)(initialState);
    
    expect(state).toBe(initialState);
  });
  
  it('successfully fetches a todo', (done) => {
    const expectedTodo = { id: 1, text: 'foo', completed: false };
    const fakeFetch = sinon.fake((arg) => {
      return {
        json: Promise.resolve(expectedTodo)
      };
    });
    const initialState = { todos: [], externals: { fetch: fakeFetch } };
    
    const expectedTodosInOrder = [
      [], // init
      [], // request
      [expectedTodo], // on success
    ];
    
    app({
      init: actions.RequestTodo(expectedTodo.id)(initialState),
      observe: ([state, effect]) => {
        expect(state.todos)
          .toDeepEqual(expectedTodosInOrder.unshift());
          
        if (expectedTodosInOrder.length === 0) {
          done();
        }
      },
    });
  });
});
```

{% endtab %}

{% tab title="actions.js" %}

```javascript
import { effects } from 'ferp';
import * as todoFx from './todoFx.js';

export const AddTodo = (todo) => (state) => [
  { ...state, todos: state.todos.concat(todo) },
  effects.none(),
];

export const RequestTodo = (todoId) => (state) => [
  state,
  todoApi.getTodo(state.external.fetch, todoId, AddTodo),
];
```

{% endtab %}

{% tab title="todoFx.js" %}

```javascript
import { effects } from 'ferp';

export const getTodo = (fetchFn, id, onSuccess, onFailure) => effects.defer(
  fetchFn(`https://jsonplaceholder.typicode.com/todos/${id}`)
    .then(response => response.json())
    .then(data => effects.act(onSuccess(data)))
    .catch((err) => (
      onFailure
        ? effects.act(onFailure(err))
        : effects.none()
    ))
);
```

{% endtab %}
{% endtabs %}

Yes, that test code looks clunky, so why not make a helper to make things a little easier?

{% code title="support/endToEndTest.js" %}

```javascript
import { app } from 'ferp';

export const endToEndTest = (init, assertions, done) => app({
  init,
  observe: (...args) => {
    const assertion = assertions.unshift();
    assertion(...args);
    if (assertions.length === 0) {
      done();
    }
  },
});
```

{% endcode %}

Which would result in:

{% tabs %}
{% tab title="actions.spec.js" %}

```javascript
import { endToEndTest } from './support/endToEndTest.js';

// ...

  it('successfully fetches a todo', (done) => {
    const expectedTodo = { id: 1, text: 'foo', completed: false };
    const fakeFetch = sinon.fake((arg) => {
      return {
        json: Promise.resolve(expectedTodo)
      };
    });
    const initialState = { todos: [], externals: { fetch: fakeFetch } };
    
    endToEndTest(
      actions.RequestTodo(expectedTodo.id)(initialState),
      [
        ([state]) => expect(state.todos).toDeepEqual([]), // init
        ([state]) => expect(state.todos).toDeepEqual([]), // request
        ([state]) => expect(state.todos).toDeepEqual([expectedTodo]), // on success
      ],
      done
    );
  });
```

{% endtab %}
{% endtabs %}

There may be other forms of helpers that can make the end-to-end portions of your tests to be more readable and manageable.


# What is a Ferp Subscription?

## The Basics

Now that you understand ferp effects, subscriptions are the next key thing to understand. An effect is a great way to grab a single bit of external data, but subscriptions are a way to grab that information over time. Some great examples would be browser DOM events like keyboard presses, web socket listeners, or intervals that you want to react to. Your subscriptions will look something like this:

{% code title="subscriptionBoilerplate.js" %}

```javascript
import { app, effects } from 'ferp';

const yourIntervalSubscription = (dispatch, interval, intervalAction) => {
  const handle = setInterval(
    () => dispatch(intervalAction),
    interval,
  );
  
  return () => {
    clearInterval(handle);
  };
};

// And to use it:

app({
  init: [
    { someBooleanValue: false },
  ],
  subscribe: (state) => [
    [yourSubscription, 1000, effectFunctionA],
    [yourSubscription, 3000, effectFunctionB],
    state.someBooleanValue && [yourSubscription, 1000, effectFunctionC],
  ],
});
```

{% endcode %}

There are three very important things to understand about subscriptions from the demo.

1. **Subscriptions always clean up after itself**. The last function in the chain is the remove function. This is called either when your subscription is removed from the subscribe array, or when the application is detached. Not cleaning up timers, listeners, and other callbacks ran by third parties can result in unpredictable code.
2. **Subscriptions are created via array**. The array consists of `[aSubscriptionFunction, ...argumentsForSubscription]`. This allows subscriptions to be memoized internally, and also for the subscription to receive dispatch in the second method.
3. **Subscriptions are a function of state, thus can be disabled by state changes**. Every call to update will reactively call subscribe. One way to disable subscriptions is through boolean toggles. If the value is truthy, the subscription will be handled by the app, and if it is falsy, it will be cleaned up and removed.
4. **Subscriptions cannot destroy themselves**. A subscription can signal to the application that it's done, but it cannot otherwise forcibly destroy itself.

## The Subscribe Array

As noted above, subscriptions are an array of arrays. The top level array is the list of subscriptions. The secondary arrays are the signatures; the first signature item is the subscription function, and the following are its arguments.

We also learned the in the above section that subscriptions can be disabled using boolean operations. We can also disable subscriptions by removing them completely from the array. You'll likely run into this situation if you have an array of items in state that require subscriptions:

{% code title="stateArrayForSubscriptions.js" %}

```javascript
import { app, effects } from 'ferp';

const clickSubscription = (dispatch, selector, clickAction) => {
  const elements = Array.from(
    document.querySelectorAll(selector),
  );
  
  const onClick = (event) => {
    dispatch(clickAciton(event));
  }
  
  elements.forEach((element) => {
    element.addEventListener('click', onClick);
  });
  
  return () => {
    elements.forEach((element) => {
      element.removeEventListener('click', onClick);
    });
  };
};

const ClickAction = (event) => (state) => [
  { ...state, mouse: { x: event.clientX, y: event.clientY } },
  effects.none(),
];

const initialState = {
  mouse: { x: 0, y: 0 },
  domQuerySelectors: ['button.with-click', 'a.with-click'],
};

app({
  // init: [],
  
  subscribe: (state) => [
    ...state.domQuerySelectors.map(selector => (
      [clickSubscription, selector, myEffectGenerator]
    )),
  ]
});
```

{% endcode %}

As the application runs, update may or may not change the `domQuerySelectors` array, which will result in some subscriptions being dropped, which will clean them up as expected.

## When to use a subscription

A subscription is something that gives you output uncontrollably. By this, I mean things like a DOM event, and more specifically, let's say a button click. Your application cannot control *when* a button click can happen, but it's probably data that you want your application to consume. Typically if the interface your using has a pattern similar to `addEventListener(a)`/`removeEventListener(a)`, `on(a)`/`off(a)`, or `const unsubscribe = thing.listen(a)`, that's a good sign that a subscription is a good fit.


# Composing Custom Subscriptions

## Writing a Subscription

### The Basics

The most basic subscription looks like this:

```javascript
const myCoolSubscription = (dispatch, ...yourArgsHere) => {
  // Do your stuff here
  
  return () => {
    // Clean your stuff up here
  };
};
```

If this doesn't do everything you want, we can definitely add some arguments:

```javascript
const myCoolSubscription = (dispatch, a, b) => {
  // Do your stuff here with a and b
  
  return () => {
    // Clean your stuff up here
  };
};
```

This is all well and good, but there is a hitch - your parameters need to be consistent. If you are dynamically creating an object, or pass in different values, your subscription will be reset. One thing about subscriptions is they introduce one-way communication, being that you set a few defaults to initialize the subscription, but all other communication is from the subscription back into the application.

### Smart Subscription Parameters

One very important detail to remember with subscriptions is a change in parameters will do a clean up of the old subscription and rebuild a new one. This means a change in value or reference. This means changing a value from `0` to `1`, `'hello'` to `'goodbye'`, or passing an inline function like `() => 'foo'`. Knowing when it's a good time to change these values to rebuild subscriptions can be hard, and knowing how to keep the same reference is equally hard. Here's an example of a bad subscription:

```javascript
const { app, effects } = require('ferp');

const tickEffect = () => ({ type: 'tick' });

const tickSubscription = (dispatch, delay) => {
  console.log('Create tick sub every', delay, 'milliseconds');
  const handle = setInterval(effects.thunk, delay, tickEffect);
  
  return () => {
    console.log('Destroy tick sub every', delay, 'milliseconds');
    clearInterval(handle);
  };
}

app({
  init: [{}, effects.none()],
  subscribe: state => [
    [tickSubscription, (Math.random() * 1000) + 1000], // Hmmmm
  ],
});
```

This is bad because the result of `(Math.random() * 1000) + 1000` will be different every time it is calculated (which will be every update), and as a result, will forcibly clean up the previous subscription and create a new subscription every application action that is ran.

If you want a consistent calculated value, you should put it in state. To do this with the above example, it would look like:

```javascript
const { app, effects } = require('ferp');


const tickSubscription = (dispatch, delay) => {
  console.log('Create tick sub every', delay, 'milliseconds');
  const handle = setInterval(effects.thunk, delay, tickEffect);
  
  return () => {
    console.log('Destroy tick sub every', delay, 'milliseconds');
    clearInterval(handle);
  };
}

app({
  init: [{ delay: (Math.random() * 1000) + 1000 }, effects.none()],
  subscribe: state => [
    [tickSubscription, state.delay], // That's better!
  ],
});
```


# Testing Your Subscriptions

## Run it like a Function

Since subscriptions are just functions, you should easily be able to execute them. The signature of every subscription is `(...params) => (dispatch) => cleanUpFn`, so we know how to get the code to execute, and how to stop it, so what's preventing us from doing that? Let's take this subscription as an example:

{% code title="mySubscription.js" %}

```javascript
export const mySubscription = (dispatch, delay, onIntervalAction) => dispatch => {
  const handle = setInterval(dispatch, delay, onIntervalAction);
  return () => {
    clearInterval(handle);
  };
};
```

{% endcode %}

Maybe a test could look something like this:

{% code title="mySubscription.spec.js" %}

```javascript
import { mySubscription } from './mySubscription.js';
import * as sinon from 'sinon';

describe('mySubscription', () => {
  it('creates an interval', () => {
    expect.assertions(1);
    sinon.spyOn(global, 'setInterval');
    const dispatch = sinon.fake();
    const myAction = () => {};
    
    const cleanup = mySubscription(dispatch, 1000, myAction);
    expect(global.setInterval.mock.calls).toHaveLength(1);
    cleanup();
    expect(dispatch.calledWith, [myAction]);
    
    setInterval.restore();
  });
});
```

{% endcode %}

## End to End Testing

Calling your subscription in a test can get you fairly far, but the real test is when your application expects some sort of payload from your subscription.

{% code title="myApplication.spec.js" %}

```javascript
import { app, effects } from 'ferp';

import { intervalSub } from './intervalSub.js';

const testify = (expectedActions, done) => (_, actionAnnotation) => {
  const actionName = expectedActions.unshift();
  expect(actionAnnotation).toBe(actionName);
  
  if (expectedActions.length === 0) {
    return done();
  }
};

describe('myApplication', () => {
  it('runs an effect from mySubscription', (done) => {
    const myAction = state => [false, effects.none()];
    
    app({
      init: [true, effects.none()],
      observe: testify([
        'ferpAppInitialization', // this is just the action/annotation of `init`
        'myAction',
      ], done),
      subscribe: state => [
        state && [intervalSub, 1000, myAction],
      ],
    });
  });
});
```

{% endcode %}


# Third-Party Libraries and Objects

## Handling Uncontrolled Third Party Objects

Not everything in the world is functional and immutable, and occasionally your application needs to manage these things. Ferp provides effects and subscriptions for handling these types of systems, but it's not always obvious which one to use and how to implement it.

### Rebuild objects by storing builder values

In the example of firebase, you may have a document reference that is constructed by:

```javascript
firebase.database(app).ref().collection('foo').document('bar')
```

While you could store the firebase ref object in state, having a serializable

{% code title="effects/firebase.js" %}

```javascript
export const firebaseReadFx = (path, afterReadAction) => effects.defer((resolve) => {
  firebase.database(app).ref(path).snapshot((value) => {
    resolve(effects.act(afterReadAction, value));
  });
});

// usage: firebaseReadFx('foo/bar', actionThatAcceptsValue)
```

{% endcode %}

### Event-driven objects

If you have objects like websockets, those are perfect for subscriptions. Here's how I would set it up:

```javascript
import { app, effects } from 'ferp';

const INITIAL_STATE = {
  websocket_url: 'wss://echo.websocket.org',
  websocket: null,
  messages: [],
};

const WebsocketSendFx = (data, websocket) => effects.thunk(() => {
  if (websocket) websocket.send(data);
  
  return effects.none();
});

const WebsocketSend = data => state => [
  state,
  WebsocketSendFx(data, state.websocket),
];

const OnConnected = (websocket) => (state) => [
  { ...state, websocket },
  effects.act(WebsocketSend, 'hello, world'),
];

const OnDisconnected = (state) => [
  { ...state, websocket: null },
  effects.none(),
];

const OnMessage = (message) => (state) => [
  { ...state, messages: state.messages.concat(message) },
  effects.none(),
};

const WebsocketSubscription = (dispatch, websocketUrl, ConnectAction, DisconnectAction, MessageAction) => {
  const websocket = new WebSocket(websocketUrl);
  
  const onOpen = () => dispatch(ConnectAction(websocket));
  const onClose = () => dispatch(Disconnect);
  const onMessage = ({ data }) => dispatch(MessageAction(data));
  
  websocket.addEventListener('open', onOpen);
  websocket.addEventListener('close', onClose);
  websocket.addEventListener('message', onMessage);
  
  return () => {
    websocket.removeEventListener('open', onOpen);
    websocket.removeEventListener('close', onClose);
    websocket.removeEventListener('message', onMessage);
  
    websocket.close();
  };
};

const dispatch = app({
  init: [INITIAL_STATE, effects.none()],
  subscribe: state => [
    state.websocketUrl && [
      WebsocketSubscription,
      state.websocketUrl,
      OnConnect,
      OnDisconnect,
      OnMessage,
    ],
  ],
});
```


