憧れの「全面刷新」と、海外現場でぶち当たった「動くレガシー」という名の壁
(ここから本文)
どうも! ヨーロッパの片隅で、C#とWPFをメインに企業向け(B2B)のシステム設計と開発をやっています、[あなたのブログ名やハンドル名など]です。
これから海外で働きたい、もしくは今まさに海外で働き始めたエンジニアの皆さんに向けて、教科書には載ってない、リアルな「現場のサバイバル術」をお届けしたいと思っています。
さて、エンジニアなら誰しも一度は夢見ますよね。**「全面刷新(Rip and Replace)」**という甘美な響き。
僕もそうでした。特にキャリアの浅い頃は、既存のコード、特に「レガシーコード」と呼ばれるものが大嫌いだった。「なんだこのコードは!」「設計したやつ、誰だ!」「俺ならもっとうまくやる。全部書き直させろ!」って。
僕の専門であるWPF(Windows Presentation Foundation)の世界なんて、まさにその宝庫です。
海外に来て、僕が最初に参加したプロジェクト。それは、ある製造業の基幹となる在庫管理システムでした。もちろん、C#とWPFで書かれていて、XAMLの裏(コードビハインド)に数千行のビジネスロジックが直書きされ、MVVM? なにそれ美味しいの? 状態。データベースへの接続文字列がなぜか設定ファイルじゃなくてコードの奥深くにハードコードされてたり(笑)。
もうね、触るのが怖いんですよ。まさに「ジェンガ」。一本抜いたら全部崩れるかもしれない。
新機能の追加を頼まれた時、僕は意気揚々とチームリーダー(ドイツ人のベテランエンジニアでした)に言いました。「こんな複雑怪奇なコードに手を入れるのは無理です。バグの温床になる。リスクが高すぎる。いっそ、最新の.NET 8とPrism(WPFのMVVMフレームワーク)を使って、全部クリーンに書き直しましょう! 3ヶ月もあればプロトタイプを見せますよ!」と。
エンジニアとしては、ロジカルで「正しい」提案だと思っていました。だって、技術的負債は返済すべきだし、クリーンなアーキテクチャはメンテナンス性を向上させる。それが正義だ、と。
そしたら、そのドイツ人リーダーは、コーヒーを一口すすって、静かにこう言ったんです。
「OK。君の言う『クリーンなシステム』が完成するのを、ビジネスは待ってくれると思うかい? このシステムは今、この瞬間も、世界中の工場のラインを動かしている。もしこのシステムが1時間止まったら、会社が被る損害は数百万ユーロだ。
君が『3ヶ月でプロトタイプ』と言ったけど、本番稼働までには最低1年半はかかるだろう。その1年半、ビジネスは『新機能なし』で我慢しなきゃいけない。
そして何より……君は、この10年間で継ぎ足されてきた『仕様書にない暗黙のビジネスロジック』を、たった1年半で100%再現できると、神に誓えるかい?」
僕は、何も言い返せませんでした。
これこそが、僕が海外の現場で学んだ最初の「人生術」です。
僕たちは「コード」を見ている。でも、ビジネスは「価値」を見ている。
そのレガシーシステムが、どれだけひどいスパゲッティコードであっても、それが**「今、動いていて、金を生んでいる」**という事実は、何物にも代えがたい「価値」なんです。
エンジニアの「技術的な正義感」や「美学」だけで、「じゃあ、全部捨てて作り直そう(Rip and Replace)」と叫ぶのは、プロフェッショナルの仕事じゃない。それはただのエゴであり、海外(特に歴史の長いヨーロッパの企業)では「経験の浅い若者」の烙印を押されてしまいます。
「じゃあ、どうするんだよ!」「クソコードを一生メンテし続けろって言うのか!」
そう思いますよね。僕も思いました。
ここで、海外のシニアエンジニアたちが当たり前に持っている視点が登場します。それが、今回のテーマである**「戦略的モダナイゼーション(Strategic Modernization)」**です。
これは「全面刷新」ではありません。「ブルドーザーで更地にする」ことじゃない。
「今動いている飛行機のエンジンを、飛行中に交換する」
もっと言えば、**「歴史的建造物の内装だけを、外観を保ったまま、最新の設備に入れ替える」**ような、高度な「外科手術」です。
ビジネス(=飛行)を止めずに、システム(=エンジン)を少しずつ、安全に、新しいものに入れ替えていく。
これ、めちゃくちゃ面白そうだと思いませんか?
このスキルを持っているエンジニアは、海外で本当に重宝されます。なぜなら、世の中の9割の企業は「レガシーシステム」で動いているからです。ピカピカのグリーンフィールド(新規開発)案件なんて、そうそうありません。
「新しいものが作れるエンジニア」は星の数ほどいます。でも、「古いものを壊さずに、育てながら若返らせるエンジニア」は、ものすごく希少価値が高い。
僕たちC# / WPFエンジニアは、まさにこの「モダナイゼーション」の最前線にいます。多くのWPFアプリは、Windows Formsから移行してきたり、あるいはWPFでガッツリ作られたものが10年選手になっていたりします。バックエンドはWCF(Windows Communication Foundation)だったり、SOAPで通信していたり…。
「このWCFを、どうやってモダンなREST API(Web API)に切り替えるか?」
「この巨大な MainWindow.xaml.cs に手を入れずに、どうやって新しい画面(機能)をプラグイン的に追加するか?」
「このオンプレミスのSQL Serverのデータを、どうやってAzureのDBに『止めずに』同期させるか?」
こういう課題を解決するため、エンジニアリングの世界には素晴らしい「パターン(型)」が用意されています。
このブログシリーズでは、僕が実際のプロジェクトで使って「これは効いた!」という具体的な近代化パターンを、僕らC#エンジニアの文脈で、実例を交えながら紹介していきます。
次回(承)では、さっそく「ストラングラー・フィグ(絞め殺しのイチジク)パターン」という、ちょっと物騒な名前だけど超強力なテクニックを紹介します。
レガシーコードは「悪」じゃありません。「宝の山」であり、僕たちの市場価値を爆上げしてくれる「最高の教材」です。
全面刷新を夢見る前に、まずは目の前の「動くレガシー」とどう向き合うか。そこに、海外で長く活躍するためのヒントが詰まっています。
システムを窒息させずに若返らせる? WCFをRESTに置き換えた「ストラングラー・フィグ」の実践
(ここから本文)
どうも! [あなたのブログ名やハンドル名など]です。「起」の記事では、僕が海外の現場で「全面刷新(Rip and Replace)」を提案して、ベテランリーダーに見事に玉砕された話をしました。「動いているレガシーシステムは、それ自体が価値なんだ」と。
「じゃあ、古いコードは触るな、と? 塩漬けにしろってこと?」
いやいや、もちろん違います。ビジネスは成長したいし、僕らエンジニアだって新しい技術を使いたい。
そこで登場するのが、僕たちエンジニアの腕の見せ所、「戦略的モダナイゼーション」です。
今日は、僕がヨーロッパの現場で「これは本当に賢い!」と感動した近代化パターンの一つ、**「ストラングラー・フィグ(Strangler Fig)パターン」**について、僕らC# / WPFエンジニアの視点でガッツリ解説します。
名前がすごいですよね。「絞め殺しのイチジク」。
これは、熱帯雨林にあるイチジクの木が、他の大きな木にツルを巻きつけながら成長し、何年もかけて最終的には元の木を覆い尽くし、自分がその場にとって代わる、という生態から名付けられました。(アーキテクチャの世界の巨匠、マーティン・ファウラー氏が提唱したパターンです)
これをシステムに置き換えると、どういうことか。
「巨大なレガシーシステム(=元の木)の外側に、新しいシステム(=イチジクのツル)を被せるように作る。そして、ユーザーからのリクエストを少しずつ新しい方に振り向け、最終的にはレガシーシステムを『窒息』(=リタイア)させる」
という戦略です。
ブルドーザーで一気に更地にする「全面刷新」とは真逆。リスクを最小限に抑えながら、システムを「じわじわと」若返らせるんです。
なぜWPFエンジニアがこれを学ぶべきなのか?
僕らWPFエンジニアが扱うシステムって、まさにこのパターンの「適応症」なんですよ。
例えば、こんなシステム、あなたの現場にありませんか?
- UI: WPF(.NET Framework 4.8)
- ビジネスロジック: UIのコードビハインド(xaml.cs)にごちゃ混ぜ
- 通信: WCF(Windows Communication Foundation)
- バックエンド: オンプレミスのSQL Server
これ、10年〜15年選手の「あるある」構成ですよね。
ここでビジネスから「このシステムを、将来的にWeb(ブラウザ)やスマホでも使えるようにしたい。あと、クラウド(Azure/AWS)にも移行したい」という要望が来たとします。
さあ、どうする?
WPFのコードビハインドにロジックが癒着しているから、Web化なんて無理。
WCFは、HTTP以外のプロトコル(TCPとか)も使えて高機能だったけど、今のクラウドネイティブな世界とは相性が悪い。モダンなWeb API(REST)やgRPCにしたい。
でも、前回の「起」で書いた通り、このシステムを**「止める」ことは許されない。**
ここで「ストラングラー・フィグ」の出番です。
実録:WCFを「絞め殺した」あの日のプロジェクト
僕が担当したプロジェクトでの実例をお話しします。(もちろん、守秘義務の範囲で少しぼかしますが)
まさに上記の「あるある」構成でした。WPFアプリが、オンプレミスサーバーで動いているWCFサービスとnet.tcp(高速だけどHTTPじゃない)で通信していました。
目標: WCFを廃止し、バックエンドをAzure上で動くモダンな「ASP.NET Core Web API(REST)」に置き換えること。
制約: WPFアプリ(クライアント)は世界中の拠点で動いており、一斉にアップデートすることは不可能。
普通に考えたら「WPFアプリのコードを書き換えて、Web APIを呼ぶように直せばいいじゃん」と思いますよね。
でも、それができない。なぜなら、WPFアプリのアップデートを拒否する拠点があったり、古いバージョンを使い続けたいという顧客の事情があったりするからです。
つまり、**「古いWPFアプリ(WCFを呼び出す)と、新しいWPFアプリ(Web APIを呼び出す)が、同時に共存できなければならない」**という超面倒な状況でした。
僕たちのチームが取った戦略は、こうです。
ステップ1:ファサード(門番)を立てる
まず、既存のWCFサービスと、新しく作るWeb APIの**「両方の前に」**立つ、「門番」となるコンポーネントを置きました。
これが「ストラングラー・ファサード(Strangler Facade)」と呼ばれるものです。
(実態は、Azure Application GatewayやAzure API Managementのような、リクエストを振り分けるリバースプロキシやAPIゲートウェイです)
すべてのWPFアプリは、この「門番」に対してリクエストを投げるように、接続先だけを変更します。(これは最小限の変更なので、古いアプリでも対応可能でした)
ステップ2:最初の「ツル」を伸ばす(新機能の実装)
ここがキモです。
既存のWCFのコードは一切触りません。
ビジネスから「新しい機能Aを追加してほしい」という要求が来ました。
僕たちは、この「機能A」を、新しいASP.NET Core Web APIとして開発します。
そして、ステップ1で置いた「門番」に設定を追加します。
「もし、/api/v2/機能A というURLへのリクエストが来たら、新しいWeb APIに流せ」
「それ以外(既存機能)のリクエストが来たら、これまで通り古いWCFに流せ」
と。
新しい機能を使うためには、WPFアプリのアップデートが必要です。新しいWPFアプリは、機能Aを呼び出すときだけ、新しいWeb APIのエンドポイント(/api/v2/機能A)を叩きます。
古いWPFアプリを使っているユーザーは?
彼らは機能Aを使えませんが、既存の機能は「門番」経由で古いWCFに流れるので、何も問題なく動き続けます。
見えますか? システムを止めずに、新しい「ツル」が一本伸びた瞬間です。
ステップ3:「ツル」で「幹」を置き換えていく
次の要求が来ました。「既存の機能B(在庫確認)のレスポンスを速くしてほしい」
OK。僕たちは、既存のWCFの中にある「機能B」のロジックを解析し、それと全く同じ動きをする(ここ大事!)「機能B’(ダッシュ)」を、新しいWeb API側に実装します。
そして「門番」の設定をこう変えます。
「/api/v1/機能B(古いWPFが叩くURL)へのリクエストが来たら、**新しいWeb APIの機能B’**に流せ」
これで、WPFアプリ側は一切コードを変更していないのに、呼び出し先がWCFから新しいWeb APIに切り替わりました。
古いWPFアプリを使っているユーザーは、ある日突然、在庫確認が爆速になって驚くわけです。「なんか知らんが速くなったぞ!」と。
僕たちは、この作業を繰り返します。
機能CをWeb APIで再実装し、門番の設定を切り替える。
機能DをWeb APIで再実装し、門番の設定を切り替える。
一本、また一本と、イチジクの「ツル」がWCFという「幹」を覆い尽くしていくイメージです。
ステップ4:古い幹の「死」を確認する
数ヶ月後。
「門番」のログを見ると、古いWCFサービスへのリクエストが「ゼロ」になりました。
すべての機能が、新しいWeb APIによって処理されるようになったのです。
この瞬間、レガシーシステムは「窒息」しました。つまり、安全にリタイア(=サーバーをシャットダウン)できることが確認できたのです。
この戦略が「得する人生術」である理由
どうでしょう。めちゃくちゃ地味ですか?(笑)
でも、これが「プロの仕事」だと、僕は海外で学びました。
この「ストラングラー・フィグ」戦略の何がすごいのか。
- リスクが超低い:一度に全部を切り替えるのではなく、機能単位で切り替えます。もし新しいWeb API側にバグがあっても、影響範囲はその機能Bだけ。「門番」の設定を戻せば、一瞬で古いWCF(動くことが保証されている)にロールバックできます。ビジネスを絶対に止めないという強い意志です。
- ビジネスを止めない:モダナイゼーションの最中も、新機能の開発(ステップ2)を並行して進められます。「全面刷新」のように、「移行が終わるまで1年半、新機能は我慢してください」なんて言う必要がない。これはビジネスにとって計り知れない価値です。
- エンジニアのモチベーションが上がる:これ、大事です。「古いWCFのクソコードを直せ」じゃなくて、「新しいWeb API(ASP.NET Core 8)で再実装しろ」と言われるんです。僕らエンジニアは、新しい技術を触れる! 幸せですよね(笑)。
このパターンは、WCF -> Web APIだけの話じゃありません。
例えば、WPFアプリ内部。
コードビハインド(xaml.cs)にロジックが5000行ある HogeWindow.xaml があったとします。
これに新機能を追加するとき、その5000行に手を入れるのは怖いですよね。
だったら、HogeWindow.xaml の中に、新機能専用の NewFeatureControl.xaml(UserControl)をポツンと置く。このUserControlの中だけは、最新のMVVMパターン(例えばPrismやMVVM Toolkit)を使って、クリーンに実装する。
これも、巨大なレガシー(HogeWindow)の「外側」に、新しいクリーンな実装(NewFeatureControl)を「被せる」、小さなストラングラー・フィグです。
「全部キレイにしないと気が済まない」というエンジニアのエゴを捨て、「動いているものは尊重しつつ、新しい部分から賢くキレイにしていく」という現実的なアプローチ。
この視点を持つだけで、レガシーコードを見る目が変わってきませんか?
「うわ、最悪だ」から、「さあ、どこから絞め殺してやろうか」という、外科医のような冷静な視点に(笑)。
次回(転)は、この近代化戦略で「隠れたボス」として立ちはだかる、「データ」の話をします。コードは新しくなった。でも、データが移行できない…という地獄。それを救う「アンチ・コラプション・レイヤー」という、これまた強力なパターンを紹介します。
コードは動いた、だがデータが死んだ。近代化の「隠れたボス」データ移行の罠と「アンチ・コラプション・レイヤー」
(ここから本文)
どうも! [あなたのブログ名やハンドル名など]です。「承」の記事では、「ストラングラー・フィグ(絞め殺しのイチジク)パターン」を使って、WCFのような古いバックエンドを、ビジネスを止めずに新しいWeb APIに「じわじわ」置き換えていく話をしました。
僕のチームは、この戦略で古いWCFサービスへのリクエストを次々と新しいASP.NET Core Web APIに振り向けることに成功しました。ログを見て、古いWCFへのトラフィックがゼロになった日、チームのみんなでハイタッチですよ。「勝った! モダナイゼーション完了だ!」と。
…と、思っていたんですよ。あの「本当のボス」に気づくまでは。
プロジェクトが次のフェーズに進んだとき、奇妙な問題が多発し始めました。
「あれ? 新しいWeb API、なんかレスポンス遅くない?」
「特定の顧客データ(Customer)を呼び出すと、新しいAPIが例外を吐くんだけど」
「新機能側で登録したデータが、古いWPFアプリ側で見ると文字化けしてる…」
僕たちは勝ち誇った気分から一転、冷や汗が出てきました。
そう。僕たちは**「アプリケーション(コード)」を近代化することに成功した**だけだったんです。
その新しいピカピカのWeb APIが、裏側で接続しにいっていたのは…結局、**15年間モノの「秘伝のタレ」のように継ぎ足されてきた、あの「レガシー・データベース(SQL Server)」**だったんです。
例えるなら、「F1カーの最新エンジン(新しいWeb API)を手に入れたぞ! これで勝てる!」と喜んでいたら、そのエンジンを載せた先が、**「50年前のトラクターの車体(レガシーDB)」**だった、みたいな。
そりゃあ、まともに走りませんよね。
近代化の「隠れたボス」=データモデルの不整合
ここに、海外の現場でベテランと若手を分ける、大きな「壁」があります。
若手エンジニアは「コード」を新しくしたがる。
でも、ベテランエンジニアは「データ」を恐れる。
なぜか?
- レガシーDBの現実:
Customersテーブルに、なぜか180個もカラム(列)がある。Statusというカラムがint型で、「1=アクティブ, 2=保留, 7=VIP, 99=削除済み」みたいな「独自ルール」で運用されている。(新しいシステムなら普通IsActive(bool) とかCustomerType(string) とかにしますよね)Notesカラム(nvarchar(MAX))に、XML形式の文字列や、カンマ区切りのIDリストが「そのまま」突っ込まれている。
僕たちの新しいWeb APIは、クリーンな設計思想で作られています。
例えば、こんなC#のモデル(クラス)を内部に持っています。
C#
// 【新システム】が望む、クリーンな顧客モデル
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; } // bool型が欲しい!
public List<string> Tags { get; set; } // タグはリストで扱いたい!
}
でも、古いDBからデータを取るには、新しいAPIサーバー側で、こんな「汚い」変換ロジックを書かざるを得ない。
C#
// 【新システム】内部に「汚い」ロジックが侵入
Customer ConvertFromLegacyDb(LegacyCustomerRow row)
{
var customer = new Customer();
customer.Id = row.CustomerID_Ver2; // カラム名が変…
customer.Name = row.FullName_JP;
// 「独自ルール」を新しいAPI側が「知って」しまっている
if (row.Status == 1 || row.Status == 7)
{
customer.IsActive = true;
}
else
{
customer.IsActive = false;
}
// 「Notes」カラムに詰め込まれたXMLをパースする処理…(地獄)
customer.Tags = ParseXmlFromNotes(row.Notes_XML);
return customer;
}
これが何を意味するか。
「レガシー(古いシステム)の『腐敗』が、新しいクリーンなシステムに『侵食』してきている」
ということです。
せっかく新しいエンジン(Web API)を作ったのに、その内部が古いトラクター(レガシーDB)の「独自ルール」を翻訳するためのロジックだらけになっていく。
これでは、新しいAPIもすぐに「新しいレガシーコード」になってしまいます。
この「腐敗」を絶対に新しいシステムに入れないぞ!と防波堤を立てる。
これこそが、僕が学んだ最強の防御パターン、**「アンチ・コラプション・レイヤー(Anti-Corruption Layer: ACL)」**です。
汚染を食い止める「防護壁」ACLとは
アンチ・コラプション・レイヤー(ACL)は、その名の通り「腐敗を防ぐ層」。
日本語に意訳するなら**「防護壁」とか「翻訳・通訳レイヤー」**です。
これは、新しいクリーンなシステム(ドメイン)と、古いレガシーなシステム(レガシーDB)の「間」に、意図的に挟み込む「別のコンポーネント」です。
[図のイメージ: [新API] <-> [ACL] <-> [レガシーDB] ]
- 役割1:翻訳ACLは、「通訳」です。新しいAPIは、ACLに対してクリーンな言葉(「ID:5の顧客情報を、Customerクラスの形でくれ」)で話しかけます。ACLは、その裏で、レガシーDBが理解できる汚い言葉(「SELECT * FROM Tbl_Cust_V2 WHERE CustomerID_Ver2 = 5 AND Status != 99」)に翻訳して実行します。そして、返ってきたドロドロのデータ(Status=1とか)を、クリーンなCustomerクラス(IsActive=true)にマッピングし直して、新しいAPIに返します。
- 役割2:防護ここが最重要。新しいAPI(ASP.NET Core Web APIプロジェクト)は、ACLのことしか知りません。 ACLの向こう側に「レガシーDB」が存在すること自体を、知りません(知る必要がない)。これにより、新しいAPIのコードは、Status=1がどうとか、NotesがXMLだとかいう**「レガシーの都合」から完全に守られます。**
C#エンジニアはどう実装する?
具体的には、C#のプロジェクト(ソリューション)で、こんな風に分離します。
- MyNewApi.Core.csproj(新しいAPIの本体。クリーンな Customer クラスやビジネスロジックだけが入っている。レガシーDBのことは一切知らない。)
- MyNewApi.Infrastructure.LegacyDb.csproj(これがACL。「防護壁」プロジェクト)
この「ACLプロジェクト」の中だけで、あの汚い変換ロジック(ConvertFromLegacyDb)や、古いDBに接続するためのコード(DapperやEF Core)を書きます。
AutoMapperのようなマッピングライブラリも、この中で使うと効果的です。
新しいAPI本体(MyNewApi.Core)は、このACLプロジェクトが提供する「きれいなインターフェース(ICustomerRepository)」を呼ぶだけ。
C#
// 【新API本体】のコード
// 依存性の注入(DI)でACLを注入してもらう
public class CustomerController : ControllerBase
{
private readonly ICustomerRepository _repo;
public CustomerController(ICustomerRepository repo)
{
_repo = repo; // この repo の実体が ACL
}
[HttpGet("{id}")]
public Customer Get(int id)
{
// クリーンな呼び出し!
// この裏側でACLが頑張っていることを、Controllerは知らない
return _repo.GetById(id);
}
}
なぜこれが「人生術」なのか
ストラングラー・フィグ(承)が、アプリケーションの「経路」を変える外科手術だとしたら、
アンチ・コラプション・レイヤー(転)は、システムの「境界線」を守る免疫機能です。
海外で働くシニアエンジニアは、この「境界線」にめちゃくちゃうるさいです。
「そのコード、レガシーの都合がこっちに漏れ出てるよ」
「その変換ロジックは、CoreプロジェクトじゃなくてInfrastructure(ACL)側に書くべきだ」
と。
これは「人生術」にも通じます。
新しい挑戦(新しいAPI)を始めるとき、過去のしがらみ(レガシーDB)に足を引っ張られそうになる。
「ああ、もう面倒だ! 新しいAPI側で、直接あの汚いDBを叩いちゃえ!」
とショートカットしたくなる。
でも、それをやったら最後。あなたの新しい挑戦は、過去の「腐敗」に汚染されて、輝きを失います。
あえて「防護壁(ACL)」という「面倒な一手間」を挟むこと。
それこそが、新しいものをクリーンなまま成功させる、プロフェッショナルな「境界線の引き方」なんです。
さて、ACLという「盾」を手に入れた僕たち。
でも、盾で防いでいるだけでは、レガシーDBという「ボス」は倒せません。
防護壁を立てて時間を稼いでいる間に、僕たちが本当にやるべきこと。
それこそが、最終章(結)で話す、本当の意味での「データ移行(Data Migration)」戦略です。
ACLは、そのための「布石」に過ぎなかったのです。
なぜ「リプレイスできるエンジニア」より「モダナイズできるエンジニア」が海外で重宝されるのか
(ここから本文)
どうも! [あなたのブログ名やハンドル名など]です。全4回にわたってお送りしてきた「戦略的モダナイゼーション」の話も、いよいよ最終回です。
長かったですよね(笑)。でも、ここまで付き合ってくれた皆さんは、もう「全面刷新だ!」と息巻いていた昔の僕とは違う、プロフェッショナルな視点を持っているはずです。
- **「起」**では、海外の現場で「動くレガシーは価値である」という現実の壁にぶち当たりました。
- **「承」**では、そのレガシーを「止めずに」置き換える「ストラングラー・フィグ」という外科手術を学びました。(WCFをWeb APIで絞め殺す話でしたね)
- **「転」**では、アプリケーションは新しくなっても、レガシーDBの「腐敗」が新しいコードを汚染する問題に直面し、それを防ぐ「アンチ・コラプション・レイヤー(ACL)」という「防護壁」を立てました。
さて、ここで満足してはいけません。
「転」で立てたACLは、あくまで「防護壁」です。
新しいWeb APIは、ACLという「通訳」を介して、相変わらずあの180カラムある古いレガシーDBを読み書きしているわけです。
これでは、本当の「近代化」は終わっていません。
僕たちの本当のゴールは、あの古いトラクターの車体(レガシーDB)を、F1カーの車体(Azure SQL Databaseとかのクリーンな新DB)に入れ替えることです。
ACLは、そのための「時間稼ぎ」であり、そして「最強の武器」だったのです。
ACLを進化させる「真のデータ移行」
「ストラングラー・フィグ」がアプリケーション(経路)の移行戦略だったのに対し、**ACLはデータ(実体)の移行戦略の「中核」**になります。
僕のチームがACLを使って、どうやって古いDBから新しいクリーンなDBに「止めずに」移行したか。その最終ステップをお話しします。
これは、ACLを「進化」させるプロセスです。
フェーズ1:ACL = 翻訳・防護(「転」の段階)
- 状態: 新API <-> ACL <-> 旧DB
- 動き:
- 新APIからの読み書きリクエストは、ACLが「翻訳」して、すべて旧DBに流します。
- まだ新DBは存在しないか、あっても空っぽです。
- 目的: 新APIのコードを「腐敗」から守ること。
フェーズ2:ACL = デュアル・ライト(並行書き込み)
- 状態: 新API <-> ACL -> 旧DB & 新DB
- 動き:
- 新APIから「書き込み」(Create/Update/Delete)リクエストが来たら、ACLはそれを両方に書き込みます。
- レガシーな形式に翻訳して、旧DBに書き込む。(古いWPFアプリが読むため)
- クリーンな形式に翻訳して、新DBに書き込む。(未来のため)
- 「読み込み」(Read)リクエストは、まだ旧DBから返します。(データの正しさが保証されているため)
- 新APIから「書き込み」(Create/Update/Delete)リクエストが来たら、ACLはそれを両方に書き込みます。
- 目的: 新旧DBの「現在」のデータを同期させること。
この「デュアル・ライト」、言うのは簡単ですが実装は地獄です。片方のDB書き込みが失敗したらどうする?(トランザクション管理)とか。でも、ここがエンジニアの腕の見せ所。
フェーズ3:バックフィル(過去データの移行)
デュアル・ライトで「今、この瞬間」のデータは同期され始めました。
でも、過去10年分の古いデータは、まだ旧DBにしかありません。
そこで、**バッチ処理(バックグラウンド処理)**を動かします。
旧DBから全データを読み込み、ACLが持っている「翻訳ロジック」を使って、新DBにクリーンな形で一気に流し込みます。
- C#エンジニアの出番:
Azure Data FactoryのようなETLツールを使うこともありますが、ロジックが複雑な場合は、C#でコンソールアプリやAzure Functionsを書くことも多いです。- ACLプロジェクト(
MyNewApi.Infrastructure.LegacyDb.csproj)の翻訳ロジックを「ライブラリとして参照」できるので、効率よく移行ツールが作れます。
フェーズ4:リード・スイッチ(読み込み先の切り替え)
- 状態: 新API <-> ACL -> 旧DB(書き込みのみ) & 新DB(読み書き)
- 動き:
- バックフィルが完了し、新DBに「過去」と「現在」すべてのデータが揃いました。
- ここで、ACLの「読み込み」(Read)ロジックを、旧DBから新DBを参照するように切り替えます。
- 目的: 新APIを、ついに旧DBの「読み込み」から解放すること。
- リスク: もし新DBのデータに不備があっても、ACLのコードを元に戻すだけで、瞬時に旧DBの読み込みにロールバックできます。超低リスク。
フェーズ5:カットオーバー(旧DBの廃棄)
- 状態: 新API <-> ACL <-> 新DB
- 動き:
- 「ストラングラー・フィグ」が完了し、古いWPFアプリがすべてリタイアしたとします。
- もう旧DBに書き込む必要はなくなりました。
- ACLの「デュアル・ライト」ロジックを削除し、旧DBへの書き込みを停止します。
- 目的: ACLはついに「翻訳・防護壁」としての役目を終え、**「クリーンな新DBとだけ対話する、ただのリポジトリ層」**に進化しました。
これで、ミッションコンプリートです。
アプリケーションも、データも、すべてが新しくなりました。
しかも、一度もビジネス(システム)を止めることなく。
なぜ「モダナイズできるエンジニア」が重宝されるのか
さて、最初の「起」で提示したサブタイトルに、ようやく答えることができます。
なぜ「全面刷新(リプレイス)できるエンジニア」より、「近代化(モダナイズ)できるエンジニア」が海外で重宝されるのか。
それは、彼らが「ビジネス」と「リスク」を理解しているからです。
- 「全面刷新」エンジニア:
- 視点:技術的(古いのが嫌い、新しいのが好き)
- 行動:すべてを壊し、ゼロから作る(ビッグバン)
- リスク:「1年半後に失敗するかもしれない」という巨大な賭けに出る。その間、ビジネスは止まる。
- 価値観:技術的な美学(エゴ)
- 「戦略的近代化」エンジニア:
- 視点:ビジネス的(動いている価値を尊重する)
- 行動:ストラングラー・フィグやACLを使い、少しずつ、安全に入れ替える(インクリメンタル)
- リスク:一つ一つのステップが小さく、検証可能で、ロールバック可能。常にリスクを最小限に抑える。
- 価値観:ビジネスの継続性
海外、特に歴史あるヨーロッパの企業は、「巨大なリスクを取るギャンブラー」を好みません。それよりも、「最小限のリスクで、着実に未来へ導いてくれる外科医」を信頼します。
僕たちC# / WPFエンジニアが相手にしているのは、まさにこの「歴史ある基幹システム」です。
この「外科手術」をやり遂げるには、
古いWCFや.NET Frameworkの知識も、
新しいASP.NET CoreやAzureの知識も、
そして何より、古いDBの「腐敗」と向き合う忍耐力も必要です。
これは、最新フレームワークを追いかけるだけのエンジニアには真似できない、「時間の壁」を越えるスキルです。
結び:僕たちの市場価値
これから海外で働きたいと思っている皆さん。
もし、あなたの今の仕事が「レガシーシステムの保守」だとしても、絶対に腐らないでください。
その「レガシー」は、あなたの市場価値を爆上げしてくれる「宝の山」です。
「なぜこのコードはこうなったのか?」
「この汚いDBスキーマが、どういうビジネスを守ってきたのか?」
それを理解し、どうすれば「壊さず、育てる」ことができるかを考え抜いた経験こそが、海外の現場で「お、こいつは信頼できるな」と思われるための、最強のパスポートになります。
新しいものが作れるのは当たり前。
古いものを、未来につなげる。
そんなエンジニアを、目指してみませんか?

コメント