最近、システムの話で「イベント駆動」がよく出てくるけど、なんとなく難しそうって感じたことない?🤔わたしも最初は「イベントって何?どうしてそんなに面倒なの?」って感じで、かなり混乱したんだよね💭
今回はそんなイベント駆動システムがなぜ難しいのかを、気軽におしゃべりするみたいにまとめてみたよ🫶
イベント駆動システムってそもそも何?
ざっくりいうと、「何かが起きた(=イベント)」をきっかけに動く仕組みのこと✨
たとえば、スマホの通知が来たら画面が変わったり、チャットアプリでメッセージが届いたらポップアップが出たりするイメージだね📱
これ、便利だしリアルタイム性バッチリだけど、実は中の仕組みを作るのがすごくむずかしいんだよ💦
難しいポイント①:見えない動きが多すぎる
普通のプログラムは順番に処理が進むけど、イベント駆動は「これが来たら次はあれをする」みたいにめちゃくちゃバラバラに動いてる感じ😳
だから、どこで何が起こってるのか追いにくいし、予想外の順番で動いたりしてバグも起きやすいんだ💭
難しいポイント②:状態管理がカオスになりやすい
イベントがどんどん起こるから、システムの状態(今どんな状況か)をちゃんと把握しておくのが超重要なのに、これがなかなかむずかしいのよね🥺
状態の管理がズレると、データが変になったり、動きがおかしくなったりしちゃう⚠️
難しいポイント③:デバッグがつらい
バグ見つけても、「どのイベントが原因?」って特定するのが一苦労💦
イベント同士が複雑に絡み合ってるから、原因の追跡が迷路みたいになることもしょっちゅう😵💫
でも、イベント駆動がよく使われる理由って?
それでもイベント駆動は、リアルタイム処理やユーザー操作にピッタリだし、システムの柔軟性を高められるから人気✨
すぐ反応できるし、処理を分散できるから、規模が大きいサービスには欠かせないんだよね👍
まとめると、
- イベントがどんどん来てバラバラに動くから追いにくい
- 状態管理が複雑化してミスが起きやすい
- バグの原因を探すのがめっちゃ大変
って感じで、初心者にはほんと手強いシステムだったりする💭
ゆっくり慣れていくしかないけど、ひとつひとつ理解できると「なるほどね~!」ってなってくるから、あきらめずに挑戦してみてね🌸✨
コメント
ハンナ
難しくはないけど、性能と同じように複雑さも増すし、性能問題の解決策としては過大評価されてると思う。
グレース
イベント駆動はシンプルさを犠牲にして性能を得るもので、一貫性が強い仕組みで「無料」で得られるものを捨てたり再構築する必要がある。
クリス
人はイベント駆動の良い性能だけ見て、一貫性を犠牲にするコストを軽く見がちだけど、それはめちゃくちゃ高くなるし分散だともっと厳しい。
ロバート
記事の例の相関IDは、一貫性が強い時に簡単に得られるスタックトレースの利点を再現しようとしている。
ロバート
相関IDを実装するのは簡単でも、それを一つのツリー状の表示にまとめるのはかなり難しいし、一貫性が強ければ親子関係の特定はほぼコストゼロ。
ハンナ
つまりトレードオフで、コストが見えにくいからこの手法は盛りすぎだと思う。 よく考えずに始めて後で痛い目を見るパターン。
グレース
イベント駆動は、イベントタイプ×キューの組み合わせが少ない時が一番うまくいくと思う。
クロエ
UIフレームワークの単一イベントキューが良い例で、イベントの種類が多すぎなければ性能もモデルもシンプル。
グレース
もしイベントやキューが多いなら、状態遷移図でイベントの発生元を限定すれば複雑さを抑えられる。
ハンナ
要は、イベントやキューがドメインごとに分かれていれば全体の複雑さは抑えられるけど、結合が増えると一気に爆発する。
クリス
やっぱりトレードオフで、性能の万能薬じゃないから将来までコストを抑えられる自信がある場合だけ使うべき。
リリー
余談だけど、非ネイティブの自分でもタイトルの質問文が変なのがすごく気になる。 「Why are event-driven systems hard?」か「Why event-driven systems are hard」じゃなきゃダメだよ。
サム
イベントの発見が一番の課題で、自動的にどんなイベントを出して何を受けるかを記録するいい方法がまだ見つかってない。 手作業のドキュメントはすぐ古くなる。
クリス
これらはイベント駆動だけの問題じゃなくて、マイクロサービスも同じでAPI破壊やデバッグの難しさ、リトライ失敗も共通で対処法も変わらない。
ロバート
処理とアクションを切り離したいならイベント駆動やマイクロサービスを使う意味がある。
ジョージ
イベント駆動は特別じゃないよ。
ハンナ
ワークフローや分散サガは難しいけどね。
ジャック
文法どうすればいいの?
マックス
全てのシステムはイベント駆動で、OSの内部ではハードウェアとのメッセージのやりとりがそれだよ。
リリー
その上に意味的な関係を持つ抽象化を重ねて、大半は複雑さを隠してる。 TCPの手順とか気にしなくていいのはそのため。
ノーラン
ただ低レベル制御が必要なニッチなケースもあり、そういう時は抽象を破って新たな抽象を作るべき。
ハンナ
多くの人はイベントから始めて上位抽象を作らずにぐちゃぐちゃにしてしまう。 イベント駆動=無設計の言い換えの場合も多い。
クリス
この記事は細かい問題に囚われて、本質を見失ってる。 こういう問題はどんな分散システムにもあって、抽象化で解決されるもの。
キンバリー
Qtのsignalsとslotsはこの記事の問題を多く解決してて、C++やPythonで型の不一致はコンパイルエラーにしてる。
ベン
JSでこんな仕組み使ってるフレームワークがあれば知りたいな。
エマ
なんでこれが違うの?
ロバート
今の職場はJava6時代にHTTPタイムアウトや非同期HTTPが弱かったからキューを使い始めた。
ミア
うちはSNSとGraphQLサブスクリプションでサービスごとにメッセージ受信を設定してて、API変更時に影響範囲がすぐわかる。 5年問題なし。
クリス
ちゃんと状態遷移図を作ればイベント駆動も難しくないよ。 何度もやってる。
グレース
イベント≠メッセージキューだよ。
ジョージ
イベント駆動をRabbitMQがあるからって言うのは間違い。 TCPもパイプもソケットも非同期メッセージシステムで、イベントはメッセージの解釈方法にすぎない。
グレース
スキーマのバージョン管理もイベント特有じゃない。 フィールド追加や削除はAPIの進化だ。
クリス
gRPCやREST、protobuf、JSON APIも同じ問題を抱えてる。 一般的な分散システムの問題を「イベント駆動は難しい」と言ってごまかしてるだけ。
ロバート
監視やデバッグも特別じゃない。 相関IDはRPCトレースにもあるし、呼び出しの連鎖と分割イベントの違いはファンアウトシステムのトレースの話。
クリス
これはイベントの問題じゃなくて分散システム全般の問題。
クリス
失敗、リトライ、DLQもキューの基本機能で、イベントでもジョブでもリクエストでも同じ。
クリス
冪等性も同様で、リトライするRPC呼び出しは冪等でなければならない。 これもネットワークの話。
リリー
最終的整合性もイベント駆動だけの話じゃなく、複数のデータコピーがある全てのシステムが抱える問題。 イベント駆動特有のコストじゃなく分散のコストだ。
グレース
イベントでは後方互換のスキーマ更新だけでなく、複数ストリームを維持してAPIの複数バージョンを同時にサポートすることで、移行期間中も対応できるよ。