react-chaosでカオスエンジニアリングをやってみよう

Ubiregi Advent Calendar 2019 3日目です。

2日目に引き続きフロントエンドエンジニアのコジャが担当します。

今回は簡単にReactでカオスエンジニアリングが体感できる`react-chaos`をやってみます。

## カオスエンジニアリングって何？

何でしょう。私も今日に至るまで言葉は知っていましたが、実際に何をするのか、何でするのかはわかりませんでした。

ざっくり調べると「擬似的に障害を起こし、実際の障害にも耐えられるようにする」ことだそうです。

詳細は以下のQiita記事がわかりやすかったです。

[カオスエンジニアリングと聞いてカオスになった人必見](https://qiita.com/naokiiiii/items/de20997a70922c01f754)


## react-chaosって？

[react-chaos](https://github.com/jchiatt/react-chaos)はReactで作られたアプリケーションに対して、`意図的にエラーを発生させる`High Order Componentです。

ただ、READMEを見てみると、以下の一文があります。

>## 🛑 Pre-Installation Notes
- This is currently WIP and a proof-of-concept.
- There is nothing in place to help ensure good performance practices. Use at your own risk.

実運用はまだのようですね。

## なにはともあれ

やっていきます。

まずは、react-router-domを使用して、簡単なルーティングするようなアプリを作ってみます。

```jsx
const App = () => {
    return (
        <BrowserRouter>
            <Layout>
                <Switch>
                    <Route exact path='/'><Home /></Route>
                    <Route path='/about'><About /></Route>
                    <Route path='/dashboard'><Dashboard /></Route>
                </Switch>
            </Layout>
        </BrowserRouter>
    )
}

```

動きはこんな感じです。

見ての通り、`/`がHome、`/about`がAbout、`/dashboard`がDashboardと表示されます。

![before.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534986/3e90ecbf-b160-4504-4a79-8b93eb3ee5e8.gif)


では早速、`<About />`にreact-chaosを適用してみましょう。
第一引数は適用対象のコンポーネント、第二引数はエラーの発生頻度、第三引数はエラーメッセージになります。

今回エラー発生頻度を10にしたので、`/about`にアクセスした時、必ずエラーが発生することになります。

```jsx
import React from 'react';
import withChaos from 'react-chaos/src/index.tsx';


const About = () => {
    return (
        <div>
            <h2>About</h2>
        </div>
    );
}

export default withChaos(About, 10, 'カスタムエラーだよ');
```

`yarn start` します。

```shell
./node_modules/react-chaos/dist/index.js
Module not found: Can't resolve './chaos-react.cjs.development.js' in '/Users/koja/workspace/react-chaos-example/node_modules/react-chaos/dist'
```

失敗します。なんでや。

## 動かないんだ...

まぁまだ慌てる段階ではない。node_modules/react-chaos/dist配下を見てみると、出力エラーの通り、index.jsしか存在しませんでした。へぇ~

リポジトリのissueを漁るとこんなのが。

[the newest npm package wrong? #10](https://github.com/jchiatt/react-chaos/issues/10)

> This is still an issue.

なるほどね。

npmのレジストリでなく、直接gitのリポジトリを指定してもダメでした。というかbuildがコケてた。

## 再挑戦

ただ、[demo](https://react-chaos.netlify.com/)は動いているので以前のバージョンを指定すれば、ビルドできるはずです。

[react-chaos v1.0.6](https://www.npmjs.com/package/react-chaos/v/1.0.6)

現vは0.1.0でその前のvは1.0.６ってことは破壊的変更があったんでしょうか？まぁあまり気にしないことにします。

```shell
yarn add -D react-chaos@1.0.6
```

yarn start して `/about`にアクセスしてみると、画面が真っ白になります。コンソールを開くと舐めたエラーメッセージが出力されています。成功です。

<img width="685" alt="スクリーンショット 2019-12-03 21.12.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534986/94b8ed1a-431b-e857-a17c-17bf26a6d143.png">



## どうやって対処する？

Reactでは予期せぬエラーが発生した時、代わりの画面を表示するError Boundaryなる方法があります。


https://ja.reactjs.org/docs/error-boundaries.html


実装はこんな感じ。

```jsx
import React, { Component } from 'react'

export default class ErrorBoundary extends Component {
    constructor(props) {
        super(props)
        this.state = { hasError: false }
    }

    static getDerivedStateFromError(error) {
        return { hasError: true }
    }
    render() {
        return this.state.hasError ? <h1>一時的なエラーが発生しています</h1> : this.props.children;
    }
}
```

エラーが発生しうるコンポーネントを子要素に持つようにします。今回は`<About />`が対象です。

```jsx
const App = () => {
    return (
        <BrowserRouter>
            <Layout>
                <Switch>
                    <Route exact path='/'><Home /></Route>
                    <Route path='/about'>
                        <ErrorBoundary>
                            <About />
                        </ErrorBoundary>
                    </Route>
                    <Route path='/dashboard'><Dashboard /></Route>
                </Switch>
            </Layout>
        </BrowserRouter>
    )
}

```


こうすればエラーが発生した時、画面がホワイトアウトするのを防いで、用意したエラーメッセージを表示してくれます。下記のgifではエラーの発生頻度を3まで落としたので、なかなか発生しませんでした。

![error.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534986/224f8d9b-5ecb-46b9-fd4f-243d38ef2fe0.gif)

## 最後に

実装まで紹介できるかなと思ってたんですが、Errorを発生させる条件が割と複雑だったのでやめました。数学ができない。