Slide 1

Slide 1 text

入門『状態』 補遺編 Kaigi on Rails 2026 過去登壇勉強会 2026/10/05 しんくう@shinkufencer

Slide 2

Slide 2 text

Who? しんくう / shinkufencer @shinkufencer コード日進月歩 https://shinkufencer.hateblo.jp/ 2

Slide 3

Slide 3 text

本日しゃべること ● 2024年に話をした”入門『状態』” でカットした部分に 「状態の変化」についてのお話をします ● 当時は台頭していなかったCoding Agentに関しても少し触れ ます 3

Slide 4

Slide 4 text

“入門『状態』”のおさらい 4

Slide 5

Slide 5 text

前回のおさらい ● ● 状態が増えると考慮すべきことが増える 状態の変化が多いと、最終的な状態を追うのが難しくなる 5

Slide 6

Slide 6 text

前回のおさらい、を踏まえて ● ● ● 状態は極力持たないほうがいい話までが前回 状態の複雑化を抑える観点でもう一つ注目したいのは「状態の変化」 今回は何を考えておくと複雑になりにくいかを話していきます 6

Slide 7

Slide 7 text

そもそも「状態の変化」とは 7

Slide 8

Slide 8 text

電球で考える「状態の変化」 ● ● 状態の変化は何かの操作によって起きる 電球の場合は「電源のON」「電源のOFF」という操作で変化する 電源ON 消灯 電源OFF 点灯 消灯 8

Slide 9

Slide 9 text

電球で考える「状態の変化」 ● ● 既に点灯している場合に「電源ON」をしても状態は変化しない 状態の変化は、操作と操作前の状態によって決定づけられる 電源ON 点灯 点灯 9

Slide 10

Slide 10 text

「状態の変化」が つらくなるシーンとは何か 10

Slide 11

Slide 11 text

「状態の変化」がつらくなるシーンは何か つらくなる場面の例として、電球クラスとして以下の操作を実装してみます。 ● ● ● ● 電球はONとOFFができる 電球は明るさの調整ができ、明るさのアップとダウンができる 明るさは0〜100で設定できるが、明るさの変更は10刻み 明るさの調整はONのときのみ可能 11

Slide 12

Slide 12 text

素直にコードを書くと以下のようになる class LightBulb def initialize @is_on = false @brightness = 0 end def turn_on return if @is_on @is_on = true @brightness = 50 end def brightness_up return unless @is_on @brightness = [@brightness + 10, 100].min end def brightness_down return unless @is_on @brightness = [@brightness - 10, 0].max end end def turn_off return unless @is_on @is_on = false @brightness = 0 end 12

Slide 13

Slide 13 text

素直に書いたコードの課題感 ● ● ● ● 例示のようなコードにすると各メソッドに状態変化のルールが散らばる どの状態からどう変化するのかを把握しようとすると複数のメソッドを横 断して読む必要がある そのため新しい操作が加わると既存の操作との整合性を考える必要がある 実際に新しい操作を追加してみる 13

Slide 14

Slide 14 text

新たな操作を増やす ● ● 新しく「現在ONならOFFに、OFFならONにする」操作を増やす シンプルに額面通り実装すると以下のようになる def toggle @is_on = !@is_on end ● 良さそう 14

Slide 15

Slide 15 text

新たな操作を増やす ● ● 新しく「現在ONならOFFに、OFFならONにする」操作を増やす シンプルに額面通り実装すると以下のようになる def toggle @is_on = !@is_on end ● 良さそう...に見えるが、turn_onの実装と比較すると明るさの処理がない ので既存の状態変化と整合しない def turn_on return if @is_on @is_on = true @brightness = 50 end OFFからONになるときに 明るさを50に設定する 15

Slide 16

Slide 16 text

新たな操作を増やす ● turn_onやturn_offの振る舞いを踏まえると、以下のような実装になる def toggle if @is_on @is_on = false @brightness = 0 else @is_on = true @brightness = 50 end end ● ● 既存の振る舞いにあわせ 値の代入処理を追加 このように新しい状態変化の操作を増やしたときに他の変化との整合性を とる必要があるが、見落としが起こりうる 状態の変化を見渡しやすく、管理しやすくするにはどうすると良いか? 16

Slide 17

Slide 17 text

「状態の変化」を 管理しやすくする考え方 17

Slide 18

Slide 18 text

「状態の変化」を管理しやすくするには ● ● これまでの方法は「操作時にどのように書き換えるか」という考え方だっ たが、切り口を変える 「状態の変化」は、変化をもたらす操作と操作前の状態によって決まるの で、その考えを基軸に整理する 18

Slide 19

Slide 19 text

「状態の変化」を管理しやすくするには ● ● 電球の場合は「消灯」の場合に「電源ON」をすると「点灯」に変化する さきほどの考え方に当てはめると以下のようになる 電源ON 消灯 操作前の 状態 点灯 操作 操作後の 状態 19

Slide 20

Slide 20 text

「状態の変化」を管理しやすくするには ● この考え方をコードで表現すると以下のようになる def transition(state, action) # 操作前の状態(state)と操作(action)から # 操作後の状態を返却する end next_state = transition(state, :toggle) ● 電球の場合はON/OFFと明るさの組み合わせが状態なので、ひとまとまり の state として扱う 20

Slide 21

Slide 21 text

状態を取り扱うためのクラスを用意する class LightingSetting attr_reader :is_on, :brightness def initialize(is_on:, brightness:) @is_on = is_on @brightness = brightness freeze end end ON/OFFと明るさを 一まとまりの値として保持する 21

Slide 22

Slide 22 text

transitionのコード def transition(state, action) case [state.is_on, action] when [false, :turn_on] LightingSetting.new(is_on: true, brightness: 50) when [true, :turn_off] LightingSetting.new(is_on: false, brightness: 0) when [false, :toggle] LightingSetting.new(is_on: true, brightness: 50) when [true, :toggle] LightingSetting.new(is_on: false, brightness: 0) when [true, :brightness_up] next_brightness = [state.brightness + 10, 100].min LightingSetting.new(is_on: true, brightness: next_brightness) when [true, :brightness_down] next_brightness = [state.brightness - 10, 0].max LightingSetting.new(is_on: true, brightness: next_brightness) when [true, :turn_on], [false, :turn_off], [false, :brightness_up], [false, :brightness_down] state else raise ArgumentError, "unsupported transition" end end 22

Slide 23

Slide 23 text

transitionのコード def transition(state, action) case [state.is_on, action] when [false, :turn_on] LightingSetting.new(is_on: true, brightness: 50) 「操作前の状態」と「操作」 で 「操作後の状態」が導き出される when [true, :turn_off] LightingSetting.new(is_on: false, brightness: 0) when [false, :toggle] LightingSetting.new(is_on: true, brightness: 50) when [true, :toggle] LightingSetting.new(is_on: false, brightness: 0) when [true, :brightness_up] next_brightness = [state.brightness + 10, 100].min LightingSetting.new(is_on: true, brightness: next_brightness) when [true, :brightness_down] next_brightness = [state.brightness - 10, 0].max LightingSetting.new(is_on: true, brightness: next_brightness) when [true, :turn_on], [false, :turn_off], [false, :brightness_up], [false, :brightness_down] state else raise ArgumentError, "unsupported transition" end end 23

Slide 24

Slide 24 text

transitionのコード def transition(state, action) case [state.is_on, action] when [false, :turn_on] LightingSetting.new(is_on: true, brightness: 50) when [true, :turn_off] LightingSetting.new(is_on: false, brightness: 0) when [false, :toggle] LightingSetting.new(is_on: true, brightness: 50) 考慮した結果として変化がない場合と そもそも考慮していないことが 区別しやすくなる when [true, :toggle] LightingSetting.new(is_on: false, brightness: 0) when [true, :brightness_up] next_brightness = [state.brightness + 10, 100].min LightingSetting.new(is_on: true, brightness: next_brightness) when [true, :brightness_down] next_brightness = [state.brightness - 10, 0].max LightingSetting.new(is_on: true, brightness: next_brightness) when [true, :turn_on], [false, :turn_off], [false, :brightness_up], [false, :brightness_down] state else raise ArgumentError, "unsupported transition" end end 24

Slide 25

Slide 25 text

LightBulbクラスのインターフェイスはそのままで class LightBulb def initialize @setting = LightingSetting.new(is_on: false, brightness: 0) end def turn_on @setting = transition(@setting, :turn_on) end def brightness_up @setting = transition(@setting, :brightness_up) end def toggle @setting = transition(@setting, :toggle) end private def transition(state, action) #略 end end 25

Slide 26

Slide 26 text

操作と操作前の状態から導く形式にすると何が嬉しい? ● ● 状態の変化に関して「操作と操作前の状態で見る」というルールができる ので、整理がしやすくなる 新しい操作を追加するときにどの状態と組み合わせを考慮したかが確認し やすくなる 「純粋関数ライクに書くことでテストを書きやすくなる」 「状態ルールを増やしたいときにクラスに切り出して整理ができる」など 副次的な効果もありますがその話も今回は割愛 26

Slide 27

Slide 27 text

でもCoding Agentが実装はしてくれるので... ● ● ここまで実装に関しての具体案を説明しましたが、昨今は人間がコードを 書かなくなった 実装そのものをしなくなったのであれば、人間が状態変化を理解できるよ うな書き方をしなくてもいいのではないか? 27

Slide 28

Slide 28 text

Coding Agentと状態変化 28

Slide 29

Slide 29 text

局所的な変更が積み重なることの懸念 ● ● ● Coding Agentは、与えられた要求に対して局所的な変更を素早く積み重 ねられる 個々の変更は、その要求だけを見れば妥当なものになりやすい 状態変化の観点では、局所的には妥当な変更でも、積み重なると全体との 整合性を見落とす可能性がある 29

Slide 30

Slide 30 text

局所的な変更が積み重なることの懸念 消灯前の明るさを覚えて、次に点灯するときに戻したい! OK、明るさを覚えるようにしたよ! 明るさが0になったら、自動的にOFFにしたい! OK、0になったらOFFで実装したよ! 30

Slide 31

Slide 31 text

局所的な変更が積み重なることの懸念 明るさが0になって自動でOFFになったあと 次にONにしたら明るさはいくつになるんですか? あれ、どういう動きになってたっけ? え、把握してないの!? 個々の要求どおり動いていたので! 状態変化全体までは把握してないです! 31

Slide 32

Slide 32 text

局所的な変更を状態変化全体と照らし合わせる ● ● ● ● 個々の要求を正しく理解していても、要求同士の相互作用を俯瞰できない と見落としが起きやすい Coding Agentに実装を任せる範囲が広がっても、システムがどう状態変 化するかは把握しておきたい そのために、状態変化を「操作」と「操作前の状態」という共通の観点で 整理しておくと、全体を把握しやすい 実装の詳細を逐一追わなくても、どの状態でどの操作がどう振る舞うかを 把握しておけば、要求同士の整合性を確認しやすい 状態変化を、人が理解・確認しやすい形にしておくことは引き続き重要 32

Slide 33

Slide 33 text

まとめ ● 「状態の変化」は、操作前の状態と操作から操作後の状態を 導くものとして捉える ● 状態変化を同じ観点で整理し、どの組み合わせを考慮したか を確認しやすくなる ● Coding Agentに実装を任せる範囲が広がっても、状態変化を 理解・確認しやすい形にしておく 33

Slide 34

Slide 34 text

Thanks! 参考資料: 状態論 (1) | Marginalia https://blog.lacolaco.net/posts/theory-of-state-01/ 負債のメタファと2026年 / Debt Metaphor in Agentic Engineering Age 202609 Edition https://speakerdeck.com/twada/debt-metaphor-in-agentic-engineering-age-202609-edition しんくう / shinkufencer a.k.a ikuo.takada @shinkufencer コード日進月歩 https://shinkufencer.hateblo.jp/ 34