mcpField
T
The Standard Versioning

The Standard Versioning

github.com/hassanhabib開発2054 回インストール13 週間前に更新
リポジトリ

The Standard Versioning について

The Standard Versioningは、リリース、ファイル、APIのバージョンと、非推奨化や機能の検出に関する規則を定めるスキルです。ソフトウェア変更の設計やレビューを行うチーム向けに、旧版の維持とモデル・サービスの振る舞いに沿ったルート設計を明示します。

主な機能

  1. 014区分のリリースバージョンを定義
  2. 02モデルとサービスのファイル規則
  3. 03バージョンとAPIルートを対応
  4. 04非推奨の通知方法を規定
  5. 05機能検出の仕組みを説明

活用シーン

  1. 01モデル変更の計画
  2. 02サービス動作のバージョン管理
  3. 03バージョン付きAPIルートの設計
  4. 04非推奨化と機能対応のレビュー

インストール

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

$npx skills add https://github.com/hassanhabib/the-standard-skills --skill the-standard-versioning

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

manifest.json
contracts/
contracts.json
enforcement/
enforcement.json
rules/
rules.md
rules.json
validations/
checklist.md

詳細

The Standard — バージョニング

このスキルについて

このスキルでは、次の項目で必須となるバージョニング方式を定義します。

  • リリースのバージョニング
  • ファイルのバージョニング(モデル、サービス、例外)
  • API のバージョニング
  • 非推奨の通知
  • ディスカバリー機能

このスキルでは、ここで定義する明示的なバージョニングモデルに従う必要があり、別のセマンティックバージョニング戦略、互換性の理論、または推測した規約に置き換えてはなりません。

このスキルは、バージョン変更を次の状態に保つためにあります。

  • 明示的
  • 構造化されている
  • 非破壊的
  • 発見可能
  • 利用者にとって安全

使用するタイミング

次の場合は、このスキルを使用してください。

  • 新しいリリースバージョンを作成するとき
  • バージョニングが必要なモデル変更を導入するとき
  • バージョニングが必要なサービスまたはルーチンの変更を導入するとき
  • 新しいバージョン管理対象のファイルやフォルダーを作成するとき
  • バージョン管理対象リソースの API ルートを定義するとき
  • コードまたは API を非推奨としてマークするとき
  • ディスカバリー機能を実装するとき
  • PR のバージョン関連の変更をレビューするとき

明示的な対象範囲マップ

このスキルは、次の主要な領域を対象とします。

  1. リリースのバージョニング
  2. コードのバージョニング
  3. 非推奨化
  4. ディスカバリー機能

このスキルにおけるコードのバージョニングには、次の項目が含まれます。

  • ファイルのバージョニング
  • API のバージョニング
  • 非推奨マーカー
  • 利用者がサポート対象の動作を理解するのに役立つディスカバリー機能の通知

リリースのバージョニング

リリース形式

リリースバージョンには、次の正確な形式を使用する必要があります。

v1.2.3.4
セグメントの意味
セグメント意味
1モデル変更
2サービスまたはルーチンの変更
3バグ修正または設定変更
4自動ビルドバージョン

これらの意味はこのスキルにおいて固定されており、別の解釈をしてはなりません。

リリースのインクリメント規則
  1. リリースバージョンは、正確に v1.2.3.4 の形式を維持する必要があります。

  2. モデル変更ではセグメント 1 をインクリメントし、セグメント 2、3、4 をゼロにリセットする必要があります。

  3. サービスまたはルーチンの変更ではセグメント 2 をインクリメントし、セグメント 3 と 4 をゼロにリセットする必要があります。

  4. バグ修正または設定変更ではセグメント 3 をインクリメントし、セグメント 4 をゼロにリセットする必要があります。

  5. 同じコードに対する新しい自動ビルドでは、セグメント 4 のみをインクリメントする必要があります。

  6. 複数の変更種別が同時に発生した場合は、最も上位の変更を優先し、それより下位のすべてのセグメントをゼロにリセットする必要があります。

リリースの例

現在のバージョンが次の場合:

v1.2.3.4

次に期待されるバージョン:

  • モデル変更 → v2.0.0.0
  • サービスまたはルーチンの変更 → v1.3.0.0
  • バグ修正または設定変更 → v1.2.4.0
  • 同じコードの自動ビルド → v1.2.3.5
  • モデル変更とサービス変更の同時発生 → v2.0.0.0
リリースに関するガイダンス

リリースバージョンは、変更があったことだけでなく、どのような変更があったかを示すために使用してください。

つまり、次のようになります。

  • モデル変更をサービスのセグメントに含めてはなりません
  • サービス変更をバグ/設定のセグメントに含めてはなりません
  • ビルドのインクリメントをコード変更の表現に使用してはなりません

ファイルのバージョニング

V0 の規約

バージョンフォルダーがないファイルは、V0 として扱います。

例:

Models/Foundations/Students/Student.cs
Services/Foundations/Students/StudentService.cs
Models/Foundations/Students/Exceptions/

これは、ディスク上では開始時の形式がバージョン管理されていなくても、論理上はバージョン 0 と見なされることを意味します。

モデルの変更

モデルを変更する場合は、元の場所のサブフォルダーであるバージョンフォルダー内に、新しいバージョン管理対象ファイルを作成する必要があります。

例:

Models/Foundations/Students/V1/StudentV1.cs

このパターンは、次のことを意味します。

  • 元の V0 モデルはそのままの場所に残ります
  • 新しいモデルバージョンはネストされた V1 フォルダーに格納されます
  • フォルダー名と型名の両方でバージョン番号が明示されます
モデルに基づくサービスの変更

モデルを変更する場合、対応するサービスも同じモデルバージョンフォルダー内でバージョン管理する必要があります。

例:

Services/Foundations/Students/V1/StudentV1Service.cs

関連する例外は、対応するバージョン管理対象モデルのパスに合わせる必要があります。

例:

Models/Foundations/Students/V1/Exceptions/
サービスの動作のバージョン管理

基盤となるモデルに変更がなく、サービスの動作が変わる場合は、その動作の進化を反映するためにサービスファイルをバージョン管理します。動作の変更には、検証ルールの変更、以前は任意だったフィールドを必須にすること、ビジネスロジックの変更などが含まれます。

モデルがまだ V0 で、サービスの動作だけが変わる場合、バージョン付きのサービスファイルは動作バージョンのサフィックスを付けてサービスの場所のルートに配置します。バージョンフォルダーは作成しません。

Services/Foundations/Students/StudentServiceV1.cs

モデルがすでにバージョン管理されており(例:V1)、サービスの動作が変わる場合、バージョン付きのサービスファイルはモデルのバージョンフォルダー内に配置し、モデルのバージョンと動作バージョンの両方をファイル名に含めます。

Services/Foundations/Students/V1/StudentV1ServiceV1.cs
モデルと動作を同時に変更する場合

同じリリースでモデルとサービスの動作の両方を変更する場合は、モデルのバージョンのみをインクリメントします。動作バージョンは V0 にリセットされ、ファイル名には含まれません。新しいモデルは定義上、新しいサービスの動作を意味するため、動作バージョンはベースラインに戻ります。

Services/Foundations/Students/V2/StudentV2Service.cs

動作バージョンのサフィックスがない場合、新しいモデルバージョンの動作バージョンが V0 であることを示します。その後、動作にさらなる変更が加えられるたびに、このサイクルを繰り返します。

ファイルのルール
  1. バージョンフォルダーがない場合、V0 とみなされます。

  2. 新しいバージョンは、以前の実装を上書きするのではなく、新しいバージョン付きファイルとフォルダーを作成して導入しなければなりません(MUST)。

  3. モデルを変更する場合、Vn サブフォルダー内にバージョン付きのモデルファイルを作成しなければなりません(MUST)。

  4. モデルを変更する場合、対応する Vn サブフォルダー内にバージョン付きのサービスファイルを作成しなければなりません(MUST)。サービスの動作のみを変更する場合は、新しいバージョンフォルダーを作成せず、動作バージョンをサフィックスとして付けたバージョン付きのサービスファイルをサービスの場所のルートに作成しなければなりません(MUST)。

  5. バージョン付きの例外は、対応するバージョン付きモデルのパス内に配置しなければなりません(MUST)。

  6. 新しいバージョンの導入とは別に、明示的な非推奨化または削除の方針が定められていない限り、以前のバージョンの既存コードを引き続き利用できる状態にしなければなりません(MUST)。

命名規則

バージョン付きのファイル名/型名は、次のパターンに従わなければなりません(MUST)。

  • モデル → {Entity}V{n}.cs
  • モデルバージョンのみのサービス → {Entity}V{n}Service.cs
  • 動作バージョンのみのサービス → {Entity}ServiceV{n}.cs
  • モデルバージョンと動作バージョンの両方を持つサービス → {Entity}V{m}ServiceV{n}.cs

動作バージョンは常に、サービス名の後ろにサフィックスとして付けます。同じリリースでモデルと動作の両方を変更する場合、動作バージョンは V0 にリセットされ、ファイル名には含まれません。

シナリオファイル名の例
モデル V1、動作バージョンなしStudentV1Service.cs
モデルバージョンなし、動作 V1StudentServiceV1.cs
モデル V1、動作 V1StudentV1ServiceV1.cs
モデル V2 を導入(動作は V0 にリセット)StudentV2Service.cs

API のバージョン管理

デフォルトの API ルート

初期 API は、バージョンプレフィックスなしで公開します。

api/Students

これが V0 のルートです。

モデルのバージョンルート

モデルが変更された場合、ルートにはモデルのバージョンを含めなければなりません(MUST)。

api/V1/Students

ここで、V1 は、このエンドポイントがバージョン 1 のモデルを表すことを利用者に示します。

サービスの動作ルート

モデルがすでにバージョン 1 で、そのモデルに対するサービスの動作が変更された場合、ルートにはモデルのバージョンと動作バージョンの両方を含めなければなりません(MUST)。

api/V1.1/Students

この形式では、次のようになります。

  • ドットの前の 1 はモデルのバージョンを示します
  • ドットの後の 1 は動作/サービスのバージョンを示します

これはモデルと動作の組み合わせであり、そのように解釈しなければなりません(MUST)。

モデルを変更せず、動作のみを変更した場合、新しいルートは api/V0.1/Students になります。モデルのバージョンは引き続き 0 ですが、動作バージョンは 1 にインクリメントされています。

API ルール
  1. api/{resource} は V0 を示します。

  2. api/Vn/{resource} はモデルバージョン n を示します。

  3. api/Vn.m/{resource} は、動作バージョン m を持つモデルバージョン n を示します。

  4. ルートのバージョンは、意図されたモデルと動作の組み合わせを伝えなければなりません。

  5. API ルートは、基盤となるモデル/サービスの組み合わせのバージョニング方針と整合性を保たなければなりません。

API の変更例

開始時点:

api/Students

モデル変更後:

api/V1/Students

V1 モデルのサービス動作をさらに変更した後:

api/V1.1/Students

非推奨化

非推奨化は、利用者が次の点を把握できるよう、十分に明確でなければなりません。

  • API が非推奨であること
  • サンセットが予定されている時期
  • 移行ガイダンスの参照先

非推奨バージョンがサンセットを迎える前に対応できるよう、利用者には十分な時間を与えなければなりません。

非推奨化の通知

ヘッダー、またはヘッダーを出力する属性を通じて非推奨化メタデータを提示する方法が有効です。

コントローラーアクション属性を使用する例:

[ApiController]
[Route("api/[controller]")]
public class SampleController : ControllerBase
{
    [HttpGet]
    [DeprecatedApi(
        Sunset = "2024-12-31",
        Warning = "This API is deprecated. Please migrate to v2.",
        Link = "https://example.com/deprecation-info")]
    public IActionResult GetSampleData()
    {
        return Ok(new { message = "Sample data" });
    }
}
主なライブラリ
パッケージ用途
Attrifyコントローラーやアクションに適用する属性を通じて、API の可視性とライフサイクル(非推奨化など)を制御するための NuGet ライブラリ

コードの非推奨化

保守やサポートが終了したコードには、次のマーカーを付けることが推奨されます。

[Obsolete("This version is deprecated and no longer maintained.")]

非推奨マーカーを使用すると、コンパイル時に保守担当者や利用者が非推奨化を確認できます。


ケイパビリティ

機能を呼び出す前に、各バージョンでサポートされる内容を利用者が確認できるよう、ケイパビリティの提供が推奨されます。

これは、モデルのバージョンやサービスの動作がバージョンまたはプロバイダーによって異なる場合に特に役立ちます。

ケイパビリティの目標

ケイパビリティの提示により、利用者が次の内容を確認できるようにします。

  • サポートされている機能
  • サポートされているモデルバージョン
  • サポートされている動作バージョン
  • 利用できないオプション機能
ケイパビリティの提示方法

ケイパビリティは、次の方法で公開できます。

  • Swagger
  • ミドルウェアベースのメタデータ
  • 専用のケイパビリティエンドポイント
  • プロバイダー固有のケイパビリティエンドポイント
プロバイダーの例

SPAL プロバイダーのようなプロバイダーベースのアーキテクチャでは、各具象プロバイダーが、サポートされている操作を利用者に伝えるケイパビリティエンドポイントを公開できます。

このパターンを使用すると、利用者は特定の操作を呼び出す前にプロバイダーがその操作をサポートしているかを安全に確認でき、実行時の失敗を回避できます。


1. 操作属性
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class StudentOperationAttribute : Attribute
{
    public string OperationName { get; }

    public StudentOperationAttribute(string operationName) =>
        OperationName = operationName ?? string.Empty;

    public StudentOperationAttribute() =>
        OperationName = string.Empty;
}

2. ケイパビリティモデル
public sealed class ResourceCapabilities
{
    public string ResourceName { get; init; } = string.Empty;
    public IReadOnlyCollection<string> SupportedOperations { get; init; } =
        Array.Empty<string>();
}

public sealed class ProviderCapabilities
{
    public string ProviderName { get; init; } = string.Empty;
    public IReadOnlyCollection<ResourceCapabilities> SupportedResources { get; init; } =
        Array.Empty<ResourceCapabilities>();
}

3. 学生プロバイダーコントラクト
public interface IStudentProvider
{
    string ProviderName { get; }

    ProviderCapabilities Capabilities { get; }

    IStudentResource Students { get; }
}

4. リソースコントラクト
public interface IStudentResource
{
    ValueTask<Student> AddAsync(Student student);
}

5. プロバイダー基底クラス(簡略化したケイパビリティ宣言)
public abstract class StudentProviderBase : IStudentProvider
{
    public abstract string ProviderName { get; }

    public abstract IStudentResource Students { get; }

    public virtual ProviderCapabilities Capabilities =>
        new ProviderCapabilities
        {
            ProviderName = ProviderName,
            SupportedResources = new[]
            {
                new ResourceCapabilities
                {
                    ResourceName = "Student",
                    SupportedOperations = GetSupportedOperations(Students)
                }
            }
        };

    private static IReadOnlyCollection<string> GetSupportedOperations(object resource)
    {
        if (resource is null)
            return Array.Empty<string>();

        return resource.GetType()
            .GetMethods()
            .Select(method =>
                method.GetCustomAttributes(typeof(StudentOperationAttribute), true)
                      .FirstOrDefault() as StudentOperationAttribute)
            .Where(attribute => attribute is not null)
            .Select(attribute => attribute!.OperationName)
            .Where(name => !string.IsNullOrWhiteSpace(name))
            .Distinct()
            .ToArray();
    }
}

6. 実装例
public sealed class StudentResource : IStudentResource
{
    [StudentOperation("Add")]
    public ValueTask<Student> AddAsync(Student student)
    {
        return ValueTask.FromResult(student);
    }
}

public sealed class StudentProvider : StudentProviderBase
{
    public override string ProviderName => "DefaultStudentProvider";
    public override IStudentResource Students { get; } = new StudentResource();
}

7. ケイパビリティ確認の拡張
public static class StudentProviderCapabilitiesExtensions
{
    public static bool SupportsOperation(
        this IStudentProvider provider,
        string resourceName,
        string operationName)
    {
        var resource = provider.Capabilities.SupportedResources
            .FirstOrDefault(r => r.ResourceName == resourceName);

        if (resource is null)
            return false;

        return resource.SupportedOperations.Contains(operationName);
    }
}

8. 使用方法
IStudentProvider provider = new StudentProvider();

if (!provider.SupportsOperation("Student", "Add"))
{
    // avoid call
    return;
}

await provider.Students.AddAsync(new Student());

重要な原則

ケイパビリティにより、実行時の不確実性を決定的な確認に置き換えられます。

  • ケイパビリティなし → 呼び出す → 失敗する → 例外を処理する
  • ケイパビリティあり → 確認する → 判断する → 安全に呼び出す

これは、次の標準原則に沿っています。

無効な操作に反応するのではなく、無効な操作を避ける


コメント