breach-encapsulation-naming

getterの濫用を防ぐための命名規約スキル。ドメインモデルでgetterが必要な場合(永続化、JSON変換など)に `breachEncapsulationOf` プレフィックスを付与することで、カプセル化を破っていることを明示する。 これにより、Tell Don't Ask原則の違反を未然に防ぎ、getterの意図しない使用を抑制する。 コードレビュー、新規実装、リファクタリング時にgetter設計が必要な場合に使用。 対象言語: Java, Kotlin, Scala, TypeScript, Python, Go, Rust。 トリガー:「getterの命名規約」「カプセル化を破るgetter」「永続化用のgetter」 「breachEncapsulation」「getterを作りたいが濫用を防ぎたい」といったgetter命名関連リクエストで起動。

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "breach-encapsulation-naming" with this command: npx skills add j5ik2o/okite-ai/j5ik2o-okite-ai-breach-encapsulation-naming

Breach Encapsulation Naming

getterを作るなら「カプセル化を破っている」と名前で叫べ。

核心原則

ドメインモデルのgetterには breachEncapsulationOf プレフィックスを付与し、カプセル化を破っていることを明示する。

アプローチ特徴効果
通常のgetter (getName())気軽に使える濫用されやすい
明示的なgetter (breachEncapsulationOfName())使用時に「破っている」と意識濫用を抑制

なぜこの命名規約が必要か

ジレンマ

  1. Tell Don't Ask原則: getterを使わず、オブジェクトに命じるべき
  2. 現実の制約: 永続化やJSON変換ではgetterが必要
  3. 問題: getterがあると、ビジネスロジックでも使ってしまう

解決策

getterを「長くて目立つ名前」にすることで:

  • 使うたびに「これは例外的な使用だ」と意識させる
  • コードレビューで発見しやすくなる
  • 静的解析ツールで検出可能になる

命名パターン

基本形式

breachEncapsulationOf<PropertyName>()

言語別の例

// Java
public String breachEncapsulationOfName() { return this.name; }
public Money breachEncapsulationOfPrice() { return this.price; }
// Kotlin
fun breachEncapsulationOfName(): String = name
fun breachEncapsulationOfPrice(): Money = price
// TypeScript
breachEncapsulationOfName(): string { return this.name; }
breachEncapsulationOfPrice(): Money { return this.price; }
# Python
def breach_encapsulation_of_name(self) -> str:
    return self._name
// Go
func (u *User) BreachEncapsulationOfName() string { return u.name }
// Rust
pub fn breach_encapsulation_of_name(&self) -> &str { &self.name }

適用判断フロー

getterが必要か?
    ↓
├─ NO → getterを作らない(Tell Don't Ask)
│
└─ YES → 対象は?
          │
          ├─ 値オブジェクト → 通常のアクセサでOK
          │   (イミュータブルかつ振る舞いが限定的なため)
          │   例: Money.amount(), UserId.value()
          │
          └─ エンティティ → breachEncapsulationOf を使用
                            │
                            └─ なぜ必要?
                                ├─ 永続化/シリアライズ → ✅ 許容
                                ├─ 表示/UI → ✅ 許容
                                ├─ テスト → ✅ 許容
                                └─ ビジネスロジック → ❌ Tell パターンに変換

値オブジェクト vs エンティティ

種類特徴getter方針
値オブジェクトイミュータブル、等価性で識別通常のアクセサ可(amount(), value()
エンティティミュータブル、IDで識別breachEncapsulationOf を使用

理由: 値オブジェクトは内部状態が変わらないため、getterを公開しても「状態を取得→外部で判断→更新」というAskパターンが発生しにくい。

アンチパターン検出

以下のパターンを見つけたら警告:

// ❌ breachEncapsulationOf + if → Tell Don't Ask違反
if (user.breachEncapsulationOfAge() >= 18) {
    // ロジック
}

// ❌ breachEncapsulationOf + 計算 → ロジックが外部に漏れている
total = item.breachEncapsulationOfPrice() * item.breachEncapsulationOfQuantity();

// ❌ 連鎖呼び出し → デメテルの法則違反
order.breachEncapsulationOfCustomer().breachEncapsulationOfAddress().getCity();

許容される使用例

1. 永続化層(リポジトリ実装)

// ✅ 永続化のためのアクセスは許容
public UserEntity toEntity(User user) {
    return new UserEntity(
        user.breachEncapsulationOfId(),
        user.breachEncapsulationOfName(),
        user.breachEncapsulationOfEmail()
    );
}

2. JSON/XMLシリアライズ

// ✅ DTOへの変換は許容
toJson(): UserJson {
    return {
        id: this.breachEncapsulationOfId(),
        name: this.breachEncapsulationOfName()
    };
}

3. テストでのアサーション

// ✅ テストでの検証は許容
@Test
void shouldChangeName() {
    user.rename("New Name");
    assertEquals("New Name", user.breachEncapsulationOfName());
}

4. デバッグ/ログ出力

# ✅ デバッグ目的は許容
logger.debug(f"User: {user.breach_encapsulation_of_name()}")

実装ガイドライン

1. ドメインモデル側

public class User {
    private final UserId id;
    private String name;
    private Email email;

    // ❌ 通常のgetterは作らない
    // public String getName() { return name; }

    // ✅ カプセル化を破ることを明示
    public String breachEncapsulationOfName() {
        return name;
    }

    // ✅ ビジネスロジックは振る舞いとして提供
    public void rename(String newName) {
        validateName(newName);
        this.name = newName;
    }

    public boolean hasName(String name) {
        return this.name.equals(name);
    }
}

2. インフラ層での使用

// リポジトリ実装
public class JpaUserRepository implements UserRepository {
    @Override
    public void save(User user) {
        UserEntity entity = new UserEntity();
        entity.setId(user.breachEncapsulationOfId().value());
        entity.setName(user.breachEncapsulationOfName());
        entity.setEmail(user.breachEncapsulationOfEmail().value());
        jpa.save(entity);
    }
}

コードレビュー観点

チェック項目対応
breachEncapsulationOf + ifTellパターンへの変換を提案
breachEncapsulationOf + 計算計算ロジックをオブジェクトに移動
ドメイン層での使用永続化/シリアライズ以外なら警告
連鎖呼び出し委譲メソッドの追加を提案
通常のgetter (getName())breachEncapsulationOf への変更を提案

静的解析との連携

カスタムリントルール例

# 検出ルール
1. breachEncapsulationOf の後に if/switch が続く → 警告
2. ドメイン層で breachEncapsulationOf を呼び出している → 警告
3. 通常の get プレフィックスがドメインモデルにある → 警告

関連スキル

スキル関係
tell-dont-ask本スキルの前提。getterを使わない設計を優先
first-class-collectionコレクションのカプセル化にも同じ原則を適用
domain-building-blocks値オブジェクト設計との整合性

参考文献

  • かとじゅん「ドメインオブジェクトのためのGetter/Setter」(2018)

詳細ガイドライン

言語別の詳細な実装パターンは references/patterns.md を参照。

関連スキル(併読推奨)

このスキルを使用する際は、以下のスキルも併せて参照すること:

  • tell-dont-ask: getterを避けるべき理由の基盤原則
  • law-of-demeter: getter連鎖が違反する構造面の原則
  • first-class-collection: コレクションのカプセル化パターン

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

domain-model-extractor

No summary provided by upstream source.

Repository SourceNeeds Review
General

cross-aggregate-constraints

No summary provided by upstream source.

Repository SourceNeeds Review
General

aggregate-design

No summary provided by upstream source.

Repository SourceNeeds Review
General

repository-placement

No summary provided by upstream source.

Repository SourceNeeds Review
breach-encapsulation-naming | V50.AI