Skip to content

イテレーション2 リファクタリング報告書

概要

イテレーション2では、コードベースの品質向上を目的として大規模なリファクタリングを実施しました。主に関数型プログラミングの導入、未使用コードの削除、アーキテクチャの整理を行いました。

実施期間

2025-08-15

リファクタリングの背景と目的

背景

  • テストカバレッジの向上(63.91% → 80%目標)
  • 保守性の向上
  • 関数型プログラミングの実践
  • アーキテクチャの整理

目的

  1. コード品質の向上
  2. 保守性の向上
  3. 技術的負債の削減
  4. アーキテクチャの適正化

実施したリファクタリング

1. 関数型プログラミングの導入(lodash/fp)

対象ファイル

src/domain/models/
├── Puyo.ts
└── Field.ts

src/domain/services/
├── ChainService.ts
├── EliminationService.ts
├── GravityService.ts
└── PuyoSpawningService.ts

実施内容

Puyo.ts

// Before: 通常の関数
export const movePuyo = (puyo: Puyo, newPosition: Position): Puyo => {
  return { ...puyo, position: newPosition };
};

// After: curry化された関数
export const movePuyo = curry((newPosition: Position, puyo: Puyo): Puyo => {
  return { ...puyo, position: newPosition };
});

Field.ts

// Before: 通常の関数
export const getPuyo = (field: Field, position: Position): Puyo | undefined => {
  return field.grid[position.row]?.[position.col];
};

// After: curry化された関数
export const getPuyo = curry((position: Position, field: Field): Puyo | undefined => {
  return field.grid[position.row]?.[position.col];
});

ChainService.ts

// Before: 通常の実装
export const calculateChainScore = (chainResults: ChainResult[]): number => {
  return chainResults.reduce((total, result) => total + result.score, 0);
};

// After: 関数型実装
export const calculateChainScore = curry((multiplier: number, chainResults: ChainResult[]): number => 
  flow(
    filter((result: ChainResult) => result.eliminatedCount > 0),
    sumBy('score'),
    (score: number) => score * multiplier
  )(chainResults)
);

導入した関数型概念

  • curry化: 部分適用可能な関数
  • data-last: データが最後の引数になるパターン
  • flow: 関数合成によるパイプライン処理
  • filter, map, reduce: 配列操作の関数型アプローチ

2. 未使用コードの削除

削除統計

  • 削除関数数: 16個
  • 削除行数: 126行
  • 影響ファイル: 3個

削除詳細

Puyo.ts (9個の関数削除)

// 削除された未使用関数
- changeColor
- getPuyoColor
- isPuyoAt
- rotatePuyo
- scalePuyo
- combinePuyos
- splitPuyo
- isValidPuyo
- getPuyoStats

Field.ts (4個の関数削除)

// 削除された未使用関数
- findPuyos
- transformField
- getPuyosByColor
- getFieldStats

ChainService.ts (3個の関数削除)

// 削除された未使用関数
- sumChainScores
- mapChainResult
- isValidChainResult

削除プロセス

  1. 使用箇所の検索

    grep -r "functionName" src/
    

  2. TypeScript未検出の確認

  3. TypeScriptの静的解析では検出困難
  4. 手動でのgrep検索を実施

  5. 段階的削除

  6. 1つずつ削除してテスト実行
  7. 影響がないことを確認

3. アーキテクチャの整理

stores ディレクトリの移動

Before:

src/
├── application/
│   └── stores/
│       ├── gameStore.ts
│       └── gameStore.test.ts
└── presentation/
    └── components/

After:

src/
├── application/ (React依存除去)
└── presentation/
    ├── stores/
    │   ├── gameStore.ts
    │   └── gameStore.test.ts
    └── components/

理由

  • 責任分離の明確化: React関連の状態管理をpresentation層に集約
  • ヘキサゴナルアーキテクチャの強化: application層からフレームワーク依存を除去
  • 保守性の向上: 関心事の分離

影響の修正

// App.test.tsx
// Before
vi.mock('./application/stores/gameStore', () => ({

// After  
vi.mock('./presentation/stores/gameStore', () => ({

4. 引数順序の統一(data-last パターン)

課題

curry化により関数の引数順序が変更され、101個のテストが失敗

対応

体系的な修正アプローチ

  1. TypeScriptエラーを活用
  2. TypeScriptの型チェックでエラー箇所を特定
  3. 1つずつ順序を修正

  4. 修正パターン

    // Before: data-first
    getPuyo(field, position)
    setPuyo(field, position, puyo)
    isEmpty(field, position)
    
    // After: data-last  
    getPuyo(position)(field)
    setPuyo(position, puyo)(field)
    isEmpty(position)(field)
    

  5. 影響ファイル

  6. Field.test.ts: 19箇所修正
  7. ChainService.test.ts: setPuyo呼び出し修正
  8. PuyoPair.ts: movePuyo呼び出し修正
  9. GravityService.ts: 各種関数呼び出し修正

品質保証プロセス

段階的検証

各リファクタリング後に以下を実施:

# 1. コードフォーマット確認
npm run format:check

# 2. リント確認  
npm run lint

# 3. TypeScript型チェック
npm run build

# 4. テスト実行
npm run test

品質メトリクス

指標 リファクタリング前 リファクタリング後 改善
テスト成功数 392/392 392/392 維持
テスト成功率 100% 100% 維持
TypeScriptエラー 0 0 維持
ESLintエラー 0 0 維持
コード行数 - -126行 改善
ビルドサイズ 309.92KB 309.60KB 0.1%減

リファクタリングの効果

1. 保守性の向上

curry化による柔軟性

// 部分適用によるヘルパー関数作成
const getPuyoAtPosition = getPuyo({ row: 1, col: 2 });
const hasPuyoAtPosition = flow(getPuyoAtPosition, Boolean);

// 関数合成による処理パイプライン
const processField = flow(
  eliminateGroups,
  applyGravity,
  calculateScore
);

純粋関数の推進 - 副作用の除去 - テスタビリティの向上 - 予測可能な動作

2. 技術的負債の削減

未使用コードの除去 - コードベースのクリーンアップ - 保守対象の削減 - 混乱の要因除去

アーキテクチャの整理 - 責任分離の明確化 - 依存関係の適正化 - 拡張性の向上

3. 開発効率の向上

型安全性 - TypeScriptによるリファクタリング支援 - エラーの早期発見 - IDEサポートの充実

関数型パターン - 再利用可能なコンポーネント - 組み合わせ可能な関数 - 宣言的なコード

課題と学び

発生した課題

1. 大規模な引数順序変更

  • 課題: curry化による引数順序変更で101個のテスト失敗
  • 対応: TypeScriptエラーを活用した系統的修正
  • 学び: 事前の影響分析の重要性

2. 未使用コード検出の困難

  • 課題: TypeScriptでは検出困難
  • 対応: grepによる手動検索
  • 学び: 自動化ツールの必要性

3. ディレクトリ移動のミス

  • 課題: 最初にcomponents下に配置
  • 対応: 即座にpresentation直下に修正
  • 学び: 要件の明確化の重要性

得られた知見

1. 段階的リファクタリングの価値

  • 小さな変更の積み重ね
  • 各段階での検証
  • リスクの最小化

2. TypeScriptの活用

  • 型システムによる安全網
  • リファクタリング支援
  • エラーの早期発見

3. テスト駆動の重要性

  • 変更の影響確認
  • リグレッション防止
  • 品質の担保

今後の改善方針

短期的改善(次イテレーション)

1. 測定環境の構築

{
  "scripts": {
    "test:coverage": "vitest run --coverage",
    "coverage:report": "nyc report --reporter=html"
  }
}

2. 自動化ツールの導入

# 未使用コード検出
npx ts-prune

# import整理
npx organize-imports-cli

# 依存関係分析
npx dependency-cruiser

3. ADRの作成

# ADR-007: 関数型プログラミングの採用

## Status: Accepted

## Context
保守性とテスタビリティの向上が必要

## Decision  
lodash/fpによる関数型プログラミングを採用

## Consequences
- 学習コストの発生
- コードの宣言的記述
- 再利用性の向上

中長期的改善

1. パフォーマンス最適化

  • ベンチマーク環境構築
  • ボトルネック特定
  • 最適化実施

2. E2Eテストの拡充

  • Playwright導入
  • ユーザーシナリオテスト
  • ビジュアルリグレッションテスト

3. 継続的品質改善

  • コードレビュープロセス
  • 品質メトリクス監視
  • 定期的リファクタリング

結論

イテレーション2のリファクタリングは、以下の点で成功しました:

成功要因

  1. 明確な戦略: 実装戦略ドキュメントに基づく体系的アプローチ
  2. 段階的実施: 小さな変更の積み重ね
  3. 品質重視: 各段階での検証
  4. 継続的改善: 問題の早期発見と対応

定量的成果

  • 126行のコード削減
  • 16個の未使用関数削除
  • 100%のテスト成功率維持
  • 0.1%のビルドサイズ削減

技術的成果

  • 関数型プログラミング基盤確立
  • アーキテクチャの適正化
  • 技術的負債の削減
  • 保守性の向上

このリファクタリングにより、より保守しやすく拡張性の高いコードベースへの移行を開始できました。次のイテレーションでは、測定と自動化を強化し、さらなる品質向上を目指します。


作成日: 2025-08-15
作成者: Claude Code
関連ドキュメント: - イテレーション2完了報告書 - イテレーション2ふりかえり - 実装戦略