mcpField
K
kotlin-functions

kotlin-functions

github.com/chrisbanes開発1.1k165 回インストール1 日前に更新
リポジトリ

kotlin-functions について

Kotlin開発者向けに、関数の所属先と、メンバー、トップレベル関数、ファクトリー、協力オブジェクト、拡張関数のどれを選ぶかを判断するスキルです。流暢な構文より、意味上の所有者と互換性を重視します。

主な機能

  1. 01意味上の所有者の特定
  2. 02誤解を招く拡張レシーバーの除外
  3. 03適切な関数形式の選択
  4. 04実装の移動と呼び出し元の更新
  5. 05可視性と互換性の確認
  6. 06変更のコンパイルとテスト

活用シーン

  1. 01Kotlin拡張関数のレビュー
  2. 02配置が不適切な生成・解析ロジックのリファクタリング
  3. 03メンバー関数と協力オブジェクトの選択
  4. 04関数API変更の互換性確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/chrisbanes/skills --skill kotlin-functions

インストール後、Claude Code で/kotlin-functionsを入力して読み込まれたか確認します。

詳細

Kotlin 関数の所有者

基本原則

関数は、意味上の所有者として最も適切で小さな単位に配置します。拡張構文が変えるのは呼び出し方であり、所有者ではありません。

プリミティブ型、共通型、ライブラリ所有型への拡張関数は、原則として避けます。誤った所有者を示し、ドメインを汚染し、補完やインポートを煩雑にし、衝突を招くためです。

手順

順番に適用します。

1. 意味上の所有者を特定する

操作と、それを所有する概念を特定します。所有者が明確でない場合は、構文を選ぶ前に作業を中断します。

2. 誤解を招くレシーバーを早い段階で除外する

String、プリミティブ型、コレクション、Flow、フレームワーク、またはサードパーティのレシーバーには、次のすべてを満たすことを求めます。

  • 範囲が狭い private/internal で、一貫性のあるスコープである。
  • レシーバーのすべての値に対して有効である。
  • ポリシー、状態、I/O、依存関係を持たない。
  • レシーバー構文にすることで、明確さが実質的に向上する。
  • より適切なプロジェクト所有の配置先がない。

1つでも満たさない場合、そのレシーバーへの拡張関数は禁止です。ステップ3で非拡張関数の形式を選びます。private fun <T> MutableList<T>.swap(...) は、リスト本来の操作であり、ポリシーに依存せず、アルゴリズムの局所的な処理であるため、条件を満たす場合があります。

3. 関数の形式を選ぶ
意味優先する形式
プロジェクト所有型に固有の振る舞いメンバー関数
型をまたぐ、状態を持たない操作トップレベル関数
生成または解析対象型のファクトリー、または名前付きトップレベル関数
ポリシー、状態、I/O、時計、ロケール、または依存関係を保持する注入されるサービス/コラボレーター
型本来の操作で、レシーバー構文のほうが明確かつステップ2の条件をすべて満たす拡張関数

振る舞いがポリシー、状態、I/O、時計/ロケール、または依存関係を保持する場合に限り、サービス/コラボレーターを使用します。それ以外では、状態を持たない関数に明示的なパラメーターを指定します。

4. 振る舞いと呼び出し元を移動する

実装を移動してから、呼び出し、インポート、関数参照を更新します。明示的な破壊的変更を伴うリリースでない限り、公開エントリーポイントは維持するか、非推奨にします。非公開の移行支援を追加するのは、具体的な利用箇所がある場合に限ります。

// Before: String falsely owns UserId construction.
fun String.toUserId(): UserId = UserId(this)

// After: UserId owns construction.
@JvmInline
value class UserId private constructor(val value: String) {
    companion object {
        fun parse(raw: String): UserId = UserId(raw)
    }
}

val id = UserId.parse(raw)
5. 確認して完了する

どの形式でも、可視性、インポート、衝突、互換性を確認します。拡張関数の場合は、null 許容レシーバー、ジェネリクス、将来のメンバーとの優先順位も確認します。コンパイルとテストを行い、失敗した場合は API の範囲を狭めるか、ステップ1に戻ります。

よくある正当化

「でも……」反論
流れるような構文にできる読みやすさだけで所有者が決まるわけではありません。
Kotlin では拡張関数を使う慣用的であっても、意味上の適切さは必要です。
private/internal であるスコープが有効なのは、すべての条件を満たす場合だけです。
ユーティリティオブジェクトはもっと悪いトップレベル関数か、対象型のファクトリーを使います。
デフォルトのポリシーは明らかであるタイムゾーンやロケールのデフォルト値もポリシーです。明示したままにします。
すでに PR に含まれている既存のコードが所有者の適切さを証明するわけではありません。

危険信号

  • String、数値、コレクション、Flow、またはベンダー型にドメイン上の意味を持たせている。
  • 拡張関数に時計、ロケール、I/O、ポリシー、または依存関係を隠している。

よくある間違い

間違い修正
Long.toDisplayDate()タイムゾーン/ロケールのポリシーはフォーマッターが担います。
拡張関数が解析を隠しているType.parse(raw) または名前付きパーサーを使います。
ライブラリ型に対する公開拡張関数ステップ1〜3に従って再分類します。

関連項目

コメント