Token导航 LogoToken导航TokenDH.com
研究检索权限需确认github未标认证来源可访问许可证需确认审计通过

when-to-wrap-primitives何时包装原语

Agent Skill

when-to-wrap-primitives 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

648

周安装

27

GitHub Stars

75

下载量

216
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:when-to-wrap-primitives(何时包装原语)
来源仓库:https://github.com/j5ik2o/okite-ai
仓库路径:skills/when-to-wrap-primitives
安装命令:
npx skills add https://github.com/j5ik2o/okite-ai --skill when-to-wrap-primitives
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/j5ik2o/okite-ai --skill when-to-wrap-primitives

简介

when-to-wrap-primitives 用于查找、检索和筛选相关信息。

  • 适用于类型系统设计或代码封装决策的支持场景。
  • 可在 Codex、Claude、Cursor、Gemini CLI 中使用。
  • 安装前需确认其是否涉及代码解析或静态分析功能。
  • 适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

SKILL.md

プリミティブ型ラップ判断ガイド

プリミティブ型をラップすべきか否かは、コスト対効果で判断する。盲目的にラップするのも、 一切ラップしないのも、どちらも設計の失敗である。

前提: Value Objectの定義は1つではない

「Value Object」という用語は文脈によって意味が異なる。議論やレビューで混乱が生じる主因である。

定義出典スコープ核心
一般的定義Wikipedia等最も広い同等性がIDではなく値に基づくオブジェクト
PofEAA定義Martin Fowler実装パターンIDに基づかず値で等価判定される小型オブジェクト。別名参照問題を避けるため不変が推奨
DDD定義Eric EvansドメインモデリングPofEAA版の特性をすべて備えた上で、ドメインの概念を計測・定量化・説明し、不変条件と副作用のない振る舞いを持つドメインオブジェクト

DDD版はPofEAA版のextends

DDD版VOとPofEAA版VOは独立した概念ではなく、特化(specialization)の関係にある。

特性PofEAA VODDD VO
値による等価判定必須必須(継承)
不変性推奨必須(強化)
ドメイン不変条件必須(追加)
ドメイン振る舞い必須(追加)

つまり:

  • DDD VO IS-A PofEAA VO → すべてのDDD VOはPofEAA VOでもある
  • PofEAA VO IS-A DDD VO → 成立しない(Ruby HashはPofEAA VOだがDDD VOではない)

DDD版は「値で等価判定される」「不変である」というPofEAA版の特性を前提として含んだ上で、 ドメイン固有の要件を追加したものである。2つの定義を並列に見ると、DDD版が PofEAA版の特性も持っていることを見落としやすいので注意。

チーム内では「PofEAAのVO」「DDDのVO」のように文脈を明示して使い分けるべき。

本スキルの立場

本スキルでは、「プリミティブ型をドメイン固有型でラップすべきか」という実践的判断に焦点を当てる。 VOの定義論争には立ち入らず、ラップすることで得られる具体的な利益がコストに見合うかで判断する。

2つのアンチパターン

Primitive Obsession(プリミティブ型への固執)

すべてをString/int/floatで表現し、ドメインの制約がコードに表れない。

fn transfer(from: String, to: String, amount: f64)
// fromとtoを取り違えてもコンパイルが通る
// amountが負でもコンパイルが通る
// 通貨の概念がない

症状:

  • 同じプリミティブ型の引数が2つ以上並ぶ
  • バリデーションロジックが呼び出し側に散在
  • 「この文字列はメールアドレスのはず」という暗黙の前提
  • 単位の取り違え(メートルとフィート、円とドル)

Value Object Obsession(過剰なラップ)

すべてのプリミティブ型を機械的にクラスで包み、複雑性だけが増す。

class CustomerFirstName(value: String)
class CustomerLastName(value: String)
class ShippingFirstName(value: String)  // CustomerFirstNameと何が違う?
class ShippingLastName(value: String)   // 同上

症状:

  • 不変条件やドメインロジックを持たない「ただのラッパー」が大量に存在
  • 文脈ごとに別の型を作るが、中身のバリデーションは同一
  • 型変換のボイラープレートがドメインロジックより多い
  • 新規メンバーが型の森で迷子になる

判断フレームワーク

5つの判断基準

プリミティブ型をラップすべきかを以下の基準で評価する。 1つでも強くYesならラップを検討。複数Yesなら強く推奨。すべてNoならラップ不要。

基準1: ドメイン不変条件があるか

その値に「常に満たすべき制約」があるか?

不変条件判断
メールアドレスRFC準拠のフォーマットラップする
金額非負、通貨との組み合わせラップする
年齢0〜150の範囲ラップする
ログメッセージ特に制約なしラップ不要
一時的なループカウンタなしラップ不要

基準2: 取り違えリスクがあるか

同じプリミティブ型の引数が複数並び、取り違えてもコンパイラが検出できないか?

// ❌ userIdとorderIdは両方String。取り違えても気づかない
fn find_order(user_id: String, order_id: String)

// ✅ 型が異なるのでコンパイラが検出する
fn find_order(user_id: UserId, order_id: OrderId)

特にID型は取り違えの被害が大きい。異なる概念のIDは型で区別すべき。

基準3: ドメイン操作を集約できるか

その値に関連する操作(加算、比較、変換など)がドメインロジックとして存在するか?

ドメイン操作判断
Money加算(同一通貨のみ)、通貨変換、比較ラップする
DateRange重複判定、包含判定、期間計算ラップする
単なる名前文字列特になし慎重に検討

基準4: 複数の値が不可分か

2つ以上の値が常にセットで意味を持つか?

// ❌ 金額と通貨が別々に渡される → 不整合の可能性
fn price(amount: f64, currency: String)

// ✅ 不可分な値を1つの型にまとめる
fn price(money: Money)

基準5: 利用箇所が複数あるか

その型が複数のコンテキスト(モジュール、レイヤー、関数)で使われるか?

状況判断
3つ以上のモジュールで使われるラップの価値が高い
2つのモジュールで使われる他の基準と合わせて検討
1つの関数内でしか使わないラップ不要(YAGNI)

判断フロー

プリミティブ型を使おうとしている
    │
    ├─ 不変条件がある? ─── Yes ──→ ラップする
    │                                (domain-primitives-and-always-valid スキル参照)
    │
    ├─ 取り違えリスクがある? ─── Yes ──→ ラップする(特にID型)
    │
    ├─ ドメイン操作がある? ─── Yes ──→ ラップする
    │
    ├─ 複数値が不可分? ─── Yes ──→ 複合型としてラップする
    │
    ├─ 利用箇所が多い? ─── Yes ──→ 他の基準と合わせて検討
    │
    └─ すべて No ──→ プリミティブ型のままでよい

ラップの度合い: 3段階

すべてを「フルスペックの型」にする必要はない。状況に応じて適切な粒度を選ぶ。

レベル1: 型エイリアス(最軽量)

不変条件はないが、取り違え防止や可読性向上が目的の場合。

// TypeScript
type UserId = string & { readonly __brand: unique symbol };
type OrderId = string & { readonly __brand: unique symbol };
// Rust(newtype)
pub struct UserId(String);
pub struct OrderId(String);

適用場面: 不変条件なし、取り違え防止が主目的

レベル2: 構築時検証付き型

不変条件があり、無効な値のインスタンス化を防ぐ。

pub struct Email(String);

impl Email {
    pub fn new(value: &str) -> Result<Self, EmailError> {
        if !value.contains('@') || value.len() <= 3 {
            return Err(EmailError::InvalidFormat);
        }
        Ok(Self(value.to_string()))
    }
}

適用場面: 明確な不変条件がある

レベル3: 振る舞いを持つドメイン型

不変条件 + ドメイン操作を集約する。

pub struct Money { amount: Decimal, currency: Currency }

impl Money {
    pub fn add(&self, other: &Money) -> Result<Money, MoneyError> {
        if self.currency != other.currency {
            return Err(MoneyError::CurrencyMismatch);
        }
        Money::new(self.amount + other.amount, self.currency)
    }
}

適用場面: 不変条件 + そこに属すべきドメイン操作がある

言語特性による選択肢

ラップの手段はクラス化だけではない。言語機能に応じて適切な手段を選ぶ。

言語軽量な手段フルラップ
Rustnewtype(struct Foo(T)newtype + impl
TypeScriptBranded Typesclass with private constructor
Kotlinvalue classdata class
Scalaopaque type / value classcase class
Gotype Foo stringstruct + コンストラクタ関数
Javaー(軽量手段がない)record / final class
PythonNewType(typing)dataclass(frozen=True)

原則: 不変条件がなく取り違え防止だけが目的なら、その言語で最も軽量な手段を使う。

レビューチェックリスト

「ラップすべきなのにしていない」の検出

  • 同じプリミティブ型の引数が2つ以上並んでいないか
  • バリデーションが呼び出し側に散在していないか
  • 「この文字列は〇〇のはず」という暗黙の前提がないか
  • 異なる概念のIDが同じ型(String等)で表現されていないか
  • 不可分な値のペア(金額+通貨等)が別々の引数になっていないか

「ラップしすぎ」の検出

  • 不変条件もドメイン操作もない「ただのラッパー」がないか
  • 型変換のボイラープレートがドメインロジックより多くないか
  • 文脈ごとに型を分けたが、中身のバリデーションが同一ではないか
  • 1箇所でしか使わない型をわざわざ作っていないか
  • 型の数がチームの認知負荷を超えていないか

関連スキルとの使い分け

スキルフォーカス使うタイミング
本スキルラップすべきか否かの判断「この型を作るべきか?」という意思決定時
domain-primitives-and-always-validラップする場合の設計と実装ラップすると決めた後の具体的な設計時
domain-building-blocksVO/Entity/Aggregate等の設計全般ドメインモデル全体の構造を設計するとき
parse-dont-validate検証結果を型で保持する変換validate→parse変換をレビューするとき

議論のための用語整理

チームで議論する際、パターン(設計概念)と実装技法を混同しないことが重要である。

パターン(何であるか)

パターン出典定義関係
Value Object(PofEAA)Fowler値で等価判定されるオブジェクト。不変が推奨基底
Value Object(DDD)EvansPofEAA VOを継承し、ドメイン不変条件と振る舞いを追加PofEAA VOのextends
Domain PrimitiveJohnsson et al.構築時検証・不変性・自己完結性を備えたドメイン固有の最小単位の型Secure by Design由来

実装技法(どう作るか)

技法特性
Branded Type / Newtype型レベルで区別するが、ランタイム検証なしRust: struct UserId(String)
Smart Constructor構築時に不変条件を検証。無効な値を作れないEmail::new(s) -> Result<Email, Error>
振る舞い付きドメイン型不変条件 + ドメイン操作をカプセル化Money::add(&self, other) -> Result<Money, Error>

パターンと実装技法の対応

パターン典型的な実装技法
PofEAA VOいずれの技法でも実現可能(値の等価性を実装すればよい)
DDD VOSmart Constructor または 振る舞い付きドメイン型
Domain PrimitiveSmart Constructor(最小単位なので振る舞いは少ないことが多い)

推奨: 「Value Objectにすべき」のようにパターン名だけで語らず、 「この値にはドメイン不変条件があるからSmart Constructorで保護すべき」 「取り違えリスクがあるからNewtypeで型を区別すべき」のように、理由と実装技法をセットで述べる。

参考文献

  • Dan Bergh Johnsson et al. "Secure by Design" - Domain Primitivesの原典
  • Martin Fowler "Patterns of Enterprise Application Architecture" - PofEAA版Value Objectの定義
  • Eric Evans "Domain-Driven Design" - DDD版Value Objectの定義
  • J. B. Rainsberger "Demystifying the Dependency Inversion Principle" - Primitive Obsessionへの言及
  • ThoughtWorks "Object Calisthenics" - 「Wrap All Primitives」ルールの出典(練習用であり本番ルールではない)

関連スキル(併読推奨)

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

  • domain-primitives-and-always-valid: ラップする判断後の具体的な設計パターン
  • parse-dont-validate: ラップ時に適用するparseパターン
  • domain-building-blocks: ラップされたプリミティブが属する値オブジェクトの設計

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

34.96%
按下载量换算76

Claude

30.25%
按下载量换算65

Cursor

18.33%
按下载量换算40

Gemini CLI

9.55%
按下载量换算21

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

权限需确认

当前来源未能明确判断权限范围,默认进入异常复核队列。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills