[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
SlideShare a Scribd company logo
ニコニコ生放送のwatchページを	
MobX	で作り直している話	
@kondei
背景事情(3行)
_人人人人人_	
> つらい <	
 ̄Y^Y^Y^Y ̄	
	
Node な	
フロントエンド	
サーバー 分離	
Atomic	Design な	
View	Component	
誕生
背景事情(詳細)
歴史	
•  第1世代:	
–  PHP	Smarty	Template,	ES5	
–  モノリシック	
•  第2世代:	
–  Groovy	Template,	TypeScript,	jQuery	
–  モノリシック	
:← いまここ	
–  Node.js,	Typescript,	React,	Flux,	Mobx	など	
–  各プロジェクトでリポジトリ分ける
なぜ作り直しているのか	
•  第2世代の問題点	
–  デプロイが遅い	
–  デザイン単体の確認がしづ
らい	
–  Groovy	Template	が独特	
–  データを管理しているのは
バックエンドチームのコード	
•  →	データを提供する仕組みが
よく分からない	
–  jQuery つらい	
–  Global CSS つらい	
–  モノリシックつらい
対策1:フロントエンド分離	
•  Docker	&	Node.js	でフロントエンドサーバーを分離	
•  合わせて	“バックエンド”	サーバーがAPI化することで、データ
取得のインターフェースを明確化	
•  メリット	
–  デプロイ遅い問題など解決	
–  Docker	インスタンス増減でスケール	
–  フロントエンドメンバーのスキルセットに合った高速開発	
–  バックエンドとのコミュニケーションコスト低減
対策2:View	Component	
•  View	Component	(VC)	を作る	
– Atomic	Design	
– React	Component	
– Storybook	活用	
– HTML,	CSS を全て取り持つ	
•  CSS	Modules	
– 見た目のことしか関知しない
ニコニコ生放送の watch ページを MobX で作り直している話
VCで解決されること	
•  企画者やデザイナーがデザインだけ気軽に
確認できる	
•  手続き的なviewが宣言的に	
•  jQuery	まみれ	
•  グローバルスコープなCSS
フロントエンド分離、VC	
という体制の上で
自分のチームが作っているもの	
	(CC)	
•  VC	に渡す	Props	を管理する	
–  自身も	React	Component	
–  「アプリケーションのドメインロジック」を書く	
–  データの管理	
•  サーバーサイドテンプレートで値を受け取る	
•  API アクセス	
•  Local	Storage	の	Save,	Load
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/flux-overview.png
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	の型(値とコールバックで別れてお
らず、1個)を利用できない	
•  connect	で描画最適化した	VC	の Organism	のラッパを	VC
の	Atomic	Design	Template に渡すためには、Templateで
Organismの型を ReactNode	に緩める必要があり、VC	は	
Props の型情報を失うし、CCの都合にVCが依存してしまう	
•  connectの型パズルが難しい	
–  とにかく怒る	
–  なんでインターフェース10個位あるの…
Redux	試してやめた理由	2:	その他	
•  Storeが1個	
–  Organism	単位でリポジトリ切って(別個の	Store	が生まれて)統
合するのを目指してるうちのアーキテクチャと相性悪い	
•  redux-sagaやreact-reduxなどの学習コストは、多めの人数
で開発していく上ではデカそうと感じた	
•  やりたいことに対して冗長感がある	
•  connectを極力使わないなどの方法で避けることはできる
かもしれないが、フレームワークの非標準なやり方でやり
たくない
Redux	所感	
•  TSでなく、VCみたいなのが整備されていない
状態で、すべて自分たちで作っていけるなら、
楽そうなフレームワークだとは思った
🤔	
🤔	
他にないかなぁ	
お	
h[p://leader22.github.io/slides/
node_gakuen-25/		💁
3行でMobX	
•  mobxのObservableを変化させると	
•  mobx-reactのObserver内で参照している所に	
•  反映される
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は型情報
を失わずにコーディングできる
MobX	採用理由:その他	
•  Store	を複数個作れる 	
–  organism	単位でいつでも切り出したいアーキテクチャ
と相性がいい	
•  Store	と	Aceon	をひとまとめにできるので、
「	Aceon	からStore	のデータを見たいけどできな
い」問題が解決される	
–  そもそもほとんどのケースで	Aceon	を分離する必要
性をあまり感じない
MobX	所感	
•  シンプル。お作法が特にない (not	フレームワー
ク)	
–  柔軟	
–  自分たちのお作法を決める必要あり	
•  React.setState	より汎用的な状態管理ができる	
–  h[ps://medium.com/@mweststrate/3-reasons-why-i-
stopped-using-react-setstate-ab73fc67a42e		
•  Observable 変化に勝手に反応するのでとても楽
どういうお作法で作っているか
HogePage	
ContainerView	
ContainerDomain	
リポジトリ依存関係
制約	
•  PageがDomain,	Viewを利用する。逆の依存は
しない	
•  ViewはOrganism単位で完結して動作する	
– 部品単体で分離して開発できるようにするため
ContainerDomain	
•  生放送のドメインに関するState,	Storeを持つ	
–  Program	
•  ID,	タイトルなど	
–  User	
•  メリット	
–  DDD的にコーディングできる	
–  ページごとに使いまわせる	
•  State 型を合成して各ページのPropsにできる
State.ts	
•  プレーンなobjectで表現した「状態」	
•  例:あるviewのState↓
Store.ts	
•  Flux のStore	じゃないよ!	
– 命名由来: h[ps://mobx.js.org/best/store.html		
•  ObservableなStateを保持し、状態を管理	
– @aceon	で	state	を書き換えるメソッドを提供	
– @computed で	state から新たな	state	を計算する
メソッドを提供	
– APIやLocal	Storageへアクセスしてデータ取得
ContainerView	
•  見た目の状態として State,	Storeを持つ	
•  ContainerDomainを参照していい	
•  各	Organism	ごとにディレクトリ分ける	
– 何でページのリポジトリに内包しないの?	
– どのページでも使う部品があるから
ContainerView	ディレクトリ構成	
•  OrganismA	
–  State.ts	
–  Store.ts	
–  Container.tsx	
–  Constants.ts	(定数、型定義系)	
–  Index.ts	(まとめてexportしてるだけ)	
•  OrganismB
Container.tsx	
•  Store	と	VC	をつなぐ	
– StoreからStateとaceonを参照し、VCのPropsを作る	
– VCをObserverでラップしたComponentを提供
Container.tsx
HogePage	
•  Hogeページの統括	
•  ContainerDomain,	ContainerView	から任意の部
品を組み合わせてページを作る	
•  Props の型は自分が使う ContainerDomain	の	
State	と、ページごとに変わる型の合成	
–  User などの共通Domainのデータがページごとにバラ
バラなPropsにならずに済む
ページからview	Storeへの	
依存性注入	
•  例:	
–  複数のviewで共有されるテキスト	
•  StoreはBaseとなるStoreを継承	
–  コンストラクタ引数で、Observableではないものは、
Observable化し保持	
–  Observableなら、そのまま保持	
•  View	Stateにinterfaceを定義し、Pageが
Observableとして持ち、View	Storeに注入
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が変わったら、ViewのProgramID
をaceonで更新	
•  ContainerDomainで状態重複とreaceon排除	
–  Viewは見た目の状態だけ持てば良くなった	
–  その代わり全てMobXに依存することに
ObservableArray	!==	Array	
•  Observable(object)すると、中にあるArrayが
ObservableArray	になってしまう	
•  ObservableArrayの挙動はArrayと違う	
– h[ps://mobx.js.org/refguide/array.html		
•  Arrayに戻したかったらpeekを叩く
observable()	時に存在するproperty	
のみ監視される	
•  h[ps://mobx.js.org/refguide/object.html	
•  mapを使うのが良いかも
ステートフルでラップしないと動かない	
•  observerでラップした部品単体で動かなかった	
•  ページのトップでobserverしたら動き、外すと動かなかった	
•  observer(statelessComponent)	は単体で動か
ない	
– トップレベルでobserver(statefullComponent)する	
•  h[ps://mobx.js.org/best/stateless-HMR.html
余談
MobX	って RxJS と似てない?	
•  h[ps://github.com/mobxjs/mobx/wiki/Mobx-
vs-Reaceve-Stream-Libraries-(RxJS,-Bacon,-
etc)	
•  実際 RxJS で書ける	
•  ほとんどのケースでは MobX	で必要十分
mobx-state-tree	
•  h[ps://github.com/mobxjs/mobx-state-tree	
•  公式が実験してるフレームワーク的なもの
結論
いいぞ	
•  プロトタイプいくつか作って技術選定	
•  TypeScript でドメイン型定義	
•  MobX	で状態管理	
•  Storybook,	knobsで動作確認	
•  アーキテクチャを分ける:	
–  ドメイン	
–  ビュー:AtomicDesign
おわり	
Special	thanks	チームメンバー
ニコニコ生放送の watch ページを MobX で作り直している話
ニコニコ生放送の watch ページを MobX で作り直している話

More Related Content

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