🙌

【初心者】ソフトウェアアーキテクチャパターン

2025/02/14に公開

状況

  • エンジニアに転職して3ヶ月が経ちました。がむしゃらにとにかくタスクをこなしてきて漸く少しコードまみれの生活にも慣れてきました。
  • 一方で、もう3ヶ月も経ってしまったことに焦りを感じています。早く仕事として使えるようになるために基礎をぶっ飛ばしてとにかく実践に触れてきたため、あまり体系的に自分の中に知識が詰まっていないことに愕然としています。
  • 例えば「Active Record」なんか完全に知ってるフリしてます。今後は実践を捌きながらも基礎をガンガン学んでいきたいと思います。

内容

Active Recordを調べようと思ったら、そもそも「ソフトウェアアーキテクチャパターン」を理解しないといけないことが分かりましたのでそこから整理してみます。

ソフトウェアアーキテクチャパターンとは?

  • ソフトウェアアーキテクチャパターンは、アプリケーションの設計を整理し、保守性や拡張性を高めるためのパターン = システムをどのように構築するかの設計の枠組み
  • 家を建てるときに「間取り」を決めるようなもので、どのようにデータを流し、処理を分けるかのルールを決める

Ruby on Rails は MVC(Model-View-Controller)パターン を採用している
これが最も基本的なアーキテクチャパターン


1. MVC(Model-View-Controller)パターン

概要
MVCは、以下の3つの役割に分けることでコードを整理しやすくするアーキテクチャパターンのこと

役割 説明
Model データの管理(DBとのやり取り、ビジネスロジック)
View ユーザーに見える画面(HTML、CSS、JavaScript)
Controller ユーザーのリクエストを処理し、ModelとViewをつなぐ

実際の流れ(ブログ記事の表示を例に)

  1. ユーザーが /articles/1 にアクセス
  2. Controller (ArticlesController) がリクエストを受け取る
  3. Model (Article クラス) から記事データを取得
  4. View (show.html.erb) でデータを整形し、HTMLを生成
  5. ユーザーのブラウザにページが表示される

実装例(Rails)

# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
  def show
    @article = Article.find(params[:id])  # Modelに問い合わせ
  end
end
<!-- app/views/articles/show.html.erb -->
<h1><%= @article.title %></h1>
<p><%= @article.body %></p>

MVCパターンを使うと、データの管理、画面の表示、リクエストの処理が明確に分かれる

他の言語の場合

  • Django(Python) も同じMVCパターン(DjangoではMTVと呼ばれるが、概念は同じ)
  • Spring(Java) でもMVCを採用
  • Express(Node.js) でも、ルーティング・モデル・ビューを分けることでMVC的に実装可能

(応用編)2. レイヤードアーキテクチャ

概要
MVCの拡張版で、アプリケーションをさらに細かい層(レイヤー)に分けるパターン

レイヤー 役割
Presentation ViewとControllerを含み、ユーザーとのやり取りを担当
Application アプリのビジネスロジック(ユースケースごとの処理)
Domain ビジネスルールやエンティティの管理
Infrastructure データベースや外部APIの管理

Railsにおける実践
RailsのMVCに加えて、以下のようにServiceクラスやRepositoryクラスを作ると、レイヤードアーキテクチャに近づけられる

実装例(Serviceクラスを導入)

# app/services/article_service.rb
class ArticleService
  def self.find_article(id)
    Article.find(id)
  end
end
# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
  def show
    @article = ArticleService.find_article(params[:id])  # Serviceを経由
  end
end

こうすることで、Controllerが直接Modelを扱わず、ビジネスロジックを切り離せる ようになる

他の言語の場合

  • Spring(Java) はこの構造が標準的
  • NestJS(Node.js) もこのような構造を推奨
  • Laravel(PHP) でもサービス層を作ることで類似の構造を実装可能

(発展編)3. クリーンアーキテクチャ

概要
レイヤードアーキテクチャをさらに厳密にし、依存関係を内側から外側に制限する考え方

レイヤー 役割
Entities(エンティティ) ドメインルールを持つ純粋なオブジェクト
Use Cases(ユースケース) アプリのビジネスルールを表現
Interface Adapters(インターフェース) ControllerやView、DB操作など
Frameworks & Drivers(外部技術) Rails, DB, Webフレームワーク

Railsにおける実践
クリーンアーキテクチャを意識する場合、以下のような構成になる

# app/domain/article.rb
class Article
  attr_reader :title, :body

  def initialize(title, body)
    @title = title
    @body = body
  end
end
# app/repositories/article_repository.rb
class ArticleRepository
  def self.find(id)
    ArticleRecord.find(id) # ActiveRecordのモデルを操作
  end
end
# app/use_cases/article_use_case.rb
class ArticleUseCase
  def self.get_article(id)
    article = ArticleRepository.find(id)
    Article.new(article.title, article.body)
  end
end
# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
  def show
    @article = ArticleUseCase.get_article(params[:id])
  end
end

こうすることで、Rails(外部技術)に依存せずに、ビジネスロジック(ユースケース)を独立させられる

他の言語の場合

  • Spring Boot(Java) ではクリーンアーキテクチャを意識した構成が一般的
  • NestJS(Node.js) でもクリーンアーキテクチャを採用しやすい
  • Go(Golang) でもこの考え方がよく使われる

所見

  • まじで全然理解してませんでした。この活動は続けたいと思います
  • でも、やはり「コントローラは薄いのが至高」という考えが根っこにあるということは一緒
  • 思ったより長くなってしまったので、Avtive Recordは次の記事にまとめることにします

次の記事

https://zenn.dev/tatsuki_otake/articles/1e35af405d9455

Discussion