[ソフトウェア開発] 関数は1つのことを行うべき

6 min read

概要

関数設計では、「関数は1つのことを行うべき」という考え方が基本原則の1つとされている。

この考え方は、ソフトウェア設計における重要な原則である「単一責任の原則(Single Responsibility Principle, SRP)」に基づいている。単一責任の原則とは、モジュールや関数が1つの責務に集中するべきであるという考え方であり、これによりコードの可読性や保守性が向上し、さらに再利用性も高まる。

この原則を守ることで、理解しやすく変更にも強いコードを実現できるため、ソフトウェアエンジニアリングの中でも特に重要なルールとされている。

原則の目的

  1. 明確な目的を持つ
    関数は単一のタスクまたはコンセプトを扱うべきであり、複数のアクションや責務を持たせるべきではない
    これにより、関数の意図が明確になり、可読性が向上する
  2. 簡潔さ
    関数は短く、直感的に理解できるようにする。複雑な処理は、複数の小さな関数に分割することで管理しやすくなり、リファクタリングや再利用が容易になる
  3. 条件や複数の責務を避ける
    andorif などで複数のタスクや条件を表現する関数は、責務が分散している可能性が高い
    これを避けることで、関数のテストや修正が簡単になる

適用方法

  1. 単一のタスクに絞る
    関数を作成する際、その関数が「何をするか」を明確にし、それ以外の処理を含めない
  2. 責務の分割
    複雑な処理を複数の小さな関数に分解し、それぞれが特定のタスクを担当するように設計する
  3. 条件の乱立を避ける
    関数内で複数の条件分岐や責務が混在していないか確認する

良い例と悪い例

悪い例

// 複数の責務を持つ関数
function processAnimal(animal: string) {
  if (animal === 'cat') {
    console.log('にゃあ!');
    console.log('猫にご飯を与えます。');
  } else if (animal === 'dog') {
    console.log('わん!');
    console.log('犬を散歩に連れて行きます。');
  } else {
    console.error('知らない動物です。');
  }
}

問題点

  • 「動物の鳴き声」と「動物ごとの行動」を1つの関数で行っている
  • 責務が分散しており、テストやリファクタリングの際、影響範囲が広くなる

良い例

// 責務を分離した関数
function makeSound(animal: string) {
  if (animal === 'cat') {
    console.log('にゃあ!');
  } else if (animal === 'dog') {
    console.log('わん!');
  } else {
    console.error('知らない動物です。');
  }
}

function feedCat() {
  console.log('猫にご飯を与えます。');
}

function walkDog() {
  console.log('犬を散歩に連れて行きます。');
}

改善点

  • 動物の音声出力 (makeSound) と行動処理 (feedCatwalkDog) を別々の関数に分離
  • 関数がそれぞれ1つの責務に集中しているため、再利用性が高くなる

利点と欠点

利点

  • コードの整理:
    関数が1つのタスクに限定されることで、コードがモジュール化され、理解しやすくなる
  • 再利用性の向上:
    独立した関数は、ほかの箇所で簡単に利用できる
  • 変更や修正が簡単:
    責務が限定されているため、安全かつ迅速に修正可能

欠点

  • 関数の増加:
    小さな関数が増えることで、コードの管理が煩雑になる可能性がある
  • 性能への影響:
    関数呼び出しが増えることで、極端な場合にパフォーマンスが低下する可能性がある

まとめ

「関数は1つのことを行う」という原則を守ることは、モジュール性、保守性、再利用性の高いコードを実現するための基本である。これにより、コードの理解が容易になり、バグの発生する可能性が減るだけでなく、将来的な変更や拡張も安全に行える。