# 通知設計書 22-count name衝突

## 概要

本ドキュメントは、dplyrパッケージの `count()` および `tally()` 関数において、カウント結果を格納する列名（デフォルトは `n`）が既に入力データに存在する場合に発生する情報通知の設計書です。

### 本通知の処理概要

この通知は、`count()` や `tally()` 関数がカウント結果を格納する際、デフォルトの列名 `n` が既に存在する場合に、別の列名（`nn`、`nnn` など）に自動的に変更されることをユーザーに知らせます。

**業務上の目的・背景**：データフレームのカウント操作において、既存の列名との衝突は予期しない結果を招く可能性があります。この通知により、ユーザーは自動的に列名が変更されたことを認識し、必要に応じて明示的な列名指定（`name` 引数）を行うことができます。これにより、データ処理の透明性と予測可能性が向上します。

**通知の送信タイミング**：`count()` または `tally()` 関数の実行時に、`name` 引数が未指定（NULL）かつデフォルト列名 `n` が既にデータフレームに存在する場合に発生します。この判定は `check_n_name()` 関数内で行われます。

**通知の受信者**：dplyrパッケージを使用するRユーザー（データサイエンティスト、統計分析者、Rプログラマー）が対象です。特に、複雑なデータパイプラインを構築している開発者にとって重要な情報です。

**通知内容の概要**：情報メッセージとして「カウント結果が `n` 以外の列名（例：`nn`）に格納されること」と「`name` 引数で明示的に列名を指定できること」が表示されます。

**期待されるアクション**：受信者は通知内容を確認し、必要に応じて `name` 引数を使用して明示的に列名を指定することが推奨されます。これにより、コードの可読性と保守性が向上します。

## 通知種別

コンソール情報通知（rlang::inform）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（関数実行時即時） |
| 優先度 | 低 |
| リトライ | 無 |

### 送信先決定ロジック

Rセッション内で `count()` または `tally()` を呼び出し、かつ以下の条件を満たす場合にコンソールを通じて情報メッセージが表示されます：
1. `name` 引数が NULL（未指定）
2. データフレームに `n` という列が既に存在する

## 通知テンプレート

### コンソール情報通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元 | dplyrパッケージ |
| 送信元名称 | rlang::inform |
| 形式 | テキスト |

### 本文テンプレート

```
Storing counts in `{name}`, as `n` already present in input
i Use `name = "new_name"` to pick a new name.
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| name | 実際に使用される列名 | n_name()関数の戻り値（nn, nnn等） | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 関数呼び出し | `count()` または `tally()` | `name` が NULL かつ `n` 列が既に存在 | check_n_name関数内で判定 |
| 関数呼び出し | `add_count()` または `add_tally()` | `name` が NULL かつ `n` 列が既に存在 | check_n_name関数内で判定 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| `name` 引数が明示的に指定された場合 | ユーザーが列名を指定しているため通知不要 |
| `n` 列が存在しない場合 | デフォルトの `n` がそのまま使用されるため通知不要 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[count/tally関数呼び出し] --> B[check_n_name関数呼び出し]
    B --> C{name引数がNULLか?}
    C -->|Yes| D[n_name関数で列名生成]
    C -->|No| E[指定された列名を使用]
    D --> F{生成された名前がnと異なるか?}
    F -->|Yes| G[inform関数で通知発行]
    F -->|No| H[通知なし]
    G --> I[処理継続]
    H --> I
    E --> I
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（インメモリ処理のみ）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 該当なし | この通知は情報メッセージのみで、エラーは発生しない | - |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 制限 | なし（条件を満たすたびに表示） |

### 配信時間帯

制限なし（関数呼び出し時に即時発行）

## セキュリティ考慮事項

特になし。本通知はユーザーコンソールへの情報表示のみで、個人情報やセキュリティに関わるデータは含まれません。

## 備考

- `n_name()` 関数は、`n` が既に存在する場合に `nn`、`nn` も存在する場合に `nnn` というように、`n` を追加していきます
- この動作は `count()` と `tally()` の両方で共通です
- `add_count()` と `add_tally()` でも同様の動作が発生します

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、列名の競合がどのように検出されるかを理解することが重要です。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | count-tally.R | `R/count-tally.R` | `vars` パラメータ（既存の列名リスト）の取得方法を理解する |

**読解のコツ**: `group_vars()` および `tbl_vars()` 関数の違いを理解することで、どの列名が検査対象となるかが分かります。

#### Step 2: エントリーポイントを理解する

処理の起点となる関数を特定します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | count-tally.R | `R/count-tally.R` | `tally.data.frame()` での `check_n_name()` 呼び出し |
| 2-2 | count-tally.R | `R/count-tally.R` | `add_tally()` での `check_n_name()` 呼び出し |

**主要処理フロー**:
1. **行122**: `name <- check_n_name(name, group_vars(x))` - tally関数での呼び出し
2. **行220**: `name <- check_n_name(name, tbl_vars(x))` - add_tally関数での呼び出し

#### Step 3: 列名チェックと通知ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | count-tally.R | `R/count-tally.R` | `check_n_name()` 関数の実装詳細 |
| 3-2 | count-tally.R | `R/count-tally.R` | `n_name()` 関数の実装詳細 |

**主要処理フロー**:
- **行264-284**: `check_n_name()` 関数の完全な実装
- **行270**: `name <- n_name(vars)` による列名生成
- **行273-278**: 列名が `n` と異なる場合の `inform()` 呼び出し
- **行286-293**: `n_name()` 関数 - 重複しない列名の生成ロジック

### プログラム呼び出し階層図

```
count() / tally() / add_count() / add_tally()
    │
    ├─ tally.data.frame() / add_tally()
    │      │
    │      └─ check_n_name(name, vars)
    │             │
    │             ├─ n_name(vars) - 一意な列名生成
    │             │      │
    │             │      └─ whileループで"n" → "nn" → "nnn"...
    │             │
    │             └─ inform() - 列名変更の通知
    │
    └─ summarise() / mutate() で結果格納
```

### データフロー図

```
[入力]               [処理]                    [出力]

既存の列名リスト ───▶ check_n_name() ───▶ 情報メッセージ
     │                     │
     │                     ├─▶ n_name()
     │                     │      │
     └─────────────────────┴──────▶ 一意な列名（"nn"等）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| count-tally.R | `R/count-tally.R` | ソース | count/tally関数と列名チェックの実装 |
| rlang | 外部パッケージ | 依存関係 | inform関数の提供 |
