JA Architecture Data Flow - aku11i/phantom GitHub Wiki
English | 日本語
このドキュメントでは、ユーザー入力から最終出力まで、Phantomのシステムを通じてデータがどのように移動するかを説明します。
データはPhantomを通じて予測可能な単一方向で流れます:
graph LR
A[ユーザー入力] --> B[CLIパーサー]
B --> C[コマンドハンドラー]
C --> D[コアロジック]
D --> E[Git操作]
E --> F[システムコール]
F --> G[結果]
G --> H[出力フォーマット]
H --> I[ユーザー出力]
style A fill:#9f9
style I fill:#9f9
style D fill:#ff9
style E fill:#f9f
例: phantom create feature-xyz origin/main
sequenceDiagram
participant User
participant CLI
participant CreateHandler
participant WorktreeCore
participant GitModule
participant FileSystem
User->>CLI: phantom create feature-xyz origin/main
CLI->>CreateHandler: {name: "feature-xyz", branch: "origin/main"}
CreateHandler->>WorktreeCore: validateWorktreeName("feature-xyz")
WorktreeCore-->>CreateHandler: Result.ok()
CreateHandler->>GitModule: getGitRoot()
GitModule->>FileSystem: git rev-parse --show-toplevel
FileSystem-->>GitModule: "/path/to/repo"
GitModule-->>CreateHandler: Result.ok("/path/to/repo")
CreateHandler->>GitModule: branchExists("origin/main")
GitModule->>FileSystem: git rev-parse --verify
FileSystem-->>GitModule: "commit-sha"
GitModule-->>CreateHandler: Result.ok(true)
CreateHandler->>WorktreeCore: createWorktree("feature-xyz", "origin/main")
WorktreeCore->>GitModule: addWorktree(name, branch, path)
GitModule->>FileSystem: git worktree add
FileSystem-->>GitModule: success
GitModule-->>WorktreeCore: Result.ok(WorktreeInfo)
WorktreeCore-->>CreateHandler: Result.ok(WorktreeInfo)
CreateHandler->>CLI: formatSuccess(WorktreeInfo)
CLI->>User: "phantom 'feature-xyz'を/tmp/phantom/repo/feature-xyzに作成しました"
例: phantom list
sequenceDiagram
participant User
participant CLI
participant ListHandler
participant WorktreeCore
participant GitModule
participant OutputFormatter
User->>CLI: phantom list
CLI->>ListHandler: {}
ListHandler->>WorktreeCore: listWorktrees()
WorktreeCore->>GitModule: listWorktrees()
GitModule->>GitModule: git worktree list --porcelain
GitModule-->>WorktreeCore: Result.ok(GitWorktreeData[])
WorktreeCore->>WorktreeCore: WorktreeInfo[]に変換
WorktreeCore-->>ListHandler: Result.ok(WorktreeInfo[])
ListHandler->>OutputFormatter: formatTable(worktrees)
OutputFormatter-->>ListHandler: フォーマットされたテーブル文字列
ListHandler->>CLI: テーブルを出力
CLI->>User: フォーマットされたテーブルを表示
graph TB
A[生のCLI引数] --> B[解析された引数]
B --> C[検証された入力]
C --> D[ドメインオブジェクト]
subgraph "CLIレイヤー"
A
B
end
subgraph "ハンドラーレイヤー"
C
end
subgraph "コアレイヤー"
D
end
変換例:
// 生の入力
["create", "my-feature", "origin/main"]
// 解析された引数
{
command: "create",
args: ["my-feature", "origin/main"],
flags: {}
}
// 検証された入力
{
name: "my-feature",
branch: "origin/main"
}
// ドメインオブジェクト
{
name: "my-feature",
branch: "origin/main",
path: "/tmp/phantom/repo/my-feature"
}
graph LR
A[Git CLI出力] --> B[生の文字列]
B --> C[解析されたデータ]
C --> D[ドメインモデル]
D --> E[Result型]
style A fill:#f9f
style E fill:#9f9
例: Worktreeリストの解析
// Git出力(porcelainフォーマット)
`worktree /path/to/main
HEAD abc123
branch refs/heads/main
worktree /tmp/phantom/repo/feature
HEAD def456
branch refs/heads/feature`
// 解析されたデータ
[
{
path: "/path/to/main",
head: "abc123",
branch: "refs/heads/main"
},
{
path: "/tmp/phantom/repo/feature",
head: "def456",
branch: "refs/heads/feature"
}
]
// ドメインモデル
[
{
name: "main",
path: "/path/to/main",
branch: "main",
isMain: true
},
{
name: "feature",
path: "/tmp/phantom/repo/feature",
branch: "feature",
isMain: false
}
]
graph TB
A[システムエラー] --> B[Gitエラー]
B --> C[ドメインエラー]
C --> D[ユーザーエラー]
subgraph "インフラストラクチャ"
A
end
subgraph "Gitモジュール"
B
end
subgraph "コアモジュール"
C
end
subgraph "CLIレイヤー"
D
end
style A fill:#f99
style D fill:#fcc
エラー変換例:
// システムエラー
Error: Command failed: git worktree add
fatal: 'feature' is already checked out
// Gitモジュールエラー
GitError: Worktree 'feature' already exists
// ドメインエラー
WorktreeError: 'feature'という名前のphantomは既に存在します
// ユーザーメッセージ
エラー: 'feature'という名前のphantomは既に存在します。
別の名前を試すか、既存のphantomを最初に削除してください。
sequenceDiagram
participant Git
participant Core
participant Handler
participant User
Git->>Git: コマンドを実行
alt 成功
Git->>Core: Result.ok(data)
Core->>Core: データを変換
Core->>Handler: Result.ok(domainObject)
Handler->>User: 成功メッセージ
else 失敗
Git->>Core: Result.error(gitError)
Core->>Core: ドメインエラーにマップ
Core->>Handler: Result.error(domainError)
Handler->>User: エラーメッセージ + ヘルプ
end
stateDiagram-v2
[*] --> 存在しない
存在しない --> 作成中: createコマンド
作成中 --> アクティブ: git worktree add
アクティブ --> 削除中: deleteコマンド
削除中 --> 存在しない: git worktree remove
アクティブ --> アクティブ: exec/shellコマンド
作成中 --> 存在しない: エラー
削除中 --> アクティブ: エラー
graph LR
A[アイドル] --> B[生成中]
B --> C[実行中]
C --> D[完了]
C --> E[失敗]
D --> F[終了コード 0]
E --> G[終了コード > 0]
style A fill:#ccc
style C fill:#9f9
style D fill:#9f9
style E fill:#f99
sequenceDiagram
participant Handler
participant Process
participant Shell
participant Output
Handler->>Process: exec(command)
Process->>Shell: spawn(command)
activate Shell
loop 出力ストリーム
Shell-->>Process: stdoutデータ
Process-->>Handler: ストリームチャンク
Handler-->>Output: チャンクを表示
end
Shell-->>Process: exit(code)
deactivate Shell
Process-->>Handler: Result<ExitCode>
Handler-->>Output: 最終ステータス
graph TB
A[ユーザー入力] --> B{有効なフォーマット?}
B -->|いいえ| C[フォーマットエラー]
B -->|はい| D{有効な文字?}
D -->|いいえ| E[文字エラー]
D -->|はい| F{名前は利用可能?}
F -->|いいえ| G[競合エラー]
F -->|はい| H[続行]
C --> I[エラーメッセージ]
E --> I
G --> I
style B fill:#ff9
style D fill:#ff9
style F fill:#ff9
style I fill:#f99
style H fill:#9f9
検証段階:
-
フォーマット検証
- 空でない名前
- パスセパレーターなし
- 特殊文字なし
-
文字検証
- 英数字とハイフンのみ
- スペースやドットなし
- パストラバーサルなし
-
利用可能性チェック
- 名前がまだ使用されていない
- 既存との競合なし
graph LR
A[ドメインオブジェクト] --> B[フィールド抽出]
B --> C[幅を計算]
C --> D[行をフォーマット]
D --> E[ヘッダーを追加]
E --> F[テーブルをレンダリング]
subgraph "データ準備"
A
B
end
subgraph "レイアウト計算"
C
end
subgraph "レンダリング"
D
E
F
end
例: リスト出力
// ドメインオブジェクト
[
{ name: "main", branch: "main", path: "/repo" },
{ name: "feature", branch: "feature/new", path: "/tmp/phantom/repo/feature" }
]
// 抽出されたフィールド
[
["main", "main", "/repo"],
["feature", "feature/new", "/tmp/phantom/repo/feature"]
]
// 計算された幅
{ name: 7, branch: 11, path: 25 }
// フォーマットされた出力
NAME BRANCH PATH
main main /repo
feature feature/new /tmp/phantom/repo/feature
graph TB
A[変換を最小限に] --> B[可能な限りストリーム]
B --> C[高価な操作をキャッシュ]
C --> D[早期失敗]
E[Git呼び出し] --> F[バッチ操作]
F --> G[Porcelainフォーマットを使用]
H[出力] --> I[プログレッシブレンダリング]
I --> J[遅延評価]
最適化戦略:
-
ストリーム処理
- 出力全体をバッファしない
- 行ごとに処理
- 即座のユーザーフィードバック
-
効率的なGit使用
- 解析には
--porcelain
を使用 - 可能な場合は操作を組み合わせる
- リポジトリ情報をキャッシュ
- 解析には
-
早期失敗
- 早期に検証
- 前提条件を最初にチェック
- 不要な作業を避ける
interface Command {
validate(input: Input): Result<ValidatedInput>
execute(input: ValidatedInput): Result<Output>
format(output: Output): string
}
const pipeline =
parseArgs
.andThen(validate)
.andThen(execute)
.andThen(format)
.mapError(handleError)
spawn(command)
.stdout
.pipe(lineParser)
.pipe(transformer)
.pipe(output)
Phantomのデータフローアーキテクチャは以下を保証します:
- 予測可能性: データは一方向に流れる
- 追跡可能性: 明確な変換ポイント
- 型安全性: 境界で強く型付け
- エラーハンドリング: 明示的なエラー伝播
- パフォーマンス: 効率的なデータ処理
単一方向のフローと明確な変換境界により、システムは理解、デバッグ、拡張が容易になります。