😽

動詞+名詞+Serviceで学ぶ!責務を1つに絞ったサービスクラス設計

に公開
2025/07/16

責務とは「その人(クラス)が担当する仕事」のこと

プログラミングの世界でよく聞く「Service Objectの責務を1つに絞り込む」という原則。この「責務」って何でしょうか?

責務 = その人(クラス)が担当する1つの仕事

🏫 学校を例に考えてみよう!

✅ 良い例:係を分担している

  • 図書係の花子ちゃん:本の整理、貸し出し管理だけを担当
  • 掃除係の太郎くん:教室の掃除だけを担当
  • 給食係の次郎くん:給食の配膳だけを担当

❌ 悪い例:係を分担せず一人でなんでもやる

  • 三郎くん:図書の管理も、掃除も、給食配膳も、プリント配りも、花の水やりも全部やる

三郎くんは忙しすぎて、どの仕事も中途半端になってしまいますよね?

💻 プログラミングでの責務

❌ 悪い例:何でもユーザーサービス

class UserService
  def call(user_params)
    # 1. ユーザー作成
    user = User.create!(user_params)
    
    # 2. メール送信
    UserMailer.welcome_email(user).deliver_now
    
    # 3. ポイント付与
    user.points.create!(amount: 100, reason: '新規登録')
    
    # 4. SNS投稿
    TwitterAPI.post("新しいユーザーが登録しました!")
    
    # 5. 管理者に通知
    AdminNotifier.new_user_registered(user)
    
    # 6. ログ出力
    Rails.logger.info "User created: #{user.id}"
    
    # 7. キャッシュ更新
    Rails.cache.delete('user_count')
    
    user
  end
end

問題点:

  • メール送信でエラーが出たら、ユーザー作成も失敗する?
  • SNS投稿機能を変更したら、ユーザー作成も影響を受ける?
  • テストが難しい(全部の機能をテストしないといけない)

✅ 良い例:責務を分けたサービス

命名規則:「動詞 + 名詞 + Service」

# 🎯 責務1: ユーザー作成だけ
class CreateUserService
  def call(user_params)
    ActiveRecord::Base.transaction do
      user = User.create!(user_params)
      Rails.logger.info "User created: #{user.id}"
      user
    end
  end
end

# 📧 責務2: ウェルカムメール送信だけ
class SendWelcomeEmailService
  def call(user)
    UserMailer.welcome_email(user).deliver_later
    Rails.logger.info "Welcome email queued for user: #{user.id}"
  end
end

# 🎁 責務3: 新規登録ポイント付与だけ
class GrantWelcomePointsService
  def call(user)
    user.points.create!(
      amount: 100,
      reason: '新規登録ボーナス'
    )
    Rails.logger.info "Welcome points granted to user: #{user.id}"
  end
end

# 🐦 責務4: SNS投稿だけ
class PostSocialMediaMessageService
  def call(message)
    TwitterAPI.post(message)
    Rails.logger.info "Posted to Twitter: #{message}"
  rescue TwitterAPI::Error => e
    Rails.logger.error "Twitter post failed: #{e.message}"
    # SNSの失敗は他の処理に影響しない
  end
end

# 🎼 責務5: 全体の流れを制御するだけ(指揮者のような役割)
class RegisterUserWorkflowService
  def call(user_params)
    # メインの処理(失敗したら全体が失敗)
    user = CreateUserService.new.call(user_params)
    
    # 副次的な処理(失敗しても登録は成功扱い)
    begin
      SendWelcomeEmailService.new.call(user)
      GrantWelcomePointsService.new.call(user)
      PostSocialMediaMessageService.new.call("新しいユーザーが登録しました!")
    rescue StandardError => e
      Rails.logger.error "Post-registration process failed: #{e.message}"
      # エラーが起きても登録自体は成功
    end
    
    user
  end
end

🤔 なぜ責務を1つに絞るのが良いの?

1. 📖 理解しやすい

悪い例: 「三郎くんは何をする人?」→「えーっと...何でもする人」
良い例: 「図書係の花子ちゃんは何をする人?」→「本の管理をする人!」

2. 🔧 壊れにくい

悪い例: 三郎くんが風邪で休んだら、全ての係の仕事が止まる
良い例: 図書係の花子ちゃんが休んでも、掃除係や給食係は普通に動く

3. 🧪 テストしやすい

悪い例: 三郎くんをテストするには、図書室も、掃除道具も、給食も全部用意が必要
良い例: 図書係のテストなら、本だけ用意すればOK

4. 🔄 再利用しやすい

悪い例: 三郎くんは他のクラスでは使えない(忙しすぎるから)
良い例: 図書係の花子ちゃんは、他のクラスの図書室でも活躍できる

📝 「動詞 + 名詞 + Service」命名規則

🎯 何をするかが一瞬で分かる

従来の命名:

UserManager        # ユーザーを...管理?何を?
DataProcessor      # データを...処理?どんな処理?
SystemHandler      # システムを...ハンドル?意味不明

動詞 + 名詞 + Service:

CreateUserService       # ユーザーを作成する!
SendEmailService        # メールを送信する!
CalculatePriceService   # 価格を計算する!

📐 命名のテンプレート

[動詞] + [名詞] + Service
  ↓       ↓        ↓
 何を    何に対して  サービスクラス
 する?              であることを示す

🔍 動詞の選び方

作成系:

  • Create - 新しく作る
  • Generate - 生成する
  • Build - 組み立てる

取得系:

  • Find - 探す
  • Search - 検索する
  • Fetch - 取得する

更新系:

  • Update - 更新する
  • Modify - 変更する
  • Refresh - 再読み込みする

削除系:

  • Delete - 削除する
  • Remove - 除去する
  • Destroy - 破棄する

処理系:

  • Process - 処理する
  • Calculate - 計算する
  • Convert - 変換する

送信系:

  • Send - 送る
  • Deliver - 配達する
  • Broadcast - 配信する

検証系:

  • Validate - 検証する
  • Verify - 確認する
  • Check - チェックする

❌ 避けるべき動詞

  • Handle - 曖昧すぎる
  • Manage - 何をマネージするか不明
  • Process - 具体的でない(CalculateやConvertの方が良い)
  • Do - 何をするか分からない

🎪 実際の命名例

ECサイトの例

class AddCartItemService          # カートに商品を追加
class RemoveCartItemService       # カートから商品を削除  
class CalculateShippingFeeService # 送料を計算
class ApplyCouponService          # クーポンを適用
class SendOrderConfirmationService # 注文確認メールを送信

ブログサイトの例

class CreatePostService           # 記事を作成
class PublishPostService          # 記事を公開
class SchedulePostService         # 記事を予約投稿
class SearchPostService           # 記事を検索
class GenerateSitemapService      # サイトマップを生成
class OptimizeImageService        # 画像を最適化

✅ 責務を見分けるコツ

❓ 質問してみよう

  1. 「このクラスは何をするクラス?」 を一言で説明できる?
  2. 「〜も〜も」 という説明になってない?
  3. 変更理由が複数ある? (メール変更、DB変更、UI変更など)

📝 名前をつけてみよう

  • 良い名前: CreateUserService, SendEmailService, CalculatePriceService
  • 悪い名前: UserManager, DataProcessor, SystemHandler

「〜Manager」「〜Handler」「〜Processor」という名前は、責務が曖昧な証拠かも!

📋 チェックリスト:良い責務設計か確認しよう

  • 動詞が明確で具体的?
  • 名詞が対象を正確に表している?
  • 一言で何をするか説明できる?
  • 他の開発者が見ても分かりやすい?
  • 「〜も〜も」という説明になってない?
  • テストしやすい?
  • 変更理由が1つ?

🎯 まとめ

責務 = その人(クラス)が担当する1つの仕事

「動詞 + 名詞 + Service」の命名規則で担当を明確にする

  • 🧠 分かりやすい - 何をするかすぐ分かる
  • 🛠️ 壊れにくい - 一部の問題が全体に影響しない
  • 🧪 テストしやすい - 必要な準備が少ない
  • 🔄 他でも使える - 再利用しやすい

Discussion