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
1.1k
Backbone.Model に 型をつけて剥がす - Typing to destroy Backbone.Model
2019年9月20日の社内勉強会の資料です
fsubal
September 20, 2019
Tweet
Share
More Decks by fsubal
See All by fsubal
負債になりにくいCSSをデザイナとつくるには?
fsubal
11
3.3k
Webデザインと フロントエンド技術🔰勉強会
fsubal
2
300
Tailwind CSSを本気でカスタマイズする方法
fsubal
17
7.5k
デザインシステムで Tailwind CSSとCSS in JSに分散投資をしたら良かった話
fsubal
20
7.2k
『Tailwind CSS実践入門』 出版記念基調講演
fsubal
9
5.3k
Sprockets CSSもやめる なぜ / Why stop using Sprockets for CSS too
fsubal
3
1.6k
The Majestic MPA
fsubal
8
3.3k
SVG + React でつくる レイヤーの自由変形 / Layer Transformation with React + SVG
fsubal
1
9.5k
カリー化はナンの役に立つのか
fsubal
27
8.9k
Other Decks in Programming
See All in Programming
CSC305 Lecture 04
javiergs
PRO
0
270
Claude Agent SDK を使ってみよう
hyshu
0
1.2k
その面倒な作業、「Dart」にやらせませんか? Flutter開発者のための業務効率化
yordgenome03
1
130
Leading Effective Engineering Teams in the AI Era
addyosmani
7
470
開発生産性を上げるための生成AI活用術
starfish719
3
1.4k
Range on Rails ―「多重範囲型」という新たな選択肢が、複雑ロジックを劇的にシンプルにしたワケ
rizap_tech
0
6.7k
チームの境界をブチ抜いていけ
tokai235
0
190
スマホから Youtube Shortsを見られないようにする
lemolatoon
27
33k
All About Angular's New Signal Forms
manfredsteyer
PRO
0
190
『毎日の移動』を支えるGoバックエンド内製開発
yutautsugi
2
250
What Spring Developers Should Know About Jakarta EE
ivargrimstad
0
260
Building, Deploying, and Monitoring Ruby Web Applications with Falcon (Kaigi on Rails 2025)
ioquatix
4
2.3k
Featured
See All Featured
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
132
19k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
37
2.6k
Speed Design
sergeychernyshev
32
1.2k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.2k
Product Roadmaps are Hard
iamctodd
PRO
54
11k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
GraphQLとの向き合い方2022年版
quramy
49
14k
Visualization
eitanlees
149
16k
The Cult of Friendly URLs
andyhume
79
6.6k
Large-scale JavaScript Application Architecture
addyosmani
514
110k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
55
3k
VelocityConf: Rendering Performance Case Studies
addyosmani
332
24k
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