RailsにおけるCQRSパターンの採用: FatModel・FatController問題の解決策
2023年のKaigi on RailsでCQRSについての発表があり、とても勉強になったのでCQRSについてまとめました。
Railsアプリケーションの開発において、FatModelやFatControllerは頻繁に直面する問題ですよね。
これらの問題は、アプリケーションの拡張性や保守性を低下させ、複雑性を増加させます。
CQRS(Command Query Responsibility Segregation:コマンドクエリ責任分離)パターンの採用により、これらの問題を効果的に解決することができます。
本記事では、RailsアプリケーションにCQRSを採用するメリットと、サンプルコードを通じてその実装方法を解説します。
CQRSパターンとは?
CQRSパターンは、アプリケーションの操作を「コマンド(データの変更)」と「クエリ(データの読み取り)」の2つに分離するアーキテクチャパターンです。これにより、アプリケーションの読み書きの責任が明確に分離され、それぞれの処理の最適化が可能になります。
CQRSのメリット
- 明確な責任分離: データの読み取りと書き込みの責任がはっきりと分離されるため、コードの可読性と保守性が向上します。
- 拡張性の向上: 読み取りと書き込みの処理が独立しているため、将来的な機能拡張やパフォーマンスの最適化が容易になります。
- 複雑性の管理: ビジネスロジックが分離されることで、システムの複雑性を効果的に管理できます。特に、読み取り専用のクエリでは、高度なクエリ最適化やキャッシュ戦略が容易に適用できます。
- テストの容易性: 責務が分離されているため、単体テストや統合テストが書きやすくなります。
FatModel・FatController問題とCQRS
Railsでは、ビジネスロジックやデータアクセスロジックがモデルやコントローラに集中しやすい傾向があります(FatModel、FatController)。
これにより、コードが肥大化し、テストや保守が困難になります。CQRSを採用することで、データの変更と読み取りを分離し、これらの問題を解決できます。
CQRSの実装サンプル
CQRSパターンをRailsアプリケーションに適用するための基本的なステップとサンプルコードを以下に示します。
コマンド(データ変更)
コマンドはデータを変更するための操作です。例)ユーザーの情報を更新する操作
# app/commands/update_user_command.rb
class UpdateUserCommand
def initialize(user, user_params)
@user = user
@user_params = user_params
end
def call
@user.update(@user_params)
end
end
コントローラでのコマンドの使用
# app/controllers/users_controller.rb
class UsersController < ApplicationController
def update
user = User.find(params[:id])
command = UpdateUserCommand.new(user, user_params)
if command.call
redirect_to user_path(user), notice: 'User was successfully updated.'
else
render :edit
end
end
private
def user_params
params.require(:user).permit(:name, :email)
end
end
クエリ(データ読み取り)
クエリはデータを読み取るための操作です。例)特定の条件に合致するユーザーを検索する操作
# app/queries/users_query.rb
class UsersQuery
def initialize(scope = User.all)
@scope = scope
end
def call(params)
@scope.where(params)
end
end
コントローラでのクエリの使用
# app/controllers/users_controller.rb
class UsersController < ApplicationController
def index
query = UsersQuery.new
@users = query.call(name: params[:name])
end
end
注意点
CQRSの導入は、アプリケーションの構造を複雑にする可能性があります。小規模なプロジェクトや単純なアプリケーションでは、導入によるメリットが得られない場合もあります。CQRSの導入を検討する際は、アプリケーションの規模や複雑さ、将来的な成長予測を総合的に考慮することが重要です。
まとめ
RailsアプリケーションでのCQRSパターンの採用は、FatModelやFatControllerといった問題を解決し、よりクリーンで保守性の高いコードベースを実現するための強力な手段です。
しかし、その導入はプロジェクトの規模やニーズに応じて慎重に行う必要があります。適切に実装されたCQRSは、アプリケーションの拡張性、保守性、およびパフォーマンスを大きく向上させることができます。
Discussion
よくまとまっていてすごく良い記事だと思いました!
発表した後に自分が誤っていたことに気づいたのですが、参照用のUserモデルと更新用のUserモデルを分離しない場合(自分の発表の場合)は、CQRSではなくCQSと表現するのが正しいようだったので共有させていただきます!