How to cook reactive programming. Part 2: Side effects.
Published: 2020-06-18 15:56:06

Despite the number, this is the third article about reactive programming. Today we are going to talk about how to handle side effects while using unidirectional approaches.
<cut>

>Before we start, I’d firstly highly recommend reading at least [How to cook reactive programming. Part 1: Unidirectional architectures introduction.](https://medium.com/@atimca/how-to-cook-reactive-programming-part-1-unidirectional-architectures-introduction-5c73f3f7793d?source=friends_link&sk=56793e72690bb9703560cfc686d29aa7). However, if you’re not familiar with frameworks such as `RxSwift` or `Combine`, or reactive programming in general, I’d suggest reading [this article](https://medium.com/atimca/what-is-reactive-programming-43e60cc4c0f?source=friends_link&sk=4ab8aa82f6e669bad59be42cba67e0ef) as well.

1. [What is Reactive Programming? iOS Edition](https://medium.com/atimca/what-is-reactive-programming-43e60cc4c0f?source=friends_link&sk=4ab8aa82f6e669bad59be42cba67e0ef)
2. [How to cook reactive programming. Part 1: Unidirectional architectures introduction.](https://medium.com/@atimca/how-to-cook-reactive-programming-part-1-unidirectional-architectures-introduction-5c73f3f7793d?source=friends_link&sk=56793e72690bb9703560cfc686d29aa7)


## Intro

Before we will move to the talk about `Side Effects` I want to introduce you to the main subject of this article.

<img src="https://habrastorage.org/webt/qk/jr/9o/qkjr9oemnaghvt4qvdsuzrwv2jy.png" align="center"/>

This is a representation of the simplest `State` which you actually can find in nearly every application. Let me transform this image into the real code.

```swift
enum State {
    case initial
    case loading
    case loaded(data: [String])
}
```

Much better! If you’re familiar with a state machine theory from the computer science class, this picture will be very recognisable to you. This is a simple state machine with 3 states. The `Initial` state can go to the `Loading` state. The `Loading` state to the `Loaded` state. And the `Loaded` state can go back to the `Loading` state. Remember I was talking about `State` data consistency. In this particular case it's really hard to make the state inconsistent. Each state of the system is represented as an enum case.

Don't worry, I'm not going to bother you with any computer science concepts here. It was mostly a representation of the ideal `State` which could be achieved. In the real world it's really hard to create only an enum state. In most cases it would be a structure. However, for the purposes of this article we will use this `State` for the experiments. And now let's move to the main topic.

## What are Side Effects?

According to **Wikipedia**

>In computer science, an operation, function or expression is said to have a side effect if it modifies some state variable value(s) outside its local environment, that is to say has an observable effect besides returning a value (the main effect) to the invoker of the operation. State data updated "outside" of the operation may be maintained "inside" a stateful object or a wider stateful system within which the operation is performed. Example side effects include modifying a non-local variable, modifying a static local variable, modifying a mutable argument passed by reference, performing I/O or calling other side-effect functions. In the presence of side effects, a program's behaviour may depend on history; that is, the order of evaluation matters. Understanding and debugging a function with side effects requires knowledge about the context and its possible histories.

However, here we’re not talking about the strict definition of the side effects. Let's remember where we ended up the last time.

```swift
struct State {
    var value: Int?

    static func reduce(state: State, event: Event) -> State {
        var state = state
        switch event {
        case .changeValue(let newValue):
            state.value = newValue
        }
        return state
    }
}

class Store {
    var state: State

    func accept(event: Event) {
        state = reduce(state: state, event: event)
    }
}
```

Generally, nearly all unidirectional architectures look like this. We have a `State` on which the rest application relies as only one source of truth. A `reducer` which alongside `Event` is the only way to mutate or update `State`. However, there should be something else. We don't live in a synchronous world, where every update for `State` can be done only with a synchronous `reduce` function. Every application needs to go to the network or database, for the new cat images. Every developer moves even hard computations on the background thread. So, how will all of this work with the existing code? The answer is side effects. In our case `Side Effects` are something asynchronous, which could mutate `State` and this "something" works on the side of the `reducer`. Imagine your beloved network service which somehow needs to be connected to the rest of the system. But first let's talk about why this architecture is called ‘unidirectional’.

One remark: `Event` in different implementations of unidirectional architectures could be called a `Mutation` or `Action` or `Message`, or maybe something different, for our purposes however naming is not so important. 

## Why is the architecture called unidirectional?

Unidirectional architecture is also known as one-way data flow. This means that data has one, and only one way to be transferred to other parts of the application. In essence, this means child components are not able to update the data that is coming from the parent component. The main benefit of this approach is that data flows throughout your app in a single direction, giving you better control over it.

I think it should be quite easy to understand with the`State` `reduce` approach from the beginning. We can change or mutate `State` only with a strict described `Event`. As a result we've got a one-way (unidirectional) data flow. However, what should we do with `Side Effects`? 

Imagine that for the `State` we have a service which as a result returns a list of the news titles.

```swift
func loadNewsTitles(completionHandler: ([String]) -> ()) {
    completionHandler(["title1", "title2"])
}
```
We know that `reducer` takes `Event` as an input not a closure...  How can we connect this service to the `reducer`? The answer is quite simple. Let’s have a `Side Effect`, which will return `Event`, not just requested data.

The resulting system will look like this:

```swift
enum State {
    case initial
    case loading
    case loaded(data: [String])
}

enum Event {
    case dataLoaded(data: [String])
    case loadData
}

func loadNewsTitles(completionHandler: (Event) -> ()) {
    loadNewsTitles { data in
        completionHandler(.dataLoaded(data: data))
    }
}

extension State {
    static func reduce(state: State, event: Event) -> State {
        var state = state
        switch event {
        case .dataLoaded(let data):
            state = .loaded(data: data)
        case .loadData:
            state = .loading
        }
        return state
    }
}
```

As you can see for now `loadNewsTitles` returns an `Event`, which could mutate the state. Our system works only in a unidirectional way. And there's an answer to why the architecture is called `Unidirectional`. After I’d answered one question, I've subsequently produced another one. How can we connect `Side Effects` and the rest of the system? This question actually is the most complicated so far. I'll try to answer it in the next section.

## Which types of side effects exist?

In nearly every `unidirectional architecture` you'll see a collaboration of `State` and some function for `reducing` this `State` according to the input `Event`. With `Side Effects` it's much more complicated. Almost every framework does this in a different way. Let me try to make you familiar with the most popular of them.

### Middleware

Let's start with the `Middleware` approach. `Middleware` provides a third-party extension point between dispatching an `Event`, and the moment it reaches the reducer. In simple terms `Middleware`, sits in the middle between you performing or dispatching  an `Event` and mutating your `State` inside the `reducer`.

<img src="https://habrastorage.org/webt/xd/2r/g5/xd2rg5cqxho59k9ibk6n9k53j_i.png" align="center"/>

Let me provide you with a code example, which I found in one well-known framework for `Redux` implementation for Swift.

```swift
let middleware: Middleware = { store, getState in
    return { next in
        return { event in
            // perform middleware logic
            switch event {
            case .loadData:
                loadNewsTitles { event in
                    store.accept(event)
                }
            case .dataLoaded:
                break
            }
            
            // call next middleware
            return next(event)
        }
    }
}
```

As you can see a `Middleware` could be treated as an asynchronous pre`Reducer`. It catches all `Events`, carries out some manipulations over it - in our case, loading news titles -, and performs a new `Event` for the system if it's necessary. So, if the `Event` is `loadData`, listed `Middleware` will load news titles and in the closure send another `Event` to the `Store`. The next `dataLoaded` `Event` will just be ignored by this `Middleware`. One of the pros of this method is the possibility to chain `Middlewares` quite easily.

Also, if you want to read more about this approach, I’d highly recommend taking a look at [`ReSwift` framework](http://reswift.github.io/ReSwift/master/getting-started-guide.html). This framework is an implementation of a unidirectional architecture, which is called `Redux` for Swift language. For those, who still refuse reactive frameworks, `ReSwift` could be a good start, because `ReSwift` doesn't use any.

### Effects

The next approach I want to talk about is the `Effects` approach. The main idea is almost the same as the `Middleware`, but all actions are going on inside `Reducer` itself.

<img src="https://habrastorage.org/webt/se/kn/xc/seknxcc53cyslptjsfiozkn2ab4.png" align="center"/>

In this approach `Reducer` has a little bit of a different shape, that I showed you before. It has a shape, which you can see below.

```swift
func reducer(state: inout State, event: Event, environment: Environment) -> Effect
```

Nearly everything should be familiar. `State` is a type that holds the current state of the application. `Event` is a type that holds all possible events that cause the state of the application to change. However, there are two new characters: `Environment` and `Effect`. `Environment` is a type that holds all dependencies needed in order to produce `Effect(s)`, such as API clients, analytics clients, random number generators, and so on.

So, how does it work for our example?

```swift
struct Environment {
    let loadNewsTitles: (Event) -> ()
}

struct Effect {
    init(work: ((State) -> ())? = nil)
    func performWorkItem() -> Event
}

extension Effect {
    /// An effect that does nothing and completes immediately.
    static let none = Effect()
}

extension Effect {
    static func loadNewTitlesEffect(loadNewsTitles: (Event) -> ()) -> Effect
}

func reducer(state: inout State, event: Event, environment: Environment) -> Effect {
    switch event {
    case .dataLoaded(data: let data):
        state = .loaded(data: data)
        return .none
    case .loadData:
        return Effect.loadNewTitlesEffect(loadNewsTitles: environment.loadNewsTitles)
    }
}
```

How does this approach work? For every call of `Reducer` you provide all necessary dependencies via `Environment` to the `Reducer` itself, and afterward your `Store` will perform every `workItem` from the `Effect` itself. And then every `Effect` will return another `Event` to the `Reducer`. Unidirectional data flow works with all power here.

You may ask, but what about the pure `Reducer` over there? You told us that `Reducer` is a pure function, and now you put `Side Effects` directly inside this function. Moreover, we mutate `State` inside this function, not just creating a new value. So, I can definitely explain that this variation of the `Reducer` is the most complicated one which we've seen so far. It has the `Environment` inside and it mutates `State`. However, let’s take a closer look. If we provide one implementation for the `loadNewTitles` service, our `Reducer` will perform the same and our `State` in the end will be the same. Yeah, in the real world, our server can answer with the different replies or different news titles, but it still has the same output - `Effect` as a return value, with the same network client in it. I hope you’ve got the idea. What about `State` mutation? Since all real mutations are always going on inside the `Store`, the main situation around changing `State` hasn't changed itself. Moreover, mutating `State` against creating new values for every `reduce` saves some performance for us. We don't need to allocate new memory each time.

I don't want to provide a working example of this approach as well. My job is to make you familiar with it and explain the basics. However, I highly recommend taking  a look at [`The Composable Architecture TCA`](https://github.com/pointfreeco/swift-composable-architecture.git) from pointfree.co. In my personal opinion this framework is the most promising for now. It has its own cons such as the minimum iOS 13 version. They also have a website with a lot of useful videos available on it. It's not free, but I have a [promocode for you](https://www.pointfree.co/subscribe/personal?ref=hnNgUrZA). I'm sorry I couldn't miss this chance...

### Query Feedback

Let's move forward or downstairs. In contrast with `Middleware` or `Effect` approaches from the previous sections, there's a `Query` approach. The `Query Feedback` approach `reacts` to new changes from the different side of the `Reducer` compared to `Middleware`.

<img src="https://habrastorage.org/webt/sb/ke/nj/sbkenj9axk8_xayeqwsfwigpjlm.png" align="center"/>

Did you notice? We’ve moved the whole way through `Side Effects` approaches? `Middleware` was before `Reducer`, `Effects` approach was inside `Reducer` and now `Query Feedback` is after reducer. Quite a journey, huh?

However, how does it work? We need to take a small piece of the `State` and start to `Observe` every change of this state. For the previous example it will look like:

```swift
extension State {
    var loadQuery: Void? {
        guard case .loading = self else { return nil }
        return ()
    }
}
```
In other words, there's some kind of `Observer`, which follows every change of this query and performs some actions over it. The optional `Void` type for my taste is the best representation when you need to understand whether you need to do any work or not.

I think you’ve likely become bored with non-working examples in this article. So, let's try at least to implement this one. I'll use the `Combine` framework for this implementation. Whoah, this is the third article about reactive programming, and only now I'll start to use a reactive framework. Also, afterward, I'll explain why I prefer to use `Combine` over vanilla Swift. Technically `Combine` is already vanilla as well, but you’ve got the point.

Here is a small table of concepts for those who are new in `Combine`.

- [Publisher declares that a type can transmit a sequence of values over time.](https://developer.apple.com/documentation/combine/publisher)
- [@Published is a type that publishes a property marked with an attribute](https://developer.apple.com/documentation/combine/published)
- [Sink attaches a subscriber with closure-based behavior to a publisher](https://developer.apple.com/documentation/combine/future/3362552-sink)
- [Cancellable a protocol indicating that an activity or action supports cancellation.](https://developer.apple.com/documentation/combine/cancellable)
- [Store stores this cancellable instance in the specified collection](https://developer.apple.com/documentation/combine/cancellable/3343581-store)

From now a little bit of tutorial started. Everything that I'll write below you can copy to your project and play with it afterward.

Let's introduce our old characters: `State`, `Reducer`, `Query` and `Event`:

```swift
enum State: Equatable {
    case initial
    case loading
    case loaded(data: [String])
}

enum Event {
    case dataLoaded(data: [String])
    case loadData
}

extension State {
    var loadQuery: Bool {
        guard case .loading = self else { return false }
        return true
    }
}

extension State {
    static func reduce(state: State, event: Event) -> State {
        var state = state
        switch event {
        case .dataLoaded(let data):
            state = .loaded(data: data)
        case .loadData:
            state = .loading
        }
        return state
    }
}
```

Nothing new so far - only a `Query` which I've shown to you recently. Now let's remove the callback from `loadNewsTitles` service and rewrite it in `Combine` fashion.

```swift
func loadNewsTitles() -> AnyPublisher<[String], Never> {
    ["title1", "title2"]
        .publisher
        .delay(for: .microseconds(500), scheduler: DispatchQueue.main)
        .collect()
        .eraseToAnyPublisher()
}
```

Mostly it's just a pre-prepared mock with a small delay, which should simulate a real network environment. And now there's a new character in this play. Let's call it `SideEffects`. Obviously it’s not me who invented this name, but let's imagine it for the bigger narrative of the story.

```swift
struct SideEffects {
    let loadNewTitles: () -> AnyPublisher<[String], Never>

    func downloadNewTitles() -> AnyPublisher<Event, Never> {
        loadNewTitles()
            .map(Event.dataLoaded)
            .eraseToAnyPublisher()
    }
}
```

As far as you can see, `SideEffects` for the `Query Feedback` approach is almost the same thing, as `Environment` for the `Effect` approach. I prefer to keep it as simple as possible, and most of the time it just converts the output from the services into `Event` which could be consumed by the `Reducer`.

And for now, there’s only one question left- how do we connect `SideEffects` with the rest of the system? The answer isn’t so complicated, and `Combine` helps with it very much. Let's build our boss `Store` entity in which we'll connect every piece of our system.

```swift
typealias Reducer = (State, Event) -> State

class Store {
    @Published private(set) var state: State
    private let reducer: Reducer
    private let sideEffects: SideEffects

    init(
        initialState: State,
        reducer: @escaping Reducer,
        sideEffects: SideEffects
    ) {
        self.state = initialState
        self.reducer = reducer
        self.sideEffects = sideEffects
    }

    func accept(event: Event) {
        state = reducer(state, event)
    }

    func start() -> AnyCancellable {
        $state
            .map(\.loadQuery)
            .removeDuplicates()
            .filter { $0 == true }
            .map { _ in () }
            .flatMap(sideEffects.downloadNewTitles)
            .sink(receiveValue: accept(event:))
    }
}
```

The most interesting part of the code listing above is the `start` function. As far as you can see, I made our `SideEffects` react to the change of the piece of the `State` `loadQuery`. And for every time when our system will be in the `loading` `State`, our `SideEffects` will go to the network service, download new `newsTitles` and notify our system that new titles have been downloaded. Do you see it? Everything in the cycle, all data flow works in the one direction.

Let's test what I've done so far.

```swift
let store = Store(
    initialState: .initial,
    reducer: State.reduce(state:event:),
    sideEffects: SideEffects(
        loadNewTitles: loadNewsTitles
    )
)
var cancellables: [AnyCancellable] = []

store
    .start()
    .store(in: &cancellables)

store
    .$state
    .removeDuplicates()
    .sink { state in print(state) }
    .store(in: &cancellables)

store.accept(event: .loadData)

// Console output

// initial
// loading
// loaded(data: ["title1", "title2"])
```

And it works, as expected! The system started from `initial` `state` then it went to the `loading` `state` after the new `Event` was sent, and ended up in `loaded` `state`. If you want to play with it some more, I've prepared [a gist](https://gist.github.com/c0c48c02088f9ce6543ab6328732b6b4).

I know that two `Cancelables` could look a little bit clumsy here, but I didn't want to make this example too complicated. There's [another framework called `RxFeedback`](https://github.com/NoTests/RxFeedback.swift) where all these problems were solved. I think that you've already got it, that this framework uses `RxSwift` from the title, right? However, there's a constructor of `Observable` - it's a `Publisher` from the `Combine` - which creates the whole `unidirectional` system for you.

```swift
typealias Feedback<State, Event> = (Observable<State>) -> Observable<Event>

extension Observable {
    public static func system<State, Event>(
        initialState: State,
        reduce: @escaping (State, Event) -> State,
        feedback: Feedback<State, Event>...
    ) -> Observable<State>
}
```

Typealias `Feedback` is a `SideEffect` itself. It takes changes in the `State` as an input and provides a sequence of `Events as output`.

In my personal opinion, this approach is the most hardcore one. As an advantage, you can take that your `State` always reflects what's going on in the system. The previous two rely on `Event` while doing any `Side Effects`, but this one only relies on the `State` itself. If you want to read a little bit more about the pros and cons of the `Effect` and `Query` approaches, you could read my [discussion with TCA creators](https://github.com/pointfreeco/episode-code-samples/issues/53). 

## Why do we need a reactive framework for this?

There are a lot of people who don't want to accept any reactive frameworks and don't understand why they are even needed. If you’re still reading this, and you are one of them, crash the like or clap button. This section is mostly for those who’ve been intrigued by the `Unidirectional` approach, but for some reason don't want to use `reactive` frameworks. Firstly I want to say, that you've already seen in my articles, that there’s nothing to be scared by in`reactive` frameworks and `reactive` programming in general. Most of you already use some techniques from it. I can say that it's much more handy to handle your data like a `sequence` or array than work with enormous closures. Use some functions, like `filter`, `map` or `reduce` etc. It really makes your code more clean and understandable. It's really hard to make a lot of mistakes from the start if you don't know how to cook it . That's why I write these articles for you.

Let me show you another advantage in a reactive framework usage. Do you remember that I relied on [`ReSwift` framework](http://reswift.github.io/ReSwift/master/getting-started-guide.html) while showing a `Middleware` approach? This is a great framework, which was written by brilliant people. However, if you try to understand how it works under the hood, or even try to work with it you will end up with structures like this.

```swift
    /// Creates a middleware function using SimpleMiddleware to create a ReSwift Middleware function.
    func createMiddleware<State: StateType>(_ middleware: @escaping SimpleMiddleware<State>) -> Middleware<State> {

        return { dispatch, getState in
            return { next in
                return { action in

                    let context = MiddlewareContext(dispatch: dispatch, getState: getState, next: next)
                    if let newAction = middleware(action, context) {
                        next(newAction)
                    }
                }
            }
        }
    }
```

There are three closures inside each other! Moreover, I've used a helper to make it more simple. Of course, you could separate all of this somehow and avoid all the callback hell. However, if you take a look at my previous `Query` example you will see how everything was simple and straightforward. I wanted to say elegant as well, but for elegance it has to be refactored a little bit . If you want to have a closer look at `ReSwift` in action, I did a small [test project](https://github.com/Atimca/Currencies) some time ago.

## Outro

There's no silver bullet on how to handle `Side Effects`. You can decide for yourself what to use. However, I think that most of you and myself will choose some pre-prepared solution like `RxFeedback` or `TCA` or `ReSwift` or something else.

<img src="https://habrastorage.org/webt/dc/b1/st/dcb1stmo5y4lyla5bbzfa56t3wm.gif" align="center" />

Finally, I have a chance to show you this gif. I took it from the `ReSwift` repo. This gif in full form represents the whole power of `Unidirectional approaches`. Technically you can store the whole history of `State` mutations and replay them at any moment you want. 

So far, you've become familiar with how to work and even how to build your own reactive framework and unidirectional architecture. However, we live in a world where applications are not one button flashlight apps anymore. We have teams of more than ten people. And if you noticed, the main idea of `Unidirectional architecture` is to keep all data inside one struct. I bet, if you start with this approach you will end up with a huge `State` and `Reducer` if not at the end of the week, then by at the end of the month. You may wonder how it's possible to separate the `Unidirectional` approach on different modules when the main idea is to keep everything in one place. What to do in this situation and what are the ways of app modularization I will show you in the next article. Let's keep in touch!

If you don't want to lose any new articles `subscribe` to my [twitter account](https://twitter.com/atimca)))

```swift
Twitter(.atimca)
.subscribe(onNext: { newArcticle in
    you.read(newArticle)
})
```