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
ypresto
April 23, 2025
Programming
3
2k
状態と共に暮らす:ステートフルへの挑戦
ypresto
April 23, 2025
Tweet
Share
More Decks by ypresto
See All by ypresto
ts-morph実践:型を利用するcodemodのテクニック
ypresto
1
770
Next.jsとNuxtが混在? iframeでなんとかする!
ypresto
3
3.7k
Cancel Next.js Page Navigation: Full Throttle
ypresto
1
3.6k
Next.js のページ遷移を全力で止める
ypresto
15
9.7k
TypeScriptの型とパフォーマンス (TSKaigi 2024)
ypresto
22
8.1k
アクセシビリティとE2Eテスト
ypresto
0
130
VS Codeのプロセスモデルとデバッグ方法 - パフォーマンスと安定性を支えるアーキテクチャ
ypresto
1
520
TypeScriptの型定義をPRする技術
ypresto
1
780
Other Decks in Programming
See All in Programming
rage against annotate_predecessor
junk0612
0
170
CloudflareのChat Agent Starter Kitで簡単!AIチャットボット構築
syumai
2
500
Kiroで始めるAI-DLC
kaonash
2
610
Laravel Boost 超入門
fire_arlo
3
220
もうちょっといいRubyプロファイラを作りたい (2025)
osyoyu
1
450
1から理解するWeb Push
dora1998
7
1.9k
知っているようで知らない"rails new"の世界 / The World of "rails new" You Think You Know but Don't
luccafort
PRO
1
180
@Environment(\.keyPath)那么好我不允许你们不知道! / atEnvironment keyPath is so good and you should know it!
lovee
0
120
ファインディ株式会社におけるMCP活用とサービス開発
starfish719
0
1.9k
Performance for Conversion! 分散トレーシングでボトルネックを 特定せよ
inetand
0
2.4k
意外と簡単!?フロントエンドでパスキー認証を実現する WebAuthn
teamlab
PRO
2
770
パッケージ設計の黒魔術/Kyoto.go#63
lufia
3
440
Featured
See All Featured
Navigating Team Friction
lara
189
15k
How to Think Like a Performance Engineer
csswizardry
26
1.9k
4 Signs Your Business is Dying
shpigford
184
22k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
33
2.4k
Visualization
eitanlees
148
16k
The Power of CSS Pseudo Elements
geoffreycrofte
77
6k
Writing Fast Ruby
sferik
628
62k
GraphQLとの向き合い方2022年版
quramy
49
14k
Raft: Consensus for Rubyists
vanstee
140
7.1k
jQuery: Nuts, Bolts and Bling
dougneiner
64
7.9k
Gamification - CAS2011
davidbonilla
81
5.4k
Art, The Web, and Tiny UX
lynnandtonic
303
21k
Transcript
© LayerX Inc. 状態と共に暮らす:ステートフルへの挑戦 ypresto @ LayerX Frontend Night -
Exploring State (2025/04/20)
© LayerX Inc. 2 ⾃⼰紹介 • LayerX バクラク事業部 ◦ 債務管理チーム
(請求書受取) ◦ ソフトウェアエンジニア ◦ 経理の⽅が利⽤するプロダクトの開発 • 趣味は主に写真とスプラ、⼦どもとおでかけ ypresto (プレスト)
© LayerX Inc. 3 フロントエンド=ステートフル フロントエンドとはステートフル、だからこそ難しい バックエンド ステートレスに設計し、状態は外部に任せる フロントエンド DOM、フォーム、非同期処理など、ステートフルが本体
© LayerX Inc. 4 フロントエンド=ステートフル • ロジックと状態が容易に結合、分解が困難 • 順番‧タイミング問題:setTimeout() •
単体テストが困難、結合テストの肥⼤化 • コンポーネント内がガチャガチャする...! useEffect()祭り!!! 複雑!!! 状態が中⼼に来ることで‧‧
None
© LayerX Inc. 6 状態という複雑さと共に暮らす • すべてのアプリケーションには、 それ以上減らせない複雑性がある • 本質的な複雑さは減らせず、移動しかできない
• 例:UIを簡単にすると、システムのロジックが複雑になる テスラーの複雑性保存則 https://www.nomodes.com/larry-tesler-consulting/complexity-law https://scrapbox.io/koushisa/複雑性保存の法則
Apollo 11 (1969) Crew Dragon Endeavour (2020) 参考: https://blog.btrax.com/jp/space-x-touchscreen https://airandspace.si.edu/collection-media/NASM-NASM2013-02663
https://www.youtube.com/live/H-l6f4wcv2I?feature=shared&t=21153
© LayerX Inc. 8 状態という複雑さと共に暮らす • ユーザー=システム要件を減らす? • システムの中で、 •
本質的でない複雑さが少なくなる場所 • 品質担保が容易な場所 • に移動する! 本質的な複雑さを「どこに移動するか」が⼤事
© LayerX Inc. 9 状態という複雑さと共に暮らす • 状態に対する本質的な操作は2種類! • 状態という複雑さから引き剥がす ステートフルの複雑性
状態 計算された 状態 (値) 変換ロジック イベントハンドラ リアクティブな接続 ⼿続き的な呼出‧変更 外界 (DOMなど) 状態の 参照‧変更 1. 状態から別の状態を計算 2. イベントに応じて 状態を変更
1. 状態から別の状態を計算する
© LayerX Inc. 11 リアクティブとDerived State 状態から状態を計算:Derived State
12 © LayerX Inc. リアクティブとDerived State:本質的でない複雑さの例 状態が変わるイベントハンドラで、 漏れずに呼ばないといけない
© LayerX Inc. 13 リアクティブとDerived State 実際の業務システムで同じこと⾔われたら‧‧
© LayerX Inc. 14 リアクティブとDerived State • イベントハンドラの網羅性やタイミング =本質的でない複雑さを意識しなくて済む •
複雑な関係性は、純粋関数に移動してテストする • 外界の複雑さは、(引数扱いの) hooksに移動する • 状態の組みたてができるのがリアクティブ リアクティブ:状態間の関係を普通のコードで表現 参考: https://zenn.dev/layerx/articles/22dd45dc69a57c
© LayerX Inc. 16 リアクティブとDerived State • 「状態間の関係」の表現に、余計なイベントハンドラが挟まる ◦ 更新漏れやタイミングの⼼配、テスタビリティ...
• よって、useState() を不必要に使⽤しない ◦ または (状態への参照が制限された) hooksに追い出す • 余談:フォームのリセットは、Dialogのライフサイクルに委ねたい useEffect() + 常にsetState() は、99%アンチパターン 状態1 状態2 状態1 useEffect(...) 別の状態変更 状態変更
Reactivity = Derived State with Confidence. リアクティブで 状態間の関係を簡潔‧安全に定義する
© LayerX Inc. 18 状態という複雑さと共に暮らす • 状態に対する本質的な操作は2種類! • 状態という複雑さから引き剥がす ステートフルの複雑性
状態 計算された 状態 (値) 変換ロジック イベントハンドラ リアクティブな接続 ⼿続き的な呼出‧変更 外界 (DOMなど) 状態の 参照‧変更 1. 状態から別の状態を計算 2. イベントに応じて 状態を変更
2. イベントに応じて状態を変更する
onChange={e => setState(e.target.value)}
制作‧著作:LayerX 終
© LayerX Inc. 22 Event const onChangeUserId = (userId) =>
{ setUserId(userId) setGroupId(users.find(u => u.id = userId)?.groups[0]?.id) # グループを初期値に設定する // 他のフィールドたちの書き換えもここに } 「便利」を実現するほど、複雑化するイベントハンドラ テスタビリティを諦めない..!
© LayerX Inc. 23 • みんな⼤好き (?) Reducer • nextState
= f(state, action) const reducer = action => { switch (action.payload.type) { case "setUser": return { userId: action.payload.userId, groupId: null } ... } • 「状態の変更」に純粋関数を強制するパターン ◦ 複数の (計算されない) 状態を同時に変えたい‧複雑なときに使いましょう イベントハンドラを純粋関数で表現する
24 © LayerX Inc. わたしたちのアプリケーションにて。 「旅費交通費」に合わせて 税区分を⾃動設定したい! 「旅費交通費」の デフォルトの税区分設定 外貨のときの
「不課税」税区分設定 適格の経過措置税区分の 対応関係設定 借⽅の勘定科⽬ 請求書の通貨 適格請求書? 借⽅の税区分 get get get set set get しかも税区分変わったら、 ほかも変えたい!!
Death. ⼿続き的な 状態操作祭り
© LayerX Inc. 26 Event • フォームへの「変更内容」を計算して返す純粋関数 ◦ transform() •
現在の状態や、1つまえのtransform()が返したdiffを引数で受ける ◦ apply(transform(transform(transform({ 借⽅勘定科⽬: 新しい値 }))) • 設定は、transformを作るときに引数として受ける • 分解でき、テストでき、いくつでも組み合わせられる • ASTの変換 (transformer) や、Goのhttp Middewareから着想 • reducerのような既存パターンに囚われず、アプリケーションの特性にあった設計を! ⽬的は純粋関数で表現することです! どう解決したか
Design Functional parts for your application. アプリケーションにあわせて、 ⼩さな純粋関数を組み合わせられるような パターンを発明する
© LayerX Inc. 28 • リアクティブを活⽤し、状態間の関係を意識して、分解して組み⽴てる • アプリケーションにあった状態変更ロジックの設計をし、⼿続き的な変更操作を減らす • 純粋関数に切り出せば、「複雑な部分」がテスタブルになる
• 余分な複雑さを減らし、複雑さを移動して、状態と上⼿に付き合っていきましょう..! まとめ
© LayerX Inc. 29 フロントエンド=ステートフル • 純粋関数で書かれた部分はテストしやすい https://www.destroyallsoftware.com/talks/boundaries • 外界に結合しない部分をぶ厚く中⼼に。そうでない殻の部分を薄く外に。
Functional Core, Imperative Shell