3層アーキテクチャに関して
はじめに
バックエンド開発を開始するにあたって3層アーキテクチャなるものに出会ったのでこれの特徴と導入するメリットについて記述しておこうと思う。
目次
- 3層アーキテクチャとは?
- 導入するメリット
3層アーキテクチャとは?
概要
・バックエンドで情報を処理する際にその情報の処理形態を3層に分割していること。
それぞれの層の名称は各人によってバラバラであるが、基本的な役割としては同じで以下のようである。
➀フロントエンドとの通信を行う層
➁情報を処理するロジックを記述する層
③DBに情報を保存したり抽出したりする層
ここでは①の層を「controller層」と呼び、②の層を「service層」と呼び、③の層を「repository層」と呼ぶことにする。
具体例
基本的に私の場合はInterfaceを使用して依存関係を構築する。
具体的には例えば下記にIUserRepositoryというインターフェースがあるとする。ここにはuser_repositoryで使用する関数などが搭載されている。
type IUserRepository interface {
FindByID(id uint) (*models.User, error)
UpdateUser(user *models.User) error
}
このインターフェースをrepository層より一つ上のservice層でも使いたいとする。
そこでservice層でコンストラクタを用いてIUserRepositoryを受け継いだ新たなインターフェースであるIUserServiceというインターフェースを作成する。
func NewUserService(repository repositories.IUserRepository) IUserService {
return &UserService{repository: repository}
}
そしてこのrepository層のインターフェースを受け継いで誕生したservice層のインターフェースにもservice層で使用する関数を投入していってあげる。
type IPortfolioService interface {
CreatePost(ctx *gin.Context, userID uint) error
GetPostByID(id uint) (*models.Post, error)
GetPostsByUserID(userID uint) ([]models.Post, error)
GetAllPosts() ([]models.Post, error)
}
今の一連の流れをcontroller層でも行うことでcontroller層でもservice層やrepository層の機能を使用することができるようになる。
導入するメリット
責務の分離
- コントローラ層は「入出力(UIやリクエスト・レスポンス)の受け渡し」に特化
- サービス層は「ビジネスロジックの実装とサービスの振る舞い」に特化
- リポジトリ層は「DB操作や外部APIへのアクセスなどのデータアクセス」に特化
それぞれの層の役割が明確になることで、コードベースが整理され、可読性・保守性の向上につながる
将来的に要件変更や新機能追加があった場合でも、影響範囲を特定しやすくなり、修正が容易になる。
テストのしやすさ
3層に分かれているため、各レイヤーごとに単体テストがしやすいのが大きなメリット
- サービス層をテストするときは、リポジトリ層をモック化してビジネスロジックだけに注目できる。
- リポジトリ層のテストでは、DB接続部分のみを検証してデータ操作の正当性を確認できる。
結合テストやエンドツーエンドテストに進む前に、層ごとに不具合を検出できるため開発効率が向上する。
拡張性・スケーラビリティ
将来的にシステムを水平分割・垂直分割する際に、層構造を採用していると柔軟に拡張できる。
- コントローラ層は負荷分散するWebサーバ群でスケールアウト
- DBやリポジトリ層はクラスター構成で耐障害性とパフォーマンスを向上
- サービス層はコンテナ化やマイクロサービス化で独立運用
といったアプローチを取りやすくなる。
保守性
サービス層・リポジトリ層など、どこを編集すればよいかが明確なため、新しいメンバーがプロジェクトに参加した際でも把握がしやすく、チーム開発での混乱を防げる点も大きなメリット
さいごに
- このようなものはほかにも様々なものがあるらしいので、なるべく多く知り、どんな開発にどんな手段が有効なのかを知りたい