概要
関数型プログラミング(FP)の理念を理解するだけでは不十分だ。
その力は「実際に書かれた命令型コードを、どう“純粋な構造”へと変換できるか」によって真価を問われる。
本稿では、典型的な命令型コードをベースに、段階的に関数型へリファクタリングを行いながら、
副作用の分離・状態の不変化・宣言的な構造をどう築くかを具体的に示す。
1. Before:命令型コード(典型例)
const users = [
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 30 },
{ name: 'Carol', age: 22 }
]
let totalAge = 0
for (let i = 0; i < users.length; i++) {
if (users[i].age >= 25) {
totalAge += users[i].age
}
}
console.log('Total age over 25:', totalAge)
- 状態
totalAge
を逐次更新 - 副作用
console.log
が処理の途中で混在 - 可読性・再利用性・テスト性に欠ける構造
2. After:関数型スタイルへの変換
const isOver25 = user => user.age >= 25
const getAge = user => user.age
const sum = arr => arr.reduce((acc, val) => acc + val, 0)
const totalAge = sum(
users
.filter(isOver25)
.map(getAge)
)
console.log('Total age over 25:', totalAge)
- 状態の更新が暗黙的ではなく、関数で明示される
- フィルター → マッピング → 集約という宣言的構造
- 処理単位が関数として再利用可能
3. リファクタリング戦略の骨格
フェーズ | 目的 |
---|---|
副作用の分離 | I/O・ログ・APIなどはロジックから分離する |
状態の不変化 |
let を排し、const + 合成をベースに |
ロジックの関数分割 | 再利用・テスト・合成しやすい形に分離する |
パイプライン構造化 | 処理の流れを map/filter/reduce で明示 |
4. 応用:ネスト構造にもFPは有効
Before(命令型)
const books = [
{ title: 'Book A', ratings: [5, 4, 3] },
{ title: 'Book B', ratings: [4, 4] },
]
let sum = 0
let count = 0
for (const book of books) {
for (const rating of book.ratings) {
sum += rating
count++
}
}
const average = sum / count
console.log('Average rating:', average)
After(関数型)
const flatten = arr => arr.reduce((acc, val) => acc.concat(val), [])
const average = nums => sum(nums) / nums.length
const ratings = flatten(books.map(book => book.ratings))
console.log('Average rating:', average(ratings))
-
flatten
,average
は文脈非依存な純粋関数 - 集約処理が構造的・再利用的に切り出されている
5. テストしやすい設計への転換
// 純粋関数化
const calcTotalAgeOver25 = users =>
sum(users.filter(isOver25).map(getAge))
// テスト例
console.assert(calcTotalAgeOver25([
{ name: 'A', age: 20 },
{ name: 'B', age: 30 }
]) === 30)
- ロジック単体のテストが可能
- 副作用のないため状態を固定しやすい
- 再利用や拡張が容易
設計判断フロー
① 変数が更新されている? → YES → map/reduce に置き換え可能か検討
② 同じコードを何度も書いている? → YES → 関数化するチャンス
③ 関数の中で I/O をしている? → YES → ロジックと副作用を分離
④ データ変換が複雑? → YES → パイプラインで明示的に記述
よくある誤解と対策
❌ 「FPは処理が読みにくくなる」
→ ✅ 初期学習コストはあるが、構造が揃えば可読性はむしろ上がる
❌ 「関数に分けすぎて管理が大変」
→ ✅ 適切な責務で関数を設計すれば、モジュール分割が自然に進む
❌ 「実務コードには向かない」
→ ✅ 複雑な業務ロジックこそ、構造化・宣言的記述による安定性が活きる
結語
関数型リファクタリングとは、
コードを「どう書くか」ではなく、「どう構造を制御するか」という戦略である。
- 副作用を制御し
- 状態を不変とし
- 処理を構造として組み上げる
それによって、コードはテストしやすく、拡張しやすく、読みやすく、壊れにくくなる。
FPとは、
“振る舞いを構造に還元し、設計を再構成可能な論理へと昇華する技法である。”