WantedlyでのReact + Reduxの導入 & 展開(高松真平)|TechHub React勉強会
Facebook・Instagram・Netflix・UBERなど多くのアプリケーションで使用されているReact.js。2016年7月21日、弊社Branding Engineerが主催するイベント「TechHub」にて、React.jsを業務ベースで運用して感じた特徴をLTして頂きました。業種を問わず様々な企業でReactを書いているエンジニアの方々にお越しいただいた中、当記事は、Watendlyの高松氏のLTを書き起こしたものになります。
スライド資料:Wantedlyでの React + Reduxの導入 & 展開
イベントリンク:TechHub|Doorkeeper
【React 勉強会】※投稿後リンク挿入
- WatendlyでのReact + Reduxの導入 & 展開/Wantedly 高松真平
- React+Reduxで新規サービスを開発して得られた知見/Branding Engineer 川野公佐
- React製社内ツールの高速化事例/Indeed 有田夏洋
WatendlyでのReact + Reduxの導入 & 展開

Wantedlyの高松といいます。
軽く自己紹介から始めたいと思います。
普段はWantedlyのWebエンジニアをしています。Wantedlyはフロントエンドエンジニアや、サーバーサイドエンジニアなどの区分けがなくて、僕もコード書いている半分の時間ぐらいはRails書いていて、半分くらいはJavaSccriptを書いています。【スライドスライド2】

半分宣伝なんですけど、最近Wantedlyでエンジニアブログやブログを書けるようになりました。僕もそこで、React系のブログをよく書いています。今日の話と被る部分もあるんですけど、そこでRailsプロジェクトにどうやってReact、Reduxを導入したかの話もしています。
QiitaのほうでもReact、Reduxを使った構成の解説であったり、サンプルアプリケーションの作り方の記事を載せていたりするので、もしよかったら見ていただきたいと思います。【スライドスライド3】

では本編の発表を始めます。全体としては、WatendlyのReact、Reduxの導入&展開という話です。【スライドスライド4】

1.Wantedlyの開発フロー

Wantedlyの開発フローがどんな感じなのかというところから始めたいと思います。
Wantedlyの下が「rake stats」という、Railsプロジェクトの統計情報を見るもので、Model数を見るとだいたい300を超えていて、結構大きめなRailsプロジェクトになっています。
Wantedlyのリポジトリ自体がものすごい大きなモノリシックなRailsアプリケーションになっていて、2011年の9月にファーストコミットがされているので、約5年ほど開発が続けられている状況です。【スライド6】

まずエンジニアカルチャーから説明しますと、Wantedlyにはディレクターがいなくて、エンジニアが自分で施策を決めて、KPIを立てて、それを実装して効果測定して、それをまたPDCAサイクルを回す組織になっています。
エンジニア中心のカルチャーであるというところが、特徴的なところです。
Wantedlyにはいくつか行動指針みたいなのが決められていて、その一つが「Code Wins Arguments」というもので、「コードは議論より強し」という精神があります。
要するに、少し議論になって「これいいのか?」のような状態になった時に、「とりあえず書いてみて試そうよ」という精神で、それが社内に行き渡っています。「とりあえずコードを書いてみる」というカルチャーが強いです。
下の写真は、左側が「Wantedly Tech Book」という、技術系の同人誌の即売会に出した本がありまして、ここに詳しくWantedlyを支えている技術について載せています。
右側はWanteldy CEOの仲が作っている、Wantedlyカルチャーブックというもので、ここに「Code Wins Argumentsとは」などが書いてあります。【スライドスライド7】

実際の開発で言いますと、基本的にRails Wayに則った開発でして、Railsが分かれば、割りとすぐ読み解けるようなコードになっています。
開発フローとしては、GitHubフローを採用していまして、マスターからトピックブランチを切って、そこで開発を行い、レビューをして、LGTMと言われると、マスターにマージされるという流れです。
その後のデプロイも、エンジニアが任意のタイミングでできるようになっていて、日に10回とかは軽くデプロイされている、という感じですね。【スライドスライド8】

特にフロントエンドの開発に絞って話をしますと、Rails Wayなので、Asets Pipelineとか、Sprocketsにそのまま乗っていたような感じで、altJSとしてはCoffeeScriptなどを使っています。
部分的にはBackbone.jsとか、Angular.jsを使っているところもあります。
ただ、下の図を見ていただけるとわかるんですけど、jQueryに行って、Backbone.jsに行って、Angular.jsに行って、またjQueryに戻って来るという状態になっていて、直近でAngular.jsを入れたのは良いんですが、正直Angular.jsは難しいところもありましたし、「Angular.jsを入れたい」と言って、推進していた人がもういなくなっているということがありまして、半ば負債化しているところがあります。ここをどうするかが課題になってきている状況です。
ここまでが、今のWantedlyの開発の状況です。【スライドスライド9】

2.React + Reduxの導入
【スライドスライド10】
ここからが、実際にReact.js、Reduxを導入していった話になります。
さっき見たように、最近入れたAngular.jsなどが、あまりうまく導入が行かなかったというのもありまして、社内的には「もうJSのフレームワーク入れるの辞めたいね」というような空気が漂っていました。
それでもSingle Page Applicationみたいな難しい物をjQueryだけで組むのは難しいし、最近のリッチなUIをつくろうとすると、すぐに1万行ほどのJS書くことになってしまい、そういう規模になってきますと、jQueryだけでやるのは大分厳しいところがあります。
React、Reduxを導入したのが今年に入っての2月で、JavaScriptフレームワークの乱立が去年、一昨年と続いていたんですけど、それがやや落ち着いて来た時期だったというのも、React、Reduxを導入することになった要因でもあります。
今回の導入部分に関しては、既存部分のソースコードが今沢山あって、それを全部置き換えようというわけではなくて、新規作成する部分から、このスタックで作っていこうという指針で入れています。
具体的にどんなものを入れたのかというのが、これらのスタックです。【スライドスライド11】

2016年現在、今の段階で比較的メジャーなものを集めたという構成になっていて、中心はReact、Reduxです。
下の方詳しく見てみると、altJSというかトランスパイラとしてはES2015 + Babelとなっています。
Babelでstageを指定してあげることで、未来の機能をどこまで使うかというのを設定できて、今はstage-3にしていて、その理由がasync/awaitを使いたかったからです。
なので、例えば、これからstage-0のdecoratorsを使いたかったら、全員で議論してステージをもっと下げていくことになります。
今のところは、ES2015 + Babelでstage-3まで使っています。
あとはReactとFluxFramework、Reduxの話ですね。
自分はFlux Utilesを推していたんですけど、2人で導入の計画をしていたときに、「いやReduxの方が、今色々揃っているし、メジャーなのでReduxでいきましょうよ」と押し負けちゃいまして、Reduxになりました。
Immutable.jsは不変データオブジェクトのようなFacebook系のライブラリで、我々はこれを全面的に使っていて、データ構造を作るときは、Immutable.jsを使うことを基本としています。
あとはCSS Modulesですね。CSS in JSをよりやりやすくしてくれて、ハッシュ値のようなものを付けて、衝突を避けてくれる仕組みがあります。ビルドにはwebpackを採用しています。【スライドスライド12】

フォルダ構成はどうなっているかと言いますと、Asset Pipelineはもう使わない方針にしていて、Railsプロジェクト直下で、appと同じ階層にfrontendのディレクトリを切ってやっています。
“frontend/assets/javascripts/react”というディレクトリがあって、ピンクの枠で囲ってあるところが、実際のReact、Reduxで使っている部分です。
このフォルダの中ではcomponentsとcontainerのディレクトリを分けていて、どちらもReactのcomponentsが入っていますが、いわゆるdumb component とsmart componentというのを分けて、描画するだけのところはcomponentsというディレクトリ、そこからアクション発行するところがcontainerのディレクトリに入っている状況です。【スライドスライド13】

ビルドと開発環境とかデプロイがどうなっているかというのがこちらです。
ビルドにはwebpackを利用しています。
webpackはwebpack-configだけで設定が完結しやすいので便利なのと、マルチエントリーポイントに対応していて、複数のエントリーポイントを受けて、複数の出力が可能だという点が採用の大きな理由です。
開発環境にはwebpack dev-serverをローカルに立てて使っていて、Hot Module Replacementなどが効くようになって開発効率が良いです。
assets pipelineから外れているので、minifyとかダイジェストの追加を自分たちでやらなければいけないんですけど、ここらへんはwebpackのプラグインで自分たちで実行していて、実際のプロダクションデプロイではここらへんが走っています。
開発環境だとwebpack dev-server で、プロダクションだとpublicの配下に出力されているので、その差を吸収しないといけないんですけど、下に貼ってあるような、Railsのヘルパーメソッドを使って吸収しています。【スライドスライド14】

ここまでのまとめです。
スタックの選定的には今の主流なものを集めたような形になっています。
開発環境的には、webpackを使っていて、開発環境とプロダクションで差があるので、ヘルパーメソッドを用意して吸収しています。【スライドスライド15】

3.社内での展開

ここから社内での展開の話に移ります。
最初から書けるメンバーが沢山いたわけではなくて、導入当初はもう一人いるメンバーと僕の二人で、どういうスタックにしようかというのを話し合って、レビューし合って、導入しました。
それが2016年2月の話で、今2016年7月ですけど、スゴイ書ける人が増えて、計5人ほどいます。
【スライドスライド17】

テンポラリーで来る、インターンの子を含めるともっといっぱいいますね。
さらにReactのコンポーネントの資産は100以上あるような状態です。図の下のほうが、自分のチームのメンバーになっています。【スライドスライド18】

自分のチームでやっていたのが、だいたいクライアントサイドで1万行超えるぐらいの大きなプロジェクトで、Reactのプロダクション使用経験であったり、Single Page Applicationの実装経験があるのが自分だけだというプロジェクトに、Reactを展開していきました。
一番最初の二週間は僕が全体の設計も考えながら、ひたすらコードを書く期間がありまして、そのコードを見本に書いてもらったメンバーの実装を丁寧にレビューしていったことが、チームの展開として一番大きなところでした。
そのときに作ったのが、下の画面にある「チケット管理機能」というもので、Wantedlyの採用企業側が使うページをSingle Page Applicationの構成でガラッと、置き換えてリリースしました。
ここからよくレビューで指摘しているポイントを集めましたので、そちらを紹介していきます。内容としては、ReactやReduxに関わらず、Single Page Applicationでよくあるものです。【スライドスライド19】

この画像の下のページが、Wantedlyの企業側が使うメッセージの画面です。タブが二つあり、左のタブが自分宛てのメッセージ、右のタブが全員分のメッセージです。ここでモーダルが開いているのが、どの募集に対する応募者かというのを絞り込むための、ダイアログです。右側がメッセージの詳細ビューという構成になっています。
ここで、レビューのポイントとなるのが、一つ目が通信のタイミングが適切かというところです。パフォーマンス・チューニングの話で出てくるんですけど、通信は時間がかかるので、通信のタイミングが適切でないと、毎回通信を行ってすごい遅く感じてしまうことがありますので、ここを一番よく見ています。
この画像で言いますと「自分のメッセージ」「全体のメッセージ」「プロジェクトのマスターデータ」ですね。最初画面をレンダするときに、この3つを全部並列で取ってくるという状態になっていて、「ここでデータ取得の時間を節約しよう」と考えます。
データの先読みが可能なら、先にしようという方針を取って、ユーザ体験を損なわれないように努力しています。
例えば右側は、メッセージを送信するときに通信してポストして、成功するかどうかが大事になりますが、とりあえず送信ボタンを押した段階で、「送信済み」のビューにします。ただそれが失敗する場合もあるので、送信しましたのビューを削除して、「エラーが起きました」というビューに変更します。
通信を待たずにビューの更新を行うことで、「体感速度を上げましょう」という試みで、ここらへんもレビューでよく指摘するポイントです。【スライドスライド20】

他のポイントで言いますと、エラーのビューやリロードボタンの削除漏れはないかをよく見ています。次のタイミングでリフレッシュしたら、そのビューも消えないといけないんですけど、それの消し漏れがあって、ずっとエラーのような画面になっているのがよくある話です。
特にSingle Page Applicationだと、いろんなパターンでいろんなアクションが発行されるので、次どのアクションに行っても、きちんと削除漏れなくリフレッシュされているかを設計上見ています。
最後によく見ているとこととしては、「Stateの置き場所は適切か」というところです。
コンポーネントごとにStateを持たすことは可能なんですけど、大体後から後悔すると思っていて、Reduxでいうとstoreにデータを持たすことが基本的で、コンポーネントに明らかに閉じたようなものは、this.stateに保持して使いたくなるんですが、外から更新することが難しかったりするので、それをどこに置くかというのでいつも悩んでいます。
基本的に画面ごとに非ドメインな画面状態などはManagerというstoreを用意しています。この画面の場合ticketDetailManagerというのがいて、そこにisLoadedやhasErrorを持たせて、フラグを建てて空にしています。この辺がよくレビューで指摘するポイントです。【スライドスライド21】

あとメンバーはどんな感じで勉強しているかというのを資料に書いておいたので、もしこれから勉強しようと考えている方は、見ていただければと思います。
サンプルとか環境の整備とかもしていて、プロダクションと同じ環境で作った同じサンプルと実習資料を用意していて、プロジェクトに入る人にやってもらおうという計画にしています。【スライドスライド22】

あとは、動作確認のためのplay groundを用意していて、プロダクションと同じパッケージが入っています。例えば自分がレビューしていて、部分的に動作確認したいときに、この環境には「Mocha」とか「 power-assert」とかを入れているので、軽くユニットテストで動かしています。
あとは新しくnpmのライブラリを入れようという時に、本当に使いやすいのかと検証してから入れてもらうようにしています。いわゆる素振り環境を自分用に用意していて、メンバーに展開しています。【スライドスライド23】

ここのまとめとしては、プロジェクトの運営上、とにかく最初に自分でたくさん書いて展開させていったのと、丁寧にレビューしているということです。
あとは資料や環境を整備して、これから入る人にも、入りやすいように努力しています。
4.まとめとこれから

最後にまとめとこれからで、まとめのほうはもういいかと思いますので、省略します。
未だできていないこととしては、最近品質との戦いがありまして、規模が大きくて、複雑度も高いので、バグりやすいというのがあります。
まだユニットテストが書けていないので、適切にユニットテストを書いていきたいと思っています。
もう一つはサーバーサイドレンダリングで、現状は全然サーバーサイドレンダリングしているところがなくて、これからアーキテクチャを含めて考えていくことになるんですけど、そのときにそもそもReactを使わないという選択肢もあるので、ここはよく考えていきたいと思っています。【スライドスライド26】

最後になりますが、一緒にReactを書いていただけるエンジニアを募集をしているので、もしよろしかったら、話を聞きに来てくださると嬉しいです。【スライドスライド27】

以上です。ありがとうございました。
スライド資料:Wantedlyでの React + Reduxの導入 & 展開
イベントリンク:TechHub|Doorkeeper
【React 勉強会】※投稿後リンク挿入
- WatendlyでのReact + Reduxの導入 & 展開/Wantedly 高松真平
- React+Reduxで新規サービスを開発して得られた知見/Branding Engineer 川野公佐
- React製社内ツールの高速化事例/Indeed 有田夏洋

