フランケンシュタイン とは、プログラミングにおいて、異なるテクノロジー、スタイル、アーキテクチャの互換性のない部分から組み立てられたコードのことです。ThoughtWorks Technology Radar(2024)の調査によると、大規模プロジェクトの28%にフランケンシュタイン症候群の兆候が見られます。これは、統一された技術的ビジョンの欠如から生じるアーキテクチャの折衷主義です。メアリー・シェリーの小説と同様に、そのようなコードは動作しますが、その保守は悪夢と化します。
重要なポイント
フランケンシュタイン(フランケンシュタインコード、フランケンシュタインパターン)は、ソフトウェアシステムが一緒に動作するように設計されていない部品から組み立てられるアンチパターンです。フランケンシュタインのモンスターのように、そのようなコードは動作しますが、醜く、予測不可能で、わずかな変更で危険です。
この用語は文学に由来します:メアリー・シェリーの小説「フランケンシュタイン、あるいは現代のプロメテウス」(1818年)では、科学者がさまざまな死体の断片から生き物を作り出しました。プログラミングでは、類推は正確です — 開発者はさまざまなフレームワーク、ライブラリ、言語の断片を取得し、それらを「生きたまま」接着して、動作するが恐ろしい結果を得ます。
フランケンシュタインとスパゲッティコードの違いは、規模と性質にあります。スパゲッティコードは、単一のテクノロジースタック内の絡み合った構造です。フランケンシュタインは、アーキテクチャレベルでの折衷主義です:同じシステム内で異なるテクノロジー、互換性のないパラダイム、対立するアプローチ。
マイクロサービスアーキテクチャは、異なるサービスに対して異なるテクノロジーの使用を許可しますが、明確な境界と標準化された相互作用プロトコルを条件とします。フランケンシュタインは、境界のない混沌とした混合です:同じコントローラにRESTとGraphQL、同じモジュールに2つのORM、同じエンティティにSQLとNoSQL。
テクニカルリーダーまたはアーキテクトの不在が根本原因です。プロジェクトにアーキテクチャの整合性を担当する人物がいない場合、各開発者は「自分のために」ツールを選択します。ある者はSpringを好み、別の者はGuiceを、3人目はカスタムDIを使用します。結果はアーキテクチャのごちゃ混ぜです。
プロジェクトの統合は2番目に多い原因です。2つのチームが異なるスタックを使用して、独立してモジュールを開発しました。モジュールを1つのアプリケーションに結合する必要がある場合、アダプターとミドルウェアで単に「接着」されます。結果はフランケンシュタインです。
企業買収は3番目のシナリオです。企業Aが企業Bを買収し、その製品を自社に統合したいと考えています。書き直しの代わりに — API、共有データベース、パッチを介した接着。1年後、システムは誰も理解できないモンスターに変わります。
| 原因 | 説明 | 典型的な結果 |
|---|---|---|
| アーキテクト不在 | 各開発者が自分のスタックを選択 | 1つのモジュールに3つの異なるHTTPクライアント |
| プロジェクト統合 | 2つの製品が1つに接着される | 2つのORM、2つのログ方法 |
| M&A | 製品ごと企業を買収 | 異なるアーキテクチャとスタイルのハイブリッド |
| 実験 | 戦略なしで新技術を導入 | 1つのファイルにJava 8 + Java 21の機能 |
| 政治的決定 | 文脈なしに上から技術を押し付け | 単純なスクリプトにエンタープライズフレームワーク |
経験豊富な開発者は、本番環境で新しい技術を試したいと考え、しばしばフランケンシュタインの源泉となります。実験を隔離されたモジュールに制限する代わりに、システムの重要な部分に実験的なコードを導入します。
古典的な例は、1つのアプリケーションでの複数のORMの使用です。一部のモジュールはHibernateを使用し、一部はMyBatis、一部は直接JDBCクエリを使用します。トランザクションは管理不能になり、キャッシュは不整合になり、新しい開発者は新しい機能にどのアプローチを使用すべきかわかりません。
2番目の例は、アーキテクチャスタイルの混合です。REST APIコントローラに、SOAPサービス呼び出し、直接SQLクエリ、ファイルシステムアクセス、HTML生成が見られます。そのようなアプリケーションのテスト、拡張、文書化は不可能です。
3番目の例は、バックエンドにPython、マイクロサービスにNode.js、デスクトップクライアントにC#、AndroidアプリにJavaが使用され、すべてのビジネスロジックが責任の明確な分離なしにそれらの間に散らばっているテクノロジースタックです。
// フランケンシュタイン — 混合スタイルとテクノロジー
// callbacks、Promises、async/awaitの組み合わせ
// callbacks
db.query("SELECT * FROM users", function(err, rows) {
if (err) handleError(err);
// callback内のPromise
fetch("/api/data").then(function(data) {
// then内のasync/await
(async () => {
const result = await processData(data);
sendResponse(result);
})();
});
});
// クリーンコード — 統一されたasync/awaitスタイル
async function getUserData(userId) {
const user = await db.query("SELECT * FROM users WHERE id = ?", [userId]);
const data = await fetch("/api/data/" + userId);
return await processData(user, data);
}
1つのデータベースが、SQLリレーショナル(正規化あり)およびNoSQLドキュメント指向(JSON列あり)として同時に使用されます。一部のクエリはORMを介して、一部はストアドプロシージャを介して、一部はコードからの直接SQLを介して実行されます。DBスキーマは文書化されておらず、マイグレーションは競合します。
オンボーディングの複雑さが最初の結果です。新しい開発者は、システムの動作を理解するために5つの言語、3つのフレームワーク、2つのアーキテクチャスタイルを知っている必要があります。オンボーディングは数週間から数ヶ月に及びます。LinkedIn(2023)によると、技術的折衷主義のプロジェクトは新しい従業員を2倍頻繁に失います。
動作の予測不可能性が2番目の結果です。Pythonマイクロサービスの変更が、明確な契約なしにデータベースを共有しているため、予期せずJavaモジュールを壊す可能性があります。そのような問題のデバッグには、スタック内のすべての技術の同時知識が必要です。
セキュリティが3番目の結果です。スタック内の各技術は、独自のセキュリティ設定、独自のパッチ、独自の監視を必要とします。5〜6の異種技術で許容可能なレベルのセキュリティを維持することは実質的に不可能です。そのうちの1つは必然的に脆弱になります。
SonarQubeは技術的負債を測定できますが、「アーキテクチャ負債」— コンポーネントの非互換性を測定することはできません。この負債は、リンターの警告ではなく、異なる技術で書かれた3つの異なるモジュールを変更せずに新しい機能を追加できないことに現れます。
最初のそして主要なステップは、テクノロジースタックの整合性に責任を持つアーキテクトまたはテックリードを任命することです。この人物は、アーキテクチャレビューなしでの新技術の導入に対する拒否権を持ちます。民主主義ではなく、主要技術に関する責任ある単独決定です。
2番目 — Architecture Decision Record(ADR)プロセスの導入。重要なアーキテクチャ上の決定(DB、フレームワーク、プロトコルの選択)は、短いテキストとして文書化されます:コンテキスト、検討された代替案、下された決定、結果。ADRはリポジトリに保存され、チーム全体が利用できます。
3番目 — 「1つのタスク — 1つのツール」の原則の確立。HTTPリクエストには1つのクライアント。ORMには1つのライブラリ。ロギングには1つのフレームワーク。例外は正当化を伴うADRを介してのみ許可されます。プロジェクトにすでにAxiosがある場合 — fetchを追加しないでください。SLF4Jがある場合 — System.outを介して書き込まないでください。
実験は許可されていますが、隔離された環境で。システムの残りに影響を与えずに新しい技術で書き直すことができるモジュールまたはサービスを割り当てます。実験が成功した場合 — ADRを介して標準化します。失敗した場合 — 結果なしに削除します。
棚卸し — 最初のステップ。テクノロジースタックの完全なマップを作成します:どのフレームワーク、ライブラリ、言語、プロトコルがどのモジュールでどのタスクに使用されているか。問題の規模がわかります:ツールの重複、競合するテクノロジー、未使用の依存関係。
標準化 — 2番目のステップ。各タスクに1つのツールを選択します。例:ORMにはHibernateのみ、ロギングにはSLF4J + Logbackのみ、APIにはRESTのみ。ADRに標準を文書化します。折衷主義が最も問題を引き起こすモジュールから置き換えを始めます。
Parallel Run戦略 — 3番目のステップ。古いツールと新しいツールは、新しいツールが信頼性を証明するまで並行して動作します。たとえば、古いHTTPクライアントと新しいものが同時に動作しますが、新しいものはリクエストの一部のみを処理します。安定化期間の後、古いものは削除されます。
// フランケンシュタイン — 1つのプロジェクトに3つのHTTPアプローチ
// モジュールA: OkHttp
OkHttpClient client = new OkHttpClient().newCall(request);
// モジュールB: RestTemplate (Spring)
restTemplate.getForObject(url, String.class);
// モジュールC: java.net.HttpURLConnection
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
// 統一アプローチ:同期にはRestTemplate、リアクティブにはWebClient
@Autowired
private RestTemplate restTemplate;
public String callApi(String url) {
return restTemplate.getForObject(url, String.class);
}
テクニカルリーダーは、フランケンシュタインと戦うための主要なツールです。マネージャーでも、象牙の塔のアーキテクトでもなく、コードを書き、PRをレビューし、アーキテクチャ上の決定を行う実践的な開発者です。そのような人物なしでは、プロジェクトは必然的に技術的折衷主義に陥ります。
RFC(Request for Comments)は、オープンソースコミュニティから借用されたプロセスです。重要な技術を導入する前に、作成者はRFCを書きます:問題、提案された解決策、代替案、実装計画。チームは議論し、投票し、承認または拒否します。RFCは透明性を生み出し、「静かな」アーキテクチャ上の決定を防ぎます。
技術レーダー(ThoughtWorks Technology Radar)は分類ツールです:Adopt、Trial、Assess、Hold。チームは定期的にレーダーをレビューし、ステータスを更新します。これは「トレンディ」と「有用」を区別し、未検証の技術を重要なコードに導入するのを避けるのに役立ちます。
アーキテクチャの最も重要な品質は一貫性(consistency)です。プロジェクト全体で使用されるあまり良くないツールでも、1つのモジュールでのみ使用される最良のツールよりも優れています。一貫性は認知負荷を減らし、オンボーディングを簡素化し、コードを予測可能にします。
よくある質問
Polyglot persistenceは、異なるタスクに異なるDBを意識的に使用することです(PostgreSQLはトランザクション、Redisはキャッシュ、Elasticsearchは検索)。フランケンシュタインは戦略のない混沌とした混合です。違いはアーキテクチャ上の決定の有無にあります:polyglotは計画であり、フランケンシュタインはその欠如です。
はい、これはよくある問題です。各マイクロサービスが中央集権的な標準なしに独自の言語、独自のDB、独自のプロトコル、独自のデプロイメントアプローチを使用する場合 — 分散型フランケンシュタインが生まれます。マイクロサービスには、共通の標準が重要です:統一プロトコル(REST/gRPC)、共通のログ形式、集中化された可観測性。
禁止するのではなく — 導きましょう。作成者にRFCを書くよう提案します:なぜ既存の解決策が適切でないか、どのような代替案が検討されたか、どのように移行するかを説明します。多くの場合、RFCを書く過程で、開発者自身が新しい技術は必要ないと理解します。RFCが説得力がある場合 — 実装しますが、計画と制約をもって。
最初に棚卸し、次に標準化。すべてを一度に書き換えようとしないでください。1つのレイヤー(例:HTTPクライアントまたはロギング)を選択し、1つのツールを選び、ADRを書き、段階的に移行します。Strangler Figパターン — アプリケーションを停止せずに、古いコンポーネントを1つずつ新しいものと交換します。
少なければ少ないほど良いです。理想的には — 1つの言語、1つのフレームワーク、1つのDB、1つのログ方法。現実的には — 2〜3の言語(明確な分割あり)、1〜2のDB、1〜2のフレームワーク。追加の技術ごとに、チームの認知負荷と保守コストが増加します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。