Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
新タクシー配車システムの裏側/dispatcher-background
Search
haco
May 23, 2017
Programming
450
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
新タクシー配車システムの裏側/dispatcher-background
haco
May 23, 2017
More Decks by haco
See All by haco
コードファースト vs スキーマファースト on Rust / code-first-vs-schema-first
haco
0
2.4k
crates.io にライブラリを公開してみた / publish-on-crates-io
haco
0
990
Other Decks in Programming
See All in Programming
フロントエンドとバックエンドで「1文字」を揃えよう
youkidearitai
PRO
0
700
RTSPクライアントを自作してみた話
simotin13
0
610
脅威をエンジニアリングの糧にして――現場編 / Turning Threats into Engineering Fuel — Field Edition
nrslib
0
280
net-httpのHTTP/2対応について
naruse
0
490
Strategic Design in the Frontend: Moduliths & Micro Frontends @DDDEurope
manfredsteyer
PRO
0
100
Even G2とAWSで推しのエージェントを召喚しよう!
har1101
1
120
ふつうのFeature Flag実践入門
irof
7
4k
「AIで開発し、AIを届ける」をEvalでつなぐ 〜AIネイティブに始めるプロダクト開発の実践〜 / Connecting "Develop with AI, deliver AI" with Eval
rkaga
4
5.1k
技術記事、 専門家としてのプログラマ、 言語化
mizchi
13
6.1k
New "Type" system on PicoRuby
pocke
1
960
エンジニアと一緒にテストコードの設計と実装を改善した話
mototakatsu
0
190
肥大化するレガシーコードに立ち向かうためのインターフェース分離と依存の逆転 / JJUG CCC 2026 Spring
hirokunimaeta
0
570
Featured
See All Featured
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
390
Into the Great Unknown - MozCon
thekraken
41
2.6k
Amusing Abliteration
ianozsvald
1
210
WENDY [Excerpt]
tessaabrams
11
38k
How to make the Groovebox
asonas
2
2.2k
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
1
2.7k
Optimising Largest Contentful Paint
csswizardry
37
3.7k
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
Code Reviewing Like a Champion
maltzj
528
40k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
First, design no harm
axbom
PRO
2
1.2k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.8k
Transcript
新タクシー配車システムの裏側 2017-05-23 : ヒカラボ発表資料 JapanTaxi : 相田 岳彦
自己紹介 2016-06 JapanTaxi 入社 06-07 月 某 API サーバ /
Golang 07-11 月 全国タクシー Android / Java 10-12 月 Google Maps 対応 12-01 月 某バッチサーバ / Scala 12-02 月 全国タクシー API / Rails 03 月- 新タクシー配車システム / ES6, Rails いろいろやってます
今回話すこと 新タクシー配車システムの紹介 技術的負債を避けるための取り組み Rails API 開発編 React フロントエンド開発編
今回話さないこと Rails や React アプリの構築方法 CI/CD の構築方法
そもそも配車システムって何さ ざっくりまとめると
お客さんからの注文を受けて オペレータが空車状況などを確認して タクシーを配車するためのシステム
今回話すところ API は Rails で作られていて フロントは React で作られているサービス
ということで技術的な話
まずは Rails の話から
Rails 開発で防いでおきたかったこと とりあえず ID パターン テーブルモデル中毒
とりあえず ID パターン ( ご存知の方)
あらゆるテーブルに ID を入れてしまう症状 詳細は "SQL アンチパターン" 参照
大前提 ウェブフレームワークの都合で テーブル設計を歪める判断は基本的にありえない
対処 Rails にはきちんと primary key を 明示する仕組みが用意されてる
Q. そうはいっても "id" がないと 冗長になるコードはあるよね? A. それでもプロダクト根幹の DB 設計を歪めるほうがダメ
テーブルモデル中毒 ( ご存知の方)
先週名付けました ( 聞いたことがなくても安心してください)
テーブルと 1:1 で紐付いた「モデル」で 全てを表現しようとする症状
行き着く先は 典型的なファットモデル… !
これが rails-way なのだという誤解を 頻繁に見かける超要注意パターン
テーブルモデル中毒を 予防するには… ?
レビューで解決… ? レビュアーが全員 毎回忘れずに チェックするのは現実的だろうか(反語)
開発者全員が危険性と 回避方法を理解すればいい… ?
しかし未経験の負債への対処はとても難しい ファットモデルのヤバさは ファットになるまで気付けない ファットになってしまったら もうすでに遅かったりして…
あらためて テーブルモデル中毒を 予防するには一体どうしたら… ?
私たちの答え 「モデリングを開発フローに組み込もう」
具体的には? アクションごとの仕様を宣言するための 言語内 DSL をコントローラに用意
個々のリクエストとレスポンスに 対応するクラスをまず最初に定義する それぞれのクラスに対応する JSON Schema ファイルも生成する
コード例 update アクションの仕様を宣言する場合 api :update, :request => Requests::V1::Hello::CreateParameter :response =>
Resources::V1::Greeting::Hello
これによって テーブルモデルを引き回すコードや view で巨大な JSON を構築するようなコード が生まれてしまう余地を取り除いた
さらに 指定した型にならないリクエストは 400 指定した型にならないレスポンスは 500 も自動化できた!
副次的な効果
JSON Schema を導入したことで : API 仕様が自動的にバージョン管理される うっかり破壊的変更を入れても簡単に気付ける (スキーマファイルも変更されるため)
リソースのモデリングによって : リソースの型をバージョニングできる 安全にバージョンアップできる 機能拡張に対する心理的障壁の除去
言語内 DSL の表現力によって リソースを今まで通りに抽象化できる JSON Schema の手作業記述を回避 正規表現のコピペ問題なども回避
次は React の話 というよりは React-Redux の話
React-Redux で防いでおきたかったこと implicit state implicit action fat dispatcher
implicit state 実装者の頭の中だけに state の定義がある状態
implicit state 「どのような状態が正しいのか」が コードで表現されていない状態 フィールドの更新漏れ・追加忘れといった 人的ミスが誘発される
解決方法 全ての state をクラスとして明示的に定義 初期状態や更新方法をクラス内で完結させる
implicit action 実装者の頭の中だけに action の定義がある状態
implicit action 「この action にはどのような値があるのか」 「この action はどの type と紐付いているのか」
抱えている問題は implicit state とほぼ同じ
解決方法 対処策も implicit state とほぼ同じ ( ただし action の場合はクラス化の必要なし)
具体的には… ? action と type を紐付ける ActionFactory を用意
これによって : factory に action の定義が明文化される reducer の依存先を action-factory だけにできる
文字列定数の type を羅列する苦行の回避
コード例 actions.js // 該当する顧客が見つかった場合のアクション export const CustomerFound = ActionFactory({ type:
'OrderEditor/CustomerFound', /** * @param {CustomerOutline} customer */ currentCustomer: customer => customer, });
reducer.js // 注文編集フォームの reducer export const editorReducer = ReducerFactory.create({ initializer:
() => { return EditorState.empty(); }, /** * @param {EditorState} state * @param {Object} action - see ./actions.js */ handlers: (state, action) => ({ [CustomerFound]: () => { return state.updateState({ customer: action.currentCustomer, }); }, }), ... });
fat dispatcher 文字通り dispatcher が肥大化する症状 fat model や fat controller
と同種のもの
解決方法 dispather の責務を絞る
具体的には? dispatcher は 文字通り action を dispatch するだけに留める 各種データの取得処理は他のモジュールに切り出す 典型例は
API リクエスト レイヤードアーキテクチャを導入して責務を分担
レイヤー構造 layouts 画面内の component に紐づく処理 domain 複数の component で共有するロジック repository
API リクエスト ストレージ (cookie, LocalStorage) 操作 dispatcher が利用する多くのモジュールは ほとんどの場合はこのレイヤにある (相対パス地獄は webpack の resolve.root 指定で回避)
まとめ Rails Rails Way をダメな設計の弁明手段にしない ダメなのは必ずしも Rails のせいではない React (Redux)
サンプルコードはそのまま真似してはいけない プロジェクトに適した方法で抽象化しよう - n-