Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

サークルポータルを支えるフロントエンドアーキテクチャの選定

 サークルポータルを支えるフロントエンドアーキテクチャの選定

虎の穴ラボ Tech Talk #1 〜社内技術LT〜でLTした、新サークルポータル フロントエンド技術選定の話です。

虎の穴ラボ株式会社

September 18, 2024
Tweet

More Decks by 虎の穴ラボ株式会社

Other Decks in Programming

Transcript

  1. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. T

    O R A N O A N A L a b サークルポータルを支える フロントエンドアーキテクチャの選定 〜 現場で役立つ技術選定のプロセス 〜
  2. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 目次

    1. とらのあな サークルポータルとは? 2. UI/UXの改善事例 3. プロジェクトの背景と目的 4. 技術選定について 4.1. 共通コンセプト 4.2. 選定基準、設計思想、実装検証について 4.3. 結果およびインパクトの評価 5. 将来の展望 6. 技術選定の振り返り 7. 付録
  3. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 虎の穴が提供する同人サークル向けの作品と販売支援プラットフォームで

    す。このポータルを利用することで、同人サークルが虎の穴に同人誌などの 販売を委託し、広くファンに届けることが可能になります。 • 作品登録と管理(物理本と電子) • 販売支援機能(特価販売キャンペーン申込み、再販チャレンジ、通販 PV 数表示など) タイトル とらのあなサークルポータルとは?
  4. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 他社管理のシステム保守運用を自社への引き継ぎを行う

    引き継ぎに当たって、虎の穴ラボで開発が可能な言語やアーキテクチャに切 り替える • 既存(Perl + jQuery)から モダンなアーキテクチャへ切り替え タイトル プロジェクトの背景と目的
  5. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 1.

    ユーザーが欲しい機能を欲しいタイミングで提供できるサービスを作る a. 他社との調整コスト、発注リードタイムを削減 b. 運用負荷、工数を下げ機能開発に工数を割く 2. 競合他社より優れた体験をユーザーにお届けするサービスを作る a. アーキテクチャ、利用技術をモダンな環境にリプレイス b. UI/UXを含めた表現の幅を広める 3. 自社社員の運用にも優しいサービスを作る a. 手動でのオペレーションを削減 タイトル プロジェクトの 3大目標
  6. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 旧アーキテクチャ(

    Perl x jQuery) 15 OracleDB Perl HTML/jQuery SQL 動的HTML Form送信 非同期通信(Ajax) SSR アーキテクチャ的には、昔からよく 使われている、サーバサイドレンダ リング(SSR)+非同期通信で作ら れている。
  7. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 今回話す部分

    新アーキテクチャ( Next.js x Kotlin) 16 OracleDB (変更なし) Next.js SSR HTML/React SQL/ORM 動的HTML 非同期通信 (Fetch) SSG Kotlin (Ktor) OpenAPI Next.js API BFF バックエンドをKotlinとし、フロン トはNext.jsでのサーバサイドレン ダリング(SSR)+非同期通信に作 り替え
  8. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 目的

    • 技術選定をスムーズに進める 概要 • 人や信頼性、コスト、非機能要 件などについて、言語毎に以下 をまとめたもの ◦ 比較する項目 ◦ 抑える項目 技術選定の共通コンセプトを作成
  9. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. アーキテクチャ

    • React.js(Next.js) • Vue.js • Vue3(Nuxt3) • jQuery / Thymeleaf レガシーなPerl+jQueryから これらの技術への移行を考えました。 (2022年12月頃) 社内標準的には Reactの方針でした が改めて技術を比較しました。 共通コンセプトでそれぞれの技術を比較
  10. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. •

    Vue.js / Thymeleaf の方がとらのあな通販は有識者は多い • 他システム(クリエイティア、通販の一部)で Vue2 は実績がある。 • Thymeleafは通販の主要言語になる • Vue3 は Vue2 からのキャッチアップが必要となる • Reactはチームで全くの業務未経験だが、別チームの Reactに詳しいメンバーが月単位でヘルプ 予定 (新サークルポータル開発は元とらのあな通販メンバーが中心) チーム内に複数名の有識者がいるかどうか 大項目 中項目 小項目 重 要 Next.js (React) Nuxt3 (Vue3) Nuxt2 (Vue2) Thymeleaf (Ktor) 人 学習 チーム内に複数名の有識 者がいる ✅ ❌ ✅ ✅
  11. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. •

    Next.js/React.js は別チームに詳しいメンバーがいるのでヘルプ予定。 • Vue2 から Vue3 へのキャッチアップがかなり難しいのではないか?との想定があった(まだ、 Nuxt3が出たばかりの頃) ◦ 社内でVue2の採用実績は当時( 2022年12月頃)は多かったが、 Vue3はほぼ無かった。 チーム内で相互学習 /レビューができるかどうか 大項目 中項目 小項目 重 要 Next.js (React) Nuxt3 (Vue3) Nuxt2 (Vue2) Thymeleaf (Ktor) 人 学習 チーム内で相互学習 /レ ビューができる ✅ ✅ ❌ ✅ ✅
  12. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. •

    当時(2022年12月頃)はReactの日本語ドキュメントはあまり整備されてなかった。 • その他、特にVueは日本語コミュニティが活発で日本語翻訳された公式ドキュメントがちゃんとあっ たが、Vue3やNuxt3に関する情報は少なかった。 (現在、Reactは公式ドキュメントの日本語訳 ができてます。かなり良い感じのもの。) 他者の運用事例も多い(文献が多い)かどうか 大項目 中項目 小項目 重 要 Next.js (React) Nuxt3 (Vue3) Nuxt2 (Vue2) Thymeleaf (Ktor) 人 学習 他者の運用事例も多い(文 献が多い) ✅ 🔺 ❌ ✅ ✅
  13. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. •

    有名サイトで有効求人数を比較しました。 • 当時(2022年12月頃)はThymeleaf(Ktor)以外は大差ない状況でした。 ◦ 現状もここはあまり変わらず。 利用者が多く転職者も集めやすいかどうか 大項目 中項目 小項目 重 要 Next.js (React) Nuxt3 (Vue3) Nuxt2 (Vue2) Thymeleaf (Ktor) 人 人材 流動 性 利用者が多く転職者も集め やすい ✅ ❓ (未知数) ✅ ❌
  14. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. •

    社内標準的にはReactの方針 ◦ FantiaがReact.jsへ置き換えを進めていた ◦ Nuxt.js はクリエイティア/通販の一部サービスが利用 社内での部署間異動が容易かどうか 大項目 中項目 小項目 重 要 Next.js (React) Nuxt3 (Vue3) Nuxt2 (Vue2) Thymeleaf (Ktor) 人 人材 流動 性 社内での部署間異動も容 易 ✅ ❌ ✅ ❌
  15. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. •

    Thymeleaf以外はユニットテストや E2E のテストの導入が可能 • ThymeleafはE2Eテストは可能、ユニットテストも jUnitを使えば可能だが他の E2E系テストと組み 合わせないとJSのテストができないかつ、一般的ではないので ❌(2022年12月当時) • Nuxt3はE2Eによるコンポーネントテストしか情報が無かった(当時)ので、 🔺 テストコードが実装可能かどうか 大項目 中項目 小項目 重 要 Next.js (React) Nuxt3 (Vue3) Nuxt2 (Vue2) Thymeleaf (Ktor) 非機 能要 件 テスト 効率 テストコードが実装可能か どうか ✅ ✅ 🔺 ✅ ❌
  16. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. •

    Thymeleaf以外はESLint、Prettierなどの導入が可能 • ThymeleafはHTML系の静的解析で代用可能、代用なので 🔺(2022年12月当時) • Vue3はVSCodeの拡張による静的解析をしようとすると、新しい Volarに移行が必要だった( Vue2 はVetur、Vue2とVue3で切り替えが必要)( 2022年12月当時) 静的コード解析が実装可能かどうか 大項目 中項目 小項目 重 要 Next.js (React) Nuxt3 (Vue3) Nuxt2 (Vue2) Thymeleaf (Ktor) 非機 能要 件 開発 効率 静的コード解析も可能 ✅ 🔺 ✅ 🔺
  17. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 国内外に対してのアンケートを参考にする

    ReactやVueも、全体に対してそれほど採用されているわけでない。 ほとんどはまだ、jQuery • 引用: https://feb19.jp/blog/20220904_jqueryreactvue 2021 JavaScript ライジングスターを見ると、Reactがわずかに優勢。フレームワークだと React.js系のNext.jsやNest、Remix等が圧倒的。 • 引用:https://risingstars.js.org/2021/ja#section-framework ウェブ制作での利用率
  18. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. Nuxt.js

    の採用事例 • 自社開発 ◦ クラウドワークス(2020/5/29) ◦ Note(2021/12/14) ◦ マイニンテンドー(2020/4/21) ◦ DMM(2019/9) • 受託開発系 ◦ 岸田文雄 公式サイト(2020/9/17) ◦ 東京都 新型コロナウイルス感染症 対策サイト(2020/3/24) Reactの採用事例 • 自社開発 ◦ Backlogなど ※ Reactの方も探したはずが、見当たらず。当時は公式サイトに採用事例が無かった。 他社での採用事例
  19. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 「Nuxt.js/Vue.js」と「Next.js/React.js」は、どちらも規模や要件、チームに応じて適材適所して、将

    来的にどちらが主流になっても大丈夫なようにするべき と考える。( 2022年12月当時) • Vue3 と React はソースコードレベルの大きな違いはない(詳細は付録を参照) • 人気自体は当時は Reactの方がある( Vue3リリース影響などで当時は Vue.jsの人気は落ちて いた印象) • 自社の方針として、今後、 Reactを推していく方針がある これらの情報から、最終的に 「React.js/Next.js」による開発がスタート!! 選定基準のまとめ
  20. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. フロントエンドに適用する設計思想としては一般的であるため

    Atomic Designを選択。 以下を重視しました。 • デザイナーさんの理解しやすさや認知度の広さ(デザイナーさんが Reactを修正する協業もあっ た) • 設計思想として、期待することは Atomic Designでも実現できる • 学習コストが DDD、Clean Architectureに比べて低い( Atomic Designは一般的で社内外の 採用実績も多かった) 設計思想そのものを導入した経緯としては • 保守性と拡張性を良くするため • ユニットテストを書きやすくするため • エンジニアとデザイナーチーム間の開発を円滑にすすめるため Atomic Design と DDD、Clean Architecture
  21. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. それぞれ、機能のサンプリングを行って

    React/Next.jsを使った場合の工数や難易度の確認を行いました。 • 共通コンポーネントの作成 • 新規画面の作成 • 既存画面の修正 それぞれ、工数的に全体スケジュールが問題ないことを確認しました。 実装検証について
  22. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. •

    既存技術( Perl+jQuery)からの脱却に成功し、社外委託から社内開発へ移行完了 ◦ 社内標準の技術への移行できた • 大きな不具合やセキュリティ的な問題はなかった ◦ 外部脆弱性診断: OK ◦ AeyeScanによる社内脆弱性診断: OK ◦ リリース: OK • 有識者以外の React分からない状態が脱却できた! ◦ 現在も世界的に Reactの人気が維持 されている(良かった) ◦ 日本語ドキュメントも前より整備された 良かったこと
  23. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. •

    ローカルビルドから実行( clean→all build)までの時間 ◦ 速(110s → 25s) • 環境構築の手間(ドキュメント見出し数) ◦ 少(約109ステップ → 約33ステップ) • CIの速度:PRマージ速度( 38.7h → 20h) • CDの速度:速( 2~3時間 → 10分) • ユニットテスト網羅率( C0):上昇( 4.57 % → 61.24 %) • コンポーネントテスト:無 → 有(71.29%) 他レガシーなサービスと比べた改善点 (規模が異なるので単純比較は不可、当社比)
  24. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. •

    既存技術からの脱却とプロダクトの寿命を開発工数より重視したことにより ◦ 工数が思ったより多くなった( Ph1とPh2に分けることに、 PH2は未リリース) • 規模が大きい機能はプロトタイプを切り捨てて、最後に一から開発した方が良かった ◦ 最初の不慣れな時に最も難易度が高い重要な機能に手をつけた ❌ ◦ 後から作り直した方が良い状態になった 😵 • 最後までバックエンドとフロントエンド( SSR、BFFのAPI)の役割や境界が曖昧なままになった ◦ Next側のAPIがログイン認証やセキュリティ対策にしか使われていない ◦ あとはバックエンドの APIへ処理をプロキシするだけ ▪ BFFのような作り方をしたかったが、時間不足などもあり難しかった ▪ ログイン認証やセキュリティ対策の実装しやすさには貢献した 課題点
  25. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. •

    Next.js 14系へのアップデート予定 ◦ セキュリティ的に脆弱な状態にならないようにアップデートしておく • AppRouterへの切り替え ◦ 単純移行なら簡単に可能そう ▪ ちゃんと RSC(React Server Component)を使うと、現状がほぼ SPAなので移行に 時間がかかる • 他のReact系のフレームワーク、または Next.js無も検討する予定 ◦ UX/ページ表示速度の改善が見込める ▪ コンポーネント毎にサーバサイドでレンダリングする ▪ コンポーネント毎にキャッシュを有効にする • この辺りに課題があるなら App Routerもアリかも。今は特にない。 今後のアップデート計画
  26. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. TODO:

    要準備 → 具体的なデータはないが、旧サークルポータルで耐えられないアクセス数が新では余裕で耐えら れているという情報がある( 2024/9/4 障害発生時) → 旧も新も DBは同じなので、単純にアプリケーションの問題がリニューアルに伴って解消したと思わ れる パフォーマンスの改善
  27. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 開発からリリースまでの期間がとても掛かってしまった。

    最初に時間がなくてプロトタイプは React.js(Next.js)のみだったので、他も作って比較した方が工数 をアーキテクチャ的に削減できたかもしれない感がある。 今なら、下記の技術でプロトタイプを作って比較したいと思います • React.js(Next.js / Server ActionやApp Routerの有無) • React.js(Remix) • React.jsのみ バックエンドとフロントが担当で明確に分かれてないのにアーキテクチャだけを分けて、 更に経験したことがない言語やフレームワークにすると、全体的な開発に時間が掛かってしまう。とい う辛みもありました。 主に開発工数について
  28. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 状態管理

    // React const [count, setCount] = useState(0); // 更新 setCount((count) => count + 1); // ++はNG // Vue // プリミティブとオブジェクトで異なる const count = ref(0); const object = reactive({}); // 更新 count++; object = { test: 0 }; Vueのreactive はオブジェク トをネストしてリアクティブにす る。 大きくは変わらない。
  29. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 副作用の実行

    // React const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }, [count]); // Vue const count = ref(0); watchEffect(() => (document.title = `You clicked ${count.value} times`)); ほぼ同等。
  30. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. JSXとテンプレート

    // React {/* コメント */} { itemList.map((item) => ( <tr> <td>{item.name}</td> </tr> )); } {isActive && <p>Paragraph</p>;} // Vue <!-- コメント --> <tr v-for="item in itemList"> <td>{{item.name}}</td> </tr> <p v-if="isActive">Paragraph</p> React-JSXはJavaScriptで そのまま書ける Vueはテンプレート言語に近い
  31. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. 双方向バインディン

    グ // React <input value={message} onChange={(e) => setMessaaga(e.target.value)}> // Vue <input v-model="message" /> or <input :value="message" @input="message = $event" /> Vueはv-modelでサポート
  32. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. コンポーネント再生

    成の違い // React function Input() { const [input, setInput] = useState(""); const inputLength = input.length; return ( <div className="App"> <input type="text" value={input} onChange={(e) => setInput(e.target.value)} /> <div>{inputLength}</div> </div> ); } // Vue <template> <div> <input type="text" v-model="input" /> <div>{{ inputLength }}</div> </div> </template> <script setup lang="ts"> const input = ref(""); const inputLength = computed(() => input.value.length); // computed </script> Vueはコンポーネントが再生成 されないので、computed で 明示的に状態変更の追尾をす る。 Reactは常に再生成されるの でmemoで再生成を避ける。
  33. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. Hooks

    コンポーネントが再レンダリングされる度に 内部の関数や変数を再生成 子コンポーネントの不要な再レンダリング※を 避けるために使用者側が React.memo や useMemo、 useCallback を使用してオブジェ クトをメモ化することが必要 ※ いわゆる、Stale Closure Composition API setup 関数の中身は、コンポーネント作成時に 一度だけ実行される。 それ以外の関数や変数も再生成はされない。 変わりにガーベージコレクションのような仕組み (WeakMap/ES6)がある。 条件分岐内で Hook を呼び出したり、Vue のコ ンポーネント外でも使える。 (ES6 Proxy、状態や更新に応じて同期) React の Hooks と Vue の Composition API の違い