単一責任の原則を関数で考える

入門 | 9分 で読める | 2026.06.18

公式ドキュメント

単一責任の原則は、SOLID原則の1つです。

クラス設計で説明されることが多いですが、初心者はまず関数で考えると理解しやすくなります。

一言でいうと

単一責任とは、1つの関数に「変更される理由」を1つだけ持たせる考え方です。

「1つのことだけをする」とよく言われますが、より実務的には「なぜこの関数を変更するのか」を見ると判断しやすいです。

悪い例

async function registerUser(input: UserInput) {
 if (!input.email.includes("@")) {
 throw new Error("invalid email");
 }

 const user = {
 email: input.email,
 name: input.name.trim(),
 };

 await db.users.insert(user);
 await mailer.send(input.email, "welcome");

 return user;
}

この関数には、入力チェック、データ整形、DB保存、メール送信が入っています。

メール文面が変わっても、DB保存方法が変わっても、入力ルールが変わっても、この関数を触ることになります。

分けた例

function validateUserInput(input: UserInput) {
 if (!input.email.includes("@")) {
 throw new Error("invalid email");
 }
}

function createUser(input: UserInput) {
 return {
 email: input.email,
 name: input.name.trim(),
 };
}

処理を分けると、それぞれの変更理由が見えやすくなります。

関数を分けるサイン

サイン
コメントで段落が分かれる// validate, // save, // send mail
名前に and が入るsaveUserAndSendMail
テストしたい観点が複数ある入力チェックとDB保存を別々に確認したい
例外の種類が違う入力エラーと通信エラーが混ざる
変更理由が複数ある仕様変更と外部サービス変更が混ざる

これらが見えたら、関数を分ける候補です。

分けすぎにも注意

単一責任は、1行ごとに関数を作るという意味ではありません。

function trimName(name: string) {
 return name.trim();
}

このような関数が必ず悪いわけではありませんが、名前を付ける意味が薄いなら、かえって読みづらくなります。

実務での目安

  • 関数名が処理内容を説明している
  • 入力と出力が分かりやすい
  • テスト名を書きやすい
  • 変更理由を1つに説明できる
  • 外部I/Oと計算処理が混ざりすぎていない

特に、DB、API、ファイル、メールなどの外部I/Oは、純粋な計算処理と分けるとテストしやすくなります。

まとめ

単一責任の原則は、関数にも使える考え方です。

関数を見たときに「この関数は何の理由で変更されるか」を1つに説明できるか確認しましょう。

参考リソース

関連記事

← 一覧に戻る
PR
PR
PR
PR