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
Backbone.Model に 型をつけて剥がす - Typing to destroy B...
Search
fsubal
September 20, 2019
Programming
1.2k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Backbone.Model に 型をつけて剥がす - Typing to destroy Backbone.Model
2019年9月20日の社内勉強会の資料です
fsubal
September 20, 2019
More Decks by fsubal
See All by fsubal
負債になりにくいCSSをデザイナとつくるには?
fsubal
11
3.6k
Webデザインと フロントエンド技術🔰勉強会
fsubal
2
360
Tailwind CSSを本気でカスタマイズする方法
fsubal
17
8k
デザインシステムで Tailwind CSSとCSS in JSに分散投資をしたら良かった話
fsubal
20
7.6k
『Tailwind CSS実践入門』 出版記念基調講演
fsubal
9
5.5k
Sprockets CSSもやめる なぜ / Why stop using Sprockets for CSS too
fsubal
3
1.7k
The Majestic MPA
fsubal
8
3.4k
SVG + React でつくる レイヤーの自由変形 / Layer Transformation with React + SVG
fsubal
1
9.9k
カリー化はナンの役に立つのか
fsubal
27
9.3k
Other Decks in Programming
See All in Programming
【やさしく解説 設計編・中級 #4】ルールの寿命と、システムの年輪
panda728
PRO
2
170
そこに3びきプロダクトがいるじゃろう——生成AI時代における“価値が届かない理由”の構造
kosuket
0
230
Welcome to the "Parametricity" 🏙️ − Generic だけど Specific な世界 −
guvalif
PRO
1
190
5分で問診!Composer セキュリティ健康診断
codmoninc
0
680
PHP Application における Kubernetes 内 gRPC 通信
ganchiku
0
550
Google Apps Script で Ruby を動かす
kawahara
0
110
AI時代、エンジニアはどう育つのか -未経験エンジニアの成長を間近で見て考えたこと-
thasu0123
0
190
【SRE NEXT 2026 Lunch Session】一人目専任SREの立ち上げを加速する ― AIと進めたオンボーディングで2分を0.04秒にした話
pkshadeck
PRO
0
3.2k
PHP初心者セッション2026 〜生成AIでは見えない裏側を知る:今だからLAMPを通して仕組みを学ぶ〜
kashioka
0
720
GDG Korea Android: 2026 I/O Extended ~ What's new in Android development tools
pluu
0
190
『コードを書く以外の』エンジニアリング〜課金基盤移行プロジェクト推進のためのTips4選
yuriko1211
0
550
地域 SRE コミュニティ最前線 - ホンマでっかSRE勉強会
tk3fftk
0
280
Featured
See All Featured
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
49
10k
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
64
56k
KATA
mclloyd
PRO
35
15k
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
250
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
53k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.5k
YesSQL, Process and Tooling at Scale
rocio
174
15k
Optimizing for Happiness
mojombo
378
71k
Side Projects
sachag
455
43k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
420
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
530
Transcript
Backbone.Model に 型をつけて剥がす Sub title pixiv Inc. subal 2019.9.20
2 誰 • pixivFACTORY • TypeScript と SVG と React、時々
Rails • 型芸、SVG芸、hooks 芸の話ができます subal
3 型芸で負債を倒す話
4
5 pixivFACTORY BOOKS
6 pixivFACTORY BOOKS • 同人誌作成機能。グッズと並ぶ、 pixivFACTORY の二大柱 • 同人誌プラン検索/入稿画面が React
+ Redux • ただし、2015年に設計された React + Redux アプリケーション • アップデートの結果表面的な記法は新しくなっている(Babel, ES6 Classes) ◦ しかし本質的な設計は…? ◦ それに、グッズ側は TypeScript で書くのが当たり前に変わっている
7 設計上の課題 • mixin の名残がある ◦ React.createClass は流石にやめているが、constructor で this
を lodash/extend している • Redux の store に Backbone.Model のインスタンスが入っている ◦ Immutable.js ならまだ分かるけど、Backbone.Model です ▪ まぁ私は Immutable.js も嫌いなのであったらあったで剥がしますけど • 他にもいろいろあるが、とりあえず ↑ を何とかする。まずはそれから
8 とりあえずのゴール • reducer で Backbone.Model を作らない • store に
Backbone.Model を持たない • コンポーネントに Backbone.Model を持ち込ませない • TS化し、型のついたただの json にする
9 現状
10
11 セッターで型をキャストする 仕組み ( ActiveModel::Attributes みたいなやつ ) モデルのデフォルト値
12 プロパティとは別にメソッドっぽいのが生えるケースがある
13 たとえばここが、number と勝手に推論される状況を作りたい
14 おっとこんなところにデ フォルト値が
15 extend() の引数内の defaults から、 返り値の型を推論する
16
17
18
19
20 1個ずつ解説します みたいな型定義で倒せるのですが…
21 Model のインスタンスの型を考える • Backbone.Model のプロパティは(厳密には違うけど)だいたい keyof defaults • 仮に、extend()
の引数を option とするとき… ◦ defaults の型は typeof option['defaults'] ◦ これを仮に P と置く ◦ すると、インスタンスの型はそれをジェネリクスに受け取る TypedModelInstance<P> と置くことができる ◦ その型は get<K extends keyof P>(key: K): K[P] というメソッドを持つはず
22 これにより、model.get('hoge') で hoge が defaults に書かれてないキーならば、 コンパイルエラーになる
23 Model のインスタンスの型を考える 2 • Backbone.Model の set は特殊で、以下の二つの記法が許容される (うげぇ…)
◦ model.set('page_size', 12) ◦ model.set({ page_size: 12 }) • TypeScript にはメソッドの型をオーバーロードする仕組みがあるので、両対応で書くことは 可能
24
25 Model のインスタンスの型を考える 3 • toJSON の型は、少なくとも推論されたすべてのプロパティを含む型を返すはず ◦ さっきの言葉で言えば、とりあえず P
あるいは P を継承した型であるはず ◦ 実は、Backbone.Model はプロパティとは別に getters という仕組みがあり、本当は それらも toJSON に含まれる ▪ が、一旦無視してすすめる
26
27 クラスの型を考える • Backbone.Model.extend() は「クラスを作る関数」 ◦ なので、返り値がクラス(あるいは newable なオブジェクト)と考える必要がある ◦
TypeScript は、任意の型に対して、それを new で呼んだときの返り値を定義するこ とができる ◦ Book クラスは ReturnType<typeof Backbone.Model.extend({ ... })> のような方法 で推論されるし、インスタンスの型は new の型定義から推論される
28
29 ここまでやると、 コンパイラは Book という「クラス」がどうい う構造かを理解し始める
30 Reducer から剥がしていく • model クラスをやめてただの JSON にしたあとで、返り値の型が変わらないことを保証した い ◦
Jest のスナップショットテストを使う • 剥がした後に残る JSON の型を、interface State として書いておきたい ◦ まぁ infer を使って出てきた結果をコピーするとか … ◦ 推論結果を参考に頑張って書くしかない( optional なキーとか推論しきれてない箇所 はあるので )
31 テストのコツ • もともと、backbone.model を生で使ったテストは書かれていたが、これは使わないことに した ◦ 剥がした後も有効であり続けるテストでないと意味がない ◦ toJSON
した結果をスナップショットテストして、 ▪ それが剥がした後も通る ▪ あるいは、落ちるけど差分が意図したものであることを検証したい
32
33
34 • props にまで Backbone のモデルインスタンスが渡っている箇所がある • コンポーネントの外に追い出したい • reducer
にしか現れない状況を作った上で、reducer を倒すみたいな感じにしたい コンポーネントに露出している model
35 toJSON するだけの selector を書く
36 useSelector を使って末端から型付け
37 • 一部の画面 / model だけしか置き換えてないのでまだまだ • 終わったらあの型定義はちゃんと捨てる ◦ 登りきった後は梯子を投げ捨てなければならない
今後
38 戦いはまだまだこれから…!
39 • とりあえず、全部ではないが Backbone.Model を剥がしながら型付け・モダン化が進ん でいる • TypeScript の型システムは無限に便利なのであーいうものでも型がつけられてしまう •
スナップショットテストはライブラリを消すときの強い味方 • useSelector は最高 まとめ
40 • 一つには優先度の問題 ◦ 「他の改修を一切留めてやるべきか」といういつもの話 • もう一つは、実はこっちのほうが事故らないかもという考え ◦ 古くて型のないコードを「読解して」書き直すのと、古いコードの実装から型を「 推論さ
せて」安全にするアプローチ ▪ 前者(書き直し)のほうが良いと自信を持って言えたか?うーん … ▪ 真面目に読むの嫌なのでコンパイラにやらせるは一つの方法としてある Q. Why not フルスクラッチ?
Backbone.Model に 型をつけて剥がす Sub title pixiv Inc. subal 2019.9.20