開発者が初めて大規模なレガシーコードベースを開きます。顧客レコードがアカウント閉鎖時にどうなるかを理解する必要があります。どのプログラムがそれを更新し、どのバッチジョブがその後それを読み取り、どのフィールドが途中で変更され、下流のシステムが最終状態に依存しているかどうかです。当然、最初に行うのは検索です。フィールド名をgrepで検索し、結果をスキャンし、いくつかのファイルを開いて読み始めます。1時間以内に、12個のプログラム、3つのSQLスクリプト、および1つのJCLジョブストリームで参照を見つけました。また、17個のコメントブロック、4つのログフォーマット文字列、2つのテストフィクスチャ、および全く関係のないサブシステムの変数で同じフィールド名を見つけました。検索結果だけでは、これらのうちどれが実際のデータ読み取りで、どれが書き込みで、どれが変換で、どれが偶然の名前の衝突なのかを判断できません。フィールドの名前はわかっていますが、コードがそれをどのように処理しているかはまだわかりません。
文字列の検索とコードの理解の間のこのギャップは、検索機能の向上によって埋められるものではありません。これは、根本的に異なる2種類の質問の間のギャップです。1つは「このテキストはどこに現れるか?」という質問、もう1つは「このコードは何をするのか?」という質問です。テキスト検索は最初の質問に対する優れた回答ですが、2番目の質問に対する回答には全くなり得ません。この2つを混同することは、ソフトウェア開発において、無駄な労力、見落とした依存関係、誤った影響評価の最も一貫した原因の1つです。この区別は、小規模な最新のコードベースよりも、大規模で異種混在のエンタープライズシステムにおいてより重要です。なぜなら、これらのシステムには、ソースファイルに表示される文字列ではなく、コードの動作にのみ存在する、数十年にわたる蓄積された構造、言語間の依存関係、および暗黙の関係が含まれているからです。コード品質メトリクスとその影響の分析で検討したように、コードベースの複雑さは保守性に大きな影響を与え、テキストパターンのみから導き出されたメトリクスは、コードが実際にどのように動作するかを決定する構造的な関係を捉えることはできません。
テキスト検索の実際の機能
テキスト検索は、生の文字シーケンスとして扱われるファイルに対して適用される部分文字列照合操作です。クエリは文字列またはパターンです。結果は、そのパターンが出現する場所のリストです。このツールは、ファイルが記述されている言語、テキストの構造を決定する文法、およびテキストが表すコード要素間の関係のモデルについて何も知りません。100万行のCOBOLソースに対するgrepは、100万行のHTMLに対するgrepと同じモデルで動作します。つまり、ファイルパスごとにグループ化されたファイル内の文字シーケンスが、文字シーケンスが一致した場合に返されます。
これは、特定の種類のタスクに非常に役立ちます。既知の文字列が出現する場所の検索、特定の用語が使用されているか、または使用されていないかの確認、命名規則の簡単な妥当性チェック、特定のエラーメッセージを含むファイルの特定などです。これらのタスクでは、文字列の検索がまさに目的であるため、テキスト検索が最適なツールとなります。grepとその同等のツールの速度、移植性、設定不要という特性は、「この文字列はこれらのファイルに存在するか、存在する場合はどこにあるのか」という質問にまさにぴったりです。
問題は、文字列に関係のない質問にテキスト検索を使用した場合に発生します。「この関数を呼び出すのは何か?」という質問は、関数名がどこに現れるかという質問ではありません。これは呼び出しグラフに関する質問であり、呼び出しグラフはコードの構造的特性であり、構築するには構文解析と意味解析が必要です。「このフィールドはどこに書き込まれているか?」という質問は、フィールド名がどこに現れるかという質問ではありません。これはデータフローに関する質問であり、答えるには特定の言語における代入意味論を理解する必要があります。「このインターフェースを変更すると何が壊れるか?」という質問は、インターフェース名がどこに現れるかという質問ではありません。これは依存関係に関する質問であり、正しく答えるにはインポート、継承、モジュール間の結合を解決する必要があります。
これらの質問はいずれも名前を起点としているため、検索タスクとして扱いたくなるかもしれません。しかし、名前はあくまでも入り口に過ぎません。答えはソースファイルのテキストではなく、コードの構造モデルの中に存在します。
ノイズ問題:意味のない結果が多すぎる
コード理解タスクに適用されるテキスト検索の最初の失敗モードは、過剰生産です。つまり、関連性のある結果よりもはるかに多くの結果が返され、どの結果が構造的に重要で、どの結果が偶然の一致であるかを識別するメカニズムがないということです。
短い識別子 status, id, typeまたは date 大規模なコードベースでは、このような識別子が何千回も出現する可能性があります。さらに長い識別子は、言語や名前空間をまたいで衝突します。 calculate_tax Pythonモジュールの関数名、COBOLの段落名、データベースのストアドプロシージャ、JavaScriptヘルパー、ログ設定の文字列など、いずれの文字列に対しても、一致するテキスト検索結果が生成されます。これらの結果を受け取る開発者は、コードに関する自身の理解に基づいて、関連する出現箇所を手動でフィルタリングする必要があります。この手動フィルタリング自体がコード理解の作業であり、つまり開発者はツールの支援なしに、本来ツールが行うべき作業を行っていることになります。
実際には、開発者は直感と経験に基づいてフィルタリングを行います。テストファイル内の結果は、おそらく本番環境での呼び出しではないと認識します。コメントブロック内の結果は、呼び出しではなくドキュメントであると認識します。無関係だと考えるファイルの結果は無視します。しかし、これらのフィルタは誤りやすく、検証不可能です。自信を持ってフィルタリングする開発者が間違っている可能性もあります。慎重にフィルタリングする開発者は何時間も費やすかもしれません。そしてどちらの場合も、得られる結果は開発者の判断を反映した一連の発見であり、検証済みのコード構造分析ではありません。
具体的な例を考えてみましょう。COBOL開発者が段落名を削除する前に、その名前を検索するとします。
COBOL
SEARCH-RESULTS FOR "CALC-INTEREST":
1. CALC-INTEREST.PGM line 5 : IDENTIFICATION DIVISION.
2. CALC-INTEREST.PGM line 42 : CALC-INTEREST.
3. FINPROCESS.CBL line 178 : PERFORM CALC-INTEREST
4. RPTMONTH.CBL line 91 : * Old routine: CALC-INTEREST replaced by CALC-INT-V2
5. CUSTBATCH.CBL line 234 : PERFORM CALC-INTEREST THRU CALC-INTEREST-EXIT
6. DATADICT.txt line 12 : CALC-INTEREST - computes monthly interest for savings accts
7. TESTHARNESS.CBL line 67 : PERFORM CALC-INTEREST
8. ARCHIVEJOB.CBL line 156 : * PERFORM CALC-INTEREST (disabled 2019-03-14)
これら 8 つの結果のうち、段落を削除すると動作しなくなるアクティブな呼び出し元は、正確には 2 つです。それは 3 行目と 5 行目です。2 行目は定義です。4 行目と 8 行目はコメントです。6 行目はデータ ディクショナリのエントリです。7 行目はテスト ハーネスです。これら 8 つの結果のうち、どの 2 つが実際の呼び出し元であるかを判断するには、各ファイルを文脈の中で読み、COBOL 構文を理解し、8 行目のコメントにある「disabled」が実行時に実際に何を意味するのかを判断する必要があります。テキスト検索によって必要な情報が得られ、コードの理解によって答えが得られました。
沈黙問題:決して返されない関連性の高い結果
2つ目の失敗モードは、結果の過少生成です。これは、テキスト検索が一致できる形式で表現されていないために、構造的に重要な結果が欠落してしまうことを意味します。
間接呼び出しは、結果が見つからない最も一般的な原因です。関数 A が関数 B を呼び出し、関数 B が非推奨の関数 C を呼び出す場合、C の名前でテキスト検索を行うと、関数 B は直接呼び出し元として見つかりますが、関数 A は間接呼び出し元として見つかりません。A が関連する結果かどうかは、検索の目的によって異なります。C をトリガーするすべてのものを理解することが目的であれば、A は重要です。直接呼び出し元を見つけることだけが目的であれば、A は無関係です。テキスト検索は呼び出しグラフの概念を持たないため、この区別をできません。一致するテキストが何の一部であるかを認識することなく、一致するテキストを返します。
言語間参照は、体系的に欠落しているカテゴリです。ミドルウェア層を介して名前で COBOL プログラムを呼び出す Java サービスには、文字列リテラルとして COBOL プログラム名が含まれており、テキスト検索で見つけることができます。しかし、プログラム名を動的に構築したり、構成ファイルから読み取ったり、抽象化層を介してディスパッチしたりする同じ Java サービスには、名前がまったく含まれていません。これらは、テキスト検索をどれだけ徹底的に適用しても見つけることができない呼び出し元です。難読化され動的に生成されたコードの静的解析のコンテキストで検討されているように、実行パスが構成、テンプレート、または実行時ディスパッチメカニズムを介して間接的に表現されている場合、それらが表す構造的関係は、ソースファイルのテキストだけでは復元できません。
フィールドエイリアスと変換は、別の種類のサイレントミスを生み出します。 WS-ACCT-BAL これは、データベースの列に書き込まれます。 ACCT_BALANCEその後、Javaサービスによって読み取られる accountBalanceそして最終的には次のようにシリアル化されました account_balance JSONレスポンスでは、同じデータ要素に対して4つの異なるテキスト文字列が表現されます。これらの文字列のいずれか1つを検索しても、他の3つは見つかりません。4つすべてが同じ基となるビジネスコンセプトを指していることを理解するには、単一の名前のすべての出現箇所を探すのではなく、変換チェーンを理解する必要があります。
コード理解に実際に必要なこと
技術的な能力としてのコード理解とは、コードの表面的なテキストではなく、その構造と意味論に基づいて推論することで、コードに関する疑問に答える能力のことです。そのためには、コードが実際に何を言っているかだけでなく、それが何を意味するのかを表すコードモデルを構築し、それを照会する必要があります。
大規模エンタープライズシステムにおける開発タスクをサポートするために必要なレベルのコード理解に関する最低限の技術要件は、相当なものです。それぞれが、テキスト検索では実現できない機能であり、テキスト検索と手作業を組み合わせても、大規模なシステムで確実に再現することはできません。
構文解析:テキストから構造へ
テキスト検索の次の段階は構文解析です。これは、ソースコードをその言語の文法に従って読み込み、コード要素間の構文関係をエンコードする構造化された表現(通常は抽象構文木)を生成することです。 PERFORM CALC-INTEREST THRU CALC-INTEREST-EXIT これは文字列ではなく、範囲ターゲットを持つ PERFORM ステートメントであることを識別する構造化オブジェクトです。両端点は現在のプログラム内の段落名であり、プログラムの PROCEDURE DIVISION 構造に対して解決可能です。
構文解析は言語固有のものです。COBOLパーサーはCOBOLの文法を理解し、JavaパーサーはJavaの文法を理解し、JCLパーサーはJCLの構文を理解します。多言語エンタープライズシステムでは、コードを理解するには、環境に存在するすべての言語に対応するパーサーが必要であり、言語間で一貫した方法で推論できる構造表現を生成します。エンタープライズ規模でのTypeScript静的解析の詳細な検討で説明したように、コードの構成方法、モジュール間の相互作用、アプリケーションを介した制御とデータの流れを理解する構造的および意味的解析は、構文チェックを超えて真のコードインテリジェンスを実現するための基礎となります。
シンボル解決:名前からエンティティへ
解析後、ソースコード内の名前は、それが参照するエンティティに解決されなければなりません。識別子 CALC-INTEREST PERFORM ステートメント内のメソッド名は、特定のプログラムまたはコピーブック内の特定の段落定義に解決されなければなりません。 calculateLegacyFee Java呼び出しでは、継承とオーバーロードを考慮して、特定のクラスの特定のメソッド定義に解決する必要があります。列名 ACCT_BALANCE SQLクエリでは、データベーススキーマ内の特定のテーブルの特定の列に解決される必要があります。
シンボル解決とは、文字列の名前を、場所、型、および他のエンティティとの関係を持つ、特定で識別可能なコードエンティティへの参照に変換する機能です。シンボル解決がない場合、すべてのコードクエリはテキストクエリになります。シンボル解決を使用すると、「この関数のすべての呼び出し元」に対するクエリは、解決済みの呼び出し関係グラフに対する構造クエリとなり、関数名がたまたま出現するすべてのファイルではなく、実際に特定の関数を呼び出している結果のみが返されます。
多言語環境では、同じ概念が言語の境界を越えて異なる名称で呼ばれるため、記号の解決は劇的に複雑になります。言語間インデックス作成による平均復旧時間の短縮というより広い文脈で検討される、フィールド等価性の言語間解決は、言語境界を越えてデータや制御の流れを追跡するあらゆる構造分析の前提条件です。これがなければ、分析は境界で終了し、得られる理解は不完全なものとなります。
制御フロー分析:実行パスの理解
制御フロー解析は、プログラムの実行経路をマッピングします。どの分岐がどのような条件下で実行されるか、どのステートメントに到達可能か、どのコードパスが実行不可能か、そしてステートメントが互いにどのような順序で実行されるかを示します。この情報は制御フローグラフとして表現され、ノードは順次実行されるコードの基本ブロックを表し、エッジは条件付きまたは無条件の制御の移譲を表します。
制御フロー分析によって、「このコードパスはどのような条件下で実行されるのか?」や「このコードはどのエントリポイントからでも到達可能か?」といった疑問に答えることが可能になります。テキスト検索では、これらの疑問に答えることはできません。なぜなら、テキスト検索は文字列の出現場所ではなく、実行パスに関するものだからです。ソースコードに記述されたステートメントは、そのステートメントが存在する分岐を制御する条件によって、実行される場合と実行されない場合があります。モジュール内で定義された関数は、実行パスが呼び出し箇所に到達するかどうかによって、呼び出される場合と呼び出されない場合があります。これらの特性を判断できるのは、制御フロー分析だけです。モダナイゼーションにおける静的コードの問題の優先順位付けに関する検討で述べたように、実際にどのコードパスが実行されるか、どのくらいの頻度で実行されるか、どのような条件下で実行されるかを理解することが、実用的な分析と、重要に見えるものの運用上の現実を反映していない発見を区別する鍵となります。
データフロー分析:コードを通して値を追跡する
データフロー分析は、プログラム内での値の移動経路を追跡します。具体的には、変数がどこで代入されるか、どこでその値が読み取られるか、代入と使用の間にどのような変換が適用されるか、そしてある変数の値が別の変数の値に依存するかどうかなどを調べます。この情報は、「このフィールドの値はどこから来るのか?」や「このフィールドの値が変更されると、どのコードが影響を受けるのか?」といった疑問に答えるのに役立ちます。
データフロー分析は、値レベルでのフィールドトレース、汚染分析、および依存関係追跡の技術的基盤です。プログラムの制御フローグラフ上で動作し、実行パスに沿って値情報を伝播させ、値の発生源、流れ、消費場所を記録します。その結果、ソースファイルのシーケンシャルテキスト内だけでなく、プログラムの実行空間全体にわたって定義と使用箇所を関連付けるデータフローグラフが作成されます。
エンタープライズシステムでは、データフロー分析が有用であるためには、言語の境界を越える必要があります。COBOLプログラムで生成され、データベースへの書き込みを経て、Javaサービスによって読み取られる値は、2つの言語の境界を越えるデータフローを持ちます。このフローを追跡するには、COBOLの代入セマンティクス、SQLのデータ移動、Javaの変数代入を、結果を手動で接続する必要のある3つの別々の分析としてではなく、同じ統合された分析の一部として理解するデータフロー分析が必要です。COBOLの専門家から現代の開発チームへの知識移転の分析で詳しく説明されているように、複雑なCOBOLシステムを現代の開発者が言語を習得することなく理解できるようにするには、ソーステキストを超越した形式でシステムの動作を表現できる構造分析が必要です。
違いが最も重要となるタスク
テキスト検索とコード理解の区別は、学術的なものではありません。それは、特定の、リスクの高い開発タスクにおいて顕著に現れます。そのようなタスクでは、間違ったツールを使用すると、一見完全に見える結果が生成されますが、実際にはそうではなく、不完全な結果に基づいて行動すると、測定可能な結果が生じる可能性があります。
変更を行う前に影響分析を行う
関数シグネチャの変更、フィールド名の変更、共有ユーティリティの動作変更を行う前に、開発者は影響を受ける要素を把握する必要があります。これが影響分析です。影響分析では、変更対象の要素に依存するすべてのコンポーネントを列挙し、変更を安全に実行し、影響を受けるすべてのコンポーネントを更新できるようにします。影響分析は、コードを理解するための作業です。コンポーネント間の依存関係を解決し、変更対象の要素から外側に向かってこれらの関係をたどり、依存関係ツリーのどのレベルでも影響を受けるすべてのコンポーネントを返す必要があります。
テキスト検索は、変更された要素名がどこに現れるかを見つけることで影響分析を近似的に行います。しかし、依存関係とコメント、直接的な依存関係と推移的な依存関係、有効な依存関係とデッドコード内の参照を区別することはできません。重大な変更を行う前に影響分析にテキスト検索を利用する開発者は、近似に基づいて安全性が極めて重要な決定を下していることになります。小規模な単一言語のコードベースであれば、近似は十分正確かもしれません。しかし、複数の言語にまたがる依存関係、多くのサービスで共有されるライブラリ、そして何十年にもわたって蓄積された呼び出し関係を持つエンタープライズシステムでは、テキスト検索の結果と実際の変更の影響との間に大きな乖離が生じる可能性があります。
広く使われているデータベース列のスキーマ変更に対して、これら2つのアプローチがどのような結果を返すかの違いを考えてみましょう。
| 開発者が知っておくべきこと | テキスト検索結果 | コード理解結果 |
|---|---|---|
| このコラムを読むプログラム | 列名を含むすべてのファイル(コメントを含む) | この列を参照するSQL SELECT文を含むプログラムのみ |
| このコラムを執筆するプログラム | 同じフィルタリングされていないリスト | この列に書き込むSQL INSERTまたはUPDATE文を使用するプログラムのみ |
| このコラムに依存するサービス | 言語間の可視性がない | 列をオブジェクトフィールドにマッピングするJava、Python、および.NETサービス |
| デッドコード参照 | 結果に含まれる、マークなし | 除外または個別にフラグ付け |
| 推移的従属変数 | 見えない | 任意の深さまで列挙可能 |
| 完全性への自信 | 不明 | インデックス付きスコープに対して検証可能 |
オンボーディングとコードナビゲーション
大規模なコードベースに初めて触れる開発者は、コードの動作、つまりコンポーネント間の接続方法、システム内を流れるデータの流れ、エントリポイントとなるプログラムとユーティリティとなるプログラム、特定のビジネスプロセスにおける実行パスなどについて、メンタルモデルを構築する必要があります。このモデル構築作業は、主にコード理解のタスクです。テキスト検索は特定の文字列を見つけるのに役立ちますが、構造的なコンテキストは提供しません。つまり、単語が出現する場所は特定できますが、その文字列を含むコードがシステム内でどのような役割を果たしているかは分かりません。
コード理解ツールは、システムの構造を分かりやすくすることで、導入プロセスを加速させます。対話型の呼び出しグラフは、どのプログラムがどのプログラムを呼び出すかを示します。データフロートレースは、フィールドの発生元と終着点を示します。制御フローの可視化は、どの条件がどの分岐の実行を左右するかを示します。依存関係マップは、どのコンポーネントを独立して変更しても安全で、どのコンポーネントに他のチームとの連携が必要かを示します。これらはどれもテキスト検索の結果ではありません。コード理解ツールが実行する構造分析の結果です。静的コード分析とは何かという文脈で検討したように、手動による読解ではなく構造分析を通して複雑なシステムをナビゲートできる能力こそが、個人が頭の中で把握するには大きすぎるシステムでもチームが効果的に作業できる理由です。
デッドコードと未使用要素の特定
デッドコードとは、定義されているものの決して実行されないコードのことです。呼び出されない関数、到達しない分岐、代入されるものの読み取られない変数などがこれに該当します。デッドコードを特定するには、完全な呼び出しグラフを構築し、どの定義済み要素が到達可能なエントリポイントから着信呼び出しエッジを持たないかを判断する必要があります。テキスト検索ではデッドコードを特定できません。なぜなら、デッドコードは定義上、どこからも参照されないからです。参照がないことは、テキスト検索で見つけられる文字列ではありません。
非推奨関数の削除においては、デッドコードの特定が直接的に重要となります。非推奨関数を呼び出しているように見える要素の中には、それ自体がデッドコードである場合があります。つまり、非推奨関数を呼び出すために記述された関数であっても、実際には呼び出されることがなく、したがって有効な依存関係を持たないということです。有効な呼び出し元とデッドな呼び出し元を区別するには、一般的にデッドコードを特定するのと同じ呼び出しグラフ分析が必要です。基本的なリファクタリング手法の文脈で検討されているように、静的使用分析は、関数、ラベル、段落、モジュールが実際に呼び出されたことがあるかどうかを判断するのに十分な情報を提供しますが、この分析はテキストの出現回数を数えるのではなく、構造的な呼び出しグラフの構築によってのみ可能となります。
セキュリティおよびコンプライアンス監査
セキュリティおよびコンプライアンス監査では、システム全体を通して機密データを追跡する必要があります。具体的には、個人識別情報がどこに保存されているか、どのコードパスからアクセスできるか、機密データにつながるすべての実行パスにアクセス制御チェックが正しく配置されているか、ログ、エラーメッセージ、またはAPI応答を通じて機密データがシステムから漏洩しないかなどを特定する必要があります。これらはデータフローおよび制御フロー分析のタスクであり、テキスト検索では適切に近似できません。
機密性の高いフィールド名をテキスト検索すると、その名前を含むファイルが見つかります。しかし、それらのファイルが正規のアクセス権限を持っているか、不正なアクセス権限を持っているか、あるいは全くアクセス権限を持っていないかを判別することはできません。また、フィールドへのアクセスに至る実行パスにアクセス制御チェックが存在するかどうかも判別できません。さらに、フィールドの値がその後ログに書き込まれたり、本来含まれるべきではないAPIレスポンスで返されたりするかどうかも追跡できません。機密性の高い値がシステム内をどのように流れるかを追跡し、信頼できない出力に到達する可能性のある場所を特定する汚染分析は、データフロー分析機能です。これは、セキュリティを意識したコード理解ツールが提供する機能であり、テキスト検索では近似できないものです。
認定条件 SMART TS XL 企業全体でコード理解を実現する
SMART TS XL は、エンタープライズシステムにはテキスト検索ではなく構造理解が必要であるという前提に基づいて構築されています。そのソフトウェアインテリジェンスプラットフォームは、環境内のあらゆる言語とプラットフォームのソースコードを解析し、それぞれの言語固有の抽象構文木を生成し、それらの木をシステム全体の構造的関係を表す統一されたクロス言語グラフに解決します。COBOLプログラム、JCLジョブストリーム、Javaサービス、.NETアプリケーション、Pythonスクリプト、SQLスキーマ、TypeScriptモジュール、構成アーティファクトはすべて、このグラフのノードとエッジとして表現され、関係は型付き接続(呼び出し、データフロー、コピーブックのインクルージョン、スキーマ参照、言語間の等価性)として表現されます。
このプラットフォームのエンタープライズ検索機能は、コード理解タスクの入り口となりますが、テキスト検索とは根本的に異なる動作をします。検索結果は、文字列の出現頻度ではなく、関係タイプとアーティファクト構造に基づいて整理されます。フィールド名をクエリすると、定義、読み取り、書き込み、SQL参照、コピーブックのインクルージョンがそれぞれ別のカテゴリに分類された結果タイプとして返されるため、「このフィールドに書き込むものは何ですか?」と尋ねる開発者は、名前が出現するすべてのファイルの混在リストではなく、書き込み関係のみを正確に受け取ることができます。このような検索結果の構造的な整理は、基盤となる相互参照モデルを反映しており、開発者は文字列の出現頻度を手動でフィルタリングすることなく、必要な具体的で実用的な情報を得ることができます。
このプラットフォームの影響分析、呼び出しグラフの走査、制御フローの可視化、およびデータフローのトレース機能はすべて、同じ統一された構造モデルに基づいて動作します。開発者が非推奨の関数を特定すると、呼び出しグラフは階層のすべてのレベルのすべての呼び出し元を表示します。スキーマの変更が計画されている場合、影響分析はすべての言語のすべてのコンシューマーを列挙します。オンボーディング中の開発者がバッチ処理を理解する必要がある場合、制御フローの可視化により、ソースコードを何百行も順番に読む必要なく、実行パスをナビゲートできます。レガシーコードベースの開発者エクスペリエンスと DX メトリクスのより広いコンテキストで検討すると、コードの複雑さと構造の複雑さが保守性を決定する要因であり、表面的なテキストだけでなく、これらの構造的特性を明らかにするツールが、複雑なシステムを大規模に管理可能にします。
何が違うのか SMART TS XL テキスト検索が提供するものは、質問に答えることと、質問を始めることの違いです。テキスト検索は調査を開始し、コードの理解はそれを完成させます。
理解の代わりに探求を行うことによる継続的なコスト
テキスト検索をコード理解の代替手段として扱うことによる実際的な弊害は、コードベースの構造的知識を必要とするあらゆる開発タスクにおいて、静かに蓄積されていきます。テキスト検索に依存する影響評価には、見落とされる依存関係が数多く存在します。言語境界で停止するフィールドトレースには、システムの一部が見落とされてしまいます。呼び出しグラフの到達可能性を分析する代わりに文字列の出現回数を数えるデッドコード識別には、誤検出が含まれ、真のデッドコードを見落としてしまいます。実行パスを通じたデータフローをトレースする代わりに機密性の高いフィールド名を検索するセキュリティ監査は、不完全で検証不可能な保証しか提供しません。
小規模で単一言語、かつ頻繁に変更されるコードベースでは、これらのコストは管理可能かもしれません。開発者は検索結果を正確にフィルタリングするのに十分なコンテキストを持ち、システムの境界はチーム全員が理解しており、手動による検査によってテキスト検索で生じたギャップが迅速に埋められ、重大なエラーを回避できます。しかし、複数の言語、数十年にわたるコードの蓄積、そして全体像を誰も理解していないチーム構造を持つ大規模なエンタープライズシステムでは、コストは増大します。見落とされた依存関係が本番環境で顕在化します。会議室では自信を抱かせた影響評価が、リリース時に予期せぬ障害を引き起こします。すべての文字列出現箇所を網羅したセキュリティ監査では、機密データを漏洩させるデータフローパスが見落とされます。すでに退職した開発者の頭の中にあった知識は、テキスト検索から再構築することはできません。なぜなら、彼らが理解していた構造的関係は、ソースファイルのどの文字列にもエンコードされていなかったからです。
テキスト検索からコード理解への移行は、一方のツールを他方のツールに置き換えるものではありません。テキスト検索は、文字列の検索、迅速な方向付け、構成チェック、ファイルナビゲーションといった、テキスト検索に適したタスクにおいて、その役割を維持します。一方、コード理解は、テキスト検索では不可能な構造分析、すなわち呼び出しグラフ、データフロートレース、影響分析、デッドコードの特定、言語間依存関係の解決などを提供します。両者は異なる抽象度で動作し、異なる種類の質問に答え、異なる目的を果たします。これらを混同すると、依存関係の見落とし、誤った評価、そして複雑なシステムに実際の動作を不完全なモデルで重大な変更を加えることによって生じるリスクの着実な蓄積という代償を払うことになります。


