JA Architecture Module Structure - aku11i/phantom GitHub Wiki

モジュール構造

English | 日本語

このドキュメントでは、Phantomのコード編成、モジュール依存関係、アーキテクチャ境界について詳しく説明します。

ディレクトリ構造の概要

ソース: CLAUDE.md#L17-L42

phantom/
├── src/                    # ソースコードルート
│   ├── bin/               # エントリーポイント
│   │   └── phantom.ts     # メインCLI実行可能ファイル
│   ├── cli/               # CLI固有のレイヤー
│   │   ├── handlers/      # コマンド実装
│   │   ├── output.ts      # コンソールフォーマット
│   │   └── errors.ts      # エラーハンドリング
│   └── core/              # ビジネスロジックレイヤー
│       ├── worktree/      # Worktree操作
│       ├── git/           # Git抽象化
│       ├── process/       # プロセス実行
│       ├── paths.ts       # パス管理
│       ├── version.ts     # バージョン情報
│       └── types/         # 型定義
├── dist/                  # ビルド出力
├── docs/                  # ドキュメント
└── wiki/                  # GitHub Wikiコンテンツ

モジュール依存関係グラフ

graph TB
    subgraph "エントリーレイヤー"
        bin[bin/phantom.ts]
    end
    
    subgraph "CLIレイヤー"
        handlers[cli/handlers/*]
        output[cli/output.ts]
        errors[cli/errors.ts]
    end
    
    subgraph "コアレイヤー - ドメイン"
        worktree[core/worktree/*]
        version[core/version.ts]
        paths[core/paths.ts]
    end
    
    subgraph "コアレイヤー - インフラストラクチャ"
        git[core/git/*]
        process[core/process/*]
        types[core/types/*]
    end
    
    bin --> handlers
    handlers --> output
    handlers --> errors
    handlers --> worktree
    handlers --> process
    handlers --> version
    
    worktree --> git
    worktree --> paths
    worktree --> types
    
    process --> types
    git --> types
    paths --> types
    
    classDef entry fill:#f9f,stroke:#333,stroke-width:2px
    classDef cli fill:#9ff,stroke:#333,stroke-width:2px
    classDef domain fill:#ff9,stroke:#333,stroke-width:2px
    classDef infra fill:#9f9,stroke:#333,stroke-width:2px
    
    class bin entry
    class handlers,output,errors cli
    class worktree,version,paths domain
    class git,process,types infra
Loading

レイヤーアーキテクチャ

1. エントリーレイヤー(src/bin/

目的: アプリケーションエントリーポイント

ファイル:

  • phantom.ts - メインCLIエントリーポイント

責任:

  • アプリケーションのブートストラップ
  • コマンドライン引数の解析
  • 適切なハンドラーへのルーティング
  • キャッチされていないエラーの処理

依存関係:

  • CLIレイヤーからのみインポート
  • 直接のコアインポートなし

2. CLIレイヤー(src/cli/

目的: ユーザーインターフェースとインタラクション

コマンドハンドラー(src/cli/handlers/

ソース: src/cli/handlers/

ファイル:

  • create.ts - phantom作成コマンド
  • delete.ts - phantom削除コマンド
  • list.ts - phantomリスト表示コマンド
  • exec.ts - phantom内でコマンド実行
  • shell.ts - インタラクティブシェルコマンド
  • where.ts - phantomパス取得コマンド
  • version.ts - バージョン表示コマンド
  • attach.ts - 既存worktreeをアタッチ

責任:

  • コア操作のオーケストレート
  • ユーザー入力の検証処理
  • 出力メッセージのフォーマット
  • 終了コードの管理

出力モジュール(src/cli/output.ts

ソース: src/cli/output.ts

責任:

  • コンソール出力フォーマット
  • テーブルレンダリング
  • カラー管理
  • 進行状況インジケーター

主要関数:

  • formatTable() - データをテーブルとしてレンダリング
  • formatError() - エラーメッセージのフォーマット
  • formatSuccess() - 成功メッセージのフォーマット

エラーハンドラー(src/cli/errors.ts

ソース: src/cli/errors.ts

責任:

  • エラーを終了コードにマップ
  • エラーメッセージのフォーマット
  • 予期しないエラーの処理

3. コアレイヤー(src/core/

目的: ビジネスロジックとドメイン操作

Worktreeモジュール(src/core/worktree/

ソース: src/core/worktree/

ファイル:

  • create.ts - Worktree作成ロジック
  • delete.ts - Worktree削除ロジック
  • list.ts - Worktreeリスト表示ロジック
  • where.ts - Worktree位置特定ロジック
  • attach.ts - 既存worktreeをアタッチ
  • validate.ts - 名前検証
  • errors.ts - ドメイン固有のエラー

コア型:

interface WorktreeInfo {
  name: string;
  path: string;
  branch: string;
  isMain: boolean;
}

依存関係:

  • 操作にGitモジュールを使用
  • 場所にPathsモジュールを使用
  • Result型を返す

Gitモジュール(src/core/git/

ソース: src/core/git/

構造:

git/
├── executor.ts          # メインGitコマンドエグゼキューター
└── libs/               # Git操作ラッパー
    ├── add-worktree.ts
    ├── attach-worktree.ts
    ├── branch-exists.ts
    ├── get-current-branch.ts
    ├── get-git-root.ts
    └── list-worktrees.ts

Gitエグゼキューター:

class GitExecutor {
  execute(args: string[]): Result<string>;
  executeJson<T>(args: string[]): Result<T>;
}

Gitライブラリ: 各ライブラリは特定のGit操作をラップします:

  • addWorktree() - 新しいworktreeを作成
  • getCurrentBranch() - アクティブブランチを取得
  • getGitRoot() - リポジトリルートを検索
  • listWorktrees() - すべてのworktreeをリスト表示

Processモジュール(src/core/process/

ソース: src/core/process/

ファイル:

  • spawn.ts - コアプロセス生成
  • exec.ts - コマンド実行
  • shell.ts - インタラクティブシェル
  • errors.ts - プロセスエラー

主要型:

interface SpawnOptions {
  cwd?: string;
  env?: Record<string, string>;
  stdio?: StdioOptions;
}

責任:

  • 安全なプロセス生成
  • I/Oストリーム管理
  • シグナル処理
  • エラー伝播

パス管理(src/core/paths.ts

ソース: src/core/paths.ts

関数:

  • getWorktreeBasePath() - phantomのベースディレクトリ
  • getWorktreePath() - phantomへのフルパス
  • ensureWorktreeDirectory() - ディレクトリを作成

パス構造:

/tmp/phantom/
└── <repo-name>/
    ├── <phantom-1>/
    ├── <phantom-2>/
    └── <phantom-3>/

Typesモジュール(src/core/types/

ソース: src/core/types/

ファイル:

  • result.ts - Result型実装

Result型:

type Result<T, E = Error> = 
  | { ok: true; value: T }
  | { ok: false; error: E }

namespace Result {
  function ok<T>(value: T): Result<T>;
  function error<E>(error: E): Result<never, E>;
}

モジュール通信パターン

1. コマンドフロー

sequenceDiagram
    participant CLI
    participant Handler
    participant Core
    participant Git
    
    CLI->>Handler: コマンド + 引数
    Handler->>Core: ビジネス操作
    Core->>Git: Gitコマンド
    Git-->>Core: Result<Data>
    Core-->>Handler: Result<DomainObject>
    Handler->>CLI: 出力をフォーマット
Loading

2. エラーフロー

graph LR
    A[Gitエラー] --> B[Result.error]
    B --> C[コアレイヤー]
    C --> D[ドメインエラー]
    D --> E[ハンドラー]
    E --> F[ユーザーメッセージ]
    
    style A fill:#f99
    style F fill:#9f9
Loading

3. データ変換

各レイヤーはデータを適切に変換します:

  1. Gitレイヤー: 生の文字列 → 解析されたデータ
  2. コアレイヤー: 解析されたデータ → ドメインオブジェクト
  3. CLIレイヤー: ドメインオブジェクト → ユーザー出力

モジュール境界とルール

1. 依存関係ルール

  • 下向きのみ: 上位レイヤーは下位レイヤーに依存
  • 上向きなし: コアはCLIからインポートしない
  • 循環なし: 構造により強制

2. インターフェース境界

各モジュールは明確なインターフェースを公開します:

// 良い: 明確なモジュールインターフェース
export function createWorktree(
  name: string, 
  branch?: string
): Result<WorktreeInfo>

// 悪い: 内部を公開
export function executeGitCommand(
  args: string[]
): ChildProcess  // Node.js型を公開しない

3. 型境界

  • コアレイヤーのドメイン型
  • CLIレイヤーにとどまるCLI型
  • types/モジュールの共有型

テスト構造

テストファイルはソースと同じ場所に配置されます:

src/
├── core/
│   ├── worktree/
│   │   ├── create.ts
│   │   ├── create.test.ts    # ユニットテスト
│   │   ├── delete.ts
│   │   └── delete.test.ts
│   └── git/
│       ├── executor.ts
│       └── executor.test.ts

テストパターン:

  • 外部依存関係をモック
  • 純粋関数を直接テスト
  • ワークフローの統合テスト

モジュールの責任

明確な分離

モジュール 責任 責任ではない
CLIハンドラー ユーザーインタラクション ビジネスロジック
Core Worktree Phantomライフサイクル Gitコマンド
Gitモジュール Git実行 ビジネスルール
Processモジュール プロセス生成 コマンドロジック
Typesモジュール 共有型 実装

単一責任の例

良い - 単一責任:

// validate.ts - 検証のみ
export function validateWorktreeName(name: string): Result<void>

// create.ts - 作成のみ
export function createWorktree(name: string): Result<WorktreeInfo>

悪い - 複数の責任:

// 関心事を混在させない
export function createAndValidateWorktree(
  name: string,
  showOutput: boolean  // コアにUIの関心事!
): Result<WorktreeInfo>

インポートガイドライン

1. インポート順序

// 1. Node.js組み込み
import { spawn } from "node:child_process";
import { existsSync } from "node:fs";

// 2. 外部依存関係(ランタイムにはなし)

// 3. 内部 - 絶対パス
import { Result } from "../types/result.js";

// 4. 内部 - 相対パス
import { validateWorktreeName } from "./validate.js";

2. バレルエクスポート

バレルエクスポート(index.ts)を避ける理由:

  • インポートを明示的に保つ
  • ツリーシェイキングを改善
  • 循環依存を減らす

3. ファイル拡張子

常に.js拡張子を含める:

// 正しい - ESMは拡張子を必要とする
import { createWorktree } from "./create.js";

// 間違い - ランタイムで失敗する
import { createWorktree } from "./create";

将来のモジュールに関する考慮事項

潜在的な新しいモジュール

  1. Configモジュール

    • ユーザー設定
    • リポジトリ設定
    • デフォルト値
  2. Pluginモジュール

    • プラグインローディング
    • フック管理
    • APIサーフェス
  3. Telemetryモジュール

    • 使用状況メトリクス
    • パフォーマンストラッキング
    • エラーレポート

モジュール原則

新しいモジュールを追加する際:

  1. 単一目的: 明確な責任が1つ
  2. 明確なインターフェース: 明確に定義されたパブリックAPI
  3. テスト可能: 可能な限り純粋関数
  4. 文書化: 明確なモジュールドキュメント
  5. 一貫性: 既存のパターンに従う

まとめ

Phantomのモジュール構造は以下を提供します:

  1. 明確な境界: 明確に定義されたレイヤーと責任
  2. 保守性: コードの検索と変更が簡単
  3. テスト可能性: 明確なインターフェースを持つ分離されたモジュール
  4. スケーラビリティ: 新機能が自然に適合
  5. 型安全性: 全体を通じた強い型付け

モジュラーアーキテクチャにより、プロジェクトが成長してもコードベースがクリーンで理解しやすく、拡張可能なままであることが保証されます。

⚠️ **GitHub.com Fallback** ⚠️