Upgrade to Pro — share decks privately, control downloads, hide ads and more …

(Vue Fes 2023) 18営業日で350コンポーネント規模のVueアプリにデザインシステムを導入する方法

Yuichiro Yamashita
October 28, 2023
4.5k

(Vue Fes 2023) 18営業日で350コンポーネント規模のVueアプリにデザインシステムを導入する方法

弊社 (株式会社フライル) では、18 営業日という超短期でデザインシステムを導入しました。このプロジェクトで得た知見を共有致します。
技術的工夫
AST を使用して事前にできる限り自動でマイグレーションした上で判別できない部分に全て TODO コメントを自動付与
ESLint のカスタムルールを実装してできる限りレビューは自動化
デザインシステムが壊れていないか確認するために VRT を実施
Autify による E2E テスト
プロジェクト管理上の工夫
手作業は短期集中でタスクのスイッチングコストをゼロに
進捗は数値で管理
マニュアルテストを複数回実施してバグに対処
最後にデザイナーとペアプロで細かいデザインを修正
プロジェクトを通じた反省と学び
コンポーネントの依存関係を事前に詳細に把握しておくべきだった (コンフリクトが起きるケースが見られた)
マイグレーション自体の間違いについて
まず上記の共有をした後に、技術的工夫 1 点目の AST によるプログラム修正の方法の共有に時間を割こうと思っています。

Yuichiro Yamashita

October 28, 2023
Tweet

Transcript

  1. 自己紹介 (baseballyama)
 • 株式会社フライル
 ◦ TypeScript / Vue / Svelte


    ◦ Kotlin / Spring Boot
 ◦ Python / Fast API / Open AI
 ◦ AWS / Terraform
 ◦ MySQL / Fargate / S3 / SQS / その他 
 
 • Svelteコアチームメンバー
 ◦ Svelte5に向けて活動中
 ◦ 少しだけ Svelte用 ESLintプラグイン 
 
 • その他
 ◦ 最近はひたすらPythonを書いている 
 ▪ この話は来月の JSConf JP で... 

  2. • 前提
 ◦ プロジェクトの概要
 ◦ Big Bang vs Incremental 


    • プロジェクト管理面での工夫
 ◦ Big Bang を選択した理由 
 ◦ 我々が重要視したこと 
 ◦ スイッチングコストを極限まで減らす 
 ◦ 重要でないページの細かいデザイン調整は後回しにする 
 ◦ 進捗は数値で見える化 
 ◦ マニュアルテストを複数回実施 
 ◦ デザイナーとのペアデザイン 
 • 技術面での工夫
 ◦ ESLintのカスタムルールでレビューはできる限り自動化 
 ◦ 可能な限り自動マイグレーション (今回の目玉) 
 ◦ デザインコンポーネントの破損はVRTで検査 
 ◦ E2Eテストで重要・頻出導線の破損を防ぐ 
 アジェンダ

  3. プロジェクトの概要
 • プロジェクト規模 (2023/10/28 (土) 現在)
 
 
 
 ※

    それ以外のファイル (例: Svelte) は省略
 • プロジェクトのスコープ
 ◦ UIコンポーネント (35個) は既に実装済み 
 ▪ (UIコンポーネントの設計やデザイン原則などは今回の発表の対象外) 
 ◦ UIコンポーネントをプロダクトに取り込む作業が今回の対象 
 
 ファイル種別
 ファイル数
 行数
 Vue
 432
 71,115
 TypeScript
 765
 9,519

  4. プロジェクトの概要
 • (デザイン原則を含む) デザインシステムを導入した理由
 ◦ サービス全体で一貫したデザインにするため
 ▪ 一貫したデザインはユーザーを迷わせません
 ◦ UIの実装を迅速にするため


    ▪ もう font-size を指定する必要はありません 😄
 • なぜ今だったのか
 ◦ いわゆる大企業と呼ばれる企業様への導入が進行中
 ▪ ユーザー数が増える前に大幅なデザイン変更を完了させたかった
 ◦ 開発者数の増加
 ▪ 開発者が増えるほどデザインシステムによる効率化効果が増す

  5. Big Bang vs Incremental
 Big Bang (一度に大規模な変更を適用) 
 • 計画とテストが非常に重要


    • 一気に大量のコードを変更するのでバグの原因特定が困難 
 • 機能開発やバグ修正と並走できない (コンフリクトする可能性が高いため) 
 
 Incremental (小さなステップに分割して変更を適用) 
 • 計画の変更が容易
 • テストを頻繁に実行するため、リスクを低減 (分散) できる 
 • 機能開発やバグ修正と並走できる 
 
 多くの場合、Incrementalが安全で効率的です。ただし、状況によりBig Bangも選択肢となる場合があります。 

  6. 我々が重要視したこと
 
 • 最短期間でリリースする
 ◦ 特にクリティカルなバグが見つかった時に対応できない期間を最小化するため 
 最短期間でリリースするために...
 • 1⃣

    (プロ管) スイッチングコストを極限まで減らす 
 • 2⃣ (プロ管) 重要でないページの細かいデザイン 調整は後回しに
 ◦ マージン・パディングなど... 
 • 3⃣ (プロ管) 進捗は数値で見える化 
 • 6⃣ (技術) ESLintのカスタムルールでレビューは できる限り自動化
 • 7⃣ (技術) 可能な限り自動マイグレーション (今 回の目玉)
 品質を維持するために...
 • 4⃣ (プロ管) マニュアルテストを複数回実施 
 • 5⃣ (プロ管) デザイナーとのペアデザイン 
 • 8⃣ (技術) デザインコンポーネントの破損はVRT で検査
 • 9⃣ (技術) E2Eテストで重要・頻出導線の破損を 防ぐ

  7. 我々が重要視したこと
 
 • 最短期間でリリースする
 ◦ 既存機能にクリティカルなバグが見つかった時に対応できない期間を最小化するため 
 最短期間でリリースするために...
 • 1⃣

    (プロ管) スイッチングコストを極限まで減らす 
 • 2⃣ (プロ管) 重要でないページの細かいデザイン 調整は後回しに
 ◦ マージン・パディングなど... 
 • 3⃣ (プロ管) 進捗は数値で見える化 
 • 6⃣ (技術) ESLintのカスタムルールでレビューは できる限り自動化
 • 7⃣ (技術) 可能な限り自動マイグレーション (今 回の目玉)
 品質を維持するために...
 • 4⃣ (プロ管) マニュアルテストを複数回実施 
 • 5⃣ (プロ管) デザイナーとのペアデザイン 
 • 8⃣ (技術) デザインコンポーネントの破損はVRT で検査
 • 9⃣ (技術) E2Eテストで重要・頻出導線の破損を 防ぐ

  8. 1⃣ スイッチングコストを極限まで減らす
 以前、Flyleでは、リファクタリングタスクを開発作業のうちの20%を使用する手法を採用し ていました。(Vue2 から Vue3 へのアップグレードの初期はこの方法を採用していまし た。)
 しかし、自分を含め進捗が芳しくなく、その20%の時間を1人に集約するアプローチに変 更したところ、一気に進捗した、という経験をしました。


    これは、複数のタスクに同時期に取り組んだことにより、毎回それぞれのタスクの情報を 思い出すのに時間がかかっていたことが原因であると結論づけました。
 以降、Flyleでは、タスクスイッチングのコストを最小化する方法 (つまりインクリメンタル アプローチであろうがビッグバンアプローチであろうが誰かが一気に対応する方法) でリ ファクタリングを実施しています。

  9. 我々が重要視したこと
 
 • 最短期間でリリースする
 ◦ 特にクリティカルなバグが見つかった時に対応できない期間を最小化するため 
 最短期間でリリースするために...
 • 1⃣

    (プロ管) スイッチングコストを極限まで減らす 
 • 2⃣ (プロ管) 重要でないページの細かいデザイン 調整は後回しに
 ◦ マージン・パディングなど... 
 • 3⃣ (プロ管) 進捗は数値で見える化 
 • 6⃣ (技術) ESLintのカスタムルールでレビューは できる限り自動化
 • 7⃣ (技術) 可能な限り自動マイグレーション (今 回の目玉)
 品質を維持するために...
 • 4⃣ (プロ管) マニュアルテストを複数回実施 
 • 5⃣ (プロ管) デザイナーとのペアデザイン 
 • 8⃣ (技術) デザインコンポーネントの破損はVRT で検査
 • 9⃣ (技術) E2Eテストで重要・頻出導線の破損を 防ぐ

  10. 正規表現ベースでの置換
 手軽にできる方法ですね。手軽にできる一方で、意図しない置換が発生する可能性が あります。
 例えば、HTMLのID属性を一括で削除したいとします。
 正規表現は /\sid=["'].*?["']/ といったところでしょうか。
 しかし、これでは const foo

    = (bar, id="foo") => {} のような文字列にもマッチしてしまい ます。
 これでは正しくリファクタリングができません。
 そこで、より高度なリファクタリングをするためには、ASTを変更することによる置換を選 択する場合があります。

  11. {
 type: 'Program',
 body: [
 {
 type: 'VariableDeclaration' ,
 declarations:

    [
 {
 type: 'VariableDeclarator' ,
 id: {
 type: 'Identifier',
 name: 'foo',
 },
 init: {
 type: 'Literal',
 value: 'bar',
 raw: '"bar"',
 },
 },
 ],
 kind: 'const',
 },
 ],
 sourceType: 'module',
 }
 ASTを変更することによる置換
 AST (Abstract Syntax Tree) とは、抽象 構文木のことです。
 例えば、const foo = "bar"; は、
 右のようなASTになります。

  12. {
 type: 'Program',
 body: [
 {
 type: 'VariableDeclaration' ,
 declarations:

    [
 {
 type: 'VariableDeclarator' ,
 id: {
 type: 'Identifier',
 name: 'foo',
 },
 init: {
 type: 'Literal',
 value: 'baz',
 raw: '"baz"',
 },
 },
 ],
 kind: 'const',
 },
 ],
 sourceType: 'module',
 }
 ASTを変更することによる置換
 “bar” を “baz” に変更する 
 {
 type: 'Program',
 body: [
 {
 type: 'VariableDeclaration' ,
 declarations: [
 {
 type: 'VariableDeclarator' ,
 id: {
 type: 'Identifier',
 name: 'foo',
 },
 init: {
 type: 'Literal',
 value: 'bar',
 raw: '"bar"',
 },
 },
 ],
 kind: 'const',
 },
 ],
 sourceType: 'module',
 }

  13. ASTの構造を理解する方法
 AST Explorer (https://astexplorer.net/) というサイトがあります。
 このサイトでは、HTML, JavaScript, CSS をはじめとし た多くのプログラム言語に関して、ASTを確認できるサ

    イトです。
 例えば、JavaScriptの場合、Acorn や Espree など多く のパーサーを使用してASTを確認できます。 
 また、ESTree という JavaScript の AST 仕様は、 ESTreeのGitHubリポジトリで確認できます。 
 https://github.com/estree/estree/blob/0fa6c005fa45 2f1f970b3923d5faa38178906d08/es5.md 

  14. VueのファイルをASTに変換する方法
 各プログラム言語に対するASTの確認方法はわかったと思います。
 しかし、Vueファイルには HTML, TypeScript, SCSS など、複数の言語を実装します。どう やってVueファイルの内容をASTに変換すれば良いのでしょうか。
 Vueの内部実装はわからないのですが、Svelteの場合、正規表現を用いて<script> ブ

    ロックと <style> ブロックを判定しています。
 ということで、正規表現で各ブロックを分割しましょう。
 const REGEXP_TEMPLATE = /(<(template).*?>)([\s\S]*)(<\/(template)>)/m;
 const REGEXP_SCRIPT_STYLE = /(<(script|style).*?>)([\s\S]*?)(<\/(script|style)>)/m;

  15. VueのファイルをASTに変換する方法
 得られたASTを走査して変更を加えるコードの雛形は以下です。
 
 import { walk } from "zimmerframe";
 walk(ast,

    null, {
 _(node, { state, next }) {
 // AST に変更を加える処理 
 manipulate(node);
 // 次のノードへ
 next(state);
 },
 });

  16. VueのファイルをASTに変換する方法
 具体的なASTを変更するコードは以下です。
 
 import type { Node } from "@babel/types/lib";


    const manipulate = (node: Node) => {
 if (node.type === "VariableDeclarator") {
 const { init } = node;
 if (init?.type === "StringLiteral") {
 init.value = "bar";
 }
 }
 };

  17. VueのファイルをASTに変換する方法
 また MagicString を使用して書き換えることもできます。
 import type { Node } from

    "@babel/types/lib";
 import MagicString from "magic-string";
 
 const magicString = new MagicString("const foo = 'foo';");
 const manipulate = (node: Node) => {
 if (node.type === "VariableDeclarator" ) {
 const { init } = node;
 if (init?.type === "StringLiteral") {
 const [start, end] = init.range ?? [];
 if (start != null && end != null) {
 magicString.overwrite(start, end, "'bar'");
 }
 }
 }
 };

  18. MagicString とは
 Suppose you have some source code. You want

    to make some light modifications to it - replacing a few characters here and there, wrapping it with a header and footer, etc - and ideally you'd like to generate a source map at the end of it. You've thought about using something like recast (which allows you to generate an AST from some JavaScript, manipulate it, and reprint it with a sourcemap without losing your comments and formatting), but it seems like overkill for your needs (or maybe the source code isn't JavaScript). 
 
 Your requirements are, frankly, rather niche. But they're requirements that I also have, and for which I made magic-string. It's a small, fast utility for manipulating strings and generating sourcemaps. 

  19. VueのファイルをASTに変換する方法
 
 とはいえ、実際に使えるレベルのコードを1から書くのは面倒だと思います。
 そこで、今回Flyleで実際に使用したコードをベースにしたリファクタリングツールをライブラリと して公開しました。 vue-service-bay というライブラリです。
 https://github.com/flyle-io/vue-service-bay
 
 README

    に使い方を書いていますので、このライブラリが皆様のリファクタリングライフを劇的 に楽にして、機能開発に専念できる環境づくりに寄与できたらとても嬉しく思います。
 また、よければスターして頂けると嬉しいです。
 弊社開発チームのメンバーも喜ぶと思います。

  20. まとめ
 • Big Bang リリースを避けられない場合もある
 ◦ それでも可能な限りスコープは最小化しよう
 ◦ そして段取りが命
 •

    自動化できるものは全て自動化しよう
 ◦ Big Bang の期間はバグ修正すらできないのでリスクが高まっていく
 ◦ 機械は人間よりも確実で早い
 ◦ vue-service-bay もよければ使ってください
 • ペアデザインはおすすめ
 ◦ 事前に決まっていない細かなデザインは最後にデザイナー・エンジニア間のペア作 業で調整するのがおすすめ。
 • マニュアルテストは何度もやろう
 ◦ お客様にご迷惑をおかけしないために

  21. デザインシステムを導入した個人的な感想
 • CSSあまり書かなくて良いの最高 (単純にコードが見やすい)
 
 • デザインシステムというレールがあるからこそESLint / Stylelint でより縛れるから

    最高
 ◦ よりコードの統一感を維持できる
 ◦ コードレビューも楽になった
 
 • デザイナー間とのコミュニケーションが簡単になって最高
 ◦ デザインシステムと乖離するデザインがあったら単に相談すればよくなった。 そしたらデザインチームで検討してデザイン原則・デザインシステムに適合し たUIに変更してくれる
 ▪ (以前は一旦ここはそれで実装するか、みたいな意思決定が多少あったのでコードがぐちゃっ とする原因になっていた)