アーキテクチャ設計ガイド¶
概要¶
本ガイドは、システム開発におけるアーキテクチャ設計の指針を提供します。バックエンドでは業務領域の特性とデータ構造の複雑さに基づいたアーキテクチャパターンの選択を、フロントエンドでは現代的なWebアプリケーション開発のベストプラクティスを定義します。
アーキテクチャ設計の原則¶
基本方針¶
- モノレポ構成: 単一リポジトリでフロントエンド・バックエンドを統合管理
- 関心事の分離: 明確な責務分離によるメンテナンス性向上
- 依存関係の方向性: 外側から内側(ドメイン)への単方向依存
- テストしやすい設計: 各層が独立してテスト可能な構造
全体構成¶
コンポーネント責務¶
アプリケーション¶
フロントエンド¶
- UI/UX: ユーザーインターフェース・ユーザー体験
- 状態管理: アプリケーション状態とサーバー状態の管理
- API連携: バックエンドとのデータ通信
- レンダリング: 効率的な画面描画とユーザーインタラクション
バックエンド¶
- ビジネスロジック: 業務ルール・制約の実装
- データ永続化: データの保存・取得・更新・削除
- セキュリティ: 認証・認可・データ保護
- 外部システム連携: API・メッセージング・ファイル処理
インフラストラクチャ¶
- ネットワーク: 負荷分散・DNS・CDN
- アプリケーション: ホスティング: サーバー・コンテナ管理
バックエンドアーキテクチャ¶
バックエンドアーキテクチャパターン選択フロー¶
判断基準¶
業務領域カテゴリー¶
| カテゴリー | 特徴 | 例 |
|---|---|---|
| 中核の業務領域 | 組織の競争優位性を決定する領域 | 商品管理、顧客管理、受注処理 |
| 補完、一般との連携 | 中核を支援する補助的な領域 | レポート出力、バッチ処理、外部連携 |
データ構造の複雑さ¶
| 複雑さ | 判定基準 |
|---|---|
| 複雑 | エンティティ間の関係が多く、ビジネスルールが複雑 |
| シンプル | 単純なCRUD操作が中心、関係性が少ない |
特殊要件¶
- 金額を扱う: 会計・決済・金融関連の処理
- 分析: 大量データの集計・分析処理
- 監査記録が必要: コンプライアンス・規制対応
アーキテクチャパターン詳細¶
1. トランザクションスクリプトパターン¶
適用場面¶
- 業務領域: 補完・一般との連携
- データ構造: シンプル
- システム規模: 小規模
特徴¶
メリット:
- 実装が直感的でわかりやすい
- 開発速度が早い
- 小規模チームでも扱いやすい
デメリット:
- コードの重複が発生しやすい
- 大規模化すると保守が困難
- ビジネスロジックが散在する
実装指針¶
// 例:会議室予約処理
public class ReservationService {
public void makeReservation(ReservationRequest request) {
// 1. バリデーション
validateRequest(request);
// 2. 重複チェック
checkConflicts(request);
// 3. 予約作成
createReservation(request);
// 4. 通知送信
sendNotification(request);
}
}
2. アクティブレコードパターン¶
適用場面¶
- 業務領域: 補完・一般との連携
- データ構造: 複雑
- システム規模: 中規模
特徴¶
メリット:
- オブジェクトとデータベースの対応が明確
- ORMとの相性が良い
- 理解しやすい構造
デメリット:
- データアクセスとビジネスロジックが密結合
- テストが困難
- ドメインロジックが薄くなる傾向
実装指針¶
// 例:予約エンティティ
@Entity
public class Reservation {
@Id
private Long id;
private Long userId;
private Long roomId;
private LocalDateTime startTime;
private LocalDateTime endTime;
// ビジネスロジックを含む
public void cancel() {
if (canCancel()) {
this.status = CANCELLED;
this.save();
}
}
public boolean canCancel() {
return startTime.isAfter(LocalDateTime.now().plusHours(2));
}
}
3. ドメインモデルパターン¶
適用場面¶
- 業務領域: 中核の業務領域
- 特殊要件: 金額を扱わない、監査記録不要
- システム規模: 中規模〜大規模
特徴¶
メリット:
- リッチなドメインモデル
- ビジネスロジックの集約
- 高い保守性・拡張性
- テスト容易性
デメリット:
- 初期の学習コストが高い
- 設計の複雑さ
- 開発速度が遅い場合がある
実装指針¶
// ドメインモデル例
public class Reservation {
private ReservationId id;
private UserId userId;
private MeetingRoomId roomId;
private TimeSlot timeSlot;
private ReservationStatus status;
// ファクトリーメソッド
public static Reservation create(UserId userId, MeetingRoomId roomId, TimeSlot timeSlot) {
validateTimeSlot(timeSlot);
return new Reservation(ReservationId.generate(), userId, roomId, timeSlot, CONFIRMED);
}
// ビジネスロジック
public void cancel(CancellationPolicy policy) {
if (!policy.canCancel(this.timeSlot)) {
throw new CancellationNotAllowedException();
}
this.status = CANCELLED;
}
}
4. イベント履歴式ドメインモデルパターン¶
適用場面¶
- 業務領域: 中核の業務領域
- 特殊要件: 金額を扱う、分析・監査記録が必要
- システム規模: 大規模
特徴¶
メリット:
- 完全な監査証跡
- 時系列分析が可能
- 高いスケーラビリティ
- 複雑なクエリに対応
デメリット:
- 実装の複雑さ
- 高い学習コスト
- 結果整合性の考慮が必要
実装指針¶
// イベント例
public class ReservationCreatedEvent extends DomainEvent {
private final ReservationId reservationId;
private final UserId userId;
private final MeetingRoomId roomId;
private final TimeSlot timeSlot;
private final LocalDateTime occurredAt;
}
// 集約例
public class ReservationAggregate {
private ReservationId id;
private List<DomainEvent> changes = new ArrayList<>();
public void create(UserId userId, MeetingRoomId roomId, TimeSlot timeSlot) {
var event = new ReservationCreatedEvent(id, userId, roomId, timeSlot, LocalDateTime.now());
apply(event);
}
private void apply(DomainEvent event) {
changes.add(event);
// 状態更新ロジック
}
}
アーキテクチャスタイル詳細¶
1. レイヤードアーキテクチャ(3層)¶
適用場面¶
- 永続化モデル: 単一
- システム特性: 標準的なエンタープライズアプリケーション
構造¶
実装指針¶
// プレゼンテーション層
@RestController
public class ReservationController {
private final ReservationService service;
@PostMapping("/reservations")
public ResponseEntity<Reservation> create(@RequestBody CreateReservationRequest request) {
var reservation = service.createReservation(request);
return ResponseEntity.ok(reservation);
}
}
// ビジネスロジック層
@Service
public class ReservationService {
private final ReservationRepository repository;
public Reservation createReservation(CreateReservationRequest request) {
// ビジネスロジック実行
var reservation = new Reservation(request);
return repository.save(reservation);
}
}
// データアクセス層
@Repository
public interface ReservationRepository extends JpaRepository<Reservation, Long> {
List<Reservation> findByUserId(Long userId);
}
2. レイヤードアーキテクチャ(4層)¶
適用場面¶
- 永続化モデル: 複数
- システム特性: 大規模エンタープライズアプリケーション
構造¶
レイヤー責務¶
| レイヤー | 責務 |
|---|---|
| プレゼンテーション | HTTP要求/応答、入力検証、認証 |
| アプリケーション | ユースケース制御、トランザクション境界 |
| ドメイン | ビジネスルール、不変条件、ドメインサービス |
| インフラストラクチャ | 外部システム連携、永続化、技術的関心事 |
3. ポートとアダプターアーキテクチャ(ヘキサゴナル)¶
適用場面¶
- ドメインモデル: あり
- 永続化モデル: 単一
- システム特性: マイクロサービス、高いテスト容易性が要求される
構造¶
実装指針¶
// 入力ポート(ユースケース)
public interface CreateReservationUseCase {
ReservationId execute(CreateReservationCommand command);
}
// 出力ポート(リポジトリインターフェース)
public interface ReservationRepository {
void save(Reservation reservation);
Optional<Reservation> findById(ReservationId id);
}
// ドメインサービス(実装)
@Service
public class ReservationService implements CreateReservationUseCase {
private final ReservationRepository repository;
@Override
public ReservationId execute(CreateReservationCommand command) {
var reservation = Reservation.create(command);
repository.save(reservation);
return reservation.getId();
}
}
// アダプター(インフラストラクチャ)
@Repository
public class JpaReservationRepository implements ReservationRepository {
private final SpringDataReservationRepository jpaRepository;
@Override
public void save(Reservation reservation) {
var entity = toEntity(reservation);
jpaRepository.save(entity);
}
}
4. CQRSアーキテクチャ¶
適用場面¶
- 永続化モデル: 複数
- 特殊要件: イベント履歴式、高スケーラビリティ
- システム特性: 複雑なクエリ要件、読み書き分離
構造¶
実装指針¶
// コマンド側
@CommandHandler
public class CreateReservationHandler {
private final ReservationWriteRepository writeRepository;
private final EventBus eventBus;
public void handle(CreateReservationCommand command) {
var reservation = new ReservationAggregate(command);
writeRepository.save(reservation);
var events = reservation.getUncommittedEvents();
eventBus.publishAll(events);
}
}
// クエリ側
@QueryHandler
public class ReservationQueryHandler {
private final ReservationReadRepository readRepository;
public List<ReservationView> handle(FindReservationsByUserQuery query) {
return readRepository.findByUserId(query.getUserId());
}
}
// イベントハンドラー(プロジェクション更新)
@EventHandler
public class ReservationProjectionHandler {
private final ReservationReadRepository readRepository;
public void on(ReservationCreatedEvent event) {
var view = new ReservationView(event);
readRepository.save(view);
}
}
テスト戦略とアーキテクチャの関係¶
ピラミッド形テスト(ドメインモデル・イベント履歴式)¶
特徴:
- ユニットテスト中心(80%)
- ドメインロジックの徹底検証
- 高品質なビジネスルール実装
ダイヤモンド形テスト(アクティブレコード)¶
特徴:
- 統合テスト中心(60%)
- データアクセスロジックの重点検証
- ORMとの連携確認
逆ピラミッド形テスト(トランザクションスクリプト)¶
特徴:
- E2Eテスト中心(70%)
- エンドツーエンドの動作確認
- シナリオベースの検証
アーキテクチャ評価基準¶
品質属性評価マトリックス¶
| 品質属性 | トランザクション スクリプト |
アクティブ レコード |
ドメイン モデル |
イベント履歴式 ドメインモデル |
|---|---|---|---|---|
| 開発速度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ | ⭐ |
| 保守性 | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| テスト容易性 | ⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| スケーラビリティ | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 複雑さ対応 | ⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 監査要件 | ⭐ | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
アーキテクチャスタイル評価マトリックス¶
| 品質属性 | レイヤード 3層 |
レイヤード 4層 |
ポートと アダプター |
CQRS |
|---|---|---|---|---|
| 学習容易性 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
| テスト容易性 | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 関心事分離 | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| パフォーマンス | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| スケーラビリティ | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 進化性 | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
実装ベストプラクティス¶
1. 依存関係管理¶
// ✅ 良い例:インターフェースに依存
public class ReservationService {
private final ReservationRepository repository; // インターフェース
private final NotificationService notificationService; // インターフェース
}
// ❌ 悪い例:具象クラスに依存
public class ReservationService {
private final JpaReservationRepository repository; // 具象クラス
private final EmailService emailService; // 具象クラス
}
2. レイヤー分離¶
// ✅ 良い例:適切なレイヤー分離
@RestController
public class ReservationController {
@PostMapping("/reservations")
public ResponseEntity<ReservationResponse> create(@RequestBody CreateReservationRequest request) {
// プレゼンテーション層の責務のみ
var command = toCommand(request);
var result = useCase.execute(command);
return ResponseEntity.ok(toResponse(result));
}
}
// ❌ 悪い例:レイヤー違反
@RestController
public class ReservationController {
@PostMapping("/reservations")
public ResponseEntity<ReservationResponse> create(@RequestBody CreateReservationRequest request) {
// ビジネスロジックをコントローラーに記述(レイヤー違反)
if (request.getStartTime().isBefore(LocalDateTime.now().plusHours(2))) {
throw new ValidationException("2時間前までの予約が必要です");
}
// ...
}
}
3. エラーハンドリング¶
// ✅ 良い例:適切なエラー伝播
public class ReservationService {
public ReservationId createReservation(CreateReservationCommand command) {
try {
var reservation = Reservation.create(command);
repository.save(reservation);
return reservation.getId();
} catch (DomainException e) {
// ドメイン例外は適切にハンドリング
throw new ReservationException("予約作成に失敗しました", e);
}
}
}
// ❌ 悪い例:例外の隠蔽
public class ReservationService {
public ReservationId createReservation(CreateReservationCommand command) {
try {
var reservation = Reservation.create(command);
repository.save(reservation);
return reservation.getId();
} catch (Exception e) {
// すべての例外を隠蔽(問題の特定が困難)
return null;
}
}
}
フロントエンドアーキテクチャ¶
フロントエンドアーキテクチャ決定フロー¶
主要アーキテクチャ決定ポイント¶
フロントエンド設計原則¶
良いアーキテクチャ決定¶
1. プロジェクト構造¶
標準的なフロントエンドプロジェクト構造¶
src/
├── components/ # (1) 共通UIコンポーネント
│ ├── ui/ # 基本UIパーツ(Button, Input, Modal等)
│ └── layout/ # レイアウトコンポーネント
├── config/ # (2) アプリケーション設定
│ ├── constants.ts # 定数定義
│ ├── env.ts # 環境変数管理
│ └── api.ts # API設定
├── features/ # (3) フィーチャー単位のコンポーネント
│ ├── auth/ # 認証機能
│ ├── reservation/ # 予約機能
│ └── meeting-room/# 会議室管理機能
├── layouts/ # (4) アプリケーションレイアウト
│ ├── AppLayout.tsx
│ ├── AuthLayout.tsx
│ └── DashboardLayout.tsx
├── lib/ # (5) 外部ライブラリ設定・ユーティリティ
│ ├── auth.ts # 認証ライブラリ設定
│ ├── api-client.ts# API クライアント
│ └── utils.ts # ヘルパー関数
├── pages/ # (6) ページコンポーネント(ルーティング)
│ ├── LoginPage.tsx
│ ├── DashboardPage.tsx
│ └── ReservationPage.tsx
├── providers/ # (7) Context Provider
│ ├── AuthProvider.tsx
│ ├── ThemeProvider.tsx
│ └── AppProviders.tsx
├── stores/ # (8) 状態管理
│ ├── authStore.ts
│ ├── uiStore.ts
│ └── index.ts
├── testing/ # (9) テスト用ユーティリティ
│ ├── setup.ts # テスト環境設定
│ ├── mocks/ # モックデータ
│ └── utils.ts # テストヘルパー
├── types/ # (10) TypeScript型定義
│ ├── api.ts # API型定義
│ ├── auth.ts # 認証関連型
│ └── common.ts # 共通型定義
└── utils/ # (11) 汎用ユーティリティ関数
├── format.ts # フォーマット関数
├── validation.ts# バリデーション
└── date.ts # 日付操作
プロジェクト規模による使い分け¶
小規模プロジェクト (シンプル構造):
src/
├── components/ # UI コンポーネント
├── pages/ # ページコンポーネント
├── hooks/ # カスタムフック
├── utils/ # ユーティリティ
├── types/ # 型定義
└── config/ # 設定
大規模プロジェクト (フル構造): 上記の標準11フォルダ構成を使用
2. コンポーネント設計¶
- 小さなコンポーネント: 単一責任の原則に従った分割
- 関心事の分離: UI・ロジック・状態管理の明確な分離
- 再利用性: 汎用コンポーネントの適切な抽象化
3. 状態管理戦略¶
4. レンダリング戦略¶
| 戦略 | 適用場面 | 特徴 | 例 |
|---|---|---|---|
| SPA | ダッシュボード・管理画面 | 高いインタラクティビティ | React |
| SSR | SEO重要・高更新頻度 | 初期表示高速・SEO対応 | Next.js |
| SSG | SEO重要・低更新頻度 | 最高のパフォーマンス | Gatsby |
悪いアーキテクチャ決定¶
❌ 避けるべき設計¶
-
フラットなプロジェクト構造
src/ ├── LoginPage.tsx # 管理困難 ├── Button.tsx # コンポーネント分類なし ├── UserService.ts # ロジック散在 ├── constants.ts # 設定管理なし ├── utils.ts # 目的不明 ├── types.ts # 型定義混在 └── ... # 数十個のファイル(役割不明) -
不適切な責務分散
src/ ├── components/ # 全コンポーネント混在 │ ├── LoginPage.tsx # ページなのにcomponents内 │ ├── Button.tsx # UIコンポーネント │ ├── AuthProvider.tsx # Providerなのにcomponents内 │ └── authStore.ts # ストアなのにcomponents内 └── utils/ # 何でも入れる場所 ├── api.ts # API設定 ├── constants.ts # 定数 ├── types.ts # 型定義 └── validation.ts # バリデーション -
巨大で密結合なコンポーネント
// ❌ 悪い例 function MegaComponent() { // 500行以上のコンポーネント // 複数の責務を持つ // テストが困難 } -
不適切な状態管理
// ❌ 悪い例:すべてをグローバル状態に const globalState = { user: {}, reservations: [], modalOpen: false, // UI状態もグローバル化 buttonColor: 'blue' // 一時的な状態もグローバル化 } -
セキュリティの軽視
// ❌ 悪い例:入力値のサニタイジング不備 function UserInput({ input }) { return <div dangerouslySetInnerHTML={{__html: input}} /> }
フロントエンド実装パターン¶
1. コンポーネント設計パターン¶
Container/Presentational パターン¶
// ファイル配置例
src/
├── features/reservation/
│ ├── components/
│ │ ├── ReservationContainer.tsx # Container
│ │ └── ReservationList.tsx # Presentational
│ ├── hooks/
│ │ └── useReservations.ts # Custom Hook
│ └── types/
│ └── reservation.ts # 型定義
// ✅ Container: ロジック担当 (features/reservation/components/ReservationContainer.tsx)
import { useReservations } from '../hooks/useReservations';
import { ReservationList } from './ReservationList';
export function ReservationContainer() {
const { reservations, loading, createReservation } = useReservations();
const handleCreate = useCallback((data) => {
createReservation(data);
}, [createReservation]);
return (
<ReservationList
reservations={reservations}
loading={loading}
onCreate={handleCreate}
/>
);
}
// ✅ Presentational: UI担当 (features/reservation/components/ReservationList.tsx)
import { LoadingSpinner } from '@/components/ui/LoadingSpinner';
import { CreateButton } from '@/components/ui/CreateButton';
import type { Reservation } from '../types/reservation';
interface Props {
reservations: Reservation[];
loading: boolean;
onCreate: (data: CreateReservationData) => void;
}
export function ReservationList({ reservations, loading, onCreate }: Props) {
if (loading) return <LoadingSpinner />;
return (
<div>
{reservations.map(reservation =>
<ReservationItem key={reservation.id} data={reservation} />
)}
<CreateButton onClick={onCreate} />
</div>
);
}
Custom Hooks パターン¶
// ✅ ビジネスロジックの分離
function useReservation() {
const [reservations, setReservations] = useState([]);
const [loading, setLoading] = useState(false);
const createReservation = useCallback(async (data) => {
setLoading(true);
try {
const result = await api.createReservation(data);
setReservations(prev => [...prev, result]);
} catch (error) {
handleError(error);
} finally {
setLoading(false);
}
}, []);
return { reservations, loading, createReservation };
}
2. 状態管理パターン¶
Context + Reducer パターン¶
// ✅ 状態とアクションの型安全な管理
interface AppState {
user: User | null;
theme: 'light' | 'dark';
}
type AppAction =
| { type: 'SET_USER'; payload: User }
| { type: 'SET_THEME'; payload: 'light' | 'dark' };
function appReducer(state: AppState, action: AppAction): AppState {
switch (action.type) {
case 'SET_USER':
return { ...state, user: action.payload };
case 'SET_THEME':
return { ...state, theme: action.payload };
default:
return state;
}
}
const AppContext = createContext<{
state: AppState;
dispatch: Dispatch<AppAction>;
} | null>(null);
3. パフォーマンス最適化パターン¶
遅延読み込み¶
// ✅ コード分割
const ReservationPage = lazy(() => import('./pages/ReservationPage'));
const UserManagementPage = lazy(() => import('./pages/UserManagementPage'));
function App() {
return (
<Router>
<Suspense fallback={<LoadingSpinner />}>
<Routes>
<Route path="/reservations" element={<ReservationPage />} />
<Route path="/users" element={<UserManagementPage />} />
</Routes>
</Suspense>
</Router>
);
}
メモ化¶
// ✅ 適切なメモ化
const ExpensiveList = memo(function ExpensiveList({ items, filter }) {
const filteredItems = useMemo(
() => items.filter(item => item.type === filter),
[items, filter]
);
return (
<ul>
{filteredItems.map(item =>
<ExpensiveListItem key={item.id} item={item} />
)}
</ul>
);
});
フロントエンド品質保証¶
1. TypeScript活用¶
// ✅ 型安全なAPI呼び出し
interface CreateReservationRequest {
roomId: string;
startTime: string;
endTime: string;
purpose: string;
}
interface ReservationResponse {
id: string;
status: 'confirmed' | 'pending' | 'cancelled';
createdAt: string;
}
async function createReservation(
request: CreateReservationRequest
): Promise<ReservationResponse> {
const response = await fetch('/api/reservations', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(request)
});
if (!response.ok) {
throw new Error('予約作成に失敗しました');
}
return response.json();
}
2. テスト戦略¶
ユニットテスト¶
// ✅ Custom Hooksのテスト
import { renderHook, act } from '@testing-library/react';
import { useReservation } from './useReservation';
test('should create reservation successfully', async () => {
const { result } = renderHook(() => useReservation());
await act(async () => {
await result.current.createReservation({
roomId: '1',
startTime: '2024-01-01T10:00:00Z',
endTime: '2024-01-01T11:00:00Z',
purpose: 'ミーティング'
});
});
expect(result.current.reservations).toHaveLength(1);
});
統合テスト¶
// ✅ コンポーネント統合テスト
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { ReservationForm } from './ReservationForm';
test('should submit reservation form', async () => {
const mockOnSubmit = jest.fn();
render(<ReservationForm onSubmit={mockOnSubmit} />);
fireEvent.change(screen.getByLabelText('会議室'), {
target: { value: '会議室A' }
});
fireEvent.click(screen.getByText('予約する'));
await waitFor(() => {
expect(mockOnSubmit).toHaveBeenCalledWith(
expect.objectContaining({
roomName: '会議室A'
})
);
});
});
フロントエンド移行戦略¶
段階的移行アプローチ¶
アーキテクチャ移行戦略¶
段階的移行アプローチ¶
移行時の注意点¶
バックエンド移行¶
- 段階的移行: ビッグバン移行は避け、モジュール単位で実施
- 後方互換性: 既存のAPIやインターフェースの維持
- データ整合性: 移行期間中のデータ同期戦略
- テストカバレッジ: 移行前後でのテスト品質維持
- パフォーマンス監視: 移行による性能劣化の早期検知
フロントエンド移行¶
- フィーチャーフラグ: 新旧機能の段階的切り替え
- コンポーネント移行: デザインシステムの統一
- 状態管理移行: データフローの一貫性維持
- バンドルサイズ監視: パフォーマンス劣化防止
- ブラウザ互換性: サポート対象ブラウザでの動作確認
インフラストラクチャアーキテクチャ¶
インフラストラクチャ設計の原則¶
基本方針¶
- Infrastructure as Code (IaC): インフラの設定をコード化し、バージョン管理
- 自動化: デプロイ・スケーリング・復旧の自動化
- モニタリングとオブザーバビリティ: システム状態の可視化と追跡
- セキュリティファースト: 設計段階からのセキュリティ考慮
- コスト最適化: リソース利用の効率化とコスト管理
デプロイメントアーキテクチャパターン¶
1. モノリシックデプロイメント¶
適用場面¶
- システム規模: 小規模〜中規模
- チーム規模: 小規模チーム
- 特性: 単一アプリケーション、シンプルなデプロイ
構造¶
メリット:
- シンプルな構成
- 低い運用コスト
- デプロイが容易
デメリット:
- スケーリングの柔軟性が低い
- 単一障害点
- 大規模化時の制約
2. マイクロサービスデプロイメント¶
適用場面¶
- システム規模: 大規模
- チーム規模: 複数チーム
- 特性: 独立したサービス、高いスケーラビリティ
構造¶
メリット:
- 独立したデプロイとスケーリング
- 技術スタックの柔軟性
- 障害の局所化
デメリット:
- 複雑な運用
- 分散システムの課題
- デバッグの困難さ
3. コンテナオーケストレーション¶
適用場面¶
- デプロイ頻度: 高頻度
- スケーリング要件: 動的スケーリング
- 特性: Kubernetes、Docker等のコンテナ技術
構造¶
メリット:
- 自動スケーリング
- 高可用性
- リソース効率化
デメリット:
- 高い学習コスト
- 複雑な設定
- 運用の複雑さ
4. サーバーレスアーキテクチャ¶
適用場面¶
- 負荷パターン: 変動が大きい
- 実行頻度: イベント駆動、バースト型
- 特性: AWS Lambda、Azure Functions等
構造¶
メリット:
- 完全なサーバー管理不要
- 自動スケーリング
- 従量課金
デメリット:
- コールドスタート
- ベンダーロックイン
- ローカルテストの困難さ
ネットワークアーキテクチャ¶
ネットワーク構成パターン¶
ネットワーク設計の要点¶
| 要素 | 考慮事項 |
|---|---|
| 負荷分散 | ロードバランサーによる複数サーバーへの分散 |
| セキュリティ | ファイアウォール、WAF、DDoS対策 |
| 可用性 | 冗長化、フェイルオーバー |
| パフォーマンス | CDN、キャッシング、帯域幅 |
スケーリング戦略¶
垂直スケーリング vs 水平スケーリング¶
スケーリング戦略の選択¶
| 戦略 | メリット | デメリット | 適用場面 |
|---|---|---|---|
| 垂直スケーリング | シンプル、データ整合性保持 | 物理的上限、ダウンタイム | データベース、レガシーシステム |
| 水平スケーリング | 柔軟性、高可用性 | 複雑な設計、データ分散 | Webアプリケーション、マイクロサービス |
オートスケーリング¶
監視とログ管理¶
監視アーキテクチャ¶
監視対象と指標¶
| カテゴリ | 監視項目 | 重要指標 |
|---|---|---|
| インフラ | CPU、メモリ、ディスク、ネットワーク | 使用率、レスポンス時間 |
| アプリケーション | レスポンスタイム、エラー率、スループット | レイテンシ、成功率 |
| ビジネス | アクティブユーザー数、トランザクション数 | コンバージョン率、利用状況 |
ログ管理戦略¶
ログレベルの定義¶
// ✅ 適切なログレベルの使用
public class ReservationService {
private static final Logger logger = LoggerFactory.getLogger(ReservationService.class);
public void createReservation(ReservationRequest request) {
logger.debug("予約作成開始: {}", request);
try {
var reservation = processReservation(request);
logger.info("予約作成成功: reservationId={}", reservation.getId());
} catch (BusinessException e) {
logger.warn("予約作成失敗(ビジネスエラー): {}", e.getMessage());
throw e;
} catch (Exception e) {
logger.error("予約作成失敗(システムエラー)", e);
throw new SystemException("予約作成処理でエラーが発生しました", e);
}
}
}
ログの集約と分析¶
- 集約: Fluentd、Logstash等でログを集約
- 保存: Elasticsearch、S3等で長期保存
- 分析: Kibana、CloudWatch Insights等で可視化・分析
セキュリティアーキテクチャ¶
多層防御アーキテクチャ¶
セキュリティベストプラクティス¶
| 領域 | 対策 | 実装例 |
|---|---|---|
| ネットワーク | ファイアウォール、WAF、DDoS対策 | AWS WAF, CloudFlare |
| 認証・認可 | 多要素認証、OAuth2.0、RBAC | Auth0, Keycloak |
| データ保護 | 暗号化(保管時・転送時)、マスキング | TLS/SSL, AES-256 |
| 監査 | アクセスログ、変更履歴、コンプライアンス | CloudTrail, 監査ログ |
セキュリティ実装例¶
// ✅ セキュアな実装
@RestController
@RequestMapping("/api/reservations")
public class ReservationController {
@PostMapping
@PreAuthorize("hasRole('USER')") // 認可チェック
public ResponseEntity<Reservation> create(
@Valid @RequestBody CreateReservationRequest request) { // 入力検証
// SQLインジェクション対策(PreparedStatement使用)
var reservation = reservationService.createReservation(request);
// 監査ログ記録
auditService.log("RESERVATION_CREATED", reservation.getId());
return ResponseEntity.ok(reservation);
}
}
バックアップと災害復旧¶
バックアップ戦略¶
RPO/RTO定義¶
| 指標 | 意味 | 目標値例 |
|---|---|---|
| RPO (Recovery Point Objective) | データ損失許容時間 | 1時間以内 |
| RTO (Recovery Time Objective) | サービス復旧目標時間 | 4時間以内 |
ディザスタリカバリパターン¶
1. バックアップ&リストア¶
- RPO: 数時間〜1日
- RTO: 数時間〜1日
- コスト: 低
- 用途: 非重要システム
2. パイロットライト¶
- RPO: 数分〜数時間
- RTO: 1時間以内
- コスト: 中
- 用途: ビジネス継続性が重要
3. ウォームスタンバイ¶
- RPO: 数秒〜数分
- RTO: 数分
- コスト: 高
- 用途: 高可用性要求システム
4. マルチサイトアクティブ/アクティブ¶
- RPO: ゼロ
- RTO: ゼロ(自動フェイルオーバー)
- コスト: 非常に高
- 用途: ミッションクリティカルシステム
Infrastructure as Code (IaC)¶
IaCツールの選択¶
| ツール | 特徴 | 適用場面 |
|---|---|---|
| Terraform | マルチクラウド対応、宣言的 | クラウド横断的なインフラ管理 |
| CloudFormation | AWS特化、AWSサービスとの統合 | AWS専用環境 |
| Ansible | 構成管理、手続き型 | サーバー設定管理 |
| Pulumi | 汎用プログラミング言語使用 | 複雑なロジック要求時 |
IaC実装例(Terraform)¶
# ✅ VPC定義
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "main-vpc"
Environment = var.environment
}
}
# ✅ サブネット定義
resource "aws_subnet" "public" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index}.0/24"
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
tags = {
Name = "public-subnet-${count.index + 1}"
}
}
# ✅ セキュリティグループ
resource "aws_security_group" "web" {
name = "web-sg"
description = "Security group for web servers"
vpc_id = aws_vpc.main.id
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
CI/CDパイプライン¶
CI/CDアーキテクチャ¶
デプロイメント戦略¶
ブルーグリーンデプロイメント¶
メリット:
- 即座にロールバック可能
- ゼロダウンタイム
- 本番環境での検証
デメリット:
- リソースが2倍必要
- データベース移行の複雑さ
カナリアデプロイメント¶
メリット:
- リスク最小化
- 段階的なロールアウト
- 問題の早期発見
デメリット:
- 複雑な管理
- バージョン混在期間
インフラストラクチャ評価基準¶
品質属性評価マトリックス¶
| 品質属性 | モノリシック | マイクロサービス | コンテナ | サーバーレス |
|---|---|---|---|---|
| 運用複雑性 | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| スケーラビリティ | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| コスト効率 | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| デプロイ速度 | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 可用性 | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 監視・デバッグ | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
コスト最適化戦略¶
| 戦略 | 実装方法 | 削減効果 |
|---|---|---|
| リソース最適化 | 適切なインスタンスサイズ選択 | 20-40% |
| 予約インスタンス | 長期コミットメントで割引 | 40-60% |
| スポットインスタンス | 余剰リソースの活用 | 70-90% |
| オートスケーリング | 需要に応じた自動調整 | 30-50% |
| ストレージ最適化 | ライフサイクル管理、圧縮 | 30-60% |
インフラストラクチャ移行戦略¶
クラウド移行パターン¶
移行時の注意点¶
- 段階的移行: すべてを一度に移行せず、段階的に実施
- パイロットプロジェクト: 小規模システムで先行検証
- データ移行計画: データの整合性とダウンタイム最小化
- セキュリティ: クラウド環境でのセキュリティ要件確認
- コスト管理: 移行コストと運用コストの可視化
まとめ¶
バックエンドアーキテクチャ選択の指針¶
- 業務ドメインの理解: 中核業務と補完業務の明確な識別
- データ複雑性の評価: エンティティ関係とビジネスルールの複雑さ
- 非機能要件の考慮: パフォーマンス、スケーラビリティ、監査要件
- チーム能力の評価: 技術的習熟度と学習意欲
- 長期戦略の整合: 将来的な拡張性と保守性の確保
フロントエンドアーキテクチャ選択の指針¶
- プロジェクト規模: 小規模・中規模・大規模に応じた構造設計
- ユーザー体験要件: SEO・パフォーマンス・インタラクティビティの優先順位
- 状態管理複雑性: データフロー・更新頻度・共有範囲の分析
- チーム構成: フロントエンド専任・フルスタック・QAエンジニアの有無
- 技術的制約: ブラウザサポート・既存システム・運用環境
インフラストラクチャアーキテクチャ選択の指針¶
- システム規模とトラフィック: 予想される負荷・成長率・ピーク時の要件分析
- 可用性要件: SLA・ダウンタイム許容度・災害復旧要件の定義
- セキュリティ要件: コンプライアンス・データ保護・監査要件の評価
- 運用体制: チームの技術力・運用負荷・自動化レベルの考慮
- コスト制約: 初期投資・運用コスト・スケーリングコストのバランス
成功要因¶
バックエンド¶
- 適切なパターン選択: 業務特性に応じた最適なアーキテクチャの採用
- 段階的な実装: 小さく始めて継続的に改善
- 品質の作り込み: テストファースト・継続的インテグレーション
- ドメイン駆動設計: ビジネスルールの適切な表現と分離
フロントエンド¶
- 適切な技術選択: 要件に応じたライブラリ・フレームワークの選定
- コンポーネント設計: 再利用性と保守性を両立した設計
- 状態管理戦略: スケールに応じた適切な状態管理手法の採用
- パフォーマンス最適化: ユーザー体験を重視したパフォーマンス設計
インフラストラクチャ¶
- 自動化の徹底: IaC によるインフラ管理とデプロイメントの自動化
- 監視とオブザーバビリティ: 包括的な監視体制と問題の早期検知
- セキュリティの組み込み: 設計段階からのセキュリティ対策実装
- コスト最適化: リソース利用の継続的な見直しと最適化
統合的成功要因¶
- チーム教育: アーキテクチャ原則の共有と実践
- 継続的改善: 定期的な設計見直しとリファクタリング
- 品質文化: 自動テスト・コードレビュー・静的解析の徹底
- 段階的移行: リスクを最小化した漸進的なアーキテクチャ改善
実践ポイント¶
開発初期¶
- 要件に基づく技術選択: 過度な技術より要件適合性を重視
- プロトタイプ開発: アーキテクチャ妥当性の早期検証
- チーム合意形成: 技術選択の背景と理由の共有
開発中期¶
- 継続的リファクタリング: 設計負債の早期解消
- パフォーマンス監視: 品質メトリクスに基づく改善
- テストカバレッジ: アーキテクチャ変更に対する安全性確保
運用期¶
- 監視・メトリクス: 実装の効果測定と改善指針
- 技術的負債管理: 計画的なアーキテクチャ改善
- スケーラビリティ対応: 成長に応じたアーキテクチャ進化
良いアーキテクチャは、システムの長期的成功の基盤となります。本ガイドを参考に、アプリケーション・インフラストラクチャそれぞれの特性を理解し、プロジェクトに最適なアーキテクチャを選択・実装してください。