Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
大規模モノレポの秩序管理 失速しない多言語化フロントエンドの運用
Search
shoota
November 16, 2025
Technology
0
30
大規模モノレポの秩序管理 失速しない多言語化フロントエンドの運用
JSConf 2025 / Findy Sponsor Key note
shoota
November 16, 2025
Tweet
Share
More Decks by shoota
See All by shoota
AIの個性を理解し、指揮する
shoota
3
690
開発生産性向上! 育成を「改善」と捉えるエンジニア育成戦略
shoota
3
1.2k
自己改善からチームを動かす! 「セルフエンジニアリングマネージャー」のすゝめ
shoota
6
13k
UT Tech sake #7
shoota
0
73
UT Teck sake #2
shoota
0
130
Other Decks in Technology
See All in Technology
Flutter DevToolsで発見! 本番アプリのパフォーマンス問題と改善の実践
goto_tsl
1
370
AI時代におけるドメイン駆動設計 入門 / Introduction to Domain-Driven Design in the AI Era
fendo181
0
670
エンタープライズ企業における開発効率化のためのコンテキスト設計とその活用
sergicalsix
1
350
エンジニア採用と 技術広報の取り組みと注力点/techpr1112
nishiuma
0
130
旧から新へ: 大規模ウェブクローラの Perl から Go への移行 / YAPC::Fukuoka 2025
motemen
1
740
What's the recommended Flutter architecture
aakira
1
1.1k
ubuntu-latest から ubuntu-slim へ移行しよう!コスト削減うれしい~!
asumikam
0
470
Proxmox × HCP Terraformで始めるお家プライベートクラウド
lamaglama39
1
190
探求の技術
azukiazusa1
5
1.5k
"おまじない"はもう卒業! デバッガで探るSpring Bootの裏側と「学び方」の学び方
takeuchi_132917
0
110
Post-AIコーディング時代のエンジニア生存戦略
shinoyu
0
250
Rubyist入門: The Way to The Timeless Way of Programming
snoozer05
PRO
5
310
Featured
See All Featured
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
Speed Design
sergeychernyshev
32
1.2k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
54k
How to train your dragon (web standard)
notwaldorf
97
6.4k
[RailsConf 2023] Rails as a piece of cake
palkan
57
6k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.2k
Practical Orchestrator
shlominoach
190
11k
Raft: Consensus for Rubyists
vanstee
140
7.2k
Building Adaptive Systems
keathley
44
2.8k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
For a Future-Friendly Web
brad_frost
180
10k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Transcript
© Findy Inc. ⼤規模モノレポの秩序管理 1 トラックD 熊野 修太 / Shuta
Kumano 失速しない多⾔語化フロントエンドの運⽤ 2025.11.16
© Findy Inc. 2 @shoota 熊野 修太 [くまの しゅうた] ファインディ株式会社
Team+開発部 Enablementチーム / フロントエンドリード フロントエンドリード、スクラムマスター、エンジニア リングマネージャーを経験 Findy Team+に魅⼒を感じ2023年1⽉よりジョイン 同2023下期に全社MVP受賞 フルリモート in ⻘森
© 2024 Findy Inc. 挑戦するエンジニアの プラットフォームをつくる。 ビジョン つくる⼈がもっとかがやけば、 世界はきっと豊かになる。 経営理念
会社概要 会社名 ファインディ株式会社 / Findy Inc. 代表取締役 ⼭⽥ 裕⼀朗 設⽴ 2014 年 2 ⽉ ※ 本格的な事業開始は2016年7⽉ 社員数 297 名 資本⾦ 18 億 5,043 万円 ※ 資本準備⾦含む 住所 東京都品川区大崎1-2-2 アートヴィレッジ大崎セントラルタワー 5階 事業許可番号 13-ユ-308478 サービス ‧ スカウト型リクルーティングサービス「Findy」 ‧ ハイスキルな業務委託エンジニア紹介サービス「Findy Freelance」 ‧ エンジニア組織⽀援SaaS「Findy Team+」 ‧ 開発ツールに特化したレビューサイト「Findy Tools」 投資家 グローバル‧ブレイン、ユナイテッド、SMBCベンチャーキャピタル、KDDI、JA三 井リース、みずほキャピタル、博報堂DYベンチャーズ、Carbide Ventures、等 3
© Findy Inc. 4
© Findy Inc. Introduction 5
© Findy Inc. 6 Introduction テスト、書いてますか?
© Findy Inc. 7 Introduction エンジニアリングの主体はテスト https://findy-code.io/engineer-lab/t-wada
© Findy Inc. 8 Introduction テスティングトロフィー ⾼品質なフロントエンドソフトウェアを⽀えるテスト構造のフレームワーク ❏ E2Eテスト ❏
Integration Test ❏ Unit Test ❏ 静的解析
© Findy Inc. 9 Introduction トヨタ⽣産⽅式 「品質を⼯程で作り込む」 テストに「次⼯程はお客様」の思想をもたらす ❏ E2Eテスト
❏ Integration Test ❏ Unit Test ❏ 静的解析
© Findy Inc. https://queue.acm.org/detail.cfm?id=3595878 10 Introduction 継続的デリバリー ビルドプロセスとテストプロセスを短く保て ❏ ⽬安は10分以内
> 我々の考えでは10分がほぼ限界である
© Findy Inc. 11 Introduction LeanとDevOpsの科学 注⼒すべきはデプロイとテストの容易性 ❏ ハイパフォーマンスな組織を作るうえで重要 >
テストの⼤半を、統合環境を⽤意せずに実施できる > アプリケーションを、それが依存するほかのアプリ ケーションやサービスから独⽴した形で、デプロイま たはリリースできる
© Findy Inc. 12 Introduction つまり、 ❏ 階層化されたテストによってソフトウェアの品質を担保しなさい ❏ それぞれのテスト階層は独⽴させ、閉じた状態で品質を作り込みなさい
❏ すべてのテストは10分以内で終わらせなさい ❏ テストの容易性を保ち、独⽴したデプロイを実現しなさい _(´ཀ`」 ∠)_
© Findy Inc. 13 Introduction テスト、書いてますか? つらくない?
© Findy Inc. 14 Introduction 余談 テストに厳しいサバンナの王者、作者は古川さん
© Findy Inc. Findy Team+ フロントエンドの リポジトリ構造 15
© Findy Inc. 16 技術スタック ❏ graphql-codegen / Apollo client
❏ eslint / prettier ❏ Storybook ❏ Playwright (E2E) ❏ i18next / react-i18next ❏ React / TypeScript ❏ Vite / Vitest リポジトリ構造
© Findy Inc. 17 技術スタック ❏ graphql-codegen / Apollo client
❏ eslint / prettier ❏ Storybook ❏ Playwright (E2E) ❏ i18next / react-i18next ❏ React / TypeScript ❏ Vite / Vitest with リポジトリ構造
© Findy Inc. 18 技術スタック リポジトリ構造
© Findy Inc. 19 Nxの機能と恩恵 1. Code generatorの標準装備 2. モノレポ内の依存関係の⾃動検出と変更検知
3. モノレポ内の依存関係の制約と管理 4. コマンド結果のキャッシュ 5. ライブラリマイグレーション リポジトリ構造 https://tech.findy.co.jp/entry/2024/08/05/090000
© Findy Inc. 20 Nxの機能と恩恵 1. Code generatorの標準装備 2. モノレポ内の依存関係の⾃動検出と変更検知
3. モノレポ内の依存関係の制約と管理 4. コマンド結果のキャッシュ 5. ライブラリマイグレーション リポジトリ構造 https://tech.findy.co.jp/entry/2024/08/05/090000
© Findy Inc. ❏ モノレポ内の依存関係の⾃動検出と変更検知 ❏ 実際にimportしているモジュールの依存関係を解析 ❏ nx affected
: 影響のあるもののみにコマンド実⾏ 21 Nxの機能と恩恵 リポジトリ構造
© Findy Inc. ❏ モノレポ内の依存関係の⾃動検出と変更検知 ❏ 実際にimportしているモジュールの依存関係を解析 ❏ nx affected
: 影響のあるもののみにコマンド実⾏ 22 Nxの機能と恩恵 リポジトリ構造
© Findy Inc. ❏ モノレポ内の依存関係の⾃動検出と変更検知 ❏ 実際にimportしているモジュールの依存関係を解析 ❏ nx affected
: 影響のあるもののみにコマンド実⾏ 23 Nxの機能と恩恵 リポジトリ構造
© Findy Inc. 24 Nxの機能と恩恵 リポジトリ構造 ❏ モノレポ内の依存関係の制約と管理 ❏ Nx独⾃のeslint
ruleを採⽤することで実現 ❏ moduleにtagを指定し、tag間の依存可否をeslint ruleに記述する。 例1) feature から ui には依存できるが、 ui から feature は依存できない 例1) feature 同⼠では依存できない UI shared feature feature feature app app
© Findy Inc. moduleの役割や責務を分離(設計)して、 実際に影響のあるモジュール(実体)のみのテストやビルドを⾏う ❏ モノレポ内の依存関係の⾃動検出と変更検知 ❏ モノレポ内の依存関係の制約と管理 25
Nxの機能と恩恵 リポジトリ構造 = 実体 = 設計 CI/CDの省⼒化
© Findy Inc. ❏ モノレポのもつmoduleが125個 ❏ 機能(画⾯)moduleが112 個 ❏ UI
やデザインを内包したComponent moduleが3個 ❏ 通信関連、ドメイン共通定義、その他ワークアラウンドが 7個 ❏ ユーティリティ関数関連が 2 個 ❏ 多⾔語化モジュールが 1個 26 現時点のコード規模 リポジトリ構造
© Findy Inc. ❏ TypeScriptコードとしては60万⾏ ❏ 多⾔語化のため、JSONファイルが7.4万⾏ 27 現時点のコード規模 リポジトリ構造
© Findy Inc. ❏ 平均のPull Request数 :23.8 /day ❏ 平均のcommit数:72.7
/day 28 コード変更量 リポジトリ構造
© Findy Inc. 多⾔語化モジュールの構築 29
© Findy Inc. 30 多⾔語化プロジェクト 多⾔語化モジュールの構築 ❏ 多⾔語化の同時並列作業&確認作業に全振り ❏ Pull
Request数が当時⽐で2.5倍以上 ❏ 3ヶ⽉弱で3000以上のセンテンスの対象抽出と⽇英翻訳処理が完了
© Findy Inc. 31 初期の翻訳アーキテクチャ 多⾔語化モジュールの構築 ❏ i18nモジュールが全ての翻訳リソースを持つ ❏ 翻訳リソースはモジュール名ごとに名前空間とファイルを分離
❏ 機能モジュールごとにファイル分割されているため変更範囲が理解しやすい ❏ i18nモジュールが⼀元管理することで翻訳リソースの管理がシンプル
© Findy Inc. 凝集度の7段階 ❏ 機能的凝集(Functional Cohesion) ❏ 1つの明確な機能のみにまとまっている ❏
逐次的凝集(Sequential Cohesion) ❏ ⼀⽅の出⼒がもう⼀⽅の⼊⼒になる。メソッドチェーン。 ❏ 通信的凝集(Communicational Cohesion) ❏ 同じデータを扱う部分を集めている ❏ ⼿続き的凝集(Procedural Cohesion) ❏ 時間的凝集(Temporal Cohesion) ❏ 論理的凝集(Logical Cohesion) ❏ 偶発的凝集(Coincidental Cohesion) 32 多⾔語化モジュールの構築 アーキテクチャと凝集度
© Findy Inc. 33 多⾔語化モジュールの構築 レガシーコードからの脱却 > ⾼品質のコードは凝集性が⾼い > ⾼品質のコードは疎結合である
> ⾼品質のコードはカプセル化されている
© Findy Inc. 32章 凝集 34 多⾔語化モジュールの構築 Tidy First? >
結合した要素は同じ親要素の⼦要素同⼠であるべきだ。 > これが凝集(Cohesion)の1つめの意味合いだ。
© Findy Inc. ❏ 1つの明確な機能(翻訳処理)のみを持つ ❏ 他の機能と疎結合で、カプセル化されている ❏ 結合した要素(⾔語ごとの翻訳ファイル)は同じ親要素の⼦要素 35
初期アーキテクチャの評価 多⾔語化モジュールの構築 妥当な設計と判断した
© Findy Inc. 36 初期アーキテクチャの問題点 - CI速度の劣化 多⾔語化モジュールの構築 ❏ i18n
moduleの変更頻度が想定よりも多い ❏ 辞書jsonの変更がi18n moduleの変更として認知される(考慮もれ) ❏ 機能変更の多くが辞書とセットなので、i18nが定常的に影響範囲になる nx affected の理解不⾜ 変更単位
© Findy Inc. 37 初期アーキテクチャの問題点 - CI速度の劣化 多⾔語化モジュールの構築 ❏ i18n
moduleに依存が集中 ❏ ほぼすべてのmoduleがi18nの影響範囲になった ❏ i18nの変更が発⽣するとほぼすべてのmoduleのCIが必要 nx affected が無⼒に
© Findy Inc. ❏ 急激な機能追加で毎⽉、複数の新しいmoduleが増え、 影響範囲と変更頻度が同時に成⻑ 38 初期アーキテクチャの問題点 - CI速度の劣化
多⾔語化モジュールの構築 moduleが 増える CI対象が 増える 変更頻度が 増える 実際には影響がないのに、 ⼤量のテストを⾼頻度に実⾏
© Findy Inc. 39 初期アーキテクチャの問題点 - CI速度の劣化 多⾔語化モジュールの構築 我々の考えでは10分がほぼ限界である ❏
CI時間 約7分から13分以上に ❏ デプロイ 約30分、多いときで40分以上
© Findy Inc. 40 初期アーキテクチャの問題点 - ビルドサイズの肥⼤化 多⾔語化モジュールの構築 ❏ 他のmoduleと同様、i18n
moduleは独⽴したモジュールとしてビルド ❏ i18nクライアント+翻訳リソース(JSON) ❏ どのSPA画⾯を開いても数MBの翻訳モジュールをロード アプリケーションを、それが依存するほかのアプリケーション やサービスから独⽴した形で、デプロイまたはリリースできる ‧すでに6000以上のセンテンスが登録済み ‧各センテンスが2⾔語で登録されており、3⾔語⽬の適⽤を⽬指してい る
© Findy Inc. 41 多⾔語化モジュールの構築 どうしてこうなった How come?
© Findy Inc. 42 多⾔語化モジュールの構築 しかも サポート⾔語増加予定 Global展開 拡⼤中!
© Findy Inc. 多⾔語化のリアーキテクチャ 43
© Findy Inc. 凝集度の7段階(の良い⽅) ❏ 機能的凝集(Functional Cohesion) ❏ 1つの明確な機能のみにまとまっている ❏
逐次的凝集(Sequential Cohesion) ❏ ⼀⽅の出⼒がもう⼀⽅の⼊⼒になる。メソッドチェーン。 ❏ 通信的凝集(Communicational Cohesion) ❏ 同じデータを扱う部分を集めている 44 凝集度の設計を⾒直し 多⾔語化のリアーキテクチャ
© Findy Inc. 凝集度の7段階(の良い⽅) ❏ 機能的凝集(Functional Cohesion) ❏ 1つの明確な機能のみにまとまっている ❏
逐次的凝集(Sequential Cohesion) ❏ ⼀⽅の出⼒がもう⼀⽅の⼊⼒になる。メソッドチェーン。 ❏ 通信的凝集(Communicational Cohesion) ❏ 同じデータを扱う部分を集めている 45 凝集度の設計を⾒直し 多⾔語化のリアーキテクチャ 通信(graphql)モジュールと同じデザインパターンが 適⽤できるのでは?
© Findy Inc. graphql モジュールの設計 ❏ 実⾏インスタンスはSingletonでmoduleにカプセル化 ❏ 各々のmoduleがDocument(静的リソース)を内包する ❏
Documentを利⽤する⼿段(Provider)をアプリケーションルートがもつ 46 凝集度の設計を⾒直し 多⾔語化のリアーキテクチャ
© Findy Inc. i18nモジュールの設計草案 ❏ 実⾏インスタンスはSingletonでmoduleにカプセル化 ❏ 各々のmoduleが翻訳⽂字列(静的リソース)を内包する ❏ リソースを利⽤する⼿段(Provider)をアプリケーションルートがもつ
47 凝集度の設計を⾒直し 多⾔語化のリアーキテクチャ
© Findy Inc. i18nモジュールの設計草案 ❏ module内に翻訳リソースが閉じるのでPull Requestの変更がmodule内に閉じる ❏ 変更が閉じることで機能moduleの増加は無関係になり、翻訳リソースも機能単位でビルドされる ❏
AppsはRouteingなど全体を知る必要があるのでもともと機能moduleには依存している ❏ リソースを利⽤する⼿段をAppsから提供できれば実現できる 48 凝集度の設計を⾒直し 多⾔語化のリアーキテクチャ いけそう 変更単位
© Findy Inc. 翻訳リソースを動的にロードする仕組みの作成 ❏ ライブラリにはi18n clientインスタンスを切り替える仕組み(Provider)はあった ❏ 画⾯ごとに切り替えるというより翻訳処理の設定を特定条件で切り替えるのが⽬的 ❏
ユーザーが画⾯を開くとその機能moduleのもつ辞書をロードさせたい ❏ 辞書⾃体はclientがキャッシュするのでReact Providerは不要 49 リアーキテクチャ 多⾔語化のリアーキテクチャ
© Findy Inc. 翻訳リソースを動的にロードする仕組みの作成 50 リアーキテクチャ 多⾔語化のリアーキテクチャ import { TeamContainer,
translateResources } from '@feature/team'; export const TeamPage = () => { const { params } = useParams(); return ( <TranslateResourceManager resourceBundles={[{ nameSpace: 'team', resources: translateResources, }]} > <TeamContainer params={params} />; </TranslateResourceManager> ); }; 機能のRoot Component 翻訳リソースを動的にロードして管理する 翻訳リソースとその名前空間を受ける feature moduleで名前解決に利⽤
© Findy Inc. ❏ それぞれの辞書リソースを分散配置 ❏ 全ページを翻訳管理Componentでラップ ❏ 機能のRoot Componentと共に翻訳データをi18n
clientに辞書登録 51 リアーキテクチャ 多⾔語化のリアーキテクチャ
© Findy Inc. • keyの型をfeature moduleごとに定義しなおし • 実体と同期しているので、keyの増減とあわせて Union型が持つ数が増減する •
module : 名前空間 : 型定義 = 1 : 1 : 1 型定義の再構築 ❏ 翻訳センテンスを識別するkeyを各featureで型に変換 ❏ コード補完 & 存在しないkeyは型エラー 52 リアーキテクチャ 多⾔語化のリアーキテクチャ /** team/i18n.d.ts */ declare module 'i18next' { interface CustomTypeOptions { resources: { team: (typeof resources)['en']; }; } } export const TeamLabel = () => { const { t } = useTranslation('team'); return <label>{t('teamMembers')}</label>; }; 名前空間の指定 keyの指定
© Findy Inc. 共通moduleの翻訳配置 ❏ UI や共有機能など、複数の機能moduleが利⽤するmoduleの辞書 ❏ これらは分散配置の対象から外し、i18n moduleに持たせる
53 リアーキテクチャ 多⾔語化のリアーキテクチャ export const SubmitButton = ( { label }: { label?: string }) => { const { t } = useTranslation('ui'); const defaultLabel = useTranslation('submit'); return <button>{label ?? defaultLabel}</button>; };
© Findy Inc. コードベースとCI時間⽐較 リアーキテクチャ 多⾔語化のリアーキテクチャ 54 Before After Now
TypeScript 353,578 ⾏ 552,539 ⾏ 613,432 ⾏ JSON 51,694 ⾏ 66,888⾏ 74,210 ⾏ 対応⾔語 2 3 3 +α 平均CI時間 13分 7分 6〜7分 ❏ コードベースが1.5倍以上でCI時間が約50% ❏ その後もCI時間7分の⽔準を維持 ❏ デプロイは変更範囲によって変動。4〜15分、稀に20分弱。
© Findy Inc. 結論 ❏ 凝集の設計判断が間違っていた ❏ moduleがどのように利⽤されるかで凝集設計をすべきだった 55 リアーキテクチャ
多⾔語化のリアーキテクチャ 結合した要素は同じ親要素の⼦要素同⼠であるべきだ。 これが凝集(Cohesion)の1つめの意味合いだ。 凝集の2つめの意味合いは、結合していない要素は別の場所 に移すべきということだ。
© Findy Inc. リアーキテクチャ 多⾔語化のリアーキテクチャ 56 失速しないフロントエンド
© Findy Inc. そのほかの取り組みや課題 57
© Findy Inc. ❏ CI時間を1つの指標としてmodule 設計を⾒直し ❏ 画⾯レイアウトを共有モジュールから分離 ❏ 共有モジュールの分割
❏ 変更頻度と成熟度 ❏ UI モジュールの分割 ❏ プリミティブとセマンティックの分割 ❏ Atomic Designではない 58 その他の取り組み その他の取り組みや課題 https://tech.findy.co.jp/entry/2025/06/30/070000
© Findy Inc. ❏ 巨⼤なStorybookの運⽤ ❏ すべてのUIを提供するサーバー ❏ 全⾔語の全センテンス =
全翻訳リソースが必要 ❏ VRT [Visual Regression Test] ❏ Storybookベースで実施していたが、上記理由で厳しい状況 ❏ Vitest v4の toMatchScreeenshot に期待 ❏ ESLint ❏ モノレポ対応が弱く、バージョンアップ (v10.x.x)に期待 ❏ --flag v10_config_lookup_from_file モノレポサポートが弱いエコシステムに課題 59 その他の取り組みや課題
© Findy Inc. まとめ 60
© Findy Inc. ❏ CIをショートカット ❏ 依存関係の⾃動検出 ❏ nx affected
[command] で必要なテストを実⾏する ❏ モジュールの依存関係の設計と管理 ❏ Nx独⾃のeslint rule ❏ 責務をeslintのtagで表現 Nxによる効率化と管理 61 まとめ PullRequestのCI時間は10分以内
© Findy Inc. moduleと凝集度設計 62 まとめ ❏ 機能的凝集(Functional Cohesion) ❏
1つの明確な機能のみにまとまっている ❏ 通信的凝集(Communicational Cohesion) ❏ 同じデータを扱う部分を集めている 機能的凝集 通信的凝集
© Findy Inc. 63 まとめ Nxはmoduleそれぞれが全体の与える影響度を教えてくれる CI時間を指標として定量的に凝集を評価する ❏ CIが遅い =
凝集の設計が悪い ❏ 凝集の設計が悪い = 結合の⽅法が悪い ❏ 結合の⽅法が悪い = 与えている責務に誤解がある
© Findy Inc. 本セッションの詳細な内容に興味をもたれましたら、 ぜひ Findyブースにぜひお越しください! 64 @shoota @shoota Follow
me ♥ ⼤規模モノレポの秩序管理 失速しない多⾔語化フロントエンドの運⽤