Slide 1

Slide 1 text

負債が溜まった レガシーフロントエンド画面を Vue.js でリプレイスした話 Vue Fes Japan Online 2022 - 2022/10/16

Slide 2

Slide 2 text

自己紹介 ● とよへい ( @t0yohei ) ● 株式会社クラウドワークス ○ Web エンジニア ● アニメとコーヒーが好き ● Vue.js / Ruby / PHP

Slide 3

Slide 3 text

想定する聞き手 ● レガシーなフロントエンドに向き合っている方 ● Vue.js での開発ノウハウに興味がある方 ● 不思議なものがみたい方

Slide 4

Slide 4 text

Midjourney

Slide 5

Slide 5 text

アジェンダ ● なぜ Vue.js 化を実施したのか ● どういう作戦で進めていったか ● 品質管理について ● 難しかったこと ● まとめ

Slide 6

Slide 6 text

なぜ Vue.js 化を実施したのか

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

クラウドワークスのフロントエンドについて ● クラウドワークスは、10年ほど前に Rails + jQuery の構成で生まれた ● 新規画面は Vue.js で作成されているが、jQuery を使った古い画面がかなり残って いる

Slide 9

Slide 9 text

クラウドワークスのフロントエンドが抱えている課題 ● 見た目を変えたいだけなのにバックエンドの Rails をいじる必要がある ● フロントエンド、バックエンドの分業がしにくい ● jQuery を書きたくない

Slide 10

Slide 10 text

これらの課題を Vue.js 化で解決しよう

Slide 11

Slide 11 text

Vue.js 化して既存画面を もっと改善しやすくしよう

Slide 12

Slide 12 text

どういう作戦で進めていったか

Slide 13

Slide 13 text

Vue.js 化の大まかな方針 ● 最終的には全画面を Vue.js 化したい ● 時間的な制約もあるので、優先順位が高いものから対応していく

Slide 14

Slide 14 text

優先順位はどうやってつけよう

Slide 15

Slide 15 text

「Vue.js 化して既存画面を もっと改善しやすくしよう」

Slide 16

Slide 16 text

将来的に改善したくなる可能性が 高い画面を優先する

Slide 17

Slide 17 text

ユーザーのアクセスが多い 一般ユーザー向け画面

Slide 18

Slide 18 text

優先順位の考慮から外した観点 ● UIの変更が頻繁に行われている画面 ○ 特定の理由で更新されているだけ (バナー更新とか) ○ 単に手を入れるのが簡単

Slide 19

Slide 19 text

両方大事にした観点 ● 対応が簡単な画面をたくさん改善 ○ ユーザーに対するインパクト ● 対応が難しい画面にじっくり挑む ○ 長期的な改善に対するインパクト

Slide 20

Slide 20 text

ひとまずの Vue.js 化を行う画面 ● 練習用の管理画面 × 1 ● 一般ユーザー向けの簡単な画面 × 2 ● 一般ユーザー向けの難しい画面 × 1 ● (これらの画面の対応が終わったら、体制を整えて Vue.js 化を継続する)

Slide 21

Slide 21 text

実装のスコープ

Slide 22

Slide 22 text

「Vue.js 化して既存画面を もっと改善しやすくしよう」 という目的に注力して、色々やりすぎない

Slide 23

Slide 23 text

何をやらないか(スコープ外) ● CSSフレームワークを外す ● バックエンドに API を生やして、API 経由でデータのやりとりをする ● その他コストがたくさんかかりそうなことは無理にやらない

Slide 24

Slide 24 text

品質管理について

Slide 25

Slide 25 text

各種ツールと人力で品質を担保 ● Storybook ○ コンポーネント毎の動作を担保 ● VRT(Visual Regression Testing) ○ 見た目の確認と、置き換え途中でデグレしていないことを担保 ● vue-test-utils ○ API 通信などの動作を担保 ● 手動テスト ○ 統合的な動きを担保

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

Storybook

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

VRT (Visual Regression Testing)

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

● フロントエンド開発体験向上のために VRT を導入してみた ● crowdworks.jp のフロントエンド活動を振り返る 2021 詳細はテックブログに

Slide 34

Slide 34 text

E2E テストは不採用 ● 負債が溜まった画面の E2E テスト、とても辛さそう ● 一括のリプレイスを考えていたので、メリットがそこまで多くなさそう ● (リプレイス全体を通して大きな問題は発生しなかったのでヨシ)

Slide 35

Slide 35 text

難しかったこと

Slide 36

Slide 36 text

Rails, jQuery のコードを Vue.js っぽいコードに書き換える

Slide 37

Slide 37 text

具体的には ● 命令的 UI を宣言的 UI にする ● Rails, jQuery のコードを Vue.js, TypeScript のコードに書き換える ● バックエンド(Rails)からフロントエンド(Vue)に適切な値を引き渡す

Slide 38

Slide 38 text

例: 仕事の予算を表示する部分

Slide 39

Slide 39 text

置き換え前のコード

Slide 40

Slide 40 text

何らかの html を生成して挿入する ここで生成された html を挿入する

Slide 41

Slide 41 text

置き換え後のコード

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

宣言的に書く

Slide 44

Slide 44 text

script setup を使って Vue.js と TypeScript で実装

Slide 45

Slide 45 text

これいるの...?ってコードが 埋まってる

Slide 46

Slide 46 text

具体的には ● A/B テストの残骸 ● どこからも参照されてなさそうなコード ● 新しく作成されるデータでは付与されることがないラベル

Slide 47

Slide 47 text

実は前から壊れていた🙄

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

本体リリースに先駆けてお掃除

Slide 50

Slide 50 text

とにかく機能が多い

Slide 51

Slide 51 text

中ボスが 50 人くらいいるイメージ

Slide 52

Slide 52 text

機能ごとにコンポーネントを分けてひたすら作成

Slide 53

Slide 53 text

工夫: Containar Component で統制を取りやすく ● style を持たない Vue コンポーネント ● 自身が含むプレゼンテーションコンポーネントにデータを受け渡す ● バックエンド API とやりとりするためのインターフェースを持つ

Slide 54

Slide 54 text

style を持たない バックエンド API とやりとりする ためのインターフェース プレゼンテーション コンポーネントにデータを受け渡す

Slide 55

Slide 55 text

工夫: Layout Component でスタイル定義を分離 ● script を持たない Vue コンポーネント ● slot を使ってコンポーネントを入れ込む

Slide 56

Slide 56 text

slot を使って コンポーネントを入れ込む script を持たない Layout Component

Slide 57

Slide 57 text

共通のスタイル定義を切り出すとかもできる 共通のスタイル定義を切り出す

Slide 58

Slide 58 text

どうして...ってコードがある

Slide 59

Slide 59 text

気になるボタン(Watchlist Button)

Slide 60

Slide 60 text

No content

Slide 61

Slide 61 text

修正前の実装

Slide 62

Slide 62 text

watchlist のデータ(json)を非同期で一 括で取ってくる 取得したデータ(json)に html が含まれ ているので、id が一致した仕事に対して その html を埋め込む watchlist button を埋め込む div が仕 事ごとに用意されている

Slide 63

Slide 63 text

取得したデータ(json)に html が 含まれているので?

Slide 64

Slide 64 text

No content

Slide 65

Slide 65 text

json に埋め込まれる html (※ 見やすさのために本来存在しない改行追加しています)

Slide 66

Slide 66 text

No content

Slide 67

Slide 67 text

json として html を受け取って、 その html を dom にぶち込んでる

Slide 68

Slide 68 text

「気になる」ボタンが押された時はもちろん DOM の埋め込み直し

Slide 69

Slide 69 text

JSON 色つけですらなく、 DOM をそのまま埋め込み職人

Slide 70

Slide 70 text

(余談) Q. watchlist の追加に失敗したら どうなるでしょう?

Slide 71

Slide 71 text

A. Status Code: 200

Slide 72

Slide 72 text

status コードは甘え。 やる気があるなら payload の文字列で 結果を判定しろ

Slide 73

Slide 73 text

どうしようこれ

Slide 74

Slide 74 text

そもそもどういう感じに なっていたら嬉しいか

Slide 75

Slide 75 text

期待する動作 1. 画面初期化時は ajax でボタンの html(json) を取ってくるんじゃなくて、 watchlist の状態だけもらっておいて Vue.js 側でボタンの出し分けをする 2. 気になるボタンが押されたら、追加リクエストを送る 3. 追加された watchlist の id をレスポンスで受け取り、取り消しボタンを表示する 4. 取り消しボタンが押されたら、2で取得した id をつけて取り消しリクエストを送 る

Slide 76

Slide 76 text

課題は何か ● 取り消しリクエストには watchlist の id が必要 ● 現状の watchlist 追加 API だと、レスポンス json の html の中に watchlist の id が埋まって いて取り出しにくい

Slide 77

Slide 77 text

どうやって解決したか

Slide 78

Slide 78 text

現状の watchlist 追加 API のレスポンスに、 追加された watchlist の id 加えてあげたら、 影響少なそうだし実装の手間少ないし、 やりたいこと実現できるし良いじゃん!!😈

Slide 79

Slide 79 text

つまり レスポンスに新しく追加した watchlist_id を足して ● html ● message ● watchlist_id (NEW!) の 3 本立てで返してあげるようにする

Slide 80

Slide 80 text

json に html が含まれている状態を 放置することになるけどいいの...?

Slide 81

Slide 81 text

No content

Slide 82

Slide 82 text

という訳で ついでに成功したかど うかも返すことに

Slide 83

Slide 83 text

めでたし!!!!

Slide 84

Slide 84 text

まとめ

Slide 85

Slide 85 text

振り返り ● Vue3 + TypeScript は開発体験が良くて、書いていて楽しい ● レガシーフロントエンドの Vue.js への置き換えは、単純にはできなくて骨が折れる ● 削れる機能は削って、もっと楽したかった ● どうして...ってコードは、一周回って変な笑いが出る

Slide 86

Slide 86 text

大事なこと ● 目的を明確にして、やらないことを決める

Slide 87

Slide 87 text

やめないこと

Slide 88

Slide 88 text

Special Thanks ● OD さん ● yamanoku さん

Slide 89

Slide 89 text

Thank you for listening !!