Files
hakorune/docs/guides/development-practices.md
Moe Charm fff9749f47 📚 Reorganize CLAUDE.md: slim down from 916 to 395 lines with proper doc links
- Keep essential information within 500 lines (now 395 lines)
- Maintain important syntax examples and development principles
- Move detailed information to appropriate docs files:
  - Development practices → docs/guides/development-practices.md
  - Testing guide → docs/guides/testing-guide.md
  - Claude issues → docs/tools/claude-issues.md
- Add proper links to all referenced documentation
- Balance between minimal entry point and practical usability
2025-08-31 06:22:48 +09:00

5.2 KiB
Raw Permalink Blame History

開発プラクティス

🔍 技術判断の鉄則

アーキテクチャ質問への対処手順

  1. 実証ファイル確認: file app, nm app, ls target/
  2. 既存コード確認: 関連ソース読み取り
  3. 仮説検証: 推測でなく実証ベース
  4. 結論: 確認済み事実のみ回答

よくある質問の実証方法

  • JIT/LLVMのABI: → file string_len_app でELF確認
  • MIR命令数: → grep "enum MirInstructionKind" src/mir/*.rs
  • プラグイン実装: → ls plugins/*/target/release/
  • C ABI統一: → nm app | grep nyash でシンボル確認

🏗️ 設計原則

📦 Everything is Box - 内部実装でも箱原理を貫く

1. 単一責任の箱

// ✅ 良い例:各モジュールが単一の責任を持つ
MirBuilder: AST  MIR変換のみ(最適化しない)
MirOptimizer: MIRの最適化のみ(変換しない)
VM: 実行のみ(最適化しない)

// ❌ 悪い例:複数の責任が混在
BuilderOptimizer: 変換も最適化も実行も...

2. 明確なインターフェース

// ✅ エフェクトは単純に
enum Effect {
    Pure,       // 副作用なし
    ReadOnly,   // 読み取りのみ  
    SideEffect  // 書き込み/IO/例外
}

// ❌ 複雑な組み合わせは避ける
PURE.add(IO) // これがpureかどうか分からない

3. 段階的な処理パイプライン

AST → Builder → MIR → Optimizer → VM
  ↑      ↑       ↑        ↑         ↑
明確な入力  明確な出力  不変保証  最適化のみ  実行のみ

🎯 カプセル化の徹底

1. 内部状態を隠蔽

// ✅ 良い例:内部実装を隠す
pub struct MirOptimizer {
    debug: bool,              // 設定のみ公開
    enable_typeop_net: bool,  // 設定のみ公開
    // 内部の複雑な状態は隠蔽
}

impl MirOptimizer {
    pub fn new() -> Self { ... }
    pub fn with_debug(self) -> Self { ... }
    pub fn optimize(&mut self, module: &mut MirModule) { ... }
}

2. 変更の局所化

  • 新機能追加時1つのモジュールのみ変更
  • バグ修正時:影響範囲が明確
  • テスト:各モジュール独立でテスト可能

🌟 美しさの基準

1. 読みやすさ > 賢さ

// ✅ 単純で分かりやすい
if effect == Effect::Pure {
    can_eliminate = true;
}

// ❌ 賢いが分かりにくい
can_eliminate = effect.0 & 0x01 == 0x01 && !(effect.0 & 0xFE);

2. 一貫性

  • 命名規則の統一
  • エラー処理の統一
  • コメントスタイルの統一

🚀 大規模化への備え

1. モジュール分割の原則

src/
├── ast/        # AST定義のみ
├── parser/     # パース処理のみ
├── mir/        # MIR定義と基本操作
│   ├── builder.rs      # AST→MIR変換
│   └── optimizer.rs    # MIR最適化
├── backend/    # 実行バックエンド
│   ├── interpreter.rs  # インタープリター
│   ├── vm.rs          # VM実行
│   └── codegen_c.rs   # C言語生成

2. テストの階層化

  • 単体テスト:各モジュール内で完結
  • 統合テスト:モジュール間の連携
  • E2Eテスト全体の動作確認

3. 設定の外部化

// ✅ フラグで挙動を制御(再コンパイル不要)
optimizer.enable_typeop_safety_net(flag);

// ❌ ハードコードされた挙動
#[cfg(feature = "typeop_safety_net")]

💡 デバッグとメンテナンス

1. 段階的なデバッグ出力

NYASH_BUILDER_DEBUG=1   # Builder のみ
NYASH_OPT_DEBUG=1      # Optimizer のみ
NYASH_VM_DEBUG=1       # VM のみ

2. 問題の早期発見

  • 各段階でのアサーション
  • 不変条件の明示的チェック
  • 診断機能の組み込み

🎭 複雑さの管理

複雑さは避けられないが、管理はできる

  1. 複雑な部分を局所化
  2. インターフェースは単純に
  3. ドキュメントで意図を明示

判断基準3ヶ月後の自分が理解できるか

🤝 プロアクティブ開発方針

🎯 エラー対応時の姿勢

エラーを見つけた際は、単に報告するだけでなく:

  1. 🔍 原因分析 - エラーの根本原因を探る
  2. 📊 影響範囲 - 他のコードへの影響を調査
  3. 💡 改善提案 - 関連する問題も含めて解決策を提示
  4. 🧹 機会改善 - デッドコード削除など、ついでにできる改善も実施

⚖️ バランスの取り方

  • 積極的に分析・提案するが、最終判断はユーザーに委ねる
  • 「ChatGPTさんに任せてる」と言われても、分析結果は共有する
  • 複数のAIが協調する場合でも、各自の視点で価値を提供する

📝

❌ 受動的: 「エラーをファイルに出力しました」
✅ 能動的: 「エラーをファイルに出力しました。主な原因は型の不一致7箇所で、
          instance_id()のメソッド呼び出し修正で5つ解決できそうです。
          また、関連してclone_boxの実装にも同様の問題を発見しました。」