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.1k
『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.4k
カリー化はナンの役に立つのか
fsubal
27
8.8k
Other Decks in Programming
See All in Programming
iOSエンジニア向けの英語学習アプリを作る!
yukawashouhei
0
140
Learn CPU architecture with Assembly
akkeylab
1
1.3k
Build your own WebP codec in Swift
kishikawakatsumi
2
860
Repenser les filtres API Platform: une nouvelle syntaxe
vinceamstoutz
2
160
Reduxモダナイズ 〜コードのモダン化を通して、将来のライブラリ移行に備える〜
pvcresin
2
660
猫と暮らすネットワークカメラ生活🐈 ~Vision frameworkでペットを愛でよう~ / iOSDC Japan 2025
yutailang0119
0
210
CSC305 Lecture 04
javiergs
PRO
0
230
詳しくない分野でのVibe Codingで困ったことと学び/vibe-coding-in-unfamiliar-area
shibayu36
2
1.7k
GraphQL×Railsアプリのデータベース負荷分散 - 月間3,000万人利用サービスを無停止で
koxya
1
1k
Swift Concurrency - 状態監視の罠
objectiveaudio
2
400
iOSエンジニア向けの英語学習アプリを作る!
yukawashouhei
0
170
(Extension DC 2025) Actor境界を越える技術
teamhimeh
1
180
Featured
See All Featured
GitHub's CSS Performance
jonrohan
1032
460k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
Stop Working from a Prison Cell
hatefulcrawdad
271
21k
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
Unsuck your backbone
ammeep
671
58k
Mobile First: as difficult as doing things right
swwweet
224
9.9k
The Art of Programming - Codeland 2020
erikaheidi
56
14k
The Invisible Side of Design
smashingmag
301
51k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
358
30k
A Modern Web Designer's Workflow
chriscoyier
697
190k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
132
19k
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