不変性
データを変更せず、新しいデータを作成するプログラミングの原則
プログラミング関数型プログラミング
不変性とは
不変性 (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 },
},
});
// 過去のイベントは変更しない → 監査証跡が完全
不変インフラストラクチャ
サーバーを更新するのではなく、新しいサーバーを作成して置き換える。詳細は「不変インフラストラクチャ」を参照。
現場での応用を知るには関連書籍も役立つ。