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
10周年を迎えたZEN Study Webフロントエンドの次の10年へ向けた工夫
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
tris
May 25, 2026
Programming
47
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
10周年を迎えたZEN Study Webフロントエンドの次の10年へ向けた工夫
TSKaigi 2026 スポンサーセッション
https://2026.tskaigi.org/talks/85
tris
May 25, 2026
More Decks by tris
See All by tris
TypeScript だけを書いて Tauri でデスクトップアプリを作ろう / Tauri with only TypeScript
tris5572
2
3k
Other Decks in Programming
See All in Programming
DynamoDBには集計系のクエリがないけどなんとかしたい
musan
1
140
Language Server 使ってる? 〜VSCode と Zed の場合〜 / Are you using a Language Server? ~For VS Code and Zed~
handlename
0
780
脅威をエンジニアリングの糧にして――現場編 / Turning Threats into Engineering Fuel — Field Edition
nrslib
0
280
Signal Forms: Beyond the Basics @ngBaguette 2026 in Paris
manfredsteyer
PRO
0
250
TypeScript+Orvalで実現する型安全かつ堅牢でスケーラブルなマルチチャネル通知基盤 / TSKaigi Night talks ~after conference~
d0riven
0
340
代数的データ型って何が嬉しいの? #frontend_phpcon_do
kajitack
8
3.7k
IBM Bobを活用したレガシーアプリの最新化
oniak3ibm
PRO
1
200
Snowflake Summitでの新機能 CoCo / CoWork / snowflake-summit-2026-overall-what-new-coco
tatsuhiro
1
130
肥大化するレガシーコードに立ち向かうためのインターフェース分離と依存の逆転 / JJUG CCC 2026 Spring
hirokunimaeta
0
550
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
320
Javaの型とAI時代に型が大事な理由 / java types and type in AI era
kishida
2
140
気づいたらRubyで100作品 ー クリエイティブコーディングが生活の一部になるまで / 100 Ruby Sketches Later: How Creative Coding Became Part of My Life
chobishiba
3
580
Featured
See All Featured
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
180
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
190
How to Talk to Developers About Accessibility
jct
2
230
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
560
Writing Fast Ruby
sferik
630
63k
Art, The Web, and Tiny UX
lynnandtonic
304
22k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
180
A Tale of Four Properties
chriscoyier
163
24k
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
730
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
210
Code Reviewing Like a Champion
maltzj
528
40k
Transcript
10周年を迎えた ZEN Study Webフロントエンドの 次の10年へ向けた工夫 株式会社ドワンゴ 教育事業 (小松) 2026/05/23 TSKaigi 2026
スポンサーセッション
自己紹介 • ドワンゴ 教育事業本部 e-learningプロダクト開発部 ZEN Study Webフロントエンドセクション 小松(こまつ) • ここ2年ほど
ZEN Study の開発に従事 • 趣味の1つ: ドライブ【距離ガバ】 日本本土の海沿いを走破+α 2 ニコニコ超会議の 配信に映り込む 不審なスタッフ
本セッションのサマリー • ドワンゴ教育事業とZEN Studyの概要 ◦ 事業・サービス ◦ これまでの10年のごく簡単な振り返り • 次の10年に向けてメンテナンス性を向上するために行なっている取り組みの一
部を、主にTypeScriptの観点から紹介 ◦ 外部とのやり取りの結果として、判別可能なユニオン型を活用し、状態を詳細にモ デリング (お昼休憩中なので、頭を使う難しい話ではなく、基本的な話をします) 3
ドワンゴの教育事業とは (1) • 主にN高グループとZEN大学に対して、教育に関するシステムを提供 N高グループ(N・S・R高) KADOKAWAとドワンゴが創るネットの高校 2016年4月開校(N高) 生徒数 3万人規模 ZEN大学
日本財団とドワンゴが創るオンライン大学 2025年4月開学 学生数 7千人規模 4
ドワンゴの教育事業とは (2) • 生徒・学生が直接使用するアプリや、学校の運営に関するシステムを提供 ◦ 学習アプリ ZEN Study ▪ 各学校向けだけではなく、一般向けにも月額課金で提供
◦ 教材作成・学校運営に関連するシステム 5
ZEN Study 10周年 🎉 • 2016年4月に「N予備校」としてサービス開始 10周年記念サイト https://www.nnn.ed.nico/pages/10th_anniversary サービスの歴史 ドワンゴ教育サービス開発者ブログ
https://blog.nnn.dev/ 10年を技術面から振り返る記事 6
10年の歴史がある = 10年の積み重ねがある • 最初の構築が急ピッチで行なわれた ◦ N高の開校と同時にリリースする必要があった ▪ 期限が決まっている中で、完全新規プロダクトの構築が行なわれた ◦
開発スピードを優先した選択が行なわれた ▪ メンテナンス性の優先度は低かった • 複雑性が積み重なっている ◦ 新機能の追加 ◦ 対象となる学校の増加 ▪ S高・R高の開校、大学の開学 ◦ リファクタリングが追い付いていないコード 7
ZEN Study 関連の開発体制 • フロントエンドはプラットフォームごとに分かれている • バックエンドは別チーム 8
ZEN Study Webフロントエンドの主な技術スタック • TypeScript + React SPA ◦ (Reactを10年使っているサービスは古参と言えそう)
• TanStack Query • React Router • React Redux 9
ZEN Study Webフロントエンド 10年間の技術変遷 次の10年を見据えて、コードベースの改善を継続して行なっている 10
次の10年に向けて メンテナンス性を向上するための 取り組み(の一部) 11 判別可能なユニオン型を利用して、状態を正確にモデリングする
判別可能なユニオン型を利用する方法の概要 • 外部 API 呼び出しの結果は、成功/失敗のケースがある • それなら汎用的な Result<T, E> を使うのが良さそう
😊 ◦ みんな Result を好きすぎて無限に Result の話をしている • でも Result<T, E> だけではツラいケースがある 😰 ◦ ローディング状態をどう表現する? ◦ エラーの中身をどうやって分ける? ◦ 使う側(コンポーネント)で細かい判定が必要で扱いにくい? ⇩ 判別可能なユニオン型を利用して、状態を正確にモデリングする方法を採用 (本質的には、外部への依存と内部実装とを切り分けている) 12
パターン1. コンポーネントで直接データを取得する • 🔥 データ取得と表示の責務が分離されていない • 🔥 コンポーネントのテストが大変 ◦ 通信をモックする必要がある
13
パターン2. データ取得をカスタムフックに分離する • 👍 データ取得と表示の責務が分離された • 👍 コンポーネントのテストが楽になった ◦ 通信ではなくカスタムフックをモックすれば良い
• 🔥 コンポーネントでの表示のために相変わらず色々と気にする必要がある ◦ 例:ローディングの判定のために特定のフラグを見る必要がある 14
パターン3. 汎用 Result (neverthrow) を使ってみる • 👍 コンポーネントでの表示時に気にすることが減った ◦ 特定の値(フラグ)を元にした判定が不要
• 🔥 ユニオン型と Result の使い分けが必要 ◦ 成功/失敗は Result だが、それ以外はユニオン型なので扱い方が異なる 15 ローディング中は undefined を 返すこととする
パターン4. カスタムフックが返す型としてユニオン型を利用 • この方式を我々は採用 • 👍 データ取得などの外部とのやり取りと表示の責務がより分離された • 👍 数々の嬉しさがある(後述)
判別可能なユニオン 16
ユニオン型を使う嬉しさ (1) • コンポーネントで switch 文によって状態ごとに容易に出し分けられる ◦ 複数の値を元にした状態の判別が不要 ◦ データの取得状態/結果とコンポーネントの表示を明確に関連付けられる
• 網羅性チェックを行える ◦ パターン追加時の堅牢性が上がる 網羅性チェックを実施可能 switch 文により単純に出し分け可能 判別可能なユニオン 17
ユニオン型を使う嬉しさ (2) • データ取得成功時のみ値があることが型で保証される ◦ 値を取得できていない状態のときは、値にアクセスできない • SUCCESS のときのみ値がある •
LOADING や ERROR のときには値がない ERROR などの状態で 値にアクセスを試みると 型エラーになる 18
ユニオン型を使う嬉しさ (3) • エラーの状態を細かく表現可能 その1 ◦ 例:リロードによる復旧可否を分ける リロードしても意味がないエラーと リロードにより復旧できるエラーを 別の型にする
リロードボタンの表示を容易に出し分けられる 19
ユニオン型を使う嬉しさ (4) • エラーの状態を細かく表現可能 その2 ◦ 例:HTTPステータスコードからコンポーネントを分離 ▪ エラーコードへ依存しないので、REST API
から GraphQL へ切り替えるような 場合も、コンポーネントに手を入れる必要がない HTTPステータスコードを直接利用するのではなく、 エラー種別ごとに型を作って、ステータスコードに 依存しないようにする 20
ユニオン型を使う嬉しさ (5) • エラーの状態を細かく表現可能 その3 ◦ 例:追加読み込みを行う API/コンポーネントにおいて、初回読込み時のエラーと追 加読込み時のエラーを区別する ▪
状況によりエラーの表示方法を変えるのが容易(初回読込み時だとエラーペー ジ、追加読込み時だとスナックバー、など) ▪ 単純に useInfiniteQuery を使うより複雑になっているとも言えるが、何を 優先するかのトレードオフ次第 21
ユニオン型を使う嬉しさ (6) • 実現方法の切替をコンポーネントと分離可能 ◦ 例:状態(履歴など)をサーバーに保存して全クライアントで同期したいが、ひと まず暫定的にローカルストレージへ保存して最低限改善する ▪ まずは暫定対応として、ローカルストレージへ保存するカスタムフックを実装 ▪
バックエンドの準備が完了し次第、API 呼び出しによりサーバーへ保存するカ スタムフックを実装 ▪ この前後で、カスタムフックの型シグネチャ(特に成功/失敗を表す戻り値の ユニオン型)が変わらなければ、コンポーネントの実装ではこの切替を意識す る必要がない 22 Webフロントエンド バックエンド まずは暫定的に ローカル保存 バックエンドの準備完了後、 サーバーへ保存 コンポーネント 呼び出しの型シグネチャに変更がなければ 意識せずに切替可能
まとめ • ZEN Study は10周年を迎えることができた 🎉 • 10年の積み重ねを踏まえつつ、次の10年に向けて改善を重ねている • TypeScriptの強力な機能である、判別可能なユニオン型を活用して、データ取
得などの状態(外部への依存)を正確にモデリングすることにより、堅牢でメ ンテナンスしやすくできた • 他にも様々な工夫・改善を行なっています! 23 めでたし めでたし 🤟