4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

実践FP設計:命令型コードを関数型にリファクタしてみる

Posted at

概要

関数型プログラミング(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とは、
“振る舞いを構造に還元し、設計を再構成可能な論理へと昇華する技法である。”

4
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?