不変性

データを変更せず、新しいデータを作成するプログラミングの原則

プログラミング関数型プログラミング

不変性とは

不変性 (Immutability) は、一度作成したデータを変更せず、変更が必要な場合は新しいデータを作成するプログラミングの原則である。関数型プログラミングの核となる概念で、バグの削減と並行処理の安全性に寄与する。

ミュータブル vs イミュータブル

// ❌ ミュータブル: 元のオブジェクトを変更
const user = { name: 'Alice', age: 30 };
user.age = 31; // 元のオブジェクトが変わる

// ✅ イミュータブル: 新しいオブジェクトを作成
const updatedUser = { ...user, age: 31 };
// user は変わらない、updatedUser は新しいオブジェクト

配列の不変操作

const items = [1, 2, 3];

// ❌ ミュータブル
items.push(4);        // 元の配列を変更
items.sort();         // 元の配列を変更

// ✅ イミュータブル
const added = [...items, 4];           // 新しい配列
const sorted = [...items].sort();      // コピーしてソート
const filtered = items.filter(x => x > 1); // 新しい配列
const mapped = items.map(x => x * 2);     // 新しい配列

なぜ不変性が重要か

データが変わらないため挙動が予測可能になり、デバッグ時に変更履歴を追跡しやすい。共有データの競合が起きないため並行処理にも安全だ。React では参照比較で変更を検出するため、不変性を守ることで再レンダリングの最適化が効く。

React と不変性

// React は参照比較で再レンダリングを判断
const [items, setItems] = useState([1, 2, 3]);

// ❌ ミュータブル: React が変更を検出できない
items.push(4);
setItems(items); // 同じ参照 → 再レンダリングされない

// ✅ イミュータブル: 新しい参照 → 再レンダリング
setItems([...items, 4]);

Rust の不変性

// Rust はデフォルトで不変
let x = 5;
// x = 6; // コンパイルエラー

let mut y = 5; // mut で明示的に可変にする
y = 6; // OK

DynamoDB と不変性

// イベントソーシング: データを変更せず、イベントを追記
await db.put({
  TableName: 'events',
  Item: {
    entityId: 'order-123',
    eventType: 'OrderCreated',
    timestamp: Date.now(),
    data: { amount: 1000 },
  },
});
// 過去のイベントは変更しない → 監査証跡が完全

不変インフラストラクチャ

サーバーを更新するのではなく、新しいサーバーを作成して置き換える。詳細は「不変インフラストラクチャ」を参照。

現場での応用を知るには関連書籍も役立つ。

関連用語