バリューストリームアナリティクス開発ガイド

バリューストリームアナリティクスは、ドメインオブジェクトに記録された2つの任意のイベント間の時間を計算し、その期間に関する集約された統計情報を提供します。

GitLabでValue Stream Analyticsを設定する方法については、アナリティクスのドキュメントをご覧ください。

ステージ

開発中、イシューやマージリクエストを、完成とみなされるまでさまざまな進行ステージに進めるイベントが発生します。 これらのステージは、Stage モデルで表現することができます。

ステージ例:

  • 名称:開発者
  • 開始イベント:イシュー作成
  • 終了イベント:コミットで最初に言及されたイシュー
  • 親です:Group: gitlab-org

イベント

イベントは、バリューストリーム分析機能の最小構成要素です。 ステージは2つのイベントで構成されます:

  • スタート
  • 終了

これらのイベントは、持続時間の計算において重要な役割を果たします。

フォーミュラduration = end_event_time - start_event_time

継続時間の計算を柔軟にするために、Event はそれぞれ別のクラスとして実装されています。これらは、計算クエリで使用されるタイムスタンプ式を定義する役割を担っています。

Event クラスの実装

実装が必要なメソッドがいくつかあります。StageEvent の基本クラスには、その詳細が記述されています。 最も重要なメソッドは以下のとおりです:

  • object_type
  • timestamp_projection

object_type メソッドは、計算のためにどのドメイン・オブジェクトをクエリするかを定義します。 現在、2つのモデルが認められています:

  • Issue
  • MergeRequest

持続時間の計算には、timestamp_projection 方式を使用します。

def timestamp_projection
  # your timestamp expression comes here
end

# event will use the issue creation time in the duration calculation
def timestamp_projection
  Issue.arel_table[:created_at]
end
注:より複雑な表現も可能です(例:COALESCE)。例については、既存のイベントクラスを見てください。

場合によっては、timestamp_projection メソッドを定義するだけでは十分ではありません。計算クエリは、どのテーブルにタイムスタンプ式が含まれているかを知っている必要があります。各Event クラスは、timestamp_projection を動作させるために計算クエリを修正する責任を負います。 これは通常、追加のテーブルを結合することを意味します。

issue_metrics テーブルを結合し、first_mentioned_in_commit_at カラムをタイムスタンプ式として使用する例:

def object_type
  Issue
end

def timestamp_projection
  IssueMetrics.arel_table[:first_mentioned_in_commit_at]
end

def apply_query_customization(query)
  # in this case the query attribute will be based on the Issue model: `Issue.where(...)`
  query.joins(:metrics)
end

開始イベントと終了イベントの検証

開始と終了のイベントペアの中には、互いに「互換性」がないものがあります。 たとえば、以下のようなものです:

  • “イシューが作成されました” から “マージリクエストが作成されました”: イベントクラスが異なるドメインモデルで定義されているため、object_type メソッドが異なります。
  • 「イシューのクローズ」から「イシューの作成」へ:イシューをクローズするには、まずイシューを作成する必要があります。
  • 「イシューがクローズされました」→「イシューがクローズされました」:期間は常に0です。

StageEvents モジュールは、許可されたstart_eventend_event のペアリング(PAIRING_RULES 定数)を記述しています。 新しいイベントが追加された場合、このモジュールに登録する必要があります。 新しいイベントを追加するには。

  1. ENUM_MAPPING 、一意の番号を持つエントリを追加します。Stage モデルでは、enumとして使用されます。
  2. PAIRING_RULES ハッシュ内のイベントと互換性のあるイベントを定義します。

サポートされる開始/終了イベントの組み合わせ:

graph LR; IssueCreated --> IssueClosed; IssueCreated --> IssueFirstAddedToBoard; IssueCreated --> IssueFirstAssociatedWithMilestone; IssueCreated --> IssueFirstMentionedInCommit; IssueCreated --> IssueLastEdited; IssueCreated --> IssueLabelAdded; IssueCreated --> IssueLabelRemoved; MergeRequestCreated --> MergeRequestMerged; MergeRequestCreated --> MergeRequestClosed; MergeRequestCreated --> MergeRequestFirstDeployedToProduction; MergeRequestCreated --> MergeRequestLastBuildStarted; MergeRequestCreated --> MergeRequestLastBuildFinished; MergeRequestCreated --> MergeRequestLastEdited; MergeRequestCreated --> MergeRequestLabelAdded; MergeRequestCreated --> MergeRequestLabelRemoved; MergeRequestLastBuildStarted --> MergeRequestLastBuildFinished; MergeRequestLastBuildStarted --> MergeRequestClosed; MergeRequestLastBuildStarted --> MergeRequestFirstDeployedToProduction; MergeRequestLastBuildStarted --> MergeRequestLastEdited; MergeRequestLastBuildStarted --> MergeRequestMerged; MergeRequestLastBuildStarted --> MergeRequestLabelAdded; MergeRequestLastBuildStarted --> MergeRequestLabelRemoved; MergeRequestMerged --> MergeRequestFirstDeployedToProduction; MergeRequestMerged --> MergeRequestClosed; MergeRequestMerged --> MergeRequestFirstDeployedToProduction; MergeRequestMerged --> MergeRequestLastEdited; MergeRequestMerged --> MergeRequestLabelAdded; MergeRequestMerged --> MergeRequestLabelRemoved; IssueLabelAdded --> IssueLabelAdded; IssueLabelAdded --> IssueLabelRemoved; IssueLabelAdded --> IssueClosed; IssueLabelRemoved --> IssueClosed; IssueFirstAddedToBoard --> IssueClosed; IssueFirstAddedToBoard --> IssueFirstAssociatedWithMilestone; IssueFirstAddedToBoard --> IssueFirstMentionedInCommit; IssueFirstAddedToBoard --> IssueLastEdited; IssueFirstAddedToBoard --> IssueLabelAdded; IssueFirstAddedToBoard --> IssueLabelRemoved; IssueFirstAssociatedWithMilestone --> IssueClosed; IssueFirstAssociatedWithMilestone --> IssueFirstAddedToBoard; IssueFirstAssociatedWithMilestone --> IssueFirstMentionedInCommit; IssueFirstAssociatedWithMilestone --> IssueLastEdited; IssueFirstAssociatedWithMilestone --> IssueLabelAdded; IssueFirstAssociatedWithMilestone --> IssueLabelRemoved; IssueFirstMentionedInCommit --> IssueClosed; IssueFirstMentionedInCommit --> IssueFirstAssociatedWithMilestone; IssueFirstMentionedInCommit --> IssueFirstAddedToBoard; IssueFirstMentionedInCommit --> IssueLastEdited; IssueFirstMentionedInCommit --> IssueLabelAdded; IssueFirstMentionedInCommit --> IssueLabelRemoved; IssueClosed --> IssueLastEdited; IssueClosed --> IssueLabelAdded; IssueClosed --> IssueLabelRemoved; MergeRequestClosed --> MergeRequestFirstDeployedToProduction; MergeRequestClosed --> MergeRequestLastEdited; MergeRequestClosed --> MergeRequestLabelAdded; MergeRequestClosed --> MergeRequestLabelRemoved; MergeRequestFirstDeployedToProduction --> MergeRequestLastEdited; MergeRequestFirstDeployedToProduction --> MergeRequestLabelAdded; MergeRequestFirstDeployedToProduction --> MergeRequestLabelRemoved; MergeRequestLastBuildFinished --> MergeRequestClosed; MergeRequestLastBuildFinished --> MergeRequestFirstDeployedToProduction; MergeRequestLastBuildFinished --> MergeRequestLastEdited; MergeRequestLastBuildFinished --> MergeRequestMerged; MergeRequestLastBuildFinished --> MergeRequestLabelAdded; MergeRequestLastBuildFinished --> MergeRequestLabelRemoved; MergeRequestLabelAdded --> MergeRequestLabelAdded; MergeRequestLabelAdded --> MergeRequestLabelRemoved; MergeRequestLabelRemoved --> MergeRequestLabelAdded; MergeRequestLabelRemoved --> MergeRequestLabelRemoved;

チームや組織は、ソフトウェアを構築する独自の方法を定義するかもしれません。 そのため、ステージはまったく異なるものになる可能性があります。各ステージでは、親オブジェクトを定義する必要があります。

現在サポートされているご両親

  • Project
  • Group

親子関係の仕組み

  1. ユーザーは価値のストリーム分析ページに移動します。
  2. ユーザーがグループを選択します。
  3. バックエンドは選択されたグループの定義されたステージをロードします。
  4. ステージへの追加や変更は、選択されたグループ内でのみ永続化されます。

デフォルトステージ

バリューストリーム分析の元の実装では、7つのステージが定義されています。 これらのステージは、各親で常に使用可能ですが、これらのステージを変更することはできません。 物事を効率化し、作成されるレコードの数を減らすために、デフォルトのステージはインメモリオブジェクトとして表現されます(永続化されません)。 ユーザーが初めてカスタムステージを作成すると、すべてのステージが永続化されます。 この動作は、バリューストリーム分析サービスオブジェクトに実装されています。 この理由は、後でステージを非表示にしたり順序付ける機能を追加したいためです。

データコレクター

DataCollector は、データベースからデータがクエリされる中心点です。 クラスは常に1つのステージでオペレーションされ、以下のコンポーネントで構成されます:

  • BaseQueryBuilder:
    • 最初のクエリの作成を担当。
    • Stage 、イベントやクエリのカスタマイズなど、特定のコンフィギュレーションを扱います。
    • UIからのパラメータ:日付範囲。
  • MedianBaseQueryBuilderからのクエリを使用して、ステージの期間中央値を計算します。
  • RecordsFetcherBaseQueryBuilder からのクエリと、可視性ルールを適用するための特定の クラスを使用して、ステージに関連するレコードを読み込みます。Finder
  • DataForDurationChart: 散布図チャートの終了時間(終了イベントのタイムスタンプ)と計算された持続時間をロードします。

新しい計算やクエリについては、DataCollector クラスの新しいメソッド呼び出しとして実装します。

データベースクエリ

データベースクエリの構造:

SELECT (customized by: Median or RecordsFetcher or DataForDurationChart)
FROM OBJECT_TYPE (Issue or MergeRequest)
INNER JOIN (several JOIN statements, depending on the events)
WHERE
  (Filter by the PARENT model, example: filter Issues from Project A)
  (Date range filter based on the OBJECT_TYPE.created_at)
  (Check if the START_EVENT is earlier than END_EVENT, preventing negative duration)

MedianSELECT ステートメントの構造 :

SELECT (calculate median from START_EVENT_TIME-END_EVENT_TIME)

DataForDurationChartSELECT ステートメントの構造 :

SELECT (START_EVENT_TIME-END_EVENT_TIME) as duration, END_EVENT.timestamp

ハイレベルの概要

  • Rails コントローラ (Analytics::CycleAnalytics モジュール): 価値ストリーム分析は、analytics ワークスペース内に実装された JSON エンドポイントを介してデータを公開します。ステージの設定も、(CRUD)JSON エンドポイントを実装します。
  • サービス (Analytics::CycleAnalytics モジュール):Stage 関連のアクションはすべて、それぞれのサービスオブジェクトに委譲されます。
  • モデル (Analytics::CycleAnalytics モジュール): モデルは、Stage オブジェクトProjectStageGroupStageを永続化するために使用されます。
  • フィーチャー・クラス (Gitlab::Analytics::CycleAnalytics モジュール):
    • クエリを作成し、機能固有のビジネスロジックを定義します。
    • DataCollector,Event,StageEvents, etc.

テスト

たくさんのイベントと可能な組み合わせがあるので、それぞれの組み合わせをテストするのは不可能です。Event クラスを使ったテストケースを少なくともひとつ用意するのがルールです。

新しいEvent を使用してステージのテストケースを記述することは、両方のイベントに対してデータを作成する必要があるため、困難な場合があります。 これを少し簡単にするために、各テストケースは、ステージがDataCollectorを通してテストされるdata_collector_spec.rb に実装する必要があります。各テストケースは、以下のケースをカバーする複数のテストになります:

  • 異なる両親:Group またはProject
  • さまざまな計算:Median,RecordsFetcher またはDataForDurationChart