# 11. Imperative Execution, Smart Defaults, and Workspace Management

Date: 2026-01-18

## Status

Accepted

## Context

これまで `beautyspot` は、関数のキャッシュ化にデコレータ (`@project.task`) を使用する方法のみを提供していました。しかし、実際の利用シナリオにおいて以下の課題が浮き彫りになりました：

1.  **サードパーティライブラリの利用**: ソースコードを変更できない関数（例: `pandas.read_csv`）や、外部APIクライアントのメソッドをキャッシュしたい場合、わざわざラッパー関数を定義する必要があり、記述が冗長になる。
2.  **アドホックな解析**: ノートブック環境や一時的なスクリプトで試行錯誤する際、関数定義の手間がオーバーヘッドとなり、開発体験（DX）を損ねる。
3.  **リソース管理の曖昧さ**: `Project` インスタンスが内部で保持する `ThreadPoolExecutor` が適切にシャットダウンされない場合、プロセスがハングするリスクがある。
4.  **ディレクトリの汚染**: 生成されるデータベースファイル (`.db`) やBlobディレクトリ (`blobs/`) がプロジェクトルート直下に作成され、ディレクトリ構成が煩雑になる。
5.  **設定の重複**: 複数のタスクで「常にBlob保存したい」「特定のバージョンを一律適用したい」といった場合、都度引数を指定するのは DRY (Don't Repeat Yourself) 原則に反する。
6.  **`None` 結果のキャッシュ**: `time.sleep` のように戻り値が `None` である関数をキャッシュしようとすると、キャッシュミスと誤認され再実行されてしまうバグが存在した。

## Decision

これらの課題を解決するため、以下の包括的なアーキテクチャ変更を行います。

### 1. 命令的実行メソッド (`project.run`) の導入
デコレータを使用せず、関数オブジェクトとその引数を渡すことで即座にキャッシュ付き実行を行う `run` メソッドを `Project` クラスに追加します。

```python
result = project.run(func, arg1, arg2, _save_blob=True)

```

* **引数設計**: キャッシュ制御用のオプション引数は、対象関数のキーワード引数 (`kwargs`) との衝突を避けるため、プレフィックス `_` を付与します（例: `_save_blob`, `_version`, `_content_type`）。

### 2. コンテキストマネージャとリソース管理

`Project` クラスをコンテキストマネージャとして設計し、`with` ブロック内での利用を推奨パターンとします。これにより、ブロック終了時に確実に `shutdown()` が呼ばれ、スレッドプール等のリソースが解放されることを保証します。

### 3. 設定の階層化とスマートデフォルト

`Project` 初期化時にデフォルト設定を受け入れ、個別の実行時にそれを継承・上書きできる仕組みを導入します。

* **優先順位**:
1. 個別の指定 (`run` や `@task` の引数)
2. プロジェクトのデフォルト (`Project` コンストラクタ引数)
3. システムのデフォルト


* **実装詳細**: これを実現するため、`task` および `run` メソッドの引数デフォルト値を固定値（`False` 等）から `None` に変更し、未指定状態を検出可能にします。

### 4. ワークスペースディレクトリによる集約

すべての生成アーティファクト（DB、Blob）を、デフォルトで隠しディレクトリ `.beautyspot/` 配下に集約します。
また、初期化時にこのディレクトリ内に `.gitignore` （内容: `*`）を自動生成し、キャッシュファイルが誤ってバージョン管理に含まれるのを防ぎます。

### 5. 番兵オブジェクトによるキャッシュ判定

キャッシュヒットの判定ロジックにおいて、`None` を「データなし」と見なすのではなく、専用の番兵オブジェクト (`CACHE_MISS = object()`) を導入して判定を行います。これにより、`None` を返す関数も正しくキャッシュ可能とします。

## Consequences

### Positive

* **高い柔軟性**: 既存のコードやライブラリ呼び出しに対して、ボイラープレートなしで即座にキャッシュを適用可能になった。
* **安全なリソース管理**: `with` 文の使用により、プロセスハングのリスクが大幅に低減した。
* **クリーンな環境**: プロジェクトルートが汚れず、Git管理からの除外も自動化されたため、ユーザーの負担が減った。
* **正確なキャッシュ**: 副作用のみを目的とした関数（戻り値なし）も扱えるようになり、適用範囲が広がった。

### Negative

* **APIの複雑化**: `project.run` の引数に特殊なプレフィックスルール（`_`）が導入されたため、ドキュメントでの周知が必要。
* **後方互換性の注意**: `Project` のコンストラクタや `task` デコレータの引数処理が変更されたため、内部実装レベルでは厳密なチェックが必要（ただし公開APIとしての破壊的変更は最小限に留めている）。

