React反省会@Wantedly 2017/05/10
React反省会@Wantedly導入して1年経ったReact周辺の技術スタックを反省しますKento Moriwaki / 森脇健斗
View Slide
シゴトでココロオドルシゴトでココロオドルReactを導入してから1年3ヶ月経ちました2
シゴトでココロオドル• 導入方法– 何を考えて、それはうまくいったか• 技術スタックの選択– 導入時に考えたこと– 反省点– 改善アイデア• 話さないこと– React自体と他のframeworkとの比較話したいこと3
シゴトでココロオドル• Kento Moriwaki• Wantedlyのエンジニア• 新卒入社して3年目• 主にRailsとReact• Feed team &International team自己紹介4
シゴトでココロオドル• jquery-ujs• Backbone• Angular 1• React– 今ここ– 2016/02から1年3ヶ月Wantedlyのフロントの歴史5
シゴトでココロオドル• 一気に全体に導入された• 詳しい人は一人だけ– コードレビューもほとんどできない– あまり良くないコードが堂々としている• みんな書きたがらない– 学習コストが高い– 勉強する余裕がない– とりあえずjQueryでなんとかすればいいかまずはAngular 1を反省6
シゴトでココロオドル• 書く人を増やすことに尽力した– 社内勉強会を何回も開催した• みんな興味はあるのでちゃんと聞いてくれた– Reactいいよ、と呟く• 一部から導入した– 独立した機能から導入した– 新機能やリニューアル時に少しずつ増やしていった• デザイナーに認めてもらう– 前回Reactで作ったのが良かったから、次もあのクオリティにしたい– React前提でデザインが進められるReact導入時に注意したこと7
シゴトでココロオドル• React書く人増えてる– 自分のチームは全員書く– ほぼ全てのチームで導入されている• 10機能で使用されている• Component数は約300その結果8よかった!
シゴトでココロオドルシゴトでココロオドルいい話はここらへんにしておいて9
シゴトでココロオドル• React入れるには、他に色々判断しないといけない– 言語は?– どうやってビルドする?– Flux?– Styleは?– ディレクトリ構成は?– テストは?• 導入当時の選択を振り返って、反省したいReact周辺の技術スタック10
シゴトでココロオドル• Tool– webpack, Babel, ESLint• Library– Redux, Redux-thunk, Immutable.js– CSSModules, react-css-modules• Other– flux, E2E test今の主な技術stack11
シゴトでココロオドルTools12
シゴトでココロオドル• Railsからは切り離し、webpackを使っている– webpack-dev-server すごく便利• 完全なSPAではない• 独立した機能から使い出して、独立したアプリケーションがいっぱいできた– Entryファイルが機能ごとに分かれている• いざ全体にReactを入れていこうと思ったら、結構困った(困っている)webpack13
シゴトでココロオドルwebpack14• 各機能が独立しているので、一緒に読み込めない• リンク一つで遷移できるはずなのに、ページのフルリロードが必要manage_posts.jsanalytics.jstickets.jsmessages.js
シゴトでココロオドル• こういうファイルが何個もある– それぞれがstoreを作って、routingしてる• まとめるのはかなり大変webpack15const store = configureStore();const history = syncHistoryWithStore(browserHistory, store);ReactDOM.render(path='/enterprise/analytics'component={AnalyticsContainer}>,document.querySelector('[react-component=EnterpriseAnalyticsContainer]'),);
シゴトでココロオドル• 反省: アプリケーションは一つで、lazy loadで必要なものだけ呼ぶようにする• webpackのdynamic importでできる– ComponentやActionだけじゃなく、reducerもreplaceできる• Storeやroutingの設定は一つになるように• 全体は一つのアプリケーションで、必要なページで追加のコードが読まれるようにwebpack16
シゴトでココロオドル• もともと入れてなかった– Ruby側で使っていなかったから• すごいペースでコードが汚くなっていく– 使ってないのにimport– 中途半端なpropTypes– `==` vs `===`– 人間の目ではレビューしきれない• 途中から導入することに• 詳しくはこちらに– 全力で大きくなるReactのコードをスタイルガイドに沿って見直したら、大変勉強になりました | Wantedly Engineer BlogESLint17
シゴトでココロオドル• 反省: 初めから入れて、徹底しよう• JSのコードは汚くなるもの• エディタでチェックするようにメンバーで共通する• レビューでは気づけないので、CIに入れてもいいかも• 厳しめに入れて、後から緩くすればいいESLint18
シゴトでココロオドルLibrary19
シゴトでココロオドル• Immutable便利– Immutable.Recordでビジネスロジックを持ったオブジェクトを作れる– OrderedSetなどのデータ構造もよく使う• どこはImmutableで、どこはPlainなのか– ReducerごとのstateはPlain– EntityをImmutableでつくる– が、徹底して統一するのは難しいImmutable.js20
シゴトでココロオドル• このオブジェクトは、Immutable?• この配列はArray or Immutable.List ?• propTypesも適当になってくる– anyがいっぱい• どちらかに統一するというよりは、型が分かれば解決できる問題– TypeScriptとかなら解決できるImmutable.js21
シゴトでココロオドル• 状態管理を行うcomponent– 主にReduxとconnectするcomponent• どこからContainerで、どこからComponentにするか– ページ単位?– Routing単位?– 実はどこでもいいContainer(Redux)22
シゴトでココロオドル• Containerは一番外側のcomponent、みたいに思っていたおかげで、propsの受け渡しが多すぎるひどいコードが増えた• すごく雑なpropTypesや、全部受け取るconnectの出来上がりContainer23export default connect(state => ({analytics: state.analytics,}),dispatch => bindActionCreators({...actions}),)(AnalyticsContainer);
シゴトでココロオドル• もっと細かくContainerを分けるべき– 必要ないstateも受けていると、パフォーマンスが下がる– 受け渡すだけのprosは、可読性も下がるし、書くのもかなり面倒さい• ディレクトリ構成も一因に– Componentから遠いので、行き来するが面倒– `import from ‘../../../containers/’;`Container24
シゴトでココロオドルLanguage25
シゴトでココロオドル• ES2015をbabelでトランスパイルしている• Stage-3まで使える– Candidateなので、大きく変わる可能性は小さい• それ以下は要相談– `static propTypes =` などは使っている– simpleで変わる心配少ない & 変わっても簡単に直せる & 可読性がかなり上がる– TypeScriptでもかけるし。。ES201526
シゴトでココロオドル• 型は必要だった?– Railsを書いている人が大部分なので、ハードルが高いと思った• CoffeeScriptからの差が大きい– 今はgolangとか書く人も増えてるし、型の良さも共通認識である(と思う)– TypeScriptのIntelliSenseがいいES201527
シゴトでココロオドル• 反省: TypeScriptにしても良かった– propTypesも標準じゃなくなるし– Googleでも標準言語になってるし– VS Codeで生産性高いし• 途中からTypeScriptにするのは骨が折れそうだから、初めからTSにできるならした方がいい• Flowでも可ES201528
シゴトでココロオドルTest29
シゴトでココロオドル• 現:JSの単体テストはなく、Railsも含めたE2Eテストで担保している• Wantedlyのwebエンジニアは、フロントもサーバーも一人で書く場合が多い– バーっと動くものをつくって、重要なところをE2Eで担保していくスタイルがあっていた• Angular時代も単体テストを書く環境はあったが、ほとんど書かれることはなかったテスト30
シゴトでココロオドル• 反省: テストはかけた方がいい• 全てE2Eテストを書くのは大変• 各Component書く必要はなさそう• ActionCreatorや、ビジネスロジックはテストが書かれるべき <- 当たり前• 環境整えるのが大変なので、誰か助けてくださいテスト31
シゴトでココロオドルDirectory Structure32
シゴトでココロオドル• react/– components/• {fooapp, barapp}/– containers/• {fooapp, barapp}– reducers/• {fooapp, barapp}– actions/• {fooapp, barapp}– lib/immutable/ディレクトリ構成33• 外側は役割ごとに分けられている• その中は、機能ごとに同じように分けている• 実際はもうちょっと汚い• 初めはflatだった• 一つの機能が離れたところに
シゴトでココロオドル• StateとUIを分けるべき– アプリケーションの状態とUIのReactとは切り離す– ComponentsとContainerはディレクトリで分けなくても良さそう• 関心ごとにまとめるべき– 一つの機能に関するコードを近くに集めることで、データの流れが追いやすくなる• 参考– Automattic/wp-calypsoディレクトリ構成34
シゴトでココロオドル• components/– {fooapp, barapp}/• Baz.jsx• BazContainer.js• state/– {fooapp, barapp}/• action.js• reducer.js• selector.js• models/ディレクトリ構成[理想]35
シゴトでココロオドルOthers36
シゴトでココロオドル• CSSModulesを使っていた– CSSが分かれていて、デザイナーでも触りやすい– Rails側でscssを使っているので、変数の共有などのために統一した• react-css-modules– className={style.tabel}– styleName=’table’– 書く量が減って、いいかなと思ったCSS37
シゴトでココロオドル• react-css-modulesのパフォーマンス– 実行時の解決なので、コストがかかる• babel-plugin-react-css-modules– BabelのCompile時に解決してくれるのでパフォーマンスがいい– 何が起きてるかわかりにくいbabelのpluginは入れたくない• 学習コストが上がる• なんでもできちゃうCSS38
シゴトでココロオドル• シンプルにCSSModulesだけで良かった• className={s.table}って書くだけで、大して面倒ではない– 直感的に理解できる– undefinedチェックとか実装時はうざいだけ <= 設定の問題– camelCaseのスタイルでもいいじゃんCSS39
シゴトでココロオドル• State treeからデータを取ってくる関数– 離れた場所のデータを組みわせて使いたい場面とかに便利– redux/reselect を使うとメモ化なども行なってくれ、パフォーマンスにも優しい• 初めは、render内で毎回計算したり、stateに保存したりしていたSelector40
シゴトでココロオドル• state treeの構造をどうするべきか– APIのデータをそのままstateに入れると、nestが深くなる– 深いデータが更新されると、上側も全て更新される– パフォーマンス的にもよろしくない– データの一貫性を保つのが難しい• Reducerのコードが複雑になるNormalize41
シゴトでココロオドル• 各entityごとにnestを均してから保存する– IDをkey, entityをvalueにしたMapに保存– 元あった場所にはIDを入れておく– propsはIDを渡して、connectでentityを取ってくる• 利点– 関係ないデータが変更されても、updateが少なくなる– Reducerの処理がシンプルになる• IDからデータを探して更新するだけNormalize42
シゴトでココロオドル• Reduxのmiddleware– Actionのdispatchに割り込んで、色々できる• 非同期処理を扱うために、redux-thunkだけ入れた– Simpleでとにかく学習コストが低い• Loggingなどの副作用や、共有化されたAPIコールなどで、適宜作っている• こういうところに単体テストがないの良くないmiddleware43
シゴトでココロオドルまとめ44
シゴトでココロオドル• React導入一年経って、うまくいっていると胸を張って言える• チームの状況を見てスタックを選択しよう– Wantedlyは一人がサーバーとフロントを両方書く体制• 大きな失敗はないけど、もっとよくできたと反省は絶えない• これから導入する人の参考になれば嬉しいまとめ45
シゴトでココロオドルWe are hiring!46https://www.wantedly.com/projects/59809