💻

レイヤードアーキテクチャについて

2025/02/19に公開

はじめに

ソフトウェア設計におけるデザインパターンの1つである、レイヤードアーキテクチャについて、システム設計をする上で学ぶ必要がありました。
レイヤードアーキテクチャの基本的な概念やその利点を、解説出来たらと思います。

本記事の対象

  • これからシステム設計を始める方
  • これまでアーキテクチャを意識してこなかった方

レイヤードアーキテクチャとは?

レイヤードアーキテクチャ(Layered Architecture)は、ソフトウェアシステムを複数のレイヤー(層)に分割し、それぞれのレイヤーが特定の機能や責任を持つデザインパターンの一つです。
このアーキテクチャスタイルは、システムの構造を整理し、開発や保守をしやすくするために広く採用されています。

捕捉ですが、レイヤードアーキテクチャ以外にも、以下のようなアーキテクチャ思想があります。

  • ヘキサゴナルアーキテクチャ
  • オニオンアーキテクチャ
  • クリーンアーキテクチャ

なぜレイヤードアーキテクチャが重要なのか?

レイヤードアーキテクチャを採用することで、以下のようなメリットがあります。

  • 分離と整理:機能ごとにレイヤーを分けることで、システム全体の整理/理解がしやすくなります。
  • 保守性:変更が必要な部分を特定のレイヤーに限定できるため、保守性が向上します。
  • 再利用性:特定のレイヤーが独立しているため、他のプロジェクトでも再利用しやすくなります。
  • 効率化:異なるレイヤーを並行して開発可能になるため、チーム内での開発効率が向上します。
  • テストの容易さ:各レイヤーを個別にテストできるため、品質保証がしやすくなります。

主なレイヤーの構成

レイヤードアーキテクチャは、システムの目的や規模によって異なるレイヤー構成を持つことがありますが、一般的には以下のようなレイヤーで構成されます。
以下のような3レイヤーで成り立つレイヤードアーキテクチャは3レイヤーアーキテクチャと呼称されることもあります。
下図のように、上位レイヤーは下位レイヤーに処理を要求し、依存しています。

レイヤードアーキテクチャ

プレゼンテーション層

プレゼンテーション層は、ユーザーとシステム間のインターフェースを担当するレイヤーです。
ユーザーからのリクエストに対して適切なレスポンスを返す役割を持っています。

役割と機能

  • リクエストデータの受け取り
  • リクエストデータのバリデーション/フォーマット変換
  • レスポンスデータのバリデーション/フォーマット変換
  • リクエスト元へのレスポンス

ポイント

  • ドメイン層に依存します。
  • 外部サービス(データベース等)と直接的に通信することは許容せず、ドメイン層を介してデータをやり取りします。

ドメイン層

ドメイン層は、システムのコアな機能であるビジネスロジックを実装するレイヤーです。このレイヤーでは、具体的な業務処理やデータの処理方法が定義されます。
ビジネスロジックの定義はチーム内で検討した上で共通認識を持つことが重要と考えています。

役割と機能

  • ビジネスロジックの実装
  • データの処理や計算
  • トランザクション管理

ポイント

  • データアクセス層に依存します。
  • システムのコアとなるビジネスロジックを実装します。
  • 外部サービス(データベース等)と直接的に通信することは許容せず、データアクセス層を介してデータをやり取りします。

データアクセス層

データアクセス層は、データベースや外部サービスとのやり取りを管理するレイヤーです。データの保存や取得、更新、削除などの操作を担当します。

役割と機能

  • 外部サービス接続の管理
  • データのCRUD操作(Create, Read, Update, Delete)
  • データの永続化

ポイント

  • 他のレイヤーに依存しない。
  • ORM(Object-Relational Mapping)ツールなどを使用することが多いイメージです。

レイヤードアーキテクチャの利点

レイヤードアーキテクチャを採用することで、以下のような具体的なメリットがあります。

システム理解の向上

機能ごとにレイヤーを分けることで、システム全体の整理/理解がしやすくなります。

保守性の向上

システムが明確なレイヤーに分かれているため、特定の機能に変更が必要な場合、そのレイヤーだけを修正すれば済みます。これにより、他の部分に影響を与えるリスクが低減します。

再利用性の高まり

各レイヤーが独立しているため、特定のレイヤーを他のプロジェクトでも再利用しやすくなります。例えば、ドメイン層を別のアプリケーションでも利用することが可能です。

開発の効率化

異なるレイヤーを並行して開発できるため、チームの分業がしやすくなります。各レイヤーの担当者がそれぞれのレイヤーに集中できるメリットがあります。

テスト容易性

各レイヤーを個別にテストできるため、バグの早期発見や品質向上に繋がります。例えば、ドメイン層だけをユニットテストすることで、ビジネスロジックの正確性を確認できます。

レイヤードアーキテクチャの課題と対策

レイヤードアーキテクチャには多くの利点がありますが、いくつかの課題も存在します。これらの課題を理解し、適切に対策することで、より効果的なアーキテクチャを実現できます。

課題1:レイヤー間の依存関係

各レイヤーが明確に分かれている一方で、依存関係により変更の影響が決定します。
例えば、下位層であるデータアクセス層の接続先がOracleからPostgreSQLに変更になった場合は、依存している上位層(ドメイン層等)へ変更による影響が波及します。
このように、ドメイン層はシステムのコアな部分となりますが、外的要因の影響を受けてしまいます。

対策

  • SOLID原則依存性逆転の原則を採用し、ドメイン層とデータアクセス層の依存関係を逆転させる手法が取られることがあります。

https://zenn.dev/tsutani2828/articles/solid_principle
https://zenn.dev/tsutani2828/articles/layeredarchitecture_dip

課題2:パフォーマンスの低下

各レイヤーを経由するたびに処理が追加されるため、パフォーマンスが低下する可能性があります。特に、大規模なシステムではこの影響が顕著になることがあります。

対策

  • 必要なレイヤーを最小限に抑え、不要なレイヤーを追加しないようにします。
  • パフォーマンスのボトルネックを特定し、必要に応じて最適化を行います。

課題3:レイヤーの過剰な分割

レイヤーを細かく分割しすぎると、システム全体が複雑になり、コードの可読性や保守性の低下に繋がることがあります。

対策

  • 定期的な設計レビューを行い、チーム内での検討および共通認識をし、必要に応じてレイヤー構成を見直します。

具体例

レイヤードアーキテクチャを用いた、外部サービスから特定のユーザー情報を取得するAPIを想定した具体例を以下に示します。

クラス図

プログラム

UserController.cs
namespace Presentation.Controllers{
    /// <summary>
    /// ユーザー関連のAPIエンドポイントを提供するコントローラクラス
    /// </summary>
    [ApiController]
    [Route("api/[controller]")]
    public class UserController : ControllerBase
    {
        private readonly UserService _userService;

        /// <summary>
        /// UserController の新しいインスタンスを初期化
        /// </summary>
        /// <param name="userService">ユーザーサービス</param>
        public UserController(UserService userService)
        {
            _userService = userService;
        }

        /// <summary>
        /// 指定されたIDに一致するユーザーを取得
        /// </summary>
        /// <param name="id">ユーザーのID</param>
        /// <returns>ユーザー情報</returns>
        [HttpGet("{id}")]
        public async Task<IActionResult> FindUser([FromRoute] string id)
        {
            var user = await _userService.FindUserById(id);
            if(user == null){
                return NoContent();
            }
            return Ok(user);
        }
    }
}
UserService.cs
namespace Domian.Services{
    /// <summary>
    /// ユーザー関連のビジネスロジックを提供するサービスクラス
    /// </summary>
    public class UserService
    {
        private readonly UserRepository _userRepository;

        /// <summary>
        /// UserService の新しいインスタンスを初期化します。
        /// </summary>
        /// <param name="userRepository">ユーザーリポジトリ</param>
        public UserService(UserRepository userRepository)
        {
            _userRepository = userRepository;
        }

        /// <summary>
        /// 指定されたIDに一致するユーザーを取得
        /// </summary>
        /// <param name="id">ユーザーのID</param>
        /// <returns>一致するユーザーの一覧</returns>
        public async Task<User> FindUserById(string id)
        {
            return await _userRepository.Find(id);
        }
    }
}

User.cs
namespace DataAccess.Entities{
    /// <summary>
    /// ユーザーを表すクラス
    /// </summary>
    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

UserRepository.cs
namespace DataAccess.Repositories{
    /// <summary>
    /// ユーザーのデータアクセスを行うリポジトリクラス
    /// </summary>
    public class UserRepository
    {

        /// <summary>
        /// 指定されたIDに一致するユーザーを外部サービスから取得
        /// </summary>
        /// <param name="id">ユーザーのID</param>
        /// <returns>一致するユーザーの一覧</returns>
        public async Task<User> Find(string id)
        {
            var user = // 外部サービスからユーザー情報を取得する処理
            return user;
        }
    }
}

解説

  • プレゼンテーション層:ユーザーからの要求を受け取ります。必要であれば、リクエストデータ検証やフォーマット変換等を行います。ドメイン層へビジネスロジック実行を要求し、ユーザーへ結果を返却します。
  • ドメイン層:ビジネスロジックを実装します。この場合は、ユーザー情報を取得することがビジネスロジックに相当します。プレゼンテーション層からの要求を受け取り、データアクセス層にデータ取得を要求し、結果をプレゼンテーション層に返却します。
  • データアクセス層:ドメイン層からの要求を受け取り、外部サービスからユーザー情報を取得し、ドメイン層へ返却します。

まとめ

レイヤードアーキテクチャは、システムを整理し、開発や保守を効率化するためのデザインパターンの1つです。この記事では、レイヤードアーキテクチャの基本概念から具体的な利点、課題とその対策を解説しました。

次のステップとしては、実際に小規模なプロジェクトでレイヤードアーキテクチャを試してみることをおすすめします。実践を通じて、各レイヤーの役割やメリット/デメリットをより深く理解できると思います。(実際に私はそうでした。)

参考文献


この記事がレイヤードアーキテクチャの基本を理解する助けになれば幸いです。ご質問やご指摘事項がございましたら、お気軽にお寄せください。

Discussion