Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
大規模改修の裏でTypeScriptとテスト導入をすすめた話
Amon Keishima
June 05, 2020
Programming
12
7.6k
大規模改修の裏でTypeScriptとテスト導入をすすめた話
Amon Keishima
June 05, 2020
Tweet
Share
Other Decks in Programming
See All in Programming
How to Fight Production Incidents?
asatarin
0
230
42tokyo-born2beroot-review
love42
0
110
Refactor with using `available` and `deprecated`
417_72ki
3
380
Cloudflare WorkersでGoを動かすライブラリを作っている話
syumai
1
320
[2023년 1월 세미나] 데이터 분석가 되면 어떤 일을 하나요?
datarian
0
610
良質な技術記事を量産する秘訣 / #MeetsPro
jnchito
16
4.3k
Rによる大規模データの処理
s_uryu
2
640
Enumを自動で網羅的にテストしてみた
estie
0
1.3k
ECテックカンファレンス2023
kspace
1
360
xarray-Datatree: Hierarchical Data Structures for Multi-Model Science
tomnicholas
0
230
Unity+C#で学ぶ! メモリレイアウトとvtableのすゝめ 〜動的ポリモーフィズムを実現する仕組み〜
rossam
1
300
WordPress(再)入門 - 基礎知識・環境編
oleindesign
1
140
Featured
See All Featured
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
22
1.7k
StorybookのUI Testing Handbookを読んだ
zakiyama
8
3.2k
A Philosophy of Restraint
colly
193
15k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
38
3.6k
Scaling GitHub
holman
453
140k
The Illustrated Children's Guide to Kubernetes
chrisshort
22
43k
For a Future-Friendly Web
brad_frost
166
7.8k
Designing for humans not robots
tammielis
245
24k
The Cult of Friendly URLs
andyhume
69
5.1k
We Have a Design System, Now What?
morganepeng
37
5.9k
How GitHub (no longer) Works
holman
298
140k
The Language of Interfaces
destraynor
149
21k
Transcript
⼤規模改修の裏で TypeScriptとテスト導⼊をすすめた話 LINE Growth Technology株式会社 UITチーム けいしま あもん
⾃⼰紹介 名前 Twitter @pittanko_pta 所属 LINE Growth Technology株式会社 UITチーム (けいしま
あもん) 慶島亜⾨
今⽇お話すること 担当しているLINEポイントクラブで メインタスクの合間をぬってTypeScriptやテストの導⼊をしている話 現状 作戦 やったこと 知⾒やハマり の順でお話していく
LINEポイントクラブとは 過去6ヶ⽉間に獲得した「LINEポイント」の総量に応じて決まる 4段階の「マイランク」ごとに、毎⽉LINEの各種サービスが お得に利⽤できる、様々な特典を受けられるプログラム 「LINEポイント」は 「LINE」の各種サービスの利⽤や、LINE公式アカウントの 友だち追加、動画視聴などで貯めることができる 前⾝はLINEフリーコインと呼ばれるもので LINEの中でも⻑く続いているサービスのひとつ ・実はWebベース
・Vue.jsで作られている
現状
プロジェクトが抱えていた問題点 2013年にスタートしたサービスであるため… テストコードが書かれていない ・Karmaが導⼊だけされているものの、テストコードがない ・しかし、リリースの度にQAを⾏うので品質は担保できていた いろんな環境が古い ・Webpackのバージョンが古い ・Babelのバージョンが古い サブプロジェクトとメインプロジェクトのビルド環境が違う ・Browserifyでビルドしている(gruntも使ってた)
・module.exports / requireを使っており import / export ではない QA: Quality Assuranceのこと
⻑期的にその問題点を考える 今まで⻑くやってきたプロジェクトなので仕⽅ない⾯もありますが 今後も⻑く続いていくだろうことを考えると… 新しく⼊ってくるメンバーが古い技術を勉強することよりも モダンな技術の知識で 即戦⼒になれるような環境 を整備するべきと考えた
問題点を解決するために… ・TypeScriptを導⼊すること ・テストを本格的に導⼊すること の2点はマストだと考えた
TypeScriptへのモチベーション コードに型がつくことで潜在的なミスを減らすことができる ・ビルドをする段階でミスに気づけるので、サービスの品質向上につながる ・コードレビューの負荷を軽減(しょうもないミスは事前に解決できそう)
テスト導⼊へのモチベーション 今後やりたいコードのリファクタリングを安⼼して⾏いたい ⼩さいバグを減らすことができれば、QAのコストも下がるかも
作戦
短期・中⻑期的な話 古いプロジェクトで機能追加案件も並⾏する場合 TSを導⼊して、テストを導⼊するのは時間がかかってしまうもの その中で早期に環境を整え、運⽤に組み込み基盤を作るのがプロジェクトでの最⼤の課題 そのために必要なのは、中⻑期を⾒据えた上での作戦(計画)を⽴てることだと思う 短期でTS運⽤基盤を構築することと、 中⻑期でのプロジェクトに適応させていくことが⼤きな鍵といえる 今回はまず、短期でのTS運⽤基盤の構築に注⼒した
作戦 TypeScriptの環境を導⼊ / Vue.js の TypeScript対応 Jestの導⼊ / Babelのアップデート /
Webpackのアップデート 脱Browserify / 脱grunt など… やりたいこと(やらないといけないこと)はたくさんあるが、 ⼀気にいろいろ変えてしまうとコードの差分が⼤きくなってしまう 動作を確認するにも時間かかるし レビュワーの負担も⼤きくなってしまう 今回の作戦は なるべく⼩さく⼊れること とした
(余談)社内の他案件の状況や傾向 LINEとしては2017年の上半期からTypeScriptの対応をリードエンジニアが始めている 新規に開発するプロジェクトではTypeScriptの採⽤に積極的な⼀⽅で 古くから存在するプロジェクトでは導⼊が遅れているようなものもある TypeScript導⼊済みのプロジェクトを⾒てみると… 社内サービスやSDKといった 社内で閉じたもの や ユーザーが直接⽬にしないもの であることが多い
ユーザーが直接に⽬にするものついては…
やったこと
まずはTypeScriptをコンパイルできるように ・既存のjsファイルのビルド結果を変えないように ・JavaScript → TypeScript に変換したものや 新規で書いた TypeScript のコードだけが正しくトランスパイルできればOK ・ビルド時間の増加について⼀旦スルー
・Vueのファイルについても⼀旦考えない 以下の⽅針でまずははじめてみる
まずはTypeScriptをコンパイルできるように 1. TypeScriptのビルド環境を整えつつ、1つだけ⼩さめのファイルをTS化した ・ビルド⽣成物を⾒て、そのファイル以外の差分がないことを確認した 2. tsconfig の allowJS オプションを有効にした ・TS→JSの参照の場合、jsDocがちゃんと書かれていれば
型チェックをしてくれる /** * @param {Number} id */ export function getArticle(id) { // 略 } import { getArticle } from 'foo' export function doSomething(id: string) { const article = getArticle(id) } foo.js bar.ts
まずはTypeScriptをコンパイルできるように 3. tsconfig の target を es2019 にした → ts-loader→babel-loaderを通すときに、tsでトランスパイルをしてほしくなかった
→ spread-arrays や rest-spread は、今まで通りbabelでpolyfillを⼊れてほしい → tsのトランスパイルで差し込まれるpolyfillで挙動が変わるかもしれない みたいな⼼配をしたくなかった // spread-arrays const nums = [ 1, 2 ]; const newNums = [ 0, ...nums ]; console.log(newNums); // [ 0, 1, 2 ]; // rest-spread let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; console.log(z); // { a: 3, b: 4 }
VueのSFCファイルをTS対応にする ・Vueの型定義を追加 ・まずはVue.extendを使う形に書き換えてみた(1ファイルだけ) → 差分が出るので、ここは⾃分で動作確認。問題ないことを確認 declare module '*.vue' { import
Vue from 'vue'; export default Vue; } export default Vue.extend({ props: { propA: { type: Number } } }) export default { props: { propA: { type: Number } } }
VueのSFCファイルをTS対応にする import { Vue, Component, Prop } from 'vue-property-decorator' @Component
export default class FooComponent extends Vue { @Prop(Number) readonly propA: number | undefined } export default { props: { propA: { type: Number } } } "vue-class-decorator" や "vue-class-component" があるが、導⼊を⾒送った ・書き換え量が多いこと ・Vue3のRFCではrejectされていること → これは特に⻑く続いているプロジェクトとして気にした また⼤規模に書き換える必要がありそうなら、ここでやることはないと判断 Example: vue-class-component
ビルド時間の短縮 TypeScriptを導⼊してから、ビルドに倍以上の時間がかかるように "fork-ts-checker-webpack-plugin" を導⼊して、型チェックのプロセスを分離した Before / 117s After / 41s
ts-loader fork-ts... ts-loader ts js ts js type-check & transpile type-check transpile
ビルド環境のシンプル化 ts-loaderでJavaScript / TypeScript 両⽅ビルドするようにした → 数秒ビルド時間が伸びる程度・環境のシンプルさを優先 module.exports = {
module: { rules: [ { test: /\.js$/, use: babelLoader, }, { test: /\.ts$/, loader: [ babelLoader, tsLoader ], } ] } } module.exports = { module: { rules: [ { test: /\.(js|ts)x?$/, loader: [ babelLoader, tsLoader ], } ] } } Before / 41s After / 45s
テストの導⼊ QAをしてもらえるとはいえ、しょうもないエラーを出すのは申し訳ない ⼀定のクオリティーを担保するためにテストを導⼊した ・KarmaからJestに移⾏した ・windowオブジェクトを使うテストが書きやすい → location.href を変更するようなコードとか ・jest.resetModules() が便利だった
→ コード中の変数でキャッシュしているコードなど ・新しく書くコード(特にユーテリティ系とか)を中⼼にテストを追加した
知⾒やハマり
リファクタ / コード修正したい気持ちはグッとこらえる 書き換える時点で「このコードおかしくない?」とか「改善できそう!!」 など、気づく点がいっぱいあると思う ⼀緒に着⼿してしまうと ・レビューのコストが上がる ・ts化とコード改善を⼀緒になると、問題が起きたときの切り分けしづらくなる みたいな問題があるので、⼼を⻤にしてコード⾃体の改善はしないようにした コード中にコメントを埋め込んだり、PRにメモを残すようにして
別のコミットやPRとしてコードの改善は⾏った
TODO<T>: any で "攻めながらanyを使う" js → ts に拡張⼦を変えただけでビルドが通らなくなるケースはあるはず そんなときにTODO型を使うと ・とりあえずビルドを通すことができる
・やるべき型をメモしておけるので、anyより便利 // 内部的にはany でエラーを回避しつつ、本来当てたい型をメモしておける const foo: TODO<Article> = getArticles(); const foo = getArticles(); // なんかエラー出るんだけど!!! ↓
Vueの型解決エラーはComputedの返り値を書け ・VueのSFCをTS化する最中に、どうしても this.hogehoge の型が解決できないときがある ・こういうときはcomputedの返り値を明⽰的に書くことでほとんど解決した computed: { getOpacity(): number {
return this.isActive ? 1 : 0; } } 注釈: 循環参照の都合上こうなってしまうようです。詳しくは公式ドキュメント参照 → https://jp.vuejs.org/v2/guide/typescript.html#戻り値の型にアノテーションをつける
まとめ
まとめ ・TypeScriptは段階的に導⼊することができる ・いきなり全部TSに書き換える必要はない ・可能なら⼀緒にユニットテストも書くとより安⼼かも ・プロジェクトに⼊ったばかりだからこそ、⾔える/思うようなこともある ・⾃分が困ったことは、今後新しくプロジェクトに⼊るメンバーも困るはず ・昔の技術を勉強するより、持っている最新の技術スタックで 即戦⼒になれるほうが双⽅ハッピーなはず
お知らせ LINEやLINE Growth Technologyで働くことに興味のある⽅向けに 社員と直接情報交換ができるカジュアル⾯談を実施しています 興味のある⽅は、「LINE Developer meetup」で検索をお願いします!
ありがとうございました!