イミュータビリティ(不変性)
一度作った値を変更せず、変更が必要なときは新しい値を作る設計方針。副作用を減らし、並行処理でも安全に扱えます。
- 1.イミュータビリティは値を後から変更せず、変更時は新しい値を作る設計方針です。
- 2.予期せぬ書き換え(副作用)が減り、複数スレッドからの同時アクセスでも安全になります。
- 3.関数型プログラミングの中核ですが、毎回コピーするコストとのバランスが必要です。
イミュータビリティとは
**イミュータブル(不変)な値とは、一度作ったら中身を変更できない値のことです。変更したい場合は、元を書き換えるのではなく、変更を反映した新しい値を作って差し替えます。逆に、後から中身を書き換えられる値はミュータブル(可変)**と呼びます。
- 配列に要素を足したい → 元の配列を変えず、足した新しい配列を作る。
- オブジェクトの1項目を直したい → コピーして該当項目だけ変えた新しいオブジェクトを返す。
「変えるのではなく、作り直す」。この発想の転換が不変性の核心です。
何がうれしいのか
不変にすると、値がいつの間にか書き換わる事故を根本から防げます。
- 予期せぬ副作用が消える — ある関数に渡した値が、その関数の中で勝手に変わる心配がありません。
- 追いやすい — 値が作られた後に変化しないので、「今この値は何か」を読むだけで把握できます。
- 共有が安全 — 同じ値を複数箇所で参照しても、誰かの変更が他へ波及しません。
// ミュータブル:渡した配列が書き換わってしまう
function addBad(arr, x) {
arr.push(x); // 呼び出し元の配列を破壊
return arr;
}
// イミュータブル:新しい配列を返し、元はそのまま
function addGood(arr, x) {
return [...arr, x]; // コピーして末尾に追加
}
並行処理での安全性
複数のスレッドが同じデータを同時に書き換えると、競合状態(レースコンディション)という厄介なバグが生まれます。不変な値はそもそも書き換わらないため、この問題が起きません。
- 可変データを共有すると、ロックなどの排他制御が必要になり、複雑さとバグの温床になります。
- 不変データはロックなしで安全に共有できるため、並行・並列処理と非常に相性が良いです。
スレッドやワーカー間でデータを渡すときは、不変にしておくと「誰がいつ書き換えたか」を疑わずに済みます。並行処理が絡む設計では、共有する値ほど不変に寄せるのが安全側の判断です。
関数型プログラミングとの関係
不変性は関数型プログラミングの中心的な考え方です。関数型では、入力から出力を計算するだけで外部の状態を書き換えない「純粋関数」を重視します。不変なデータは、この純粋さを自然に支えます。
- 純粋関数 — 同じ入力なら必ず同じ出力。外を変えない。テストしやすい。
- データを書き換える代わりに、変換した新しいデータを返すスタイルが基本になります。
// 元配列を変えずに、各要素を2倍した新配列を得る
const nums = [1, 2, 3];
const doubled = nums.map((n) => n * 2); // [2, 4, 6]、nums は不変
ミュータブルとの比較
どちらが常に優れているわけではなく、トレードオフがあります。
| 観点 | ミュータブル(可変) | イミュータブル(不変) |
|---|---|---|
| 変更方法 | その場で書き換える | 新しい値を作って差し替える |
| 副作用 | 起きやすい | 起きにくい |
| 並行安全性 | 排他制御が要る | ロックなしで安全 |
| メモリ/速度 | 上書きで効率的 | コピーのコストがかかる |
コピーのコストと現実解
不変性の代償は、変更のたびにコピーが発生することです。巨大なデータを少し変えるだけで全体を作り直すと、メモリと時間を浪費します。
大きな配列やオブジェクトを高頻度で更新する場面では、丸ごとコピーがボトルネックになり得ます。実務では、変わらない部分を共有して差分だけ作る「永続データ構造」や、内部だけ一時的に可変にして最後に固める手法(イミュータブル系ライブラリの仕組み)で、コピーコストを抑えます。
- ホットパス(高頻度・性能が重要な箇所)では、局所的に可変を許す判断も現実的です。
- 「境界の外へ渡す値は不変、内部の局所処理は可変も可」という使い分けがよく取られます。
まとめ
イミュータビリティは、値を変更せず必要なら作り直す設計方針です。予期せぬ書き換え(副作用)を防ぎ、並行処理でもロックなしで安全に共有でき、関数型プログラミングの土台にもなります。一方で毎回コピーするコストは無視できず、巨大データの高頻度更新では工夫が要ります。外へ公開する値は不変に、性能が要る局所は可変も検討——このバランス感覚が実務での落としどころです。
プログラミング Article
イミュータビリティ(不変性)を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
不変性
比較で見る軸
難易度: intermediate / カテゴリ: プログラミング / タグ数: 3
導入後に効く点
予期せぬ書き換え(副作用)が減り、複数スレッドからの同時アクセスでも安全になります。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- intermediate
- カテゴリ
- プログラミング
- タグ数
- 3
判断チェックリスト
- 自社の用途が「不変性 / 関数型」に近いか確認する。
- 強みである「イミュータビリティは値を後から変更せず、変更時は新しい値を作る設計方針です。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。