🚀

リリースのためのAzure DevOps

2022/11/05に公開

image-20221104231631765

概要

プロダクトをリリースすることを主眼とするScrumプロセスをAzure DevOpsを使って実践する方法を構築します。また、Azure DevOps上で気軽にモニターできるようにシステムとの親和性も考慮します。

基本資料

この記事の語彙や発想の基本となっている資料は以下の通りです。

  • Scrum Guides - チーム理論

  • DevOps - 開発・運用理論

  • Azure DevOps - 上記の理論を実践適応するための開発プラットフォーム

対象

構成を適応する対象は以下の通りです。

  • ソフトウェアチーム
  • 50人以上のプロジェクト
  • 2年以上の開発期間

方針

リリースすることを重視する

ユーザーに広く受け入れられるプロダクトを開発するためには、ユーザーからの多くのフィードバックが必要となります。そのため迅速かつ継続したリリースのためのプロセス(ここでは、 Work Itemの設定の仕方とBranch運用のこと)によって、良いプロダクトを開発できるように支援できます。

ユーザーに与えたい体験(Epic)とそれに必要な機能(Feature)の記述に比重を置きます。また、ソースコード上においてもEpic/Featureに記述された内容がわかり易く反映されるようなアーキテクチャを構築し語彙も統一していきます。

Requirementで仕様を網羅するのは理想的ですが、属人的になりがちで負荷に対して漏れも多いものです。Releaseに集中しコンパクトなプロセスにするためにRequirementを利用しない、EpicとFeature中心としたプロセスを推したいです。網羅的な仕様は、その検証によって生じるVerification Test(所謂インテグレーションテストやユーザーシナリオテスト)をカテゴリ別に管理することで把握できるようにします

Branchの運用はTrunk-based Development Workflowを施行し、速く・細かくソフトウェアを更新できるようにします。またPipeline(CI/CD)によってすぐに失敗できる環境を整え、リリースまでに可用性を高めていきます。

階層構造をシンプルにする

階層構造に頼りすぎると作業しにくい構造となります。作業しやすい環境づくりを大切にします。そのため階層を最低限に保つようにします。

同一Work Item Type間の関係は親子関係ではなくSuccessor(依存関係)で表現します。また、Areaを利用することでカテゴライズのための階層構造を減らしていきます。

300人を超えるようなプロジェクトになると組織構造に合わせてAzure DevOps上のProjectを分離したくなりますが、Work ItemやRepos(ソースコード)が分断されるので注意が必要です。1プロダクト1Projectが良いです。ソースコードが多く分離が必要な場合は、フレームワークやコンポーネント郡で分離します。Reposを分離すると情報が整理されますがデプロイメントが複雑になるというトレードオフがあります。

問題管理をシンプルにする

使用できるWork Item Typeを最小にし、作業プロセスを単純化します。

そのためBugを利用しません。我々エンジニアはしばしば発生した問題に対して仕様から漏れているかどうか、つまり問題を「Bug」とするか「変更」とするかどうかで争いがちです。しかしそれはプロダクトを介してユーザーによりよい体験を与えることと関係ありません。時間がもったいないと思うのです。

リリースしたプロダクトをユーザー(開発者も含む)が障害を感じるのであればImpedimentを発行します。プロダクトに変更が必要な場合は、Epicに関連付け対応できるFeatureを作成し対応します。Epic以下はすべて計画作業と同じプロセスになるためシンプルな運用となります。

入力項目をシンプルにする

入力項目とRuleを最小限にします。大切なのは、心理的なハードルによってWork Itemの発行が阻害されるような状況を避けることです。Work Itemの発行が減少するとProjectの元気がなくなり、不正も発生しやすくなります。

Templateを使ってDescription上に必要な情報項目を展開するようにすれば、項目を統一しつつ柔軟な運用が可能です。これにより、心理的なItem発行のハードルを下げながら、雑な発行を防ぎます。また項目が沢山あるWork Itemに比べると属人的にになりにくいです。

ただし、後戻りに時間がかかるような、コミット時や完了時のRuleは多少厳しくします。

テストの実行を自動化する

手早いリリースを継続的に行っていくためには変更しやすい環境が必要です。そのために複数のレイヤーでテストをPipelineを使って自動化し何度も繰り返し行うようにします。

そのためには、シミュレーターを実装したり、DIを利用してコンポーネント毎にテストできるようにするなどの工夫を惜しまないようにします。また、テストは至るところで実行され続けるため、変更がなければ100%成功するテストを意味があるように実装する必要があります。

Version管理

Release VersionとDev Versionの2通りのVersionを設けます。Version番号の更新はPipelineを通して行います。

  • Release Version

    {MajorVersion}.{MinorVersion}.{PatchRevision}.{BuildNumber}で表現します。Major VersionとMinor VersionはEpicによって規定します。

  • Dev Version

    Main.{BuildNumber}で表現します。Mainの更新に合わせてインクリメンタルに更新されます。

プロセスの全体像

プロセスは大きく5つのブロックに分かれています。5つのブロックの目的とそれに応じた設定を各章で述べていきます。

リリースを重視したプロセスの全体構造を以下に示します。

image-20221104231754883

上記構造に合わせてOrganization SettingsからProcessのBack Log Levelsの設定を以下のようにします。

image-20221103155724013

Project Settingsの各Team Configurationも同様に設定します。

image-20221103192447442

Project Settingsで基本設定のIterationとAreasも設定します。Iterationは3週間以内でインクリメントすることがお勧めです。Areasの使い方は各ブロックで説明します。

image-20221104134641721

Portfolio Backlog Block

リリースするための核となるブロックです。

image-20221029211857145

Epic - ユーザー体験

  • 目的

    Epicはプロダクトによってユーザーに与えたい体験を表現するWork Itemです。

    市場分析によって得たニーズをもとに重要性の高いものからユーザーに体験してもらいフィードバック得るための単位です。Epicを積み重ねることで、市場に本当に必要なものを見つけ出します。

    ひとつのEpicはプロダクトのリリースのVersionを示します。対象のVersionの与えるユーザー体験のVisionとチームからみたGoalが表現されている必要があります。

  • 完了の定義

    基本的な完了の定義はユーザーシナリオテストをパスすることです。期間的には1クォータで完了できる内容となります。

  • Iteration

    リリース予定のIterationを設定します。

  • Area

    使用しません。プロジェクト直下に設定します。

  • Release Note

    Release Note項目をEpicに追加して、ユーザー向けの情報を記述します。Descriptionでも大丈夫ですが、ユーザを意識しすぎて情報が薄まったり、逆に不要な内部情報が含まれてしまう可能性があるため別項目にする方が良いです。

  • リンク

    Epicにはそれを実現するための機能を示す複数のFeatureをChildとしてリンクします。またEpicを検証するための複数のTest CaseをChildとしてリンクします。

    EpicにはRelease Branch(Versionごとに分岐したBranch)をリンクします。もしもリリース後、このVersionで想定する体験が出来ない場合はこのEpicを再オープンしRelease Branchを更新しRevisionをインクリメントます。この対応をパッチと呼びます。

    パッチ対応時は新しいFeature及びPBIを作成します。

  • 再オープンが可能なケース

    パッチ対応

Feature - 機能

  • 目的

    Featureはプロダクトの持つ機能を表現するWork Itemです。

  • 完了の定義

    基本的なFeatureの完了の定義はFeature Verification(=インテグレーションテスト)をパスすることです。Feature Verificationはできる限り自動化します。期間的には1ヶ月(2sprint)以内で完了できる内容となります。

    約1ヶ月以内で設計 -> 実装 -> UT -> ITまで行うのはかなりハイテンポです。これはAzure DevOpsのPipelineを整備して、Continuous Integration(CI)を実現する必要があります。CIのコストを惜しむと安定したリリースは不可能です。CIを練り込みましょう。

  • Iteration

    Featureの完了予定のIterationを設定します。

  • Area

    プロジェクト名/Teams/Team名

    対象の機能の開発をリードするTeamをAreaに割り当てます。これによりリファインメントの担当が明確になります。Areaを機能別に割り当てないことでTeamは機能横断的な作業がしやすくなります。

  • リンク

    FeatureのParentにRelease Versionを示すEpicをリンクします。Childには実装に必要なPBIを全てリンクします。FeatureとFeatureの依存関係はSuccessorによって表現します。またFeatureを検証するための複数のTest CaseをChildとしてリンクします。

    Pull Request(ソースコードの変更とレビュー情報)はFeatureへリンクします。

  • Effort

    プロダクトにおけるこの機能の価値を表す数値です。値が大きほどプロダクトに対する価値が大きいです。プロダクトオーナー間で共通の指標をもとに値を決定します。作業量を最大の価値基準とおきます。

  • 再オープンが可能なケース

    完了したSprintと同じSpritであれば再オープンできます。それ以外は不可です。

Portfolio Backlogのためのモニター

  • Boards - Delivery Plans

    リリースまでの全体計画を俯瞰することが可能です。ChildにWork Itemをつけることでその進捗率も見ることが出来ます。

    image-20221103192012444

    Work Itemをクリックすることで、依存関係がハイライトされます。

    image-20221031214142952

    また、Work Itemの右上にあるチェーンのアイコンを押すことで、依存関係が文字列でポップアップされます。

    image-20221031214249868

  • Boards - Backlogs - プロジェクト直下のTeam - Epics

    どのVersionでどのFeatureをReleaseするかをリストとして確認できます。

    image-20221028214021548

  • Boards - Backlogs - 各開発Team - Features

    各TeamでFeatureのPriorityを決定する画面です。

    image-20221103192059389

    FeatureのChildのPBIを表示する事もできます。

    image-20221103192114676

Verification Block

プロダクトのVerification Testを定義するブロックです。

image-20221029203811662

Test Case - User Scenario Verificationの定義

  • 目的

    Epicに記述されたユーザー体験をユーザシナリオに落とし込みUser Scenario Verificationを定義するWork Itemです

  • 完了の定義

    ユーザーシナリオを定義しマニュアルテストを実行できる状況が整っていることです。テスト結果は完了の定義の対象外となります。

  • Iteration

    使用しません。プロジェクト直下に設定します。

  • Area

    プロジェクト名/System/{Major Version}.{Minor Version}

  • リンク

    EpicにTestsとしてリンクします。

  • テストの変更

    Epicの追加によって過去のテストが不要になる場合があります。その場合は既存のテストをClosed(Obsolete)にして新しいTest CaseをそのEpicの追加するとともに新規Test Caseを定義します。

  • テストの実行方法

    Test Plansから手動テストを実行します。

Test Case - Feature Verificationの定義

  • 目的

    Featureを検証するためのFeature Verificationを定義するWork Itemです。

  • 完了の定義

    自動テストを定義し実行できる状況が整っていることです。テスト結果は完了の定義の対象外となります。

  • Iteration

    使用しません。プロジェクト直下に設定します。

  • Area

    プロジェクト名/Feature/機能カテゴリ

  • リンク

    FeatureにTestsとしてリンクします。

    Test Codeを実装します。Test Method名とDLLを指定します。テスト実装のためのPull RequestはFeatureへリンクします。

  • テストの変更

    User Scenario Verificationと同じくFeatureの追加によって過去のテストが不要になる場合があります。その場合はEpicと同様既存のテストにをClosed(Obsolete)にして新しいTest CaseをそのFeatureの追加時に新規に定義します。

    Test CodeのリファクタリングはTest Caseのリンクをそのままにコードのみ修正します。

  • テストの実行方法

    Pipelineからテストが実行されるように定義します。

    Pull Request、リリース、夜間テストなどに関連づくPipelineから呼び出して使うことで検証およびリグレッションをします。

Test Plan - Test Suiteをまとめる

  • 目的

    User Scenario VerificationとFeature VerificationのためのTest Suiteをまとめる特殊なWork Itemです。Test Suiteの更に下にTest Caseがまとめられます。

  • 生成

    特殊なアイテムで、Test Plansのメニューからのみ生成できます。

  • 完了の定義

    完了の概念はありません。このTest PlanがActiveかInactiveなのかだけ選択します。

  • Iteration

    基本的には使用しません。プロジェクト直下に設定します。

    テストするIterationが決まっている場合はそのIterationを設定します。

  • Area

    Test対象によって使い分けます。

    プロジェクト名/Feature or プロジェクト名/System/Version

  • リンク

    必要ありません。Test PlansのメニューでTest対象のTest Suiteを関連付けます。

Test Suite - Test Caseをまとめる

  • 目的

    User Scenario VerificationとFeature VerificationのためのTest Caseをまとめる特殊なWork Itemです。Test Plansのメニューからのみ生成できます。

  • 生成

    特殊なアイテムで、Test Plansのメニューからのみ生成できます。

  • 完了の定義

    Releaseのような一度だけ利用されるようなTest PlanのTest Suiteは関連づくTest Caseがすべて成功した場合に完了となります。継続的に利用されるTest PlanのTest Suiteは常にActiveです。

  • Iteration

    使用しません。プロジェクト直下に設定します。

    テストするIterationが決まっている場合はそのIterationを設定します。

  • Area

    Test対象によって使い分けます。

    プロジェクト名/Feature or プロジェクト名/System/Version

  • リンク

    必要ありません。Test PlansのメニューでTest先を登録します。

Feature Verificationのためのモニター

  • Test Plans - Test plans - Define

    目的にあったテスト計画を作成します。Test PlanとTest Suiteを作成してTest Caseと関連付けます。

    image-20221028214413168

    image-20221028214439214

  • Test Plans - Test plans - Define - Run Web Application

    手動テストが実行できます。

    image-20221031215722020

  • Test Plans - Test plans - Execute - View execution history

    手動/自動問わずテスト結果が格納されていきます。

    image-20221031215535379

    • Test Plans - Progress report

      image-20221031215349625

Product Backlog Block

Sprintの作業進捗を管理するためのブロックです。

image-20221029205032031

PBI - 機能の部品

  • 目的

    Product Backlog Item(PBI)はTeamがSprintを通して作業しやすいようにFeatureを分解するためのWork Itemです。

  • 完了の定義

    基本的な定義の定義はプロダクトコードおよびテストコードのPull Request完了です。ユニットテストはPull Requestから自動起動し、その完了条件となっている必要があります。期間的には最大でも2週間(1sprint)以内で完了できる内容となります。

  • Iteration

    作業予定のIterationを設定します。

  • Area

    プロジェクト名/Teams/チーム名

  • Value Type

    Productを設定します

  • リンク

    Parentはその機能全体を示すFeatureをリンクします。Childに進捗を示すTaskをリンクします。

  • Featureに情報を集中する

    PBIは使い捨てのアイテムと考えます。PBIはSprint完了後に再度見る必要がないように必要な情報をFeatureに集中します。また、Pull RequestのリンクはFeatureにします。

    過去にさかのぼってまで閲覧するPBIのデータはEffort、Area、Value Typeくらいです。

  • 再オープンが可能なケース

    完了したSprintと同じSpritであれば再オープンできます。それ以外は不可です。

PBI - 機能実装以外の項目

  • 目的

    コミュニケーションサポート、リファインメント、調査などの機能実装以外の項目のためのWork Itemです。

  • 完了の定義

    作業完了で閉じることも出来ますが、Sprint間ずっと行うサポート作業などは、Sprint終了時に同時に閉じます。

  • Iteration

    作業予定のIterationを設定します。

  • Area

    プロジェクト名/Teams/チーム名

  • Value Type

    Product以外の運用作業に応じたタイプを設定します。

  • リンク

    Parentは不要です。Childに進捗を示すTaskをリンクします。

    ParentとなるFeatureをつくる運用も悪くないですが無くても問題ないです。いかにシンプルに運用するかと考えると無い方が方針として良いと思います。

  • 再オープンが可能なケース

    なし

Task - 進捗

  • 目的

    作業進捗を示すWork Itemです。

  • 完了の定義

    Sprint開始時に作成しタスク完了で閉じます。

    1日1個以上のペースで消化できるようにTaskに分解します。残Task数で自動集計されるバーンダウンをもとにスタンドアップミーティングを行います。

  • Iteration

    進行中のIterationを設定します。

  • Area

    プロジェクト名/Teams/チーム名

  • リンク

    ParentはPBIをリンクします。

  • 再オープンが可能なケース

    なし

Product Backlogのためのモニター

  • Boards - Sprints - Taskboard

    Taskboardを利用することで、日々のSprint作業のTaskの進捗をインタラクティブに操作・管理できます。

    image-20221031213744037

  • Boards - Sprints - Backlog

    TeamのSprint作業の一覧、プライオリティーをOrder(並び順)で確認できます。

    image-20221031184524225

  • Boards - Sprints - Analytics

    進捗をバーンダウンで確認することが出来ます。スタンドアップミーティングでTaskboardとセットで利用します。

    image-20221103183743520

Source Code Block

ソースコードの管理をするブロックです。

image-20221029212301442

Main/Release Branch - Workflow

BranchはTrunk-based Development Workflowで運用します。

image-20221104132712292

  • Main Branch

    Main Branchはチームが開発のために利用するメインのBranchでありソースコードの統合先です。

    実装はPull Requestを介してMain Branchに次々統合します。細かくマージをすることで競合解決の手間を減らしつつ、自動で行われる既存UT/Feature Verificationによって影響を把握できます。

  • Release Branch

    Release BranchはEpicで既定した想定するVersionごとのユーザシナリオが可能となるようソースコードをまとめます。

    Code CutoffのタイミングでRelease BranchをMain Branchから新たに切り出します。Versionごとに新しいRelease Branchを作成します。Code Cutoffまでの期間中にそのVersionでReleaseすべき作業に集中できていれば、Release BranchへのCherry-Pickの回数を少なくすることができます。

    Release BranchはVersionごとEpicにリンクします。

Pull Request

Pull Requestはコードレビューのアイテムです。Main Branchから切り出した作業BranchをMain Branchに統合するためのレビューとして機能します。

  • Pull Requestにこだわる

    Pull Requestを発行する前にPersonal Review及びTestコードの作成、Pipelineの成功、静的解析、テストカバレッジを確認します。チームが快くコード読めるように精査してから作業者はPublishします。(Pull Requestが楽しいチームはいいですよね!)

    また、問題をすぐに対処できるのはこのPull Requestの工程までです。Pull RequestにこだわることはShift-Leftです。

  • Branch Policy

    Branch Policyを設定することで、Pull Requestを完了するための条件を設定できます。一定のカバレッジ以上のテストを含むPipelineの成功を完了条件とします。

  • リンク

    Pull RequestはFeatureにリンクします。

Pipeline

PipelineとはBuildとテストのプロセスを自動化するものです。

大きく4つのPipelineを定義します。

  • Pull Request Pipeline

    コードレビュー時に実行されるPipelineです。このPipelineの成功やこのPipelineから実行されるカバレッジや静的解析などの条件をクリアしない限り、Main BranchにマージすることはPolicyによってできません。これによりMain Branchの品質を一定以上に保つことが出来ます。

  • Build Pipeline

    Main/Release Branchが更新されたときに実行されるPipelineです。これによりMain BranchのVersionが更新され、開発環境の最新VersionがDeployされます。

  • Release Pipeline

    リリースを行うためのPipelineです。Release BranchのBuild、UT、関係するFeature Verificationなどに加えてユーザ承認のプロセスを行います。このPipelineの完了をもってプロダクトがユーザの手にリリースされます。

  • Nightly Pipeline

    一日一回実行される夜間テストのPipelineです。Main Branchと直近のRelease Branchを対象に関係するFeature Verificationを実施します。

Source Code Blockのためのモニター

  • Repos - Files

    image-20221031220528220

  • Pipelines - Pipelines

    各Pipelineの実行履歴

    image-20221031222624085

  • Pipelines - Pipeline選択 - Analysis

    • Pipeline failure report

      image-20221031222115763

    • Test failure report

      image-20221031221853181

  • Pipelines - Releases

    リリースのためのPipelineです。

    image-20221031222140268

User Reaction Block

フィードバック/問題を管理するブロックです。

image-20221029212730162

Impediment

  • 目的

    Impedimentはプロダクトに発生している障害を取り扱うWork Itemです。

    障害はエンドユーザーだけでなく開発者も含みます。

  • 完了の定義

    問題が発生しなくなることを確認することです。

  • Iteration

    対応完了期限のIterationを設定します。

  • Area

    使用しません。プロジェクト直下に設定します。

  • リンク

    ソースコードの修正がない場合は不要です。

    修正が必要な場合は、対処を示すFeatureをPredecessorでリンクし、対処のリリースタイミングに合わせてEpicをParentにリンクします。

  • Templateをつかう

    Impediment作成時にテンプレートを展開し作成者に促します。

    問題の発生した環境、Version、ログ、スクリーンショット、操作手順などがあるとトリアージや修正対応時に役立ちます。

  • トリアージ状況を表現

    発生した障害に対してDescriptionをみてResolutionと対応するIterationを決定しつつPriorityと決定することをトリアージと呼びます。トリアージ済みかどうかを示すTriagedというStateを追加すると便利です。

  • エンドユーザーとの対応状況

    エンドユーザーとの対応を記述するためのFieldを追加します。

    エンドユーザー環境で発生した障害やUserとの対応状況をここに記述していきます。

  • 再オープンが可能なケース

    なし。再発した場合も再度作り直しプロセスを踏み直します。

User Reaction Blockのためのモニター

  • Daily Plans

    Portfolio Backlogと同様です。

  • Backlogs - プロジェクト直下

    image-20221103191810811

最後に

私はAzure DevOpsはリリース当初から使っていて、今のプロジェクトと比較しながらいいところ/もっとできそうなことを漠然と思い描いていました。こんなプロセスだったらいいなを案にしてまとめてみました。

Azure DevOpsの使い方は千差万別。プロダクトの品質特性に合わせた運用が良いと考えてます。紹介したプロセスはその土台になると思います。リリースすることを重視し、よりよいプロダクトを作れる方法をもっと模索していきたいです。

Discussion