🛠️
Serviceクラスの肥大化を防ぐためのPORO導入
株式会社ウェイブで国内向けアニメ配信サービス「AnimeFesta」のエンジニアをしているflat山です
RailsのPORO導入のリファクタリングに至った記録です
はじめに
- RailsのServiceクラスが増加し、クラスの役割が分かりにくくなった。
- この状況をなんとかしたくて、PORO(Plain Old Ruby Object)を導入してみた。
PORO導入の背景
- Serviceクラスは便利だが、責務が曖昧になりやすい。
- テーブルに紐づかないロジックの整理に悩むことが多かった。
- ActiveModelを活用し、バリデーションや属性を持つシンプルなRubyオブジェクト(PORO)を試してみた。
実装例
# 従来のServiceクラス
class CsvExportService
def generate_csv(user, date_range)
# データ抽出とCSV生成が混在
end
end
# PORO+ActiveModelによる分離
class CsvExportData
include ActiveModel::Model
include ActiveModel::Attributes
attribute :user_id, :integer
attribute :name, :string
attribute :email, :string
attribute :order_count, :integer
validates :user_id, :name, :email, presence: true
end
# 利用例
user_data = CsvExportData.new(user_id: 1, name: "山田", email: "yamada@example.com", order_count: 3)
if user_data.valid?
# CSV出力処理
end
導入による効果
- クラスの責務が明確になった。
- 可読性が上がり、コードの意図が伝わりやすくなった。
- バリデーションや属性管理がPORO内で完結するので、テストも楽になった。
課題・注意点
- ActiveModelに不慣れなメンバーには、最初ちょっと学習コストがあった。
- どこまでPORO化するかは、チームで話し合って決めるのが大事だと感じた。
チームでの反応
- クラスの役割が明確になり、設計やテストの話がしやすくなった。
- ActiveModelの使い方に慣れるまでは、サンプル実装を共有してフォローした。
まとめ
- Serviceクラスの肥大化や責務の曖昧さに悩んでいるなら、POROとActiveModelの導入はおすすめできる方法。
- まずは新しい機能や小さなリファクタから、気軽に試してみるのが良いと感じた。
- この記事が、同じような悩みを持つ方のヒントになれば幸いです。
参考
株式会社ウェイブのエンジニアによるテックブログです。 弊社では、電子コミック、アニメ配信などのエンタメコンテンツを自社開発で運営しております! wwwave.jp/service/
Discussion