レガシーアプリケーションのストラングレーション:事例集

原文:ThoughtWorks の Paul Hammant のブログ記事 Legacy Application Strangulation : Case Studies

Strangulation を英和辞書で引くと「絞殺」とかぶっそうな言葉しか出てこないので訳文ではカタカナにしています。


アプリケーションのStrangler

Martin Fowlerが「Strangler Application」というタイトルの記事を書いたのは2004年のことだった。 レガシーアプリケーションや不適切なソリューションを止めて、より優れた、より安価な、より拡張性を備えた状態へ移行するための安全な方法が紹介されている。元から動いているものの一部を新しく開発したもので置き換え、しばらく共存させるのだ。システム全体を停止することなく、徐々に置き換えていく。Webアプリケーションだったら次のようになる。

古いソリューションの備えた全ての機能を新しいソリューションへ置き換えることを目的として、一連のリリースを行う。会社によっては、他に何か始める前にソリューションを適切な状態に整えることに合理性を見出すだろう。だが、どれくらいの時間がかかるにせよ、開発チームに属していない人には移行している期間は何も成果を挙げていないように見えるし、たとえ事前に相談されていたとしてもそう考えてしまうだろう。費用を出している側の役員や重役会議のメンバー、バランスシートを気にしているステークホルダーもやがてそれに気付いて、文句を言ってくるかもしれない。

ストラングレーションと同時に新しい機能を組み込むようにすると、設備投資の観点から正当化しやすくて良いだろう。だが、ビッグバンリリースにならないように気をつけなければならない。目に見えるような結果がでなければ、財布を握っている人から文句を言われてしまうだろうからだ。どれだけ整然とした計画をたてたとしても、何度目かのリリースの後に行われる予算計画の見直しで中止になる可能性がある。書き直すために費やした苦労はプロジェクトの中断による衝撃を増すことになるので、ビッグバンアプローチはリスクを高めるだけなのだ。

事例

とある航空会社のオンライン予約システム

事例として紹介する航空会社は、かなり早い時期にチケットの売り上げを増やすための仕組みをWebに移行した。90年代の中頃の話だ。アプリケーションはNSAPI プラグインをC++言語で実装したものだった。

2008年のC++スタックの安定性や性能はいまいちで、任意のWebサイトやWebアプリケーションを拡張する基盤を開発するための環境として使い物にならなかった。それに、他の新しい言語と比べて開発者を集めるのも一苦労だった。

クライアントはJavaやSpringを望んでいたが、最新のテクノロジーのどれを使っていても同じだったと思う。この事例の見どころは、C++スタックによるアプリケーションと刷新した新しいアプリケーションを商用環境で同時に利用していたところだ。URLをベースに単純な機能分割をして、ロードバランサーでリクエストを振り分けるようにした。2つのアプリケーションは同一のセッション方式を採用していたし、セッション情報を共有するようにしていた。そのため、従来型のユーザー体験にこだわる利用者を強制的にリダイレクトさせることもできた。決して簡単なことではなかったが、「後方互換性」という観点を完全に満たすことができていた。

PoCの後、ThoughtWorksのメンバー(Kent SpillnerやJessica Austin)および Scaper solution のメンバーが中心となり、現行のWebサイトを利用して、新しいテクノロジーによる実証実験(プロトタイピングの説明を参照)を行った。その後、アプリケーションを全面的に移行するための数年間におよぶ移行計画をたてた。計画策定と実施には何社ものコンサルタントが関わっており、Thoughtworks はその中の1社でしかなかった。開発はいくつものタイムゾーンをまたぐ複数の都市で同時に進められ、一番忙しい時期には100人ものメンバーがコミット権限を持っていた。

ストラングレーションの開始となる最初のリリースは2009年に行われた。そこから、リリースの規模は異なるものの6週間から8週間ごとに進められた。Stranglerリリースが完了したのは2011年のことだった。ストラングレーション期間中に行われた全ての大規模なリリースは、既存のC++スタックを部分的に取り出したものだった。新しいアプリケーションに移行するとき、予算に余裕のある一部の機能を強化することができた。

私個人の最大の貢献はリリースの順序を守らせるために全ての作業を一箇所に収めるよう腐心したことだ。実装も手伝った。

とある貿易会社の取引記録システム

この事例については、当時の同僚 Chris Stevenson とアジャイルコミュニティの友人である Andy Pols が XP Conference 2004 に論文を投稿している。Martin Fowler の記事でも引用されている。

彼らは論文に「InkBlot」プロジェクト(実際の名前と異なるがよく似ている)のことを書いていた。私も当時同じクライアントのところに在籍していた。直接関わっているわけではなかったが、毎週その進み具合を見聞きすることができた。IT部門でエネルギー関連のトレーダーを担当している人(誰か一人というわけではない。彼らは年間数百億ドルもの収益を上げていた)が「職務変更プログラム」の一環として、私たちの開発チームと同じ場所で過ごしていたからだ。

そのときチームにいたのは、切れ者のシニア開発者たち( Joe Walnes、Nick Pomfret、Ben Hogan、Trevor Gordon )と、とても気性の穏やかなプロジェクトマネージャーの Martin Gill だった。Martin と Joe と Chris は ThoughtWorks のスタッフで、他は地元で活動しているフリーランスだった。ビジネスアナリストの Gavin Smith がピンストライプのスーツに身を包んだ様子が思い出される。

彼らは、クライアントのトップトレーダーが頻繁に利用している PowerBuilder のアプリケーションを扱うことになった。アプリケーションは Sybase データベースに接続するものだった。大規模なトレーディング会社では売買記録簿(Wipedia にないのは当然の言葉)が広く使われているが、進行中の取引を集めたデータセットの中でも本当に表面的なものしかなかった。アプリケーションにはデータもフロントエンドも備わっていたので、問題は最新のテクノロジーを取り込むことだった。そのときは Java+Swing を採用することになった。Webアプリケーションではなかったので、段階的に移行しながらリバースプロキシで1つのアプリケーションのように見せかけるテクニックを使うことはできなかった。

「InkBlot」は、古いシステムから新しいシステムへ段階的に機能を移行するプロジェクトだった。新しいアプリケーションが古いアプリケーションを完全に置き換えるまで、古いアプリケーションは商用環境で動かし続けることになる。その時が来るまで、両方のアプリケーションを利用し続けるのだ。これこそが ストラングレーション だ。以前なら、クライアントはアプリケーションを書き直すには長い時間が必要だと考えていたし、望ましい成果を得るには非常に大きな挑戦が必要になるとも考えていた。それゆえに、ストラングレーション 方式の採用をクライアントに納得してもらうのは簡単なことだった。ストラングレーション が済んだ後、開発チームは自ら技術的な課題の解決に向けて動き出した。

Joe は「InkBot」プロジェクトについて次のように回想している。

論文の中で Joe のお気に入りの箇所を引用する。私もここは気に入っている。 「私たちは決してユーザーに新しいシステムを強制しなかったし、古いシステムへのアクセスも防がなかった。古いシステムを使い続ける理由が無くなるほど魅力的なシステムを作ればいいと信じていたからだ。それは、私たちがユーザーの真の要求に答えようとしていたことにもなる。」

彼らはうまく設計された Swing アプリケーションを作ることができた。そして、トレーダーが Excel ファイルを開いていたら、DDE(Dynamoc Data Exchange)で通信できるようにもなっていた。前述したように、最初のリリースは読み取り専用で動くようになっており、何人かのトレーダーは毎日新しいバージョンを使ってくれていた。

Martin の記憶によると、コードベースの書き直しは3回では済まなかったそうだ。極めて高い生産性を誇る開発チームにとって書き直しは「新しい機能の提供を中止する」妨げにはならなかった。テスト駆動開発(TDD)をしていたので当たり前のように再設計をし、戦術的にも極めて安全に実装をやり直していた。別に計画していた機能の作り込みを並行して進めることを止める理由は何もなかったのだ。もちろん、共有しているtrunkにはたくさんのコミットが流れ込んでいた。アプリケーションが毎日展開される間に何度もコミットされていた。

開発チームは3日くらいのイテレーションで XP(eXtreme Programming)を行っていた。ストーリーはとても小規模で、何かが終わったらすぐに次のストーリーに着手するような、形式にこだわらない進め方をしていた。当時のアジャイルコミュニティではそれほど定着していなかったが、彼らのやっていたことはまさにリーン開発だったのだ。このプロジェクトについて書かれたホワイトペーパーでは、アジャイルマインドが達成したことを強調していた。

マルチテナント鉄道旅客券予約システム

この事例は、2008年から2011年にかけて Visual Basic 6 で実装されたシステムを.NET に移行する際に ストラングレーション を行ったものだ。最終的には ASP.NET に落ち着いたが、新機能を開発しながら進めたため、完了するまで数年を要したそうだ。古いシステムの新しいシステムが共存している期間は長く続いて、一番忙しい時期のリリース周期は6週間に1度だった。古いシステムを完全にリプレースして停止したあとは、本来の機能強化の計画にしたがって開発とリリースは継続していた。

かなり大規模なチーム構成だったが、早い時期に抽象化層やフィーチャートグルを実装し、ブランチモデルを Trunk-Based-Developmentに切り替えた。不具合を発見するまでの時間は極めて短く、それは改修コストを表した曲線にも反映されていた。

技術的な挑戦という意味では、まさに Model-View-Controller アーキテクチャの分解だった。流行に敏感なビジネス担当者は新しいシステムが世間でWeb2.0と呼んでいる振る舞いをしていることに気付いていた。そして、ユーザーストーリーで書かれていたバックログの大部分にはそのための設計意図が表されていた。古いシステムのコンポーネントごとに、利用者のニーズを満たすMVP(Minimal Viable Product)として新しいシステムへ置き換えられたのだった。ほぼ0に等しいと言えるほど単純な作業では済まないリスクもあったし、分割の境目を間違えばステークホルダーから中止を言い渡されるリスクもあった。どちらも、滅多に発生しないとも言えるし、いつでも発生しうるとも言えるものだった。

開発チームが全ての水準のテストを行った。ユニットテストのカバレッジは90%を記録していた。結合テストと機能テストでは ThoughtWorks の製品である Twist も使われており、規制当局から承認を得るまでの期間を短縮するのに役に立っていた。

個人情報管理ポータル

この事例では、2009年から2012年にかけてJavaで実装されたWebシステムを JRuby on Railsへ移行し、Web 2.0 のフィーチャーを追加している。移行というより、統合といったほうが正しいかもしれない。顧客の視点からすると、新しく開発した機能の割合が大きかったからだ。ストラングレーション は並行して進められていたが、エンドユーザーを驚かせないようにすることが優先されていた。

初年度は、4半期ごとに段階的ロールアウトを行った。次の半年間は毎月リリースしていた。プロジェクトの最後の年では、2週間ごとにリリースしていた。

ナショナルスーパーマーケットの仕入れ管理システム

この事例は、モノリシックアーキテクチャの仕入れ管理システムを使用している従来型スーパーマーケットのものだ。何年もかけて、データベースを中心に据えた Java + Swing システムを Rails とJavaのマイクロサービスに移行した。たとえば、データベースに組み込まれていた業務ロジックをマイクロサービス化するなど。新しいシステムでは、業務機能単位で分割したDVCSリポジトリを使用している。

前述の InkBot の事例のように、完全に異なるテクノロジーへ移行するための賢いプロキシは存在しない。エンドユーザーは社内ユーザーだったのでトレーニングをする時間を取ることができた。これはギャップを乗り越えるために有効だった。

計画するだけで、プログラムを移行するだけではすまない規模のプロジェクトになることがわかった。いまだに新しいシステムへ移行できていないシステムもいくつか存在するし、計画もだいぶ複雑になっている。価格交渉や仕入れ契約の交渉など、業務機能の明確なカテゴリに合わせて分割を検討した。重要な機能を移行するときの開発作業はきわめて忙しいものだった。ストラングレーション リリースをしたあとは目に見えて性能が改善し、依存関係グラフもずっとわかりやすくなった。

最初のリリースは、プロジェクトを開始してから数ヶ月たってからになった。その後毎月リリースを行っている。

当時の業務担当者たちはステークホルダーとしてストラングレーションの価値を認めてプロジェクトを支援してくれたし、今では全員が協力的になってくれている。

個人向け中古品販売カタログのWebポータルシステム

このプロジェクトは、Oracle Endeca から Java/Javascript へ移行するもので、たくさんの小さなアプリケーションを単一のアーキテクチャへ統合するものだった。発展性という観点では、数年前のことだけど ストラングレーションには1年間かかった。クライアントはリリースごとの差分を確認できるようにすることを望んでいた。エンドユーザーが失望してしまわないように願っていたからだ。そのため、ストラングレーション が終わる頃、ロールアウトの計画に A/B テストが組み込まれた。

古いシステムに組み込まれていたデザインやインタラクティブ性のある拡張機能は、再構築して早い時期に新しいシステムにも組み込まれた。最終的にはこのコードは削除するつもりだったそうだ。読者からすると無駄なことをしているように思うかもしれない。確かに本来の ストラングレーション ではないが、コストとリスクのバランスを取る一般的な戦略だったのだ。おかげで、プロキシを介してアクセスするエンドユーザーは一貫したユーザー体験を得て、満足してくれた。

プロジェクトにとって、利用者が主として売りに出している商品こそが、一番重要なものだった。プロジェクトが終わりに近づくにつれて、付属品のような商品カテゴリを設けることも視野に入れられるようになった。

本質的に古いシステムを覆い隠すことについて懐疑的な意見もあったが、ロールアウトしてからそれが正解であることがわかった。最初のストラングレーションリリースには約6ヶ月かかった。その後は、毎週のリリースを数ヶ月続けた。毎週のリリースが遅すぎる、ということであれば、ビジネス担当者が望んでいた利用状況を丁寧に分析できる機能が、開発を遅らせている要因だった。

さらなる情報源

A ThoughtWorks Quarterly Technology Briefing

2010年の Quarterly Technology Briefing で、ThoughtWorks の Amit Uttam と Derek Longmuir は、うまく行かなかったビッグバンリリースの事例としてハーシーズ、FBI、Windows Vista について講演している。

Pretotyping

www.pretotyping.orgを参照。

2人のGoogler(Alberto Savoia と Patrick Copeland)とその同僚である Jelemy Clark が中心人物だ。彼らがアプリケーションを構築する方法は、それが次善の策であっても、やがてはリプレースするのだとしても、元のシステムを利用できるようにしておくことが前提になっている。Pretotyping の優位性は簡易的なプロトタイピングと、失敗や中断を素早く判断することにある。とても説明しきれるものでもないので、興味があるなら彼らの紹介動画を見て欲しい。

クライスラーのC3プロジェクト

アジャイルの光の戦士 Ron Jeffries は、10年たった今でもクライスラーにおけるC3プロジェクトの中断のことを覚えているという。

我々は壊れた部品を置き換えなければならない。

1度に1つだけ、一番価値のあるものからだ。

彼が後悔しているのは新しいシステムへ移行するのに ストラングレーション しなかったことだ。また、どの部品を優先するべきか(優先しないべきか)慎重に判断すればよかったと思っている。

ストラングレーション に関する他の情報

ここまで紹介したとおり、ストラングレーション が特に適しているURLの使い方がある。C++から他の近代的なテクノロジーに移行する事例はまさにそのようなものだった。JavaからRuby/Rails への移行も同じやり方でできるだろうし、同じJavaでもリファクタリングの難しいフレームワークから移行することもできるだろう。数多くの利点がある。そのためには、書き直しをする代わりに、コードを移植して、育てて、ユニットテストを追加していくことになるだろう。

私が以前に書いた「シングルトン脱出計画」では、ストラングレーション しないところを除いて大きな違いはなく、完全なリプレースより機能分割して漸進的に改善していく方法を説明している。

技術的にはロードバランサーを使えばよい話だ。もっとも、すでに「リバースプロキシ」を導入しているなら技術的に変わりはない。Apache のモジュールを使ってもいいし、HAProxyを使ってもいい。アジャイルコミュニティの知人である Joshua Gough はストラングレーションを詳しく説明する記事の中でWebアプリケーションにおけるリプレースの効果について触れている。URLをよく見ていれば、裏で2つのアプリケーションが動作していることは分かるが、ユーザー体験としてその違いはまったくわからない。私は古いシステムと新しいシステムへリクエストを振り分けるプロキシを配置するのがよいと思う。少なくとも、アプリケーションの機能に対してURL中のディレクトリ部分が別れているとしたら、古いシステムから新しいシステムへの移行は安全に進められるだろう。

同僚の Jez Humble は、Branch by Absraction の考え方とストラングレーションとの関係を説明する記事を書いている。彼の記事では、フィーチャートグルや優れたオブジェクト指向設計のプラクティスについても言及している。

ベストプラクティス

Andy Pols と Chris Stevenson の論文には目を通しておくべきベストプラクティスが紹介されている。Joshua Gough の記事ではもう少し詳しい内容が紹介されている。読んだほうがよい。

10年間 InkBot に関わってきた ThoughtWorks の同僚と会話した上での私の見解を述べる。

  1. ストラングレーションは段階的に進めるべきだ。アプリケーションは常にデプロイできる状態を維持しなければならない。最初のリリースは1ヶ月以内に、以降のリリースは少なくとも2週間ごとにしなければならない。できなければ失敗するだろう。おそらくスポンサーからプロジェクトの中止が言い渡されるからだ。
  2. 全員が合意した上で、ストラングレーション と並行して既存機能の拡張や新たな「ビジネス価値」を追加するようにしなければならない。ストラングレーションの作業を進めながらも、ある程度の時間を機能拡張に費やすべきだ。それは、それぞれのリリースについて、費用を払う側の立場から見た価値を与えるためだ。ROIという言葉には、IT設備がEOLを迎えるまでに費やすコストを表すと同時に、システムが改善したことを実感するための尺度という側面がある。関係者全員が新しいリリースを期待するような状況を形成しなければならない。
  3. 結合テストや機能テストについて、テストスイートを追加することが重要だ。ほとんどの場合、古いシステムのユニットテストカバレッジはそれほど高くない。機能テストがあれば、古いシステムから新しいシステム(あるいはその逆)へ移行するときのトラブルを未然に防ぐことができるだろう。
  4. 非機能要件(NFR)を気にして安易な再実装をするべきではない、という考え方をしていると、プロジェクトの主導権が危険にさらされるかもしれない。「中止したい派」の勢力が大きくなる可能性があるのだ。お偉いさんの中には、お気に入りのテクノロジーを使わせて、嫌いなテクノロジーを排除したがる人がいる。テストは、開発チームの中に賛成派と反対派を生み出すだろう。
  5. アジャイルなやり方は、開発者の生産性と商用環境への段階的なデリバリー回数を最大化してくれる。商用環境へのリリース間隔をずっと長くしたいのでなければ、ストラングレーション にウォーターフォールを採用するべきではない。Pols と Stevenson の論文はアジャイル開発の問答集としても優秀だ。
  6. 最後に、ユーザーも覚えていないような隠された背景とそこに依存した機能が存在する可能性に注意しよう。そして、ビジネスアナリストがリバースエンジニアリングした振る舞いが間違っている可能性を忘れないこと。これは「書き直し」をするならどんなときでも起こりうるリスクとなる。