Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.
ニコニコ生放送のwatchページを	
MobX	で作り直している話	
@kondei
背景事情(3行)
_人人人人人_	
> つらい <	
 ̄Y^Y^Y^Y ̄	
	
Node な	
フロントエンド	
サーバー 分離	
Atomic	Design な	
View	Component	
誕生
背景事情(詳細)
歴史	
•  第1世代:	
–  PHP	Smarty	Template,	ES5	
–  モノリシック	
•  第2世代:	
–  Groovy	Template,	TypeScript,	jQuery	
–  モノリシック	
:← いまここ...
なぜ作り直しているのか	
•  第2世代の問題点	
–  デプロイが遅い	
–  デザイン単体の確認がしづ
らい	
–  Groovy	Template	が独特	
–  データを管理しているのは
バックエンドチームのコード	
•  →	データを...
対策1:フロントエンド分離	
•  Docker	&	Node.js	でフロントエンドサーバーを分離	
•  合わせて	“バックエンド”	サーバーがAPI化することで、データ
取得のインターフェースを明確化	
•  メリット	
–  デプロイ遅...
対策2:View	Component	
•  View	Component	(VC)	を作る	
– Atomic	Design	
– React	Component	
– Storybook	活用	
– HTML,	CSS を全て取り持つ	
•...
VCで解決されること	
•  企画者やデザイナーがデザインだけ気軽に
確認できる	
•  手続き的なviewが宣言的に	
•  jQuery	まみれ	
•  グローバルスコープなCSS
フロントエンド分離、VC	
という体制の上で
自分のチームが作っているもの	
	(CC)	
•  VC	に渡す	Props	を管理する	
–  自身も	React	Component	
–  「アプリケーションのドメインロジック」を書く	
–  データの管理	
•  サーバーサイドテンプレ...
Container	
Component	
View	Component	Propsを作っ
て渡す	
フロントエンド	
サーバー	
載
せ
る
PcWatchPage	
•  watchページの作り直しの CC	
– h[p://live2.nicovideo.jp/watch/lvXXXX	
•  MobX	
•  <head>は持たず、一旦<body>の中身のみ
PcWatchPage の技術的目的	
•  Watchページ内でのSPA化の余地を残す	
– 番組ザッピング機能など	
– 他ページとの間のSPA化はしない	
•  Sever	Side	Rendering	(SSR)	する
なぜ MobX
生放送	HTM5	PC	プレーヤー	
•  その前に作っていたプレーヤーでは、
h[ps://github.com/facebook/flux	利用	
出典:	h[p://azu.github.io/slide/react-meetup/img/...
Facebook	Flux	問題点	
•  Dispatcher	を介する意味があまりない	
– ほとんど payload:	callback	=	1:1	
•  Aceon	Creator から	Store	のデータを参照した
くてもできない
フレームワーク選定条件	
•  Facebook/flux	利用時の問題点が解消される	
•  メンバーの学習コストが低い	
•  TypeScript	との親和性が高い	
•  VC	との親和性が高い
VC との親和性が高いとは?	
Atomic	Design	Template	に	Organism を渡す方式
🤔	 社内外で流行ってるし、
これで書いてみるか
Redux	試してやめた理由:4行	
•  connect の型つらい	
•  Store	1個つらい	
•  難しい	
•  つまりうちの制約に合っていない
Redux	試してやめた理由	1:	型	
•  connect	の mapStateToProps(値) と
mapDispatchToProps(アクションを呼ぶコールバック) が別
れており、VC	の	Props	の型(値とコールバックで別...
Redux	試してやめた理由	2:	その他	
•  Storeが1個	
–  Organism	単位でリポジトリ切って(別個の	Store	が生まれて)統
合するのを目指してるうちのアーキテクチャと相性悪い	
•  redux-sagaやrea...
Redux	所感	
•  TSでなく、VCみたいなのが整備されていない
状態で、すべて自分たちで作っていけるなら、
楽そうなフレームワークだとは思った
🤔	
🤔	
他にないかなぁ	
お	
h[p://leader22.github.io/slides/
node_gakuen-25/		💁
3行でMobX	
•  mobxのObservableを変化させると	
•  mobx-reactのObserver(のrender)内で参照し
ている所に	
•  反映される
MobX	採用理由:	型	
•  もともと TypeScript	で書かれており、型だけ古いとか
複雑みたいなことがない	
•  各	organism	の	VC	をラップして描画最適化でき、その
際に	Props	の型情報を失わない	
•  h...
MobX	採用理由:その他	
•  Store	を複数個作れる 	
–  organism	単位でいつでも切り出したいアーキテクチャ
と相性がいい	
•  Store	と	Aceon	をひとまとめにできるので、
「	Aceon	からStore	...
MobX	所感	
•  シンプル。お作法が特にない (not	フレームワー
ク)	
–  柔軟	
–  自分たちのお作法を決める必要あり	
•  React.setState	より汎用的な状態管理ができる	
–  h[ps://medium.c...
どういうお作法で作っているか
HogePage	
ContainerView	
ContainerDomain	
リポジトリ依存関係
制約	
•  PageがDomain,	Viewを利用する。逆の依存は
しない	
•  ViewはOrganism単位で完結して動作する	
– 部品単体で分離して開発できるようにするため
ContainerDomain	
•  生放送のドメインに関するState,	Storeを持つ	
–  Program	
•  ID,	タイトルなど	
–  User	
•  メリット	
–  DDD的にコーディングできる	
–  ページごとに...
State.ts	
•  プレーンなobjectで表現した「状態」	
•  例:あるviewのState↓
Store.ts	
•  Flux のStore	じゃないよ!	
– 命名由来: h[ps://mobx.js.org/best/store.html		
•  ObservableなStateを保持し、状態を管理	
– @aceon	で	st...
ContainerView	
•  見た目の状態として State,	Storeを持つ	
•  ContainerDomainを参照していい	
•  各	Organism	ごとにディレクトリ分ける	
– 何でページのリポジトリに内包しないの?	...
ContainerView	ディレクトリ構成	
•  OrganismA	
–  State.ts	
–  Store.ts	
–  Container.tsx	
–  Constants.ts	(定数、型定義系)	
–  Index.ts	(...
Container.tsx	
•  Store	と	VC	をつなぐ	
– StoreからStateとaceonを参照し、VCのPropsを作る	
– VCをObserverでラップしたComponentを提供
Container.tsx	
2017/0804追記	
当初こうやっていたがダメでした
ダメだったこと	
•  @types/react	のバージョンを上げたら怒られた	
•  そもそもこれだとrenderでobservable参照してな
いので反映されない	
–  h[ps://mobx.js.org/refguide/obse...
ちゃんとReact.Component	
でラップしましょう	
型は諦めた
HogePage	
•  Hogeページの統括	
•  ContainerDomain,	ContainerView	から任意の部
品を組み合わせてページを作る	
•  Props の型は自分が使う ContainerDomain	の	
Sta...
ページからview	Storeへの	
依存性注入	
•  例:	
–  複数のviewで共有されるテキスト	
•  StoreはBaseとなるStoreを継承	
–  コンストラクタ引数で、Observableではないものは、
Observab...
BaseとなるStore
DomainStores	
•  ページで使うdomain	storeの集約を持ち、そ
れをviewに注入
ContainerInfra	
•  色んなリポジトリから使うもの	
– BaseのStore	
– URL加工奴	
– API	Client作る奴
MobX	知見
useStrict(true)	にするべき	
•  false	
– どこからでも this.state	=	hoge できる	
•  true	
– @aceon	をつけたメソッド以外でやると
console.error	
– 全アクションが...
reaceonは極力使わない方が良い	
•  h[ps://mobx.js.org/refguide/reaceon.html		
•  当初はページ状態の変化をreaceonでviewに反
映していた	
–  ページのProgramIDが変わ...
ObservableArray	!==	Array	
•  Observable(object)すると、中にあるArrayが
ObservableArray	になってしまう	
•  ObservableArrayの挙動はArrayと違う	
– ...
observable()	時に存在するproperty	
のみ監視される	
•  h[ps://mobx.js.org/refguide/object.html	
•  mapを使うのが良いかも	
•  やはりmapよりObjectが圧倒的に使...
ステートフルでラップしないと動かない	
•  observerでラップした部品単体で動かなかった	
•  ページのトップでobserverしたら動き、外すと動かなかった	
•  observer(statelessComponent)	は単体で...
余談
MobX	って RxJS と似てない?	
•  h[ps://github.com/mobxjs/mobx/wiki/Mobx-
vs-Reaceve-Stream-Libraries-(RxJS,-Bacon,-
etc)	
•  実際 Rx...
mobx-state-tree	
•  h[ps://github.com/mobxjs/mobx-state-tree	
•  公式が実験してるフレームワーク的なもの
結論
いいぞ	
•  業務時間でプロトタイプいくつか作って技術選定	
•  TypeScript でドメイン型定義	
•  MobX	で状態管理	
•  Storybook,	knobsで動作確認	
•  アーキテクチャを分ける:	
–  ドメイン	...
おわり	
Special	thanks	チームメンバー
ニコニコ生放送の watch ページを MobX で作り直している話
Nächste SlideShare
Wird geladen in …5
×

ニコニコ生放送の watch ページを MobX で作り直している話

5.743 Aufrufe

Veröffentlicht am

MobXはいいぞ

Veröffentlicht in: Ingenieurwesen
  • Dating direct: ❶❶❶ http://bit.ly/39mQKz3 ❶❶❶
       Antworten 
    Sind Sie sicher, dass Sie …  Ja  Nein
    Ihre Nachricht erscheint hier
  • Sex in your area is here: ❶❶❶ http://bit.ly/39mQKz3 ❶❶❶
       Antworten 
    Sind Sie sicher, dass Sie …  Ja  Nein
    Ihre Nachricht erscheint hier

ニコニコ生放送の watch ページを MobX で作り直している話

  1. 1. ニコニコ生放送のwatchページを MobX で作り直している話 @kondei
  2. 2. 背景事情(3行)
  3. 3. _人人人人人_ > つらい <  ̄Y^Y^Y^Y ̄ Node な フロントエンド サーバー 分離 Atomic Design な View Component 誕生
  4. 4. 背景事情(詳細)
  5. 5. 歴史 •  第1世代: –  PHP Smarty Template, ES5 –  モノリシック •  第2世代: –  Groovy Template, TypeScript, jQuery –  モノリシック :← いまここ –  Node.js, Typescript, React, Flux, Mobx など –  各プロジェクトでリポジトリ分ける
  6. 6. なぜ作り直しているのか •  第2世代の問題点 –  デプロイが遅い –  デザイン単体の確認がしづ らい –  Groovy Template が独特 –  データを管理しているのは バックエンドチームのコード •  → データを提供する仕組みが よく分からない –  jQuery つらい –  Global CSS つらい –  モノリシックつらい
  7. 7. 対策1:フロントエンド分離 •  Docker & Node.js でフロントエンドサーバーを分離 •  合わせて “バックエンド” サーバーがAPI化することで、データ 取得のインターフェースを明確化 •  メリット –  デプロイ遅い問題など解決 –  Docker インスタンス増減でスケール –  フロントエンドメンバーのスキルセットに合った高速開発 –  バックエンドとのコミュニケーションコスト低減
  8. 8. 対策2:View Component •  View Component (VC) を作る – Atomic Design – React Component – Storybook 活用 – HTML, CSS を全て取り持つ •  CSS Modules – 見た目のことしか関知しない
  9. 9. VCで解決されること •  企画者やデザイナーがデザインだけ気軽に 確認できる •  手続き的なviewが宣言的に •  jQuery まみれ •  グローバルスコープなCSS
  10. 10. フロントエンド分離、VC という体制の上で
  11. 11. 自分のチームが作っているもの (CC) •  VC に渡す Props を管理する –  自身も React Component –  「アプリケーションのドメインロジック」を書く –  データの管理 •  サーバーサイドテンプレートで値を受け取る •  API アクセス •  Local Storage の Save, Load
  12. 12. Container Component View Component Propsを作っ て渡す フロントエンド サーバー 載 せ る
  13. 13. PcWatchPage •  watchページの作り直しの CC – h[p://live2.nicovideo.jp/watch/lvXXXX •  MobX •  <head>は持たず、一旦<body>の中身のみ
  14. 14. PcWatchPage の技術的目的 •  Watchページ内でのSPA化の余地を残す – 番組ザッピング機能など – 他ページとの間のSPA化はしない •  Sever Side Rendering (SSR) する
  15. 15. なぜ MobX
  16. 16. 生放送 HTM5 PC プレーヤー •  その前に作っていたプレーヤーでは、 h[ps://github.com/facebook/flux 利用 出典: h[p://azu.github.io/slide/react-meetup/img/flux-overview.png
  17. 17. Facebook Flux 問題点 •  Dispatcher を介する意味があまりない – ほとんど payload: callback = 1:1 •  Aceon Creator から Store のデータを参照した くてもできない
  18. 18. フレームワーク選定条件 •  Facebook/flux 利用時の問題点が解消される •  メンバーの学習コストが低い •  TypeScript との親和性が高い •  VC との親和性が高い
  19. 19. VC との親和性が高いとは? Atomic Design Template に Organism を渡す方式
  20. 20. 🤔 社内外で流行ってるし、 これで書いてみるか
  21. 21. Redux 試してやめた理由:4行 •  connect の型つらい •  Store 1個つらい •  難しい •  つまりうちの制約に合っていない
  22. 22. Redux 試してやめた理由 1: 型 •  connect の mapStateToProps(値) と mapDispatchToProps(アクションを呼ぶコールバック) が別 れており、VC の Props の型(値とコールバックで別れてお らず、1個)を利用できない •  connect で描画最適化した VC の Organism のラッパを VC の Atomic Design Template に渡すためには、Templateで Organismの型を ReactNode に緩める必要があり、VC は Props の型情報を失うし、CCの都合にVCが依存してしまう •  connectの型パズルが難しい –  とにかく怒る –  なんでインターフェース10個位あるの…
  23. 23. Redux 試してやめた理由 2: その他 •  Storeが1個 –  Organism 単位でリポジトリ切って(別個の Store が生まれて)統 合するのを目指してるうちのアーキテクチャと相性悪い •  redux-sagaやreact-reduxなどの学習コストは、多めの人数 で開発していく上ではデカそうと感じた •  やりたいことに対して冗長感がある •  connectを極力使わないなどの方法で避けることはできる かもしれないが、フレームワークの非標準なやり方でやり たくない
  24. 24. Redux 所感 •  TSでなく、VCみたいなのが整備されていない 状態で、すべて自分たちで作っていけるなら、 楽そうなフレームワークだとは思った
  25. 25. 🤔 🤔 他にないかなぁ お h[p://leader22.github.io/slides/ node_gakuen-25/ 💁
  26. 26. 3行でMobX •  mobxのObservableを変化させると •  mobx-reactのObserver(のrender)内で参照し ている所に •  反映される
  27. 27. MobX 採用理由: 型 •  もともと TypeScript で書かれており、型だけ古いとか 複雑みたいなことがない •  各 organism の VC をラップして描画最適化でき、その 際に Props の型情報を失わない •  h[ps://mobx.js.org/best/react-performance.html •  observer (HogeViewComponent) の型が React.ClassicComponentClass<HogeVCのProps> –  VCのAtomic Design Templateで各Organismを React.Component<HogeVCのProps> で受け取れて、VCは型情報を失わ ずにコーディングできる •  型情報はダメでした(後述)
  28. 28. MobX 採用理由:その他 •  Store を複数個作れる –  organism 単位でいつでも切り出したいアーキテクチャ と相性がいい •  Store と Aceon をひとまとめにできるので、 「 Aceon からStore のデータを見たいけどできな い」問題が解決される –  そもそもほとんどのケースで Aceon を分離する必要 性をあまり感じない
  29. 29. MobX 所感 •  シンプル。お作法が特にない (not フレームワー ク) –  柔軟 –  自分たちのお作法を決める必要あり •  React.setState より汎用的な状態管理ができる –  h[ps://medium.com/@mweststrate/3-reasons-why-i- stopped-using-react-setstate-ab73fc67a42e •  Observable 変化に勝手に反応するのでとても楽
  30. 30. どういうお作法で作っているか
  31. 31. HogePage ContainerView ContainerDomain リポジトリ依存関係
  32. 32. 制約 •  PageがDomain, Viewを利用する。逆の依存は しない •  ViewはOrganism単位で完結して動作する – 部品単体で分離して開発できるようにするため
  33. 33. ContainerDomain •  生放送のドメインに関するState, Storeを持つ –  Program •  ID, タイトルなど –  User •  メリット –  DDD的にコーディングできる –  ページごとに使いまわせる •  State 型を合成して各ページのPropsにできる
  34. 34. State.ts •  プレーンなobjectで表現した「状態」 •  例:あるviewのState↓
  35. 35. Store.ts •  Flux のStore じゃないよ! – 命名由来: h[ps://mobx.js.org/best/store.html •  ObservableなStateを保持し、状態を管理 – @aceon で state を書き換えるメソッドを提供 – @computed で state から新たな state を計算する メソッドを提供 – APIやLocal Storageへアクセスしてデータ取得
  36. 36. ContainerView •  見た目の状態として State, Storeを持つ •  ContainerDomainを参照していい •  各 Organism ごとにディレクトリ分ける – 何でページのリポジトリに内包しないの? – どのページでも使う部品があるから
  37. 37. ContainerView ディレクトリ構成 •  OrganismA –  State.ts –  Store.ts –  Container.tsx –  Constants.ts (定数、型定義系) –  Index.ts (まとめてexportしてるだけ) •  OrganismB
  38. 38. Container.tsx •  Store と VC をつなぐ – StoreからStateとaceonを参照し、VCのPropsを作る – VCをObserverでラップしたComponentを提供
  39. 39. Container.tsx 2017/0804追記 当初こうやっていたがダメでした
  40. 40. ダメだったこと •  @types/react のバージョンを上げたら怒られた •  そもそもこれだとrenderでobservable参照してな いので反映されない –  h[ps://mobx.js.org/refguide/observer- component.html •  It wraps the component’s render funceon in mobx.autorun •  Document読めって話だった –  この部品単体ではなく、1階層上のページ全体の observerで全部再描画されてた
  41. 41. ちゃんとReact.Component でラップしましょう 型は諦めた
  42. 42. HogePage •  Hogeページの統括 •  ContainerDomain, ContainerView から任意の部 品を組み合わせてページを作る •  Props の型は自分が使う ContainerDomain の State と、ページごとに変わる型の合成 –  User などの共通Domainのデータがページごとにバラ バラなPropsにならずに済む
  43. 43. ページからview Storeへの 依存性注入 •  例: –  複数のviewで共有されるテキスト •  StoreはBaseとなるStoreを継承 –  コンストラクタ引数で、Observableではないものは、 Observable化し保持 –  Observableなら、そのまま保持 •  View Stateにinterfaceを定義し、Pageが Observableとして持ち、View Storeに注入
  44. 44. BaseとなるStore
  45. 45. DomainStores •  ページで使うdomain storeの集約を持ち、そ れをviewに注入
  46. 46. ContainerInfra •  色んなリポジトリから使うもの – BaseのStore – URL加工奴 – API Client作る奴
  47. 47. MobX 知見
  48. 48. useStrict(true) にするべき •  false – どこからでも this.state = hoge できる •  true – @aceon をつけたメソッド以外でやると console.error – 全アクションがログに残る
  49. 49. reaceonは極力使わない方が良い •  h[ps://mobx.js.org/refguide/reaceon.html •  当初はページ状態の変化をreaceonでviewに反 映していた –  ページのProgramIDが変わったら、ViewのProgramID をaceonで更新 •  ContainerDomainで状態重複とreaceon排除 –  Viewは見た目の状態だけ持てば良くなった –  その代わり全てMobXに依存することに
  50. 50. ObservableArray !== Array •  Observable(object)すると、中にあるArrayが ObservableArray になってしまう •  ObservableArrayの挙動はArrayと違う – h[ps://mobx.js.org/refguide/array.html •  Arrayに戻したかったらpeekを叩く
  51. 51. observable() 時に存在するproperty のみ監視される •  h[ps://mobx.js.org/refguide/object.html •  mapを使うのが良いかも •  やはりmapよりObjectが圧倒的に使い易いの で、うちは一旦 ? を禁止して “ | undefined” に し、Stateの?を検知するメタテストを追加する ことにした
  52. 52. ステートフルでラップしないと動かない •  observerでラップした部品単体で動かなかった •  ページのトップでobserverしたら動き、外すと動かなかった •  observer(statelessComponent) は単体で動か ない – トップレベルでobserver(statefullComponent)する •  h[ps://mobx.js.org/best/stateless-HMR.html
  53. 53. 余談
  54. 54. MobX って RxJS と似てない? •  h[ps://github.com/mobxjs/mobx/wiki/Mobx- vs-Reaceve-Stream-Libraries-(RxJS,-Bacon,- etc) •  実際 RxJS で書ける •  ほとんどのケースでは MobX で必要十分
  55. 55. mobx-state-tree •  h[ps://github.com/mobxjs/mobx-state-tree •  公式が実験してるフレームワーク的なもの
  56. 56. 結論
  57. 57. いいぞ •  業務時間でプロトタイプいくつか作って技術選定 •  TypeScript でドメイン型定義 •  MobX で状態管理 •  Storybook, knobsで動作確認 •  アーキテクチャを分ける: –  ドメイン –  ビュー:AtomicDesign
  58. 58. おわり Special thanks チームメンバー

×