2024.10.21
お互い疑心暗鬼になりがちな、経営企画と事業部の壁 組織に「分断」が生まれる要因と打開策
リンクをコピー
記事をブックマーク
加藤潤一氏(以下、加藤):「なぜEvent Sourcingなのか」という話で、Event Sourcingの場合はどうなっているかというと、CRUDのステートソーシングは、最新のエンティティを上書きする考え方です。Event Sourcingは、そのとき発生した変更を追記していく考え方になります。
「状態はどういうふうに作るの?」という話ですが、イベントから状態を導出する考え方です。関数にイベントをapplyしていくと、そのときの状態に対してイベントをapplyするかたちになるので、どんどん状態を作って更新していける。すべてのイベントがapplyされると最新状態になるような考え方です。
そのイベントの必要性はコマンドとクエリが分離されていますが、結果的に統合しないといけないので、イベントが使わるような話です。
“イベント”と言っているものは、もともとはDDDのドメインイベントという考え方からきていて、イベントそのものは過去に起きたできごと、ドメイン上のイベントを意味します。一般的には動詞の過去形で表現され、イベントからコマンドを想起可能です。例えば「貨物の出荷みたいなものだと、過去形を現在形に直せばだいたい想起可能ですよね」みたいな話があります。
コマンドとイベントは似ています。コマンドもアクターみたいなものに投げられて、そこでコマンドが拒否されることがあります。アクターの中で、このコマンドは受理できるとなった場合に、拒否されずに受理されると、状態が変わってイベントが生成されます。そのイベントはEvent Sourcingだとディスクとかに保存されます。そのため、コマンドは拒否されるかもしれませんが、イベントはすでに起こったことを示します。
なぜイベントを使うかは簡単で、コマンド側からクエリ側に変更を伝搬させないとインテグレーションできないからです。一番わかりやすい方法としては「ポーリングしたらええやん」という話がありますが、変更がないときもポーリングで負荷をかけてしまうので、ポーリングは絶対スケールしません。
同時接続数が増えて、ポーリング自体も増えると、なにもタスクがないのにコマンド側に負荷をかけている。相手側のポーリング先に負荷をかけてしまうので、スケールしないと言われています。そのためどうするかというと、イベントをPub/Subする。「コマンド側からクエリ側を呼び出すので、クエリ側はなにもしないてもいいよ」「待っててね」という話です。
こういった考え方は、連携する方法としては「Event Sourcingを使うといいよ」みたいものがありますが、ほかにもCDCとOutboxを使うパターンがあります。今日は紹介しませんが、興味があったら検索してみてください。結局はEvent Sourcingとほとんど同じになっちゃいます。
僕のブログにも書きましたが、Event Sourcing以外に現実的な選択肢はない感じです。そのため、CQRSやるということは、ほぼEvent Sourcingをやることになります。
利点と欠点です。、先ほども話しましたが、イベントは更新されず追記のみなので、ロックが不要です。ロックはどこかでトランザクション管理みたいなものをやらないと、不正なイベントが追加されたりしたらまずいと思います。例えば、create したあとにupdateがこないといけないのに、updateが先にきてcreateがきちゃうようなイベントの並びは許容できないと思います。Akkaの場合は、アクターがそれを管理します。
そういった問題はありますが、それをクリアしたあとのイベントの保存、永続化という部分でいうと、ロックが不要で追記のみになるので、スケーラビリティを確保しやすいです。
特定の時点のReadModelをイベントから導出できます。先ほど言ったような考え方で、いつでもReadModelを、その時点のReadModelを取り出せます。
ドメインイベントがあればReadModelの設計はいつでもやり直せます。イベントを絶対消してしまうことはできませんが、ReadModelの設計をミスしてしまったのであれば、もちろん再構築コストはかかりますが、いつでもイベントからReadModelの新しい設計に基づいて作り直すことはできます。
こういったイベントが監査ログや行動履歴の分析に利用しやすい副次的な効果もあります。ただし、大量のイベントから状態をリプレイする際に時間がかかってしまうことはあるので、Akkaではアクターの最新状態をスナップショットとして保存する機能があります。
スナップショットに加え、それ以降の差分イベントでリプレイ時間を短縮できる機能が備わっています。原則的にすべてのイベントをストレージに保存する必要があるところが、抵抗を感じるところです。
一応、スナップショット保存時に古いイベントを消すこともできます。本当にそれを消しても大丈夫かは、ビジネス的な観点で考える必要はありますが、技術的には古いイベントを消すことは可能です。
やっと新アーキテクチャの話です。リアクティブシステムとCQRSを反映したアーキテクチャを考えています。これは検証環境で開発中のもののアーキテクチャ図です。一番左側にAkka-Clusterがあり、Write APIという枠があると思いますが、これがそのコマンドサイドです。
コマンドサイドとクエリサイド、ちょうどその真ん中より右のRMU(Read Model Updater)で境界が切れていて。左側のWrite API、Message BusまでがWrite APIのチームで、右側のRMUとRead APIとClientがクライアントサイドのチームというかたち。今の実際のチームはクライアントサイドのチームがRead APIも開発する構成になっています。
コマンドサイドはドメインロジックを実行してドメイン状態を変える機能のみを提供します。例えば、でメッセージ投稿やタイトルの変更はChatworkのルームなどのWrite API側で受けます。真ん中にRoomAggregateActorがいますが、PostMessageみたいものを受け取ると、Write API側からこのRoomAggregateActorにPostMessageというメッセージが届きます。
このアクターは軽量プロセスなので、起動している状態になっています。そのメッセージが届いたら、起動している状態に対してメッセージがきて、ロジックが反応します。ステートはオンメモリでもっているので、PostMessageというコマンドが受理されたら、MessagePostedというイベントがJournal DBに保存されます。
今のところDynamoDBでやっていますが、DynamoDBの場合だと、DynamoDB Streamsなどを使って、Message BusというStreamを流す中間のメッセージのバスみたいなものがあって。Kafkaを使っていますが、KafkaからRMUにメッセージをconsumeして、ReadModelを構築します。メッセージのDTOなどをメッセージDBから取り出して、Read APIがクライアントからの要求に応じて結果を返すようなことをやっています。
このアクターが起動している状態のなにがうれしいのか。1つ特徴的なものが、Journal DBはイベントがどんどん蓄積されていきますが、データベースの状態とRoomAggregateActorの状態は完全に同期されている状態なので、Postであれはあまり関係ありませんが、UpdateMessageなどだと、既存のエンティティを取得して、それに対して状態を変えて、新しい状態をDBに保存し直すみたいなことがよく起きます。
最初にReadが発生して、そのエンティティの状態を変えてもう1回アップデートし直すようなことをよくやると思いますが、Akkaの場合はデータベースと状態が完全に同期されているので、最初の読み込みがなくなります。
そのため、コマンドを受信したらビジネスロジックをそのまま実行して、変わった状態はEvent Sourcingなので保存しない。アクターがオンメモリでもっているのが正しい状態なので、データベースはイベントを保存するだけです。
真の状態というのはアクターがもっていて、データベースはただのバックアップという扱いです。メモリでドメインの状態がすぐ手元にあるからこそ、ビジネスロジックが書きやすかったり、設計しやすかったりする特徴があります。そういった利点を活かして、ドメインモデルを作って実装していけるのは1つ魅力的なところです。今考えているものは、ざっくりこういう考え方に基づいています。
先ほども話がありましたが、本日紹介した技術はアメリカとかだと「キャズムを超えてる」みたいな、「なんだと?」みたいな話があって。弊社で使っている技術を囲ってみました。「この技術を使ったからどうだ」という話でもないんですが、トレンド的に「なんか日本とアメリカでは、だいぶギャップがあるな」みたいな話はあります。
日本語の書籍が出ないと、みんな手を動かさないようなところがあるのかもしれませんが、書籍が5年・10年遅れたりはよくあることなので、日本でも事例の1つになっていければいいかなと思っています。
リアクティブシステムを目指すには、それなりに複雑な仕組みが必要になってきます。もちろん高い技術力も求められます。全体が複雑になりすぎないように気をつけることもしないといけないので、濃淡つけていけるように、というところで四苦八苦しながらやっているところですね。
あと、技術の話ばかりをしましたが、技術的な話だけではなくて。いきなりマイクロサービスでわかってないのに最初から分けて始めるのではなく、はじめは分けやすいように1つから始めて、事業やビジネスやユーザーのことをわかっていきながら分けていくみたいことが好ましいと思っていて。
そういった部分で、組織的な問題もあると思っています。こういったことは組織戦略の問題と合わせて考えていかないといけないので、まだまだやることはけっこういっぱいあるなという印象です。
事業的にも、技術的にも成長の余地がけっこうあるので、プロダクトをともに支えてくれるエンジニアを募集中です。仕事はいろいろあるので、なにかあれば気軽に相談ください。
今日はありがとうございましたということで、ご清聴ありがとうございました。
司会者:ありがとうございました。Twitterからもいくつか感想などをもらっているので、私からちょっとだけピックアップしたいと思っています。
司会者:「メッセージパッシング、非同期、失敗を受け入れる……。Bulkheadingの考え方という最近のソフトウェアの思想が、どんどんErlangの思想に近くなってますね」というコメントが、私としてもすごく印象的だなと思っていて。
私は個人的にこの手のプログラミングを温故知新で勉強したいなと思って、最近『すごいErlangゆかいに学ぼう! 』とかを買っているので、このあたりを読んでいるとね。
加藤:そうなんですよね。Erlangの仕様とか見るとけっこうびっくりしますが、そういった昔から可用性を考えて言語とかを設計すると、こういうふうになるのかなって。そういう意味では、本当に学ぶべきところはあると思います。
司会者:そうですね。コロナ禍でなかなか家の外に出られないと思いますが、こういう本などをぜひ読んで時間を過ごしてもらえるといいのかな、なんて思っています。
関連タグ:
2024.11.13
週3日働いて年収2,000万稼ぐ元印刷屋のおじさん 好きなことだけして楽に稼ぐ3つのパターン
2024.11.21
40代〜50代の管理職が「部下を承認する」のに苦戦するわけ 職場での「傷つき」をこじらせた世代に必要なこと
2024.11.20
成果が目立つ「攻めのタイプ」ばかり採用しがちな職場 「優秀な人材」を求める人がスルーしているもの
2024.11.20
「元エースの管理職」が若手営業を育てる時に陥りがちな罠 順調なチーム・苦戦するチームの違いから見る、育成のポイント
2024.11.11
自分の「本質的な才能」が見つかる一番簡単な質問 他者から「すごい」と思われても意外と気づかないのが才能
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
2024.11.18
20名の会社でGoogleの採用を真似するのはもったいない 人手不足の時代における「脱能力主義」のヒント
2024.11.19
がんばっているのに伸び悩む営業・成果を出す営業の違い 『無敗営業』著者が教える、つい陥りがちな「思い込み」の罠
2024.11.13
“退職者が出た時の会社の対応”を従業員は見ている 離職防止策の前に見つめ直したい、部下との向き合い方
2024.11.15
好きなことで起業、赤字を膨らませても引くに引けない理由 倒産リスクが一気に高まる、起業でありがちな失敗