「WPFおじさん」が海外で生き残るためにKafkaを学んだ話:イベントソーシングは、コードより「文化の壁」をハックする思考法だった

「その仕様、いつ誰が決めた?」— 海外チームで僕らが失い続ける「文脈(コンテキスト)」と、イベントソーシングの出会い

記事本文(起)

どうも、皆さん。ヨーロッパの片隅で、今日も元気にC#とWPFの「レガシーコード」と格闘しています、現役ITエンジニアです。

日本から海を渡って、かれこれ数年。僕の主戦場は、金融系や製造業向けの、ガチガチのエンタープライズ向けデスクトップアプリ開発。そう、何を隠そう「WPFおじさん」です。XAMLをこねくり回し、MVVMパターンで「ああでもない、こうでもない」と、ピクセル単位のUI調整と、複雑怪奇な業務ロジックの狭間で生きています。

さて、そんな僕が、なぜ今日「イベントソーシング(Event Sourcing)」なんていう、キラキラした(?)モダンなテーマで筆を執っているのか。

「イベントソーシング? ああ、Kafkaとか使ってマイクロサービス間でやるアレでしょ?」「Web系の大規模トランザクションの話だよね?」「WPF? デスクトップ? まだ生きてたんだ(笑)」

…うん、分かります。そのツッコミ、痛いほど分かります。

数年前まで、僕もそう思っていました。イベントソーシングなんて、僕らのような「クライアントサイド開発者」ましてや「レガシー(と呼ばれがちな)技術」を扱うエンジニアには、無縁の世界だ、と。

僕らの世界は、常に「最新の状態でよろしく」です。データベース(DB)にある「現在の顧客情報(Current State)」が正義。ユーザーが「保存」ボタンを押したら、DBのテーブルをUPDATEする。それで完了。シンプルですよね?

この「状態(State)」ベースの考え方は、日本の開発現場では非常に強力でした。仕様書は(ある程度)きっちり存在し、要件定義も(ある程度)明確。「なぜこのデータがこうなっているのか?」という疑問は、大抵の場合、仕様書を読み込むか、隣の席のシニアエンジニアに聞けば解決しました。


しかし、海外(グローバルチーム)は違った。

僕がこのブログで伝えたい「人生術」の核心がここにあります。海外でエンジニアとして働くことの本当の難しさは、言語(英語)でも、技術スタックの違いでもありません。

それは、**「文脈(コンテキスト)の圧倒的欠如」**との戦いです。

僕のチームは、僕(日本人)がいるヨーロッパの拠点の他に、アメリカ(US)の開発チーム、インド(IN)のQAチーム、そして本国(EUの別拠点)のビジネスアナリスト(BA)で構成されています。

時差は当たり前。コミュニケーションは基本チャットと週一の定例。

ある日、こんなことがありました。

僕が担当していたWPFアプリケーションで、ある重要な顧客データの入力ロジックを変更するタスクが降ってきました。理由は「USチームが新しく作るWebポータル側で、そのデータが必要になったから」とのこと。

僕はチャットでUSチームの担当者とやり取りし、言われた通りにロジックを修正し、デプロイしました。

その2週間後、大問題が発生しました。

「おい、日本のTaro(仮名)! お前が直したせいで、EU側のレポーティング(帳票)システムが全部コケてるぞ!」

インドのQAチームから、深夜に叩き起こされました。

慌てて調べると、僕が「USのWebポータル向け」に修正したデータの持ち方が、古くからある「EUの帳票システム」が想定していた形式と異なっていたのです。

僕は叫びました。「だって、USチームはこれでいいって言ったんだ!」「EUの帳票のことなんて、俺のチケット(Jira)には一言も書いてなかったぞ!」

USチームの担当者に「なぜ帳票の件を言わなかったんだ?」と詰め寄ると、彼はこう言いました。

「ああ、ごめん。その帳票システムのこと、僕知らなかったんだ。僕は先月ジョインしたばかりで。

…これが、グローバルチームの日常です。

メンバーの入れ替わりは激しく、ドキュメントは常に古い。仕様の「歴史」や「背景」を知る古老は存在せず、全員が「今、目の前にあるチケット」だけを見て作業している。

僕らは、「なぜ、このデータは今、この状態なのか?」という**「歴史=文脈」**を、日々、猛烈な勢いで失い続けているのです。

「現在の状態(State)」だけを上書き(UPDATE)し続ける従来のDB設計では、この「失われた文脈」を追う術がありません。ログを漁っても、分かるのは「誰が」UPDATEしたかだけ。「なぜ」そのUPDATEが必要だったのか、その変更が「他の誰」に影響するのかは、DBのどこにも記録されていないのです。

「もう限界だ」

そう思った時、僕はとあるカンファレンスのセッションで、Web系エンジニアが当たり前のように語る「イベントソーシング」の概念図(Event Store, Aggregates, Projections)と再会しました。

以前は「Web系の流行り」としか思えなかったその図が、その日の僕には違って見えました。

「全ての変更を『イベント(出来事)』として『記録(Store)』する?」

「『状態』は、その『イベントの歴史』を積み重ねた結果(Projection)として導出する?」

…待てよ。

これって、僕が今、このチームで失って絶望している「文脈(コンテキスト)」そのものを、システム設計のレベルで担保しようとするアーキテクチャじゃないか?

もし、あの時。「USチームがWeb対応のため項目Aを追加した(Event: UsWebSpecificationAdded)」という「出来事」と、「EU帳票チームが項目Aをブランクとして扱っていた(Event: EuReportSpecificationDefined)」という「出来事」が、時系列で「記録」されていたら?

もし、僕のWPFアプリが「現在の状態」だけを見るのではなく、その「イベントの歴史」を参照して動作していたら?

「イベントソーシングは、技術の問題じゃない。これは、僕らWPF開発者も含めた、複雑な海外プロジェクトで生き残るための『記録』の思考法であり、時差と文化を超えて『文脈』を共有するための『人生術』なんじゃないか?

そう気付いた瞬間、僕はWPFおじさんであるにもかかわらず、Kafkaのドキュメントを夢中で読み始めていました。

—というのが、今回の「起」です。

このブログでは、「技術としてのイベントソーシング(Event Store, Aggregates, Projections)の概要」や「Axon FrameworkやKafkaといったツール」の話も、もちろんします。

ですが、それ以上に「なぜ、その技術思想が、海外で働く僕らエンジニアを救うのか」という、実体験に基づいた「ハック」の部分を、この後、「承」「転」「結」と、ガッツリ語っていきたいと思います。

「歴史の教科書」としてのKafka?— 僕らWPFエンジニアが誤解していた「イベント」の本当の意味

記事本文(承)

さて、前回の「起」では、僕がグローバルチームで「文脈(コンテキスト)の喪失」という名の地獄(EU帳票システム大炎上)を経験し、「これ、イベントソーシングで救えるんじゃね?」とKafkaのドキュメントに飛びついた話をしました。

(読んでない人は、まず「起」を読んでね。あれはマジで、僕の海外エンジニア人生のターニングポイントだったので)

とはいえ、です。

「WPFおじさんが、いきなりKafkaとかイベントソーシングとか、意識高すぎだろ」

「デスクトップアプリと、Webスケールの分散システムじゃ、水と油だよ」

そう思うでしょ? 僕も、心の中のリトル僕がそう叫んでいました。

僕らにとって「イベント」といえば、Button_Click(クリックイベント)とか、せいぜいINotifyPropertyChanged(プロパティ変更通知)の世界です。ユーザー操作(UI)か、データバインディング(ViewModel)の話。

でも、イベントソーシングが言う「イベント」は、それらとは似て非なる、もっと強烈なヤツだったんです。


僕らが愛した「現在の状態(Current State)」という幻想

まず、僕らWPF/MVVMエンジニアが、いかに「現在の状態」に依存して生きてきたかを告白します。

僕らの仕事は、突き詰めれば「ViewModel」という名の「状態」を管理することです。

ユーザーがテキストボックスに何か入力したら、string MyText プロパティを更新する。

ボタンが押されたら、DBに接続してデータを取ってきて、ObservableCollection<MyData> Items に Add する。

Items が更新されたら、INotifyPropertyChanged が発火して、UI(DataGrid)が自動で変わる。

美しいですよね? MVVMは最高です。

そして、そのViewModelの「状態」を永続化(保存)するために、僕らはDBを使います。

Customer テーブルの Address カラムを、ViewModelの CustomerAddress プロパティの値で UPDATE する。

「現在の状態」こそが正義。過去? 知りません。UPDATE 文が発行された瞬間、古い住所データは上書きされ、歴史から消え去る。それが僕らの常識でした。

でも、前回の「EU帳票事件」で、この常識が牙を剥きました。

「なぜ、この住所データは、この(奇妙な)形式で登録されているのか?」

その理由(=USチームのWebポータル対応)は、Customer テーブルのどこにも残っていなかった。


イベントソーシングの三種の神器:文脈を「記録」する仕組み

「状態」を上書きし続ける限り、「文脈」は失われ続ける。

じゃあ、どうするか?

「上書き(UPDATE)するのを、やめよう」

これが、イベントソーシングの出発点です。

「は? 何言ってんの? データ変更できなかったら仕事にならんだろ!」

はい。僕もそう思いました。

ここで登場するのが、イベントソーシングの「三種の神器」です。これが、僕が「起」で直面した問題を解決するカギでした。

1. イベントストア (Event Store): 「決して書き換えない歴史の教科書」

これが全ての心臓部です。

従来のDBが「最新の顧客名簿(状態)」だとしたら、イベントストアは**「学級日誌(出来事)」**です。

  • 従来のDB: TaroYamada さんの住所は Tokyo です。(現在の状態)
  • イベントストア:
    • 2025-01-10 09:00 「TaroYamada さんが Osaka で入会しました」 (Event: CustomerRegistered)
    • 2025-06-15 14:30 「TaroYamada さんが Tokyo に引っ越しました」 (Event: CustomerAddressChanged)

従来のDBは、Osaka だった過去を忘れます。でもイベントストアは、起きた「出来事(イベント)」を、時系列で、ひたすら「追記(Append)」していきます。

削除(Delete)も、上書き(Update)も、絶対にしません。

「Taroさん、退会したよ」という場合も、データを消すんじゃなく、「TaroYamada さんが退会しました」 (Event: CustomerDeactivated) という「出来事」を追記するんです。

これが何を意味するか?

「なぜ、Taroさんの住所は今、Tokyoなのか?」という問いに、100%答えられるということです。「だって、6月15日に引っ越したから(そういうイベントが記録されてるから)」と。

2. アグリゲート (Aggregates): 「ビジネスルールの番人」

「じゃあ、イベントストアに何でもかんでも追記すればいいんだな!」

…とはなりません。ここにビジネスロジックが必要です。

例えば、「顧客の住所変更は、アクティブな会員しか許可しない」というルールがあったとします。

僕らWPFエンジニアなら、ViewModelあたりに if (customer.IsActive) { ... } みたいなコードを書きますよね。

アグリゲートは、その「ビジネスルール」と「状態」をカプセル化するオブジェクトです。WPFでいうViewModelにちょっと似ていますが、もっと厳格な「番人」です。

  1. UI(WPFアプリ)が「住所変更して!」という「コマンド(命令)」をアグリゲートに送る。
  2. アグリゲート(CustomerAggregate)は、自分の「現在の状態」(=過去のイベントを再生して得た状態)をチェックする。「お、こいつはアクティブ会員だな」と。
  3. ルール上OKなら、アグリゲートは「住所が変更された」という新しい「イベント(CustomerAddressChanged)」を生成します。
  4. この新しいイベントが、イベントストア(歴史の教科書)に追記されます。

アグリゲートは、「このコマンド(命令)は、歴史の教科書に載せる(イベントストアに追記する)価値があるか?」を判断する、唯一の責任者なんです。

3. プロジェクション (Projections): 「読み取り専用の『現在』」

さて、ここで僕らWPFエンジニアは最大の疑問にぶち当たります。

「イベントストアが『歴史の教科書』だってのは分かった。でも、WPFの画面に『顧客一覧』を表示したい時、まさか毎回、全イベントを再生して『現在の状態』を計算するのか? 10年分の学級日誌を読み返さないと、今のTaroさんの住所が分からないのか!?」

…その通り。まともにやったら、パフォーマンスが死にます。

そこで登場するのが**「プロジェクション(Projections)」**です。

これは、イベントストア(歴史)を監視していて、新しいイベントが追記されるたびに、非同期で「読み取り専用のDB(リードモデル)」を更新していく仕組みです。

  • イベントストアに CustomerAddressChanged(住所変更イベント)が追記された!
  • プロジェクションが「お、イベント来たな」と検知する。
  • WPFの画面表示(DataGrid)がいつも参照している、おなじみのSQL Serverとかの CustomerView テーブルの Address カラムを UPDATE する。

そう。ここで初めて UPDATE が登場します。

プロジェクションは、僕らWPFエンジニアが一番馴染み深い「現在の状態」を作るための仕組みです。

ただし、重要なルールがあります。このプロジェクション(読み取り用DB)は、**「間違って消えても、イベントストア(歴史)から100%再構築できる」**ということです。

「EU帳票システム」も、このプロジェクションの一種として設計すべきだったんです。

「US Webポータル」用のプロジェクションと、「EU帳票」用のプロジェクションは、同じイベントストア(歴史)を参照しつつ、それぞれ都合の良い「現在の状態」を作ればよかった。

もし僕が、CustomerAddressChanged というイベントだけを追記していれば、USチームはそれをWeb用に解釈し、EUチームはそれを帳票用に解釈するプロジェクションを、それぞれが作れたはずなんです。


Kafkaは「超高性能な学級日誌(イベント)の配達人」

じゃあ、KafkaとかAxon Frameworkは、この三種の神器とどういう関係なのか?

前回、僕はUSチームとEUチームの間で「文脈」が途切れた話を書きました。

**Kafkaは、まさにこの「途切れた文脈(=イベント)」を、時差やチームの壁を超えて、確実(Exactly-once)に、順番通り(Order-guaranteed)に届けるための「超高性能な郵便システム(メッセージブローカー)」**です。

アグリゲートが生成した「住所変更しました!」というイベント(郵便物)を、Kafkaが受け取る。

そして、それを「購読(Subscribe)」している「US Webポータル用プロジェクション」と「EU帳票用プロジェクション」の両方に、確実に配達する。

もしKafkaがいたら、僕は「USチームのために」ロジックを変えるんじゃなく、「『住所が変更された』というイベントを発生させる」という実装だけをすればよかった。

USチームもEUチームも、その「イベント」を見て、自分の仕事(プロジェクションの更新)を勝手にやってくれたはずなんです。

Axon Framework(Javaの世界ですが)や、C#の世界でいうNEventStore、EventStoreDBといったツールは、この「イベントストア」「アグリゲート」「プロジェクション」といった面倒な仕組みを、より簡単に実装するための「フレームワーク」というわけです。

「全部作り直しか?」— 理想論のKafkaと、”WPFおじさん”の現実的な泥沼(と、一筋の光明)

記事本文(転)

「起」で海外チームの「文脈(コンテキスト)喪失」という地獄を語り、「承」でイベントソーシング(Event Store, Aggregates, Projections)とKafkaが、その「歴史(文脈)」を記録する理想的なアーキテクチャである、という話をしました。

ここまで読んでくれた皆さん、特に僕と同じような(WPF/Windows系)レガシーな現場にいるエンジニアは、きっとこう思ったはずです。

「いや、Taro(仮名)。お前の言ってる理想は分かった。で? お前のその10年モノのWPFアプリ、どうすんの?

そう。

それこそが、僕がぶち当たった「転」— 理想と現実の、あまりにも分厚いカベでした。

僕は「承」で学んだ三種の神器(Event Store, Aggregates, Projections)の美しさに、すっかり魅了されていました。

「これだ! これでウチのぐちゃぐちゃのシステムも、あの『EU帳票事件』も全て解決する!」

僕は息巻いて、ヨーロッパとアメリカとインドを繋いだ(時差のせいで全員が眠そうな)アーキテクチャ会議で、拙い英語で「イベントソーシング」の概念図をブチ上げました。

「僕らは『現在の状態』に依存しすぎている! 『出来事(イベント)』を記録するEvent Store中心の設計に、今こそ切り替えるべきだ!」

…会議室(Zoom)は、静まり返りました。

数秒の沈黙の後、ようやく口を開いたUSのシニアアーキテクト(僕よりずっと偉い人)が、一言こう言いました。

「Taro。君の情熱は分かった。で、誰がその『10年モノのWPFアプリ』と、それにまとわりつく500本のストアドプロシージャ(DB内の処理)を、書き直すんだ?

「…それは…」

「我々の顧客は、来月リリース予定の『新機能A』を待っている。君の言う『イベントストアの構築』は、その新機能Aのリリースにどう貢献する? むしろ、リグレッション(バグ)のリスクを増やすだけじゃないか?」

ぐうの音も出ませんでした。

これが現実です。海外(というか、どこの現場でも)エンジニアリングは「理想」で飯は食えません。「ビジネス価値」が全てです。

僕らWPFエンジニアが日々向き合っているのは、ピカピカのマイクロサービス(Greenfield)じゃない。数え切れないほどの「過去の仕様」と「技術的負債」が積み重なった、巨大な「泥だんご(Brownfield)」なんです。

この「泥だんご」を、いきなり「イベントソーシング」という美しいアーキテクチャに置き換えるなんて、**「ビッグバン・リライト(一斉作り直し)」**以外の何物でもない。そして、歴史が証明している通り、「ビッグバン・リライト」は、ほぼ100%失敗します。


MVVM(状態)とEvent Sourcing(イベント)の「水と油」

さらに、技術的なカベもありました。

「承」で説明した通り、イベントソーシングの「現在の状態(プロジェクション)」は、イベントストア(歴史)から非同期で「導出」されます。

でも、僕らのWPF/MVVMは?

INotifyPropertyChanged の世界は、**「今、この瞬間」**の状態が欲しいんです。

ユーザーがボタンを押した。CustomerViewModel の Save() メソッドが呼ばれる。

ここで Save() がやることが「イベント(CustomerSaved)をKafkaに投げて、あとはよろしく」だったらどうなりますか?

画面(View)は、いつ更新されるんですか?

「保存しました」というメッセージは、いつ出すんですか?

非同期のプロジェクションがDBを更新して、それがまた何らかの仕組みでViewModelに通知される…?

「おいおい、Button_Click の裏側で、そんな大層な世界一周旅行をさせる気か!?」

僕らの愛するMVVMの「状態(State)」のシンプルさと、イベントソーシングの「イベント(Event)」の流れは、あまりにも「水と油」だったんです。

理想に燃えていた僕は、一気に現実に引き戻されました。

「ダメだ…。『WPFおじさん』が流行りの技術に手を出そうとしたのが間違いだったんだ」

「僕は、このまま『文脈』が失われていく現場で、USチームとEUチームの板挟みになりながら、古いWPFコードにパッチを当て続けるしかないんだ…」

僕は諦めて、あの日炎上した「EU帳票」の問題を、結局、最も「レガシー」な方法で修正しました。

そう。USチームとEUチームの両方に対応できるよう、Customer テーブルに新しい「フラグ(IF_US_USE_THIS_FORMAT)」みたいな最悪のカラムを追加することで…。

(転:ここまでが前半の「絶望」パート。ここから「光明」が差します)


泥沼で見つけた「現実的な第一歩」

その最悪の「フラグ」カラムを追加する UPDATE 文を書いていた、まさにその時。

僕の頭に、一つの「問い」が浮かびました。

「イベントソーシング(Event Sourcing)は、ダメだった」

「でも、『出来事を記録する』という思想は、絶対に間違っていない」

「僕が本当に欲しかったのは、『システム全部の作り直し』だったのか?」

「いや、違う」

「僕が欲しかったのは、ただ一つ。『僕がやったこの最悪のUPDATEを、僕以外の誰か(USチームやEUチーム)が、僕に聞かなくても、知ることができる』。それだけじゃなかったか?」

アグリゲート? イベントストア?

そんな大層なものじゃなくていい。

「『今、TaroがCustomerテーブルをUPDATEしたぞ!』という『事実』を、Kafkaに『通知(Notification)』するだけでも、世界は変わるんじゃないか?」

これは、「イベントソーシング(Sourcing: 源泉)」ではありません。

これは、「イベント駆動(Driven)」な考え方です。

システム(WPFアプリ)のコアは、今まで通り「状態」を UPDATE する。

でも、その UPDATE が行われた「直後」に、**「何が起きたか」**という「イベント」を、外部に(Kafkaに)向かって「叫ぶ(Publish)」んです。

Customer ID: 123 の Address が Tokyo に変更されました!」

この「叫び」さえあれば、

US Webポータルチームは、「お、イベント来たな。じゃあウチのWeb用DB(プロジェクション)も更新しとくか」と、勝手に動ける。

EU 帳票チームも、「お、住所変わったな。でもウチの帳票は古い住所のまま参照しなきゃな」と、勝手に動ける。

僕はもう、彼らのためにコードを「書き分ける」必要がない。

僕はただ、「事実(イベント)」を叫ぶ。それだけが僕の仕事になる。

「でも、どうやって? あの10年モノのWPFアプリのコード、UPDATE 文の直後にKafkaにPublishするコードなんて、怖くて追加できないぞ…」

そこで僕は、ある魔法のような技術(パターン)に出会いました。

「Change Data Capture (CDC)」(変更データキャプチャ)です。

これは、僕ら(アプリケーション開発者)が手を出せない「DBの奥底」、「トランザクションログ」という聖域を「監視」する仕組みです。

Debezium(デベジウム)のようなCDCツールを使うと、こうなります。

  1. 僕のレガシーWPFアプリが、今まで通り、何も変えずにUPDATE Customer ... を実行する。
  2. DB(SQL Serverとか)が「うっす、UPDATEしときます」と、トランザクションログに「Customerのここ、変えました」と記録する。
  3. CDCツール(Debezium)が、そのログを**「盗み見て」、「おい!Customerが変更されたぞ!」という「イベント」を、自動的にKafkaにぶち込んでくれる。**

…分かりましたか?

僕は、WPFアプリのコードを、一行も変更する必要がなかったんです。

「ビッグバン・リライト」なんて必要なかった。

「イベントソーシング」という完璧な理想を、最初から目指す必要もなかった。

僕らレガシーシステムと戦うエンジニアが取るべき道は、**「今あるモノ(レガシー)を尊重しつつ、その『外側』で、いかに『文脈(イベント)』を流通させるか?」**という、もっと泥臭く、もっと現実的なハックだったんです。

この「CDC + Kafka」という現実解は、僕の海外エンジニア人生における、まさに「転換点」となりました。

「完璧」より「通知(Notification)」を愛せ — イベント思考が教えてくれた、海外エンジニアのサバイバル術

記事本文(結)

長かった「WPFおじさん」の海外奮闘記も、いよいよ最終回(「結」)です。

「起」で、時差と文化の壁が生む「文脈(コンテキスト)の喪失」という地獄(EU帳票事件)を嘆き、「承」で、「イベントソーシング(Event Sourcing)」という、失われた文脈を「歴史」として記録する美しい理想に出会いました。

そして「転」で、その理想が「10年モノのWPFアプリ(レガシー)」という現実の壁に叩き潰され…しかし、泥沼の中から**「Change Data Capture (CDC)」**という、「レガシーを一切変更せずに、DBの『変更という事実(イベント)』をKafkaに通知する」という、現実的な光明を見つけた話までしました。

「理想のアーキチャを夢見て、現実のレガシーに絶望し、そして現実的なハック(CDC)を見つけた」

今日は、その「ハック」が、僕の海外エンジニア人生、いや、僕の「働き方」そのものを、どう変えたのか。

このブログのテーマである「海外で働くエンジニアが得する情報、人生術」として、お伝えしたいと思います。


何が変わったか? — 「調整役」からの解放

CDC(Debezium)が、僕らのレガシーなSQL Serverのトランザクションログを監視し、全てのINSERT/UPDATE/DELETEを「イベント」としてKafkaに垂れ流し始めてから、数ヶ月。

僕の仕事は、劇的に変わりました。

かつて「EU帳票事件」を引き起こした、あの「US Webポータル」と「EU帳票」の板挟み問題。

もし今、同じような「USチームからの仕様変更依頼」が来たら、僕はどう動くか?

以前の僕は、「EUチームに影響ないかな…」「USチームの担当者に、EU側の事情も説明しなきゃ…」と、**全チームの「文脈」を自分一人で背負い込み、すり合わせる「調整役」**をやっていました。

今の僕は、違います。

USチームの依頼を受け、僕は自分の責務(WPFアプリ)のロジックを修正し、Customer テーブルのデータを、新しい仕様通りに UPDATE する。

以上、終わり。

僕は、EUチームにチャットも打ちません。

なぜなら、僕が UPDATE を実行した瞬間、CDCがそれを検知し、「TaroのWPFアプリが Customer ID: 123 の Address を変更したぞ!」という「事実(イベント)」が、Kafkaに流れるからです。

  • USチームは、そのイベントを購読(Subscribe)し、「よし、ウチのWebポータル用DB(プロジェクション)も更新しよう」と動く。
  • EUチームも、そのイベントを購読し、「お、Taroがデータを変えたな。でもウチの帳票システムは、この変更は無視して、古いロジックのまま動かそう」と、自分たちで判断する

分かりましたか?

僕はもう、「調整」も「根回し」もしていません。

僕はただ、自分のアプリケーションの**「責務(Contract)」**を果たしただけ。

(僕の責務は「Customer テーブルのデータを正しく更新すること」)

そして、その「結果(=イベント)」を、**Kafkaという「公(おおやけ)の掲示板」に「通知(Publish)」**しただけ。

その「通知」を見て、どう「解釈(Subscribe)」するかは、USチームとEUチーム、それぞれの「責務」なんです。


これが本当の「疎結合(Loose Coupling)」という人生術

僕らは技術用語として「疎結合(そけつごう)」という言葉を学びます。モジュールは独立しているべきだ、と。

でも、海外のグローバルチームで働いてみて、痛感しました。

僕らに本当に必要なのは、技術的な疎結合であると同時に、**「働き方の疎結合」**なんだ、と。

「起」で僕がやっていたのは、最悪の「密結合」な働き方です。

時差も文化も違う、顔も見たことないUSチームの「文脈」と、EUチームの「文脈」を、僕(日本人)が必死に理解し、その「間(あいだ)」でコードを調整しようとしていた。

無理ですよ、そんなの。

メンバーは来月には辞めてるかもしれない。ドキュメントは3年前から更新されていない。そんな環境で、「全部わかってる人」になろうとすること自体が、間違いだったんです。

イベントソーシングやCDCが教えてくれた「イベント思考」は、この「密結合」の呪いを解く「人生術」でした。

  1. 自分の「責務(Contract)」を明確にせよ。
    • 僕の仕事は「全チームの幸せ」を考えることじゃない。僕の仕事は「僕のWPFアプリがDBにデータを正しく書くこと」だ。
  2. 自分の「仕事の結果(事実)」だけを「通知(Publish)」せよ。
    • 自分がやったことを、隠さず、遅れず、「公の場(Kafka)」に通知する仕組みを作れ。
  3. 他人の「解釈(Subscribe)」に、踏み込むな。
    • その「通知」を見て、USチームがどう動くか、EUチームがどう判断するかは、彼らの「責務」だ。僕が「調整」してはいけない。彼らが自分で判断できるように、「事実」だけを提供しろ。

これは、日本人エンジニアが海外で働く上で、最強の「心理的安全性」ハックだと僕は思っています。

僕らは(文化的に)「気を遣いすぎる」んです。「僕がこれを変えたら、あの人(EUチーム)が困るんじゃないか…」と。

その「気遣い」が、グローバルチームでは「余計なお世話(=密結合)」となり、結果として「EU帳票事件」のような大事故を引き起こす。

そうじゃない。

「僕はこれを変えましたよ」と**「通知」すること**こそが、グローバルチームにおける最大の「誠意」であり「気遣い」なんです。


結論:「WPFおじさん」の戦い方

僕は今でも「WPFおじさん」です。相変わらずXAMLをこねくり回し、INotifyPropertyChanged と戦っています。

でも、僕の働き方は、KafkaとCDCに出会う前とは全く違います。

「イベントソーシング」という完璧な理想のアーキテクチャを、いきなりレガシーシステムに持ち込もうとして、「転」で僕は一度、玉砕しました。

ビッグバン・リライトは、悪です。

僕らレガシーシステムと戦うエンジニアが取るべき道は、違いました。

  • 完璧を目指すな。いきなり「イベントソーシング」の三種の神器(Event Store, Aggregates, Projections)を全て揃えようとするな。
  • 今あるモノ(レガシー)を尊重しろ。10年モノのWPFアプリ(泥だんご)は、そのままでいい。それはビジネスを支えてきた「資産」だ。
  • ただし、「通知」しろ。その「資産」が、今、何をしているのか。その「事実(イベント)」だけを、外の世界に知らせる「仕組み(CDCやKafka)」に投資しろ。

「状態(State)」ベースのレガシーなWPFアプリと、「イベント(Event)」ベースのモダンなアーキテクチャ。

この二つは「水と油」じゃない。「共存」できるんです。

そして、この「イベント思考(=自分の仕事の結果は、公に通知する)」こそが、「文脈」が失われがちなカオスな海外チームで、僕らエンジニアが互いを信頼し、自分の仕事に集中し、そして何より、心理的安全性高く生き残るための、最高の「人生術」なんだと、僕は確信しています。

長くなりましたが、最後まで読んでくれて、ありがとうございました。

もし、あなたの現場も「文脈」の喪失に悩んでいるなら、この記事が、その「泥沼」から抜け出す小さなヒントになれば、幸いです。

コメント

タイトルとURLをコピーしました