380 lines
9.5 KiB
Markdown
380 lines
9.5 KiB
Markdown
|
|
# 🔍 Hakorune 機能発見性(Discoverability)問題の深層分析
|
|||
|
|
|
|||
|
|
**問題**: ChatGPTですら、こんな冗長コードを書いてしまう:
|
|||
|
|
```nyash
|
|||
|
|
hex_digit(ch) {
|
|||
|
|
if ch == "0" { return 0 }
|
|||
|
|
if ch == "1" { return 1 }
|
|||
|
|
if ch == "2" { return 2 }
|
|||
|
|
// ... 続く16行
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**本来あるべき姿**(既に実装済み機能で書ける):
|
|||
|
|
```nyash
|
|||
|
|
// 方法1: match式(Phase 12.7実装済み)
|
|||
|
|
hex_digit(ch) {
|
|||
|
|
return match ch {
|
|||
|
|
"0" => 0, "1" => 1, "2" => 2, "3" => 3,
|
|||
|
|
"4" => 4, "5" => 5, "6" => 6, "7" => 7,
|
|||
|
|
"8" => 8, "9" => 9, "a" => 10, "b" => 11,
|
|||
|
|
"c" => 12, "d" => 13, "e" => 14, "f" => 15,
|
|||
|
|
_ => 0
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 方法2: Mapリテラル(実装済み)
|
|||
|
|
static box HexUtils {
|
|||
|
|
hex_map: MapBox
|
|||
|
|
|
|||
|
|
birth() {
|
|||
|
|
me.hex_map = new MapBox()
|
|||
|
|
me.hex_map.set("0", 0)
|
|||
|
|
me.hex_map.set("1", 1)
|
|||
|
|
// ...
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
hex_digit(ch) {
|
|||
|
|
return me.hex_map.get(ch)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 方法3: indexOf(StringBox実装済み)
|
|||
|
|
hex_digit(ch) {
|
|||
|
|
local hex_chars = "0123456789abcdef"
|
|||
|
|
return hex_chars.indexOf(ch)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📊 根本原因分析(5つの問題)
|
|||
|
|
|
|||
|
|
### **問題1: ドキュメント導線の弱さ**
|
|||
|
|
|
|||
|
|
**現状**:
|
|||
|
|
```
|
|||
|
|
docs/reference/language/LANGUAGE_REFERENCE_2025.md (1,500行)
|
|||
|
|
↓
|
|||
|
|
機能は書いてある
|
|||
|
|
↓
|
|||
|
|
でも「いつ使うか」が分からない
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**不足している情報**:
|
|||
|
|
- ❌ 「こういう場合はmatch式を使う」
|
|||
|
|
- ❌ 「配列ルックアップ vs Map vs match の使い分け」
|
|||
|
|
- ❌ 「Anti-Pattern(やってはいけない書き方)」
|
|||
|
|
|
|||
|
|
### **問題2: サンプルコード不足**
|
|||
|
|
|
|||
|
|
**現状**:
|
|||
|
|
```
|
|||
|
|
apps/examples/ ← 基本的なサンプルのみ
|
|||
|
|
apps/tests/ ← テストケースはあるが学習用ではない
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**不足**:
|
|||
|
|
- ❌ Cookbook/Recipe集(「~したい時は?」)
|
|||
|
|
- ❌ Best Practice集
|
|||
|
|
- ❌ イディオム集(慣用句)
|
|||
|
|
|
|||
|
|
### **問題3: AI学習データの不足**
|
|||
|
|
|
|||
|
|
**現状**:
|
|||
|
|
```
|
|||
|
|
ChatGPT/Claudeの学習データ:
|
|||
|
|
- JavaScript: 大量
|
|||
|
|
- Python: 大量
|
|||
|
|
- Rust: 中程度
|
|||
|
|
- Nyash/Hakorune: ほぼゼロ
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**結果**: JavaScriptパターンで書いてしまう
|
|||
|
|
```javascript
|
|||
|
|
// JavaScript風(冗長)
|
|||
|
|
if (x == "a") return 1
|
|||
|
|
if (x == "b") return 2
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### **問題4: 糖衣構文の発見性**
|
|||
|
|
|
|||
|
|
**実装済みだが知られていない機能**:
|
|||
|
|
- ✅ match式(Phase 12.7)
|
|||
|
|
- ✅ Lambda式
|
|||
|
|
- ✅ ?演算子(Result伝播)
|
|||
|
|
- ✅ Mapリテラル
|
|||
|
|
- ✅ 配列メソッド(indexOf/find等)
|
|||
|
|
|
|||
|
|
**問題**: 「機能がある」ことは分かっても、「いつ使うべきか」が分からない
|
|||
|
|
|
|||
|
|
### **問題5: Linter/Static Analysis不足**
|
|||
|
|
|
|||
|
|
**現状**: コード品質チェックがない
|
|||
|
|
```nyash
|
|||
|
|
// これを書いても警告が出ない(出るべき)
|
|||
|
|
if ch == "0" { return 0 }
|
|||
|
|
if ch == "1" { return 1 }
|
|||
|
|
// ... 続く
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**理想**: Linterが検出
|
|||
|
|
```
|
|||
|
|
Warning: Consider using match expression instead of if-else chain
|
|||
|
|
→ Suggested refactoring:
|
|||
|
|
match ch { "0" => 0, "1" => 1, ... }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 解決策(5つの柱)
|
|||
|
|
|
|||
|
|
### **解決策1: Cookbook/Recipe集の作成** 🔴 最優先
|
|||
|
|
|
|||
|
|
**構成案**:
|
|||
|
|
```markdown
|
|||
|
|
docs/cookbook/
|
|||
|
|
├── README.md
|
|||
|
|
├── patterns/
|
|||
|
|
│ ├── lookup-table.md # ルックアップテーブル実装
|
|||
|
|
│ ├── string-parsing.md # 文字列解析
|
|||
|
|
│ ├── error-handling.md # エラー処理パターン
|
|||
|
|
│ └── collections.md # コレクション操作
|
|||
|
|
├── anti-patterns/
|
|||
|
|
│ ├── if-chain.md # if連鎖のアンチパターン
|
|||
|
|
│ ├── manual-loop.md # 手動ループのアンチパターン
|
|||
|
|
│ └── null-check.md # null チェックのアンチパターン
|
|||
|
|
└── refactoring/
|
|||
|
|
├── if-to-match.md # if → match変換
|
|||
|
|
├── loop-to-map.md # ループ → map/filter変換
|
|||
|
|
└── manual-to-builtin.md # 手動実装 → ビルトイン変換
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**例**: `docs/cookbook/patterns/lookup-table.md`
|
|||
|
|
```markdown
|
|||
|
|
# ルックアップテーブルパターン
|
|||
|
|
|
|||
|
|
## ❌ Anti-Pattern(やってはいけない)
|
|||
|
|
```nyash
|
|||
|
|
hex_digit(ch) {
|
|||
|
|
if ch == "0" { return 0 }
|
|||
|
|
if ch == "1" { return 1 }
|
|||
|
|
// ... 冗長
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## ✅ Pattern 1: match式(推奨、シンプルなルックアップ)
|
|||
|
|
```nyash
|
|||
|
|
hex_digit(ch) {
|
|||
|
|
return match ch {
|
|||
|
|
"0" => 0, "1" => 1, "2" => 2, ...
|
|||
|
|
_ => 0
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## ✅ Pattern 2: indexOf(文字列ベース)
|
|||
|
|
```nyash
|
|||
|
|
hex_digit(ch) {
|
|||
|
|
return "0123456789abcdef".indexOf(ch)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## ✅ Pattern 3: MapBox(複雑な値)
|
|||
|
|
```nyash
|
|||
|
|
static box HexMap {
|
|||
|
|
map: MapBox
|
|||
|
|
birth() {
|
|||
|
|
me.map = new MapBox()
|
|||
|
|
me.map.set("zero", 0)
|
|||
|
|
// ...
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 使い分け
|
|||
|
|
- シンプルなルックアップ → match式
|
|||
|
|
- 連続文字 → indexOf
|
|||
|
|
- 複雑な値/初期化 → MapBox
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### **解決策2: Quick Reference拡充** 🟡
|
|||
|
|
|
|||
|
|
**現状**: 文法中心
|
|||
|
|
**改善**: Use Case中心に再構成
|
|||
|
|
|
|||
|
|
```markdown
|
|||
|
|
# Use Case別 Quick Reference
|
|||
|
|
|
|||
|
|
## 文字列解析
|
|||
|
|
- hex変換 → indexOf/match
|
|||
|
|
- split → string.split()
|
|||
|
|
- 正規表現 → RegexBox
|
|||
|
|
|
|||
|
|
## ルックアップ
|
|||
|
|
- 固定値 → match
|
|||
|
|
- 動的 → MapBox
|
|||
|
|
- 連続 → indexOf
|
|||
|
|
|
|||
|
|
## 繰り返し処理
|
|||
|
|
- 変換 → array.map()
|
|||
|
|
- フィルタ → array.filter()
|
|||
|
|
- 集約 → array.reduce()
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### **解決策3: サンプルコード集の充実** 🟡
|
|||
|
|
|
|||
|
|
**追加すべきサンプル**:
|
|||
|
|
```
|
|||
|
|
apps/examples/
|
|||
|
|
├── cookbook/
|
|||
|
|
│ ├── hex_parser.hkr # hex解析の正しい書き方
|
|||
|
|
│ ├── json_parser.hkr # JSON解析
|
|||
|
|
│ ├── state_machine.hkr # ステートマシン
|
|||
|
|
│ └── validator.hkr # バリデーション
|
|||
|
|
├── best-practices/
|
|||
|
|
│ ├── match_vs_if.hkr # match vs if使い分け
|
|||
|
|
│ ├── map_vs_array.hkr # Map vs Array選択
|
|||
|
|
│ └── error_handling.hkr # エラー処理パターン
|
|||
|
|
└── anti-patterns/
|
|||
|
|
├── if_chain_bad.hkr # ❌ 悪い例
|
|||
|
|
└── if_chain_good.hkr # ✅ 良い例
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### **解決策4: Linter/フォーマッター導入** 🟢
|
|||
|
|
|
|||
|
|
**Phase 18-20で実装検討**:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Linter実行
|
|||
|
|
$ hakorune lint my_code.hkr
|
|||
|
|
|
|||
|
|
Warning: Inefficient if-else chain detected
|
|||
|
|
--> my_code.hkr:10:5
|
|||
|
|
|
|
|||
|
|
10 | if ch == "0" { return 0 }
|
|||
|
|
11 | if ch == "1" { return 1 }
|
|||
|
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ Consider using match expression
|
|||
|
|
|
|
|||
|
|
= help: match ch { "0" => 0, "1" => 1, ... }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**検出すべきAnti-Pattern**:
|
|||
|
|
1. If-else連鎖(match式推奨)
|
|||
|
|
2. 手動ループ(map/filter推奨)
|
|||
|
|
3. 未使用変数
|
|||
|
|
4. 型不一致(opt-in型チェック時)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### **解決策5: AI学習用データ整備** 🟢
|
|||
|
|
|
|||
|
|
**コンテキスト注入用ファイル**:
|
|||
|
|
```
|
|||
|
|
docs/for-ai/
|
|||
|
|
├── PATTERNS.md # 推奨パターン集
|
|||
|
|
├── ANTI_PATTERNS.md # アンチパターン集
|
|||
|
|
├── IDIOMS.md # 慣用句集
|
|||
|
|
└── COMMON_MISTAKES.md # よくある間違い
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**CLAUDE.mdに追加**:
|
|||
|
|
```markdown
|
|||
|
|
## 🤖 AI開発者への注意事項
|
|||
|
|
|
|||
|
|
### ❌ やってはいけないパターン
|
|||
|
|
1. If-else連鎖 → match式を使う
|
|||
|
|
2. 手動for文 → map/filter/reduce
|
|||
|
|
3. null手動チェック → ?演算子
|
|||
|
|
|
|||
|
|
### ✅ 推奨パターン
|
|||
|
|
1. ルックアップ → match/indexOf/MapBox
|
|||
|
|
2. 変換 → array.map()
|
|||
|
|
3. エラー処理 → Result + ?演算子
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📅 実装優先順位
|
|||
|
|
|
|||
|
|
### **Phase 17(即座)** 🔴
|
|||
|
|
1. **Cookbook/Recipe集作成**
|
|||
|
|
- `docs/cookbook/patterns/lookup-table.md`
|
|||
|
|
- `docs/cookbook/anti-patterns/if-chain.md`
|
|||
|
|
- `docs/cookbook/refactoring/if-to-match.md`
|
|||
|
|
|
|||
|
|
2. **CLAUDE.md拡充**
|
|||
|
|
- AI開発者への注意事項セクション追加
|
|||
|
|
- よくあるアンチパターン明記
|
|||
|
|
|
|||
|
|
### **Phase 18-19** 🟡
|
|||
|
|
3. **サンプルコード集**
|
|||
|
|
- `apps/examples/cookbook/` 作成
|
|||
|
|
- ベストプラクティス実装例
|
|||
|
|
|
|||
|
|
4. **Quick Reference再構成**
|
|||
|
|
- Use Case中心に再編成
|
|||
|
|
|
|||
|
|
### **Phase 20-22** 🟢
|
|||
|
|
5. **Linter/フォーマッター**
|
|||
|
|
- Anti-Pattern検出
|
|||
|
|
- 自動リファクタリング提案
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 期待される効果
|
|||
|
|
|
|||
|
|
### **短期効果(Phase 17)**
|
|||
|
|
- ✅ AI(ChatGPT/Claude)がアンチパターンを避ける
|
|||
|
|
- ✅ 新規開発者が正しい書き方を学べる
|
|||
|
|
- ✅ コードレビュー時の指摘減少
|
|||
|
|
|
|||
|
|
### **中期効果(Phase 18-19)**
|
|||
|
|
- ✅ サンプルコードからコピペで正しいコード
|
|||
|
|
- ✅ 言語機能の利用率向上
|
|||
|
|
- ✅ コード品質の一貫性向上
|
|||
|
|
|
|||
|
|
### **長期効果(Phase 20-22)**
|
|||
|
|
- ✅ Linterが自動で品質保証
|
|||
|
|
- ✅ リファクタリングが容易
|
|||
|
|
- ✅ 技術的負債の削減
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 💡 名言化
|
|||
|
|
|
|||
|
|
> **「機能があっても、使われなければ意味がない」**
|
|||
|
|
>
|
|||
|
|
> Hakoruneは強力な機能を持つ。
|
|||
|
|
> しかし、その使い方が伝わらなければ宝の持ち腐れ。
|
|||
|
|
>
|
|||
|
|
> **Cookbook/Recipe集で「発見性」を高める**ことが、
|
|||
|
|
> 次のPhaseの最重要課題。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎊 まとめ
|
|||
|
|
|
|||
|
|
ChatGPTが冗長なif連鎖を書いてしまった問題は、
|
|||
|
|
**言語機能の不足ではなく、発見性(Discoverability)の問題**。
|
|||
|
|
|
|||
|
|
**解決策5本柱**:
|
|||
|
|
1. 🔴 Cookbook/Recipe集作成(Phase 17、最優先)
|
|||
|
|
2. 🟡 Quick Reference拡充(Phase 17-18)
|
|||
|
|
3. 🟡 サンプルコード集(Phase 18-19)
|
|||
|
|
4. 🟢 Linter/フォーマッター(Phase 20-22)
|
|||
|
|
5. 🟢 AI学習用データ整備(Phase 17-19)
|
|||
|
|
|
|||
|
|
**Phase 17で即座に着手すべき**:
|
|||
|
|
- `docs/cookbook/` ディレクトリ作成
|
|||
|
|
- Anti-Pattern集の整備
|
|||
|
|
- CLAUDE.mdへのAI開発者向け注意事項追加
|
|||
|
|
|
|||
|
|
これにより、「つよつよ機能」が「実際に使われる」ようになりますにゃ!
|