AIと「プログラマー脳」に学ぶ!変数の役割フレームワークでコードリーディングを効率化しよう
はじめに
こんにちは!
ネクスタで開発エンジニアをしている日野岡です。
今回は『プログラマー脳』(フェリエンヌ・ヘルマンス著)という本で紹介されている「変数の役割フレームワーク」を使って、人間の認知的負荷を下げつつ、複雑なコードをより深く理解するためのプロンプトをご紹介します。
変数の役割フレームワークとは?
プログラミングをしていると、「この変数は何のために存在しているんだろう?」と悩むことがありますよね。「変数の役割フレームワーク」は、そんな悩みを解決するための考え方です。
このフレームワークでは、プログラム内の変数を11の役割に分類します。変数の目的や振る舞いを理解することで、コード全体の流れや意図がつかみやすくなります。
11種類の変数の役割を知ろう
1. 固定値(Constants)
初期化後に値が変わらない変数です。C#ではconst
やreadonly
で宣言されることが多いですね。
// 定数宣言
const double PI = 3.14159265359;
const string CONNECTION_STRING = "Server=myServerAddress;Database=myDataBase;";
// 読み取り専用フィールド
readonly int MaxRetryCount = 5;
2. ステッパー(Stepper)
ループ処理で繰り返しごとに値が変化する変数です。for
ループのカウンター変数が典型例です。
// 基本的なforループのステッパー
for (int i = 0; i < 10; i++)
{
Console.WriteLine($"現在の値: {i}");
}
3. フラグ(Flags)
条件や状態を示す変数です。通常はブール値ですが、列挙型が使われることもあります。
// ブールフラグ
bool isValid = false;
if (ValidateInput(input))
{
isValid = true;
}
// 列挙型フラグ
enum ProcessStatus
{
NotStarted,
InProgress,
Completed,
Failed
}
4. ウォーカー(Walker)
データ構造内の現在位置を追跡する変数です。リンクリストやツリーの走査によく使われます。
// リンクリストのウォーカー
public void TraverseLinkedList(LinkedListNode<int> head)
{
LinkedListNode<int> current = head; // ウォーカー
while (current != null)
{
Console.WriteLine(current.Value);
current = current.Next;
}
}
5. 直近の値の保持者(Last Value Holder)
一連の処理の中で最後に処理された値や最新の値を保持する変数です。
// ユーザーの最後のクリック位置を追跡
Point lastClickPosition;
void OnMouseClick(object sender, MouseEventArgs e)
{
lastClickPosition = new Point(e.X, e.Y);
// lastClickPositionを使った処理
}
6. 最も重要な値の保持者(Most-Wanted Holder)
アルゴリズムや処理の中で特に重要な値(最大値、最小値など)を保持する変数です。
// 配列内の最大値を見つける
int FindMax(int[] numbers)
{
if (numbers.Length == 0)
throw new ArgumentException("配列が空です");
int max = numbers[0]; // 最も重要な値の保持者
for (int i = 1; i < numbers.Length; i++)
{
if (numbers[i] > max)
max = numbers[i];
}
return max;
}
7. 収集者(Gatherer/Accumulator)
反復処理の中で値を集約していく変数です。合計値の計算や文字列の連結などに使われます。
// 数値の合計を計算
int CalculateSum(int[] numbers)
{
int sum = 0; // 収集者
foreach (int number in numbers)
{
sum += number;
}
return sum;
}
8. コンテナ(Container)
複数の値を格納するためのデータ構造を表す変数です。配列、リスト、辞書などが該当します。
// リストコンテナ
List<string> names = new List<string>();
names.Add("Alice");
names.Add("Bob");
// 辞書コンテナ
Dictionary<string, int> scores = new Dictionary<string, int>();
scores["Alice"] = 95;
scores["Bob"] = 87;
9. フォロワー(Follower)
他の変数の値や状態に連動して変化する変数です。インデックスと値のペアなどが該当します。
// 配列のインデックスとその値のペア
void ProcessArrayWithIndices(int[] array)
{
for (int i = 0; i < array.Length; i++)
{
int value = array[i]; // フォロワー(iの値に連動)
Console.WriteLine($"インデックス {i}: 値 {value}");
}
}
10. オーガナイザー(Organizer)
データの整理や再構成を担当する変数です。ソート、グループ化、変換などの操作に使われます。
// データのソート
int[] SortArray(int[] original)
{
int[] sorted = (int[])original.Clone(); // オーガナイザー
Array.Sort(sorted);
return sorted;
}
11. テンポラリ(Temporary)
一時的な計算や値の保存に使用される変数です。値の交換や中間結果の保存などに使われます。
// 値の交換
void SwapValues(ref int a, ref int b)
{
int temp = a; // テンポラリ
a = b;
b = temp;
}
11種類の変数の役割を一括で分類するプロンプト
ひと昔前はこれを人間がメモを取りながら行っていたわけですが、これをAIに一気にやってもらうというのが今回の主題になります。
今回紹介するプロンプトを使うことで、コードの全体像を素早く把握し、各変数の関連性や重要度を理解することができ、コードリーディングが格段に効率化されます。
[対象のソースコード名]に登場するすべての変数を
「変数の役割フレームワーク」に基づいて分類してください。
各変数がどの役割(固定値、ステッパー、フラグ、ウォーカー、直近の値の保持者、
最も重要な値の保持者、収集者、コンテナ、フォロワー、オーガナイザー、テンポラリ)に
該当するか分析し、その理由も説明してください。
また、分類結果を以下の形式でまとめてください:
1. 固定値(Constants):
- [変数名]: [理由]
- ...
2. ステッパー(Stepper):
- [変数名]: [理由]
- ...
(以下、11の役割すべてについて同様に)
さらに、このコードの主要な処理フローと、
各変数の役割がどのように連携して全体の目的を達成しているかも説明してください。
実際のプロンプト実行例
public class OrderProcessor
{
private const decimal TAX_RATE = 0.1m;
private readonly int _maxOrderItems = 100;
public List<OrderItem> ProcessOrder(List<OrderItem> items, string customerId)
{
List<OrderItem> processedItems = new List<OrderItem>();
bool hasDiscount = IsVipCustomer(customerId);
decimal totalAmount = 0;
for (int i = 0; i < items.Count && i < _maxOrderItems; i++)
{
OrderItem currentItem = items[i];
decimal itemPrice = currentItem.Price;
if (hasDiscount)
{
decimal discountAmount = itemPrice * 0.15m;
itemPrice -= discountAmount;
}
decimal taxAmount = itemPrice * TAX_RATE;
decimal finalPrice = itemPrice + taxAmount;
currentItem.FinalPrice = finalPrice;
processedItems.Add(currentItem);
totalAmount += finalPrice;
}
if (totalAmount > 10000)
{
decimal bonusDiscount = totalAmount * 0.05m;
totalAmount -= bonusDiscount;
}
Console.WriteLine($"Order processed. Total amount: {totalAmount}");
return processedItems;
}
private bool IsVipCustomer(string customerId)
{
// 実装省略
return customerId.StartsWith("VIP");
}
}
public class OrderItem
{
public string ProductId { get; set; }
public decimal Price { get; set; }
public decimal FinalPrice { get; set; }
}
分析結果:
# 変数の役割フレームワークによる分類
1. 固定値(Constants):
- TAX_RATE: 税率として0.1mの固定値を持ち、計算中に変更されない
- _maxOrderItems: 注文アイテムの最大数として100の固定値を持つ(readonlyで宣言)
2. ステッパー(Stepper):
- i: forループで0から始まり、1ずつ増加し、items.Countまたは_maxOrderItemsに達すると終了
3. フラグ(Flags):
- hasDiscount: 顧客がVIPかどうかを示すブール値
4. ウォーカー(Walker):
- currentItem: items配列を走査するために使用される変数
5. 直近の値の保持者(Last Value Holder):
- 該当なし
6. 最も重要な値の保持者(Most-Wanted Holder):
- totalAmount: 注文の合計金額を保持し、最終的に出力される重要な値
7. 収集者(Gatherer/Accumulator):
- totalAmount: 各アイテムの最終価格を累積的に加算
- processedItems: 処理済みのアイテムを収集するリスト
8. コンテナ(Container):
- processedItems: 処理済みのOrderItemオブジェクトを格納するリスト
- items: 入力として受け取るOrderItemオブジェクトのリスト
9. フォロワー(Follower):
- itemPrice: currentItemの価格に基づいて変化
- finalPrice: itemPriceとtaxAmountに基づいて計算される
10. オーガナイザー(Organizer):
- 該当なし
11. テンポラリ(Temporary):
- discountAmount: 割引額の一時的な計算に使用
- taxAmount: 税額の一時的な計算に使用
- bonusDiscount: 大口注文の追加割引の計算に使用
# 処理フローと変数の連携
このコードは注文処理システムの一部で、以下の流れで動作しています:
1. 固定値(TAX_RATE, _maxOrderItems)が処理の基本パラメータを設定
2. フラグ(hasDiscount)が顧客タイプに基づく割引適用の条件を制御
3. ステッパー(i)とウォーカー(currentItem)が協力して注文アイテムリストを走査
4. フォロワー(itemPrice, finalPrice)が各アイテムの価格計算を担当
5. テンポラリ変数(discountAmount, taxAmount)が中間計算を支援
6. 収集者(totalAmount, processedItems)が結果を集約
7. 最も重要な値の保持者(totalAmount)が最終的な注文金額を保持
各変数が明確な役割を持ち、連携することで、注文アイテムの処理、価格計算、割引適用という全体の目的を達成しています。
まとめ: AIと「変数の役割フレームワーク」でコード理解を加速し、認知的負荷を軽減する
このフレームワークに基づいてAIに分析させることで、各変数がコード内でどのような目的を持ち、どのように機能しているのかが一目で把握できるようになります。これにより、複雑なソースコードを読む際の認知的負荷が軽減され、コード全体の構造や処理の流れをより迅速かつ深く理解することが可能になります。
AI技術が発展する現代においても、「変数の役割フレームワーク」のようなプログラミングにおける普遍的な概念や、過去の技術書で培われた知見は非常に有効です。これらをAIツールと組み合わせることで、私たちはコードリーディングの効率を格段に向上させ、より本質的な開発作業に集中できるようになるでしょう(なるはず!)。
Discussion