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

Vue.jsのGitHubから学ぶ意思決定

 Vue.jsのGitHubから学ぶ意思決定

Vue Fes Japan 2026 セッションの登壇資料です。

Avatar for Yuto Nagai(Future)

Yuto Nagai(Future)

October 24, 2026

More Decks by Yuto Nagai(Future)

Other Decks in Technology

Transcript

  1. ⾃⼰紹介 永井 優⽃/Yuto NAGAI フューチャーアーキテクト株式会社 シニアコンサルタント コードキャンプ株式会社 PdM(兼務出向) ‧北海道⼤学 公共政策⼤学院卒。部活はESSと⽇本語ディベート

    ‧2017年、IT未経験でフューチャーに新卒⼊社 ‧流通系やヘルスケア、国の医療DX案件を経て、現在は社内のAI推進、 新⼈研修の⽀援、CodeCampでエンジニアリング教育事業 X‧GitHub @yut0naga1 社外では ‧法政⼤学法学部 ⾮常勤講師、TSKaigi運営 ‧全⽇本ディベート連盟 マネージャー #Vue #TypeScript #競技ディベート #中⼩企業診断⼠ #⽇本BBQ協会認定BBQインストラクター #vuefes #vuefes_medpeer
  2. 今⽇話すこと‧話さないこと 記録に書かれた事実と、私の解釈を分けて話す 話すこと 話さないこと ‧ 問題‧候補‧制約‧決定を ‧ Vueの公式な歴史 たどる読み⽅ ‧

    どこで提案が変わったか 事実 記録に書かれたこと 解釈 そこから私が考えたこと ‧ 「開発チームは内⼼こう考えていた」 という断定 話し⼿はコミッターではなく、 ⼀⼈のVueユーザー #vuefes #vuefes_medpeer
  3. 判断する⼒は、どこで⾝につける? 判断する⼒は、npm installできない $ npm i 判断力 npm error code

    E404 npm error 404 Not Found - GET https://registry.npmjs.org/判断力 - Not found npm error 404 npm error 404 '判断力@*' is not in this registry. npm error 404 npm error 404 Note that you can also install from a npm error 404 tarball, folder, http url, or git url. #vuefes #vuefes_medpeer
  4. 意思決定は、どんな順序で進むか? 案を⽐べて議論するなかで、よりよい案が出てくる その積み重ねで、いちばんよい案を選ぶ 課題 困っていることを ⾔葉にする 案を出す → A案‧B案…… 現状維持も案の⼀つ

    ⽐べて議論する → メリットと 選ぶ → デメリットを⽐べる いちばんよい 案を選ぶ 議論のなかで、C案やBの改案B’が出てくる よりよい案が積み重なっていく 甲⼄つけがたいトレードオフでは、何を判断軸にしたかまで読みたい このあとのCaseも、この枠組みで⾒ます #vuefes #vuefes_medpeer
  5. 決まるまでの途中経過は、どこに残っているか? GitHubのIssue‧PR‧RFCに、決まるまでの会話が残っている Issue ⇄ PR 利⽤者や開発者の 困りごと ⇄ RFC Pull

    Request Request for Comments 変更案と、そのレビュー 意⾒を求める設計提案。 問題設定‧代案‧ 採⽤案が書かれる 完成したAPIが答えそのもの、 GitHubの議論は答えに⾄るまでの過程 私はこっちを⾒たい。 #vuefes #vuefes_medpeer
  6. 3リポジトリ‧10年以上‧25,403件の記録を集めた 25,403件 3リポジトリ vuejs/vue Vue 2の実装 vuejs/core Vue 3以降の実装 vuejs/rfcs

    設計提案 Issue‧PR‧RFCを収集 10年以上 対象期間 出所:GitHub vuejs/vue‧vuejs/core‧vuejs/rfcsの公開記録を筆者が収集‧集計 #vuefes #vuefes_medpeer
  7. 25,403件を、どこから読み始めるか? 数えられる情報だけで順位をつけ、読む順番を決める 25,403件 すべてを順番には 読めない 数えて採点 → 数えられる 先に読む候補 →

    情報だけを使う ランクで 並べる 原⽂を開く → 中⾝はここで 確かめる 順位は、歴史的な重要度そのものではない 9位 core #9162 style: update format & lint config 整形ルールの変更 40位 rfcs #222 New script setup and ref sugar 後半で⽋かせない記録 出所:筆者集計の中⽴ランキング(output/11_score_comparison.md) #vuefes #vuefes_medpeer
  8. 採点では、何を⾒て、何を⾒ないか? Issue‧PRで主に⾒るのは、議論の量‧変更の広さ‧決定とのつながり ⾒る ⾒ない 議論の量 変更の広さ 決定とのつながり コメント‧レビューの数 変更ファイル数‧⾏数 マージ‧参照‧

    (上限あり) リリースとの近さ ラベル AIによる内容評価 テーマ語 Composition API、 TypeScriptなど 読みたい結論に都合よく順位を作らないため。 件数はln(1+件数)で圧縮する 注:参照数はIssue‧PRの番号だけで数え、参照先のリポジトリを区別しない。順位は読む順番の⽬安で、重要度の尺度ではない(配点は13枚⽬) #vuefes #vuefes_medpeer
  9. 議論の件数が少ないRFCはどう取り扱う? RFC本⽂には基礎点を置き、議論が少なくても候補に残す 基礎点 + 本⽂の⻑さ + リンク数 RFC本⽂であること ⻑いほど良い、 本⽂内のGitHubリンク。

    ⾃体に点を置く という意味ではない 関連記録をたどれる⽬安 配点に決まった正解はない。 だから採点スクリプトに、項⽬‧数値‧理由も吐かせる。 最後は⼈が原⽂で確かめる。 #vuefes #vuefes_medpeer
  10. 参考|採点の配点 Issue‧PRは10項⽬、RFC本⽂は3項⽬ 配点は読む順番を決めるための⽬安 Issue‧PR(n=件数) RFC本⽂ コメント数 4.5 × ln(1+n) 基礎点

    +22 レビュー+レビューコメント数 5 × ln(1+n) 本⽂の⽂字数 1.5 × ln(1+文字数) 変更ファイル数(PR) 4 × ln(1+n) GitHubリンク数 1件につき +2 追加+削除⾏数(PR) 2 × ln(1+n)、上限20 マージ済み(PR) +7 vuejs/rfcsのPR +12 マイルストーンあり +4 他の記録からの参照数 7 × ln(1+n) リリース⽇との近さ 3日以内 +8/14日 +5/30日 +2 状態変化‧参照のイベント数 3 × ln(1+n)、上限12 #vuefes #vuefes_medpeer
  11. 上位5件の結果 上位5件は「公開API」と「内部実装」に分かれた 1 rfcs #42 Function-based API 106.36 公開API 2

    core #5912 リアクティビティ効率化 103.84 内部実装 3 core #2345 effectの性能‧メモリ 81.70 内部実装 4 rfcs #182 SFC Improvements 81.66 公開API 5 core #10397 リアクティビティ再設計 80.38 内部実装 公開API:利⽤者に⾒えるAPIの形。今⽇はこちらを読む 内部実装:リアクティビティ‧性能‧メモリ 注:スコアの差は記録の量とつながりの差で、技術の優劣ではない #vuefes #vuefes_medpeer
  12. 公開APIのうち、どの記録を主役にする? 13位の#78を主役にする 上位の#42‧#182‧#227と同じ課題でつながって⾒える #42 1位 #227 Function-based API #182 8位

    #17 30位 <script setup> Class API(⾒送り) 4位 SFC Improvements #78 13位 Composition API 上位10件 事実 中⽴ランキングの上位10件に、#42‧#182‧#227の3件が⼊る 解釈 #78も含め、機能ごとの整理を選び、SFCで書きやすくするまでを追える。 採⽤案と不採⽤案を⽐べられる 出所:筆者集計の中⽴ランキング(output/11_score_comparison.md) #vuefes #vuefes_medpeer
  13. Caseの⾒取り図 Options APIから<script setup>まで六段階でたどる 1 2 3 Options API 問題

    Class API案 出発点 RFC 0013 今も使える 4 5 6 Function- Composition <script based API案 API setup> #17 #42 #78 #182 → #227 不採⽤ #78へ改訂 採⽤ #227で採⽤ Composition API:状態や処理を機能ごとにまとめる、Vue 3で導⼊されたAPI <script setup>:Composition APIを.vueファイルで書きやすくした仕組み #vuefes #vuefes_medpeer
  14. Options APIでは、カウンターをどう書くか? 状態‧計算‧更新を、役割ごとの箱に分けて書く ボタンで数を増やし、2倍も表⽰する export default { data() { return

    { count: 0 } }, computed: { doubled() { return this.count * 2 } }, methods: { increment() { this.count++ } } } data 状態 computed 計算値 methods 更新 どこに何を書くかが決まり、 初めて読む⼈も迷いにくい count に関わるコードは 三か所に分かれる #vuefes #vuefes_medpeer
  15. Composition APIでは、同じカウンターをどう書くか? 同じ機能の状態‧計算‧更新を、近くにまとめて書ける import { ref, computed } from 'vue'

    export default { setup() { const count = ref(0) const doubled = computed(() => count.value * 2) function increment() { count.value++ } return { count, doubled, increment } } } count のコードを ⼀か所で読める Options APIが悪くなったわけではない。⼩さい部品では今も読みやすい #vuefes #vuefes_medpeer
  16. Composition APIの出発点 コードが離れる、再利⽤しにくい、型を追いにくい、の三つ 1 コードが離れる 機能が増えるにつれ、⼀つの機能に関するコードが離れてしまう 2 再利⽤しにくい ロジックを別の部品で使い回すための、すっきりした仕組みがない 3

    型を追いにくい TypeScriptが型を追いにくい → Class API‧Function-based API‧Composition APIがどう答えたかを⽐べる 出所:vuejs/rfcs RFC 0013「Composition API」Motivation #vuefes #vuefes_medpeer
  17. 案①:Class API 何を得ようとし、何に頼ったか? 型推論を狙ったが、propsの型は不確実なデコレータに頼った RFC #17の記法で書いたカウンター 事実 狙いは型推論と、 ネイティブのクラスで import

    Vue from 'vue' import { prop } from '@vue/decorators' 書けること RFC #17 Drawbacks class Counter extends Vue { @prop step: number count = 0 get doubled() { return this.count * 2 } increment() { this.count += this.step } } "It is thus still quite risky to design the API around decorators at this point." 解釈 注:記法(extends Vue‧ゲッター‧@prop)はRFC #17本⽂に基づく。Counter‧stepの例は説明⽤に作成 出所:vuejs/rfcs #17本⽂(class-apiブランチ) 何を前提に置くかも、 設計の選択だった #vuefes #vuefes_medpeer
  18. 案②:Function-based APIは、何を得ようとしたか? 機能ごとに関数へまとめ、別の部品で使い回す function useSearch() { const keyword = ref('')

    const results = ref([]) async function search() { results.value = await fetchResults(keyword.value) } return { keyword, results, search } } // 別の部品でも、同じ検索ロジックを使い回す const { keyword, results, search } = useSearch() 注:記法は現在のComposition APIに合わせた説明⽤の例 役割ごと data computed methods ↓ 機能ごと useSearch() usePagination() useForm() #vuefes #vuefes_medpeer
  19. 採⽤されたComposition APIは、既存の書き⽅をどう扱ったか? Options APIを置き換えず、並べて使える追加のAPIにした 事実 PR本⽂の冒頭 #42 Function-based API 冒頭のQ&A

    "Do I have to rewrite all my code?" → "No. ... purely additive" 既存のコードを全部書き直す必要はない。新しいAPIは純粋に追加的 #78 Composition API(#42の改訂版) 冒頭 "position the API as an advanced, additive API that works alongside existing API" 名前をComposition APIに変え、既存のAPIと並んで動く⾼度な追加APIと位置づけた 出所:vuejs/rfcs #42‧#78のPR本⽂(2026-10-05 原⽂確認) #vuefes #vuefes_medpeer
  20. 現状維持も⼊れて⽐べると、最終案は何を選んだか? 現状も残し、型推論と再利⽤の両⽅を狙ったように⾒える 案(記録をもとに整理) 狙い‧位置づけ 課題‧⾒直し 現状維持 書き換えが要らない RFC 0013の三つの課題が残る Class

    API 型推論。 デコレータへの依存 #17 ネイティブのクラスで書ける (⾒送り) Function-based API ロジックの整理‧再利⽤。 廃⽌の可能性の記述を、 #42 型推論も 利⽤者の声で削除 Composition API #42の改訂。 refと普通の値の区別。 #78 既存APIと並ぶ追加API ⾃由度に伴う規律 Options API 解釈 現状も残す。よりよい案にまとめたうえで、⽋点は記録の上受け⼊れた 出所:vuejs/rfcs #17本⽂、#42‧#78のPR本⽂、RFC 0013「Composition API」Motivation‧Drawbacks #vuefes #vuefes_medpeer
  21. Composition APIを選んだあと、SFCで書くときに何が残ったか? テンプレートで使う値を毎回returnで返す⼿間が残っていた setup() { const count = ref(0) const

    increment = () => count.value++ return { count, increment } } <script setup> const count = ref(0) const increment = () => count.value++ </script> setup():最後にreturnで返す 値を⼀つ増やすたびに、 returnにも書き⾜す <script setup>:returnは不要 トップレベルの値を、 テンプレートで直接使える 注:SFC(Single File Component)は画⾯‧状態‧スタイルを⼀つの.vueファイルに書く形式。両⽅ともimportは省略 #vuefes #vuefes_medpeer
  22. <script setup>は、最初の提案のまま決まったのか? 初期案は置き換えられ、 論点を分けた新しい提案がマージされた 1 2 3 #182 #222 #227

    RFC 0040 SFC Improvements New script setup <script setup> #227の確定形 2020-06-29 作成 2020-11-09 クローズ and ref sugar 2020-11-09 作成 2021-07-01 マージ 冒頭に太字で、 2020-10-30 作成 2020-11-09 クローズ #222への置き換えを予告 ref sugarと ⼀緒に提案 4 #222から切り離し、 トップレベルの変数を、 単独で議論 テンプレートから 出所:vuejs/rfcs #182‧#222‧#227のPR本⽂、RFC 0040(スクリーンショットは2026-10-05撮影‧⽇付はUTC) 直接使える #vuefes #vuefes_medpeer
  23. <script setup>は、最初の提案のまま決まったのか? 初期案は置き換えられ、 論点を分けた新しい提案がマージされた #182 2020-06-29 → #222 2020-10-30 →

    #227 2020-11-09 → RFC 0040 #182 2020-11-09 クローズ この版の<script setup>は、 #222の新しい版に 置き換えられる、と 太字で書かれている 出所:vuejs/rfcs #182‧#222‧#227のPR本⽂、RFC 0040(スクリーンショットは2026-10-05撮影‧⽇付はUTC) #vuefes #vuefes_medpeer
  24. <script setup>は、最初の提案のまま決まったのか? 初期案は置き換えられ、 論点を分けた新しい提案がマージされた #182 2020-06-29 → #222 2020-10-30 →

    #227 2020-11-09 → RFC 0040 #222 2020-11-09 クローズ <script setup>と、 .valueなしでrefを使う 糖⾐構⽂を⼀緒に提案 出所:vuejs/rfcs #182‧#222‧#227のPR本⽂、RFC 0040(スクリーンショットは2026-10-05撮影‧⽇付はUTC) #vuefes #vuefes_medpeer
  25. <script setup>は、最初の提案のまま決まったのか? 初期案は置き換えられ、 論点を分けた新しい提案がマージされた #182 2020-06-29 → #222 2020-10-30 →

    #227 2020-11-09 → RFC 0040 #227 2021-07-01 マージ #222から <script setup>を 切り離して単独で議論する。 #222への フィードバックも反映 出所:vuejs/rfcs #182‧#222‧#227のPR本⽂、RFC 0040(スクリーンショットは2026-10-05撮影‧⽇付はUTC) #vuefes #vuefes_medpeer
  26. <script setup>は、最初の提案のまま決まったのか? 初期案は置き換えられ、 論点を分けた新しい提案がマージされた #182 2020-06-29 → #222 2020-10-30 →

    #227 2020-11-09 → RFC 0040 RFC 0040 #227がRFCとして残ったもの トップレベルの変数を テンプレートへ公開する、 新しいscriptの形 出所:vuejs/rfcs #182‧#222‧#227のPR本⽂、RFC 0040(スクリーンショットは2026-10-05撮影‧⽇付はUTC) #vuefes #vuefes_medpeer
  27. <script setup>は、最初の提案のまま決まったのか? 初期案は置き換えられ、 論点を分けた新しい提案がマージされた 1 2 3 #182 #222 #227

    RFC 0040 SFC Improvements New script setup <script setup> #227の確定形 2020-06-29 作成 2020-11-09 クローズ and ref sugar 2020-11-09 作成 2021-07-01 マージ 冒頭に太字で、 2020-10-30 作成 2020-11-09 クローズ #222への置き換えを予告 ref sugarと ⼀緒に提案 解釈 4 #222から切り離し、 トップレベルの変数を、 単独で議論 テンプレートから 直接使える ⼀度出した案を置き換え、範囲を絞り直して前に進んだ 出所:vuejs/rfcs #182‧#222‧#227のPR本⽂、RFC 0040(スクリーンショットは2026-10-05撮影‧⽇付はUTC) #vuefes #vuefes_medpeer
  28. 参考|<script setup>は、短く書くためだけの仕組みってこと? コンパイラが読む形式にして、短く書けて型も書きやすくした <script setup> 実⾏前にコンパイラが読む 変数を把握 → テンプレートの変数を知る 型を書きやすい

    → propsとイベントの型を 専⽤のマクロで書く <script setup lang="ts"> const props = defineProps<{ step: number }>() const emit = defineEmits<{ change: [value: number] }>() </script> 出所:Vue公式ドキュメント <script setup> API、RFC 0040(コード例はVue 3.3以降の記法) #vuefes #vuefes_medpeer
  29. Caseから、どんな意思決定を学べたか? 答えだけでなく、決め⽅まで持ち帰れる 3 4 6 ⾒取り図の段階 記録に残っていた判断と、その根拠 Class API案 前提の危うさをもとに⾒送り

    #17‧RFC 0013 仕様が未確定のデコレータに頼る点を「リスクの⾼い前提」とした Function-based API案 OptionsAPIを置き換えず、両者を残した #42‧#78 新APIは「純粋に追加的」。廃⽌の記述は利⽤者の声を受けて削除 <script setup> 論点を分けて、前に進めた #227 SFC improvements およびref sugarと切り離し、<script setup>だけ を議論した 出所:RFC 0013、vuejs/rfcs #17‧#42‧#78‧#227の本⽂(2026-10-05 原⽂確認) #vuefes #vuefes_medpeer