Uncategorized

三層構造再入門:冗長コードを解消し、より堅牢なWebアプリへ

こんにちは!Web開発における三層構造、一度は学んだものの、いざ実装しようとすると
「あれ、どこに何を記述すればいいんだっけ?」と手が止まってしまうこと、ありますよね。
私もまさにその状態でした。
冗長なコードを解消し、より保守性の高いアプリケーションを目指すべく、三層構造に再挑戦した過程を共有したいと思います。

三層構造とは?

Webアプリケーションを、役割ごとに「プレゼンテーション層」「アプリケーション層」「データ層」の3つに分割する設計モデルです。
各層を独立させることで、システムの保守性、拡張性、再利用性が向上します。

プレゼンテーション層 (Presentation Layer)

  • ユーザーインターフェース (UI) を担当し、ユーザーとの直接的なやり取りを行います。
  • HTML, CSS, JavaScript など、フロントエンド技術が用いられます。
  • ユーザーからのリクエストをアプリケーション層へ送信し、アプリケーション層からの応答をユーザーに表示します。

アプリケーション層 (Application Layer)

  • アプリケーションの主要な処理 (ビジネスロジック) を担当します。
  • プレゼンテーション層からのリクエストに基づき、データの処理、計算、検証などを行います。
  • データ層と連携し、データの検索、作成、更新、削除を行います。
  • Java, Python, PHP など、サーバーサイドのプログラミング言語が用いられます。

データ層 (Data Layer)

  • データの保存と管理を担当します。
  • データベースやファイルシステムなどが含まれます。
  • アプリケーション層からの要求に応じて、データの読み書きを行います。

三層構造を図で表すと

 ┌──────────────┐
 │ プレゼンテーション層 │←ユーザー
 └──────┬──────┘
        │
 ┌──────┴──────┐
 │ アプリケーション層 │
 └──────┬──────┘
        │
 ┌──────┴──────┐
 │ データ層 │
 └──────────────┘

実際のコード例と解説

今回、ポモドーロタイマーアプリケーションを例に、各層の実装を見ていきましょう。

プレゼンテーション層 (PomodoroController.java)

Java

package com.example.pomodorotimer.controller;

import com.example.pomodorotimer.service.PomodoroService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PomodoroController {

    private final PomodoroService pomodoroService;

    @Autowired
    public PomodoroController(PomodoroService pomodoroService) {
        this.pomodoroService = pomodoroService;
    }

    @PostMapping("/pomodoro")
    public String startPomodoro(@RequestParam int workMinutes, @RequestParam int workSeconds,
            @RequestParam int breakMinutes, @RequestParam int breakSeconds) {
        int workTotalSeconds = workMinutes * 60 + workSeconds;
        int breakTotalSeconds = breakMinutes * 60 + breakSeconds;
        pomodoroService.startPomodoro(workTotalSeconds, breakTotalSeconds);
        return "ポモドーロタイマーを開始しました。";
    }
}
  • @RestController: JSON や文字列などのレスポンスを返します。
  • @Autowired: Spring の依存性注入 (DI) により、PomodoroService のインスタンスが自動的に注入されます。DI により、クラス間の依存関係が疎になり、コードの保守性・柔軟性が向上します。
  • @RequestParam: HTTP リクエストのパラメータをメソッドの引数にマッピングします。例えば、/pomodoro?workMinutes=25&workSeconds=0&breakMinutes=5&breakSeconds=0 というリクエストの場合、workMinutes には 25, workSeconds には 0, ... がそれぞれ渡されます。

アプリケーション層 (TimerService.java, PomodoroService.java)

Java

// TimerService.java
package com.example.pomodorotimer.service;

import java.util.Timer;
import java.util.TimerTask;
import org.springframework.stereotype.Service;

@Service
public class TimerService {

    public void startCountdown(int taskSeconds, Runnable onFinish) {
        // ... (タイマー処理の実装)
    }
}

// PomodoroService.java
package com.example.pomodorotimer.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class PomodoroService {

    private final TimerService timerService;
    // ... (ポモドーロタイマーのロジック)
}
  • @Service: アプリケーション層の処理を記述します。ここでは、タイマー機能とポモドーロタイマーのロジックが実装されています。

データ層 (Task.java, TaskRepository.java)

Java

// Task.java
package com.example.pomodorotimer.domain;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import java.time.LocalDateTime;

@Entity
public class Task {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    // ... (タスクの属性)
}

// TaskRepository.java
package com.example.pomodorotimer.repository;

import com.example.pomodorotimer.domain.Task;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface TaskRepository extends JpaRepository<Task, Long> {
}
  • @Entity: データベースのテーブルに対応するエンティティを宣言します。
  • @Id, @GeneratedValue: エンティティの ID を定義します。
  • @Repository: エンティティを操作するためのインターフェースを宣言します。

まとめ

三層構造を意識することで、コードの見通しが良くなり、保守性・拡張性が向上することを実感しました。
最初は戸惑うかもしれませんが、各層の役割を理解し、適切な場所にコードを記述することで、より堅牢なWebアプリケーションを開発できるはずです。

-Uncategorized