Agileでのソフトウェア開発
GitLabの管理方法
進捗管理
-
リリースプランニング
- Milestone機能を使用してリリースのバージョンごとに集計、管理を行っている(13.3)
- まだ具体的な対応時期が決まっていないものは
Backlog
と言うマイルストーンに入れる - Backlogの中で具体的な対応時期は決まっていないが直近に対応するものは
Next 1-3 releases
などで管理 - https://gitlab.com/groups/gitlab-org/-/milestones/48
-
イテレーション
- Iteration機能を使用して、イテレーションごとのタスクを管理、集計している(#18 (2021-02-04 - 2021-02-17))
要求の管理
-
エピック
- Epic機能を利用して、複数のFeature(User Story)を取りまとめている。(Support multiple, automated Iteration Cadences)
- エピックの中にはマイルストーンが異なる(リリースタイミングが異なる)Feature(User Story)が入っている
-
Feature
- 個別のIssueが対応する(Match existing users to Epics)
- Issueには
Problem to Solve
とProposed Solution
で要求事項と解決方法が記載されている(大抵のケース)
アジャイルの目的
背景
プロジェクト型からプロダクト型への変化
プロジェクトマネジメントとProductManagementの違い
- プロジェクトにおける最大のリスクは終了しないこと、プロダクトは終了すること
様々な競合製品や競合サービスのある中から、「目まぐるしく変化する市場環境や顧客ニーズに答えていく」という要求に応える必要がある
これによって、ソフトウェア開発の前提がプロジェクト型からプロダクト型へ変化していく
こうした前提の変化に従来の計画駆動型の開発は限界を迎え、アジャイルが導入された
不確実性の
Cynefinの5つの分類
多くのソフトウェア開発のプロジェクトや活動は複雑系に分類される。そして、複雑系はアジャイル開発と反復型開発の領域である。プロジェクトの大部分が複雑系に含まれる場合、実際にうまくいくアプローチには実験が組み込まれていなければならず、問題を完全に定義するには調査が必要となる。
More Effective Agile “ソフトウェアリーダー”になるための28の道標
複雑系に分類される問題が増えれば増えるほど、アジャイルを導入する効果が
プロジェクト管理の基本
ユーザ目線で見た価値で要求を管理、チームのパフォーマンスを計測する
ユーザーストーリーの活用
ユーザ目線で見た価値で要求を管理するという点で、アジャイルのプラクティスとしてユーザストーリーを活用する
ベロシティによるチームの生産性の計測
チームがユーザ目線で見た価値をどの程度提供することができているのかベロシティという指標で計測、管理する。
アジャイルのプラクティス
一般的に以下のプラクティスとそれに紐づく穏健がアジャイル開発の特徴とされるが、すべてをそのまま適用する必要はなく、それぞれのチームや開発するものの特性に応じて採用すればOK。
ポイント | 説明 | 恩恵 |
---|---|---|
短いリリースサイクル | 動くソフトウェアを数日または数週間のサイクルで開発する | 顧客からすぐにフィードバックを得られ、軌道修正が迅速にできる(チームとして柔軟性が持てる)。また、欠陥を見つけたそばからコストをかけずに修正できる。 |
小さなバッチでの実行 | --- | 同上 |
事前の大まかな計画とジャストインタイムの詳細な計画 | 必要になった段階で計画を詳細化する | 後で変更される可能性が高い事前な計画にかけるコストを削減できる。 |
事前の大まかな要求獲得とジャストインタイムでの要求の詳細化 | 要求の詳細化はプロジェクトの開始後まで先送りされる | 計画の項と同様に後から変更される可能性が高い要求の詳細化にかかるコストの削減につながる。 |
創発的な設計 | 設計作業の細かな点は実際に必要になるまで先送りされる(設計/アーキテクチャの一部については事前設計に価値を置く) | 要求の項に関連して、後から変更される要求に対する無駄な設計作業の削減に繋がる。 |
継続的な自動テスト(開発と統合) | テストはコーディングと並行して行われる。また、テストの自動化に重点を置く | 欠陥が紛れ込んでから修正するまでの修正コストが削減される。 |
頻繁なコラボレーション | スタンドアップミーティングなど頻繁なコラボレーションが推奨される | |
実証主義的 | 当初の計画に従うよりも、実際にチームが体験したことに重きを置く | 不確実な状況でチームが経験から学び、改善することができるようになる。 |
前提
- 短期間でのデプロイ回数が増加
- 開発も含めてプロダクト開発そのものがイテレーティブなものに
品質管理の考え方
不確実な状況や不確実な問題に対して柔軟で臨機応変に対応できる組織を作ることがアジャイルの考え方。
これを品質面で考えると「まだ見つかっていない欠陥ができるだけ少ない状態」こそが柔軟に動くために必要。
極端に言ってしまえばイテレーション(スプリント)の最後にテストをしないでもOKなようにする?
変わらない部分
ユーザーインパクト
アジャイルだろうがウォーターフォールだろうが開発主砲に関わらず最終的な目的はビジネスとして顧客に価値を提供すること。
そのためには品質の低いソフトウェアをリリースした場合のユーザインパクトは変わらない。
バグで使い物にならないということがあってはならない。
変わる部分
イテレーティブな開発
イテレーションを回して機能開発をしていく以上、小さいバッチでの作業になる。
そのため作業が終わったのに
また、設計や開発が明確にフェーズわけされないため、実装を繰り返しながら少しずつ変えていく。
そのため、相対的に実施するテストの回数は増加する。
それを全てマニュアルテストで行うとコストが非常に高くなる。
そのため、品質とコストのバランスを取るには適切な自動化が欠かせない。
欠陥の挿入
- 欠陥は開発チームが作業をすればするほど紛れ込む
- 挿入されてからまだ見つかっていない欠陥(潜在的な欠陥)が多ければ多いほど、後からバグフィックス
等追加で必要な対応が発生し、予算とスケジュールに更なる不確実性をもたらす(予測不可能なスケジュールの変更や対応費用の増加が発生し、臨機応変に対応できる状態から離れていく) - また単純に欠陥は挿入されてから検出/除去するまでの時間が短ければ短いほど、効率的に対応できる
- 上記より欠陥が挿入されてから即座に修正されるプロジェクトの方が効率的と考えられる
潜在的な欠陥を最小限に抑えるプラクティス
以下のプラクティスを組み込む。
- ユニットテスト
- ペアプログラミング
- 静的解析
- コードレビュー
- 継続的インテグレーション
完成の定義の活用
完成の定義を活用することでQA作業をあらゆる作業と結びつけることが可能となり、それにより潜在的な欠陥を減らすことができる。
以下はMore Effective Agileより転載した完成の定義の例だが、開発を伴う作業にこれらの定義を適用すれば(またはCI等で自動でチェックするようにすれば)、検出、対処が可能な欠陥を増やすことができる。
- コードレビューを通過している
- 静的コード解析を通過している
- ユニットテストがエラーなしで完了している
- ユニットテストによるステートメントカバレッジが70%以上である
- システムテストと結合テストが完了している
- 自動化した非機能テストがエラーなしで完了している
- ビルドした時にエラーや警告が出ていない
- パブリックAPIが全て文書化されている
DevSecOps
これはセキュリティに関しても同じことが言える?
DevSecOpsでよく聞く「シフトレフト」(セキュリティを左に)もセキュリティに関する保証を開発プロセスの中に組み込むことで、欠陥の検出をできるだけ早くするという点では同じこと?
品質面のメトリクスの測定
- 何を測定すればいい?
- テストの割合
- コードカバレッジ
- テストケース数
- テストの失敗数?
- ソフトウェアの複雑差
- ソフトウェア複雑度
- テストの割合
参考資料
テスト戦略
以下はテスティングピラミッドというもので、それぞれのテストについて上に行くほどコストが高く、下に行くほどサイズが小さいことを示しており、自動テストの割合をこれぐらいにすると効率的なテストが行えるというプラクティスを示している。
もちろん、すべてのプロジェクト、すべてのシステムで同じ割合が最適なわけではなく、プロジェクトによっては全く逆の割合が効率的ということもありうるが、どういった種類のテストをどのぐらい実施するかという戦略を考える上で参考となる。
また、同様の概念にGoogleが利用しているテストサイズがあり、以下の表の通り実行時間や外部依存性の利用に応じてテストサイズをSmall, Medium, Largeに分類している。
Feature | Small | Medium | Large |
---|---|---|---|
ネットワークアクセス | No | localhost only | Yes |
データベース | No | Yes | Yes |
ファイルシステムアクセス | No | Yes | Yes |
外部システムの利用 | No | Discouraged | Yes |
マルチスレッド | No | Yes | Yes |
Sleep statements | No | Yes | Yes |
System properties | No | Yes | Yes |
Time limit (seconds) | 60 | 300 | 900+ |
Googleのテストサイズはテストの種類だけでなく、開発フローの中でどのタイミングでどのテストを実行するかという戦略を考える上で参考となる。
例えば、実行に時間のかからないSmallテストはプッシュの度に実行して開発者ができるだけ素早くフィードバックを得られるようにし、比較的実行に時間のかかるMediumはマージされるときに実行など、実行時間に応じて開発フローの中に効率的にテストを組み込むことができる。
テスト自動化の設計
- 小さく、並列で動かせるようにしておく
- 特にユニットテスト(Small Test)は短い時間で動かせることが重要になるので、将来的にテストケース数が増えた時に備えて並列実行できるようにしておく必要性がある(テストごとの独立性が求められる)
-
プロジェクトへの適用
前述のテスティングピラミッドやテストサイズの考えを参考にプロジェクトの性質や言語ごとにどのようなテスト戦略を立てる。
また、テスティングピラミッドには含まれていなかったが、マニュアル(人手)でのテストが必要な部分ももちろんあるので、開発フローや継続的インテグレーションの検討と合わせてどのタイミングでどういったテストを実施すれば効率的かを考慮して決定する。
自動テストの意味
- 事例で学ぶテストピラミッドを使ったテスト戦略
- 結合テストと呼ぶのをやめた話
- CIとTest Sizesの話
- 組織にテストを書く文化を根付かせる戦略と戦術
- Googleが提唱するTestSizeとJava,MavenによるTestSizeの実現方法について
- テストから見えてくる グーグルのソフトウェア開発 を読んだ
QAプロセスの効率性を挙げ、人為的なミスを減らせる
問題は、これらのテストが反復的な作業であるということです。先ほどの簡単な例でも「対象の項目をクリックして」、結果を「確認する」プロセスが何度も繰り返されていますね。このような反復作業を毎回手動で行うと、アプリケーションが複雑になるほど、テストに対するコストが増大します。テストコストが増加することでテストが疎かになり、最終的にはアプリケーションの品質低下につながることがあります。またコードを変更する度に、関連機能をテストする必要があるため、その負担からコードの改善を妨げ、コードの品質を低下させることもあります。
このように、繰り返し実行されるテスト作業をコードで作成して自動化すると、テストに対するコストが減り、テスト漏れや誤った検証などのミスを防止することができます。また、コード修正の不安がなくなり、積極的にリファクタリングができるようになります。これはすなわち、コードの品質向上につながります。
フロントエンド
開発フローの作成
基本的な方針
- まだ見つかっていない欠陥ができるだけ少ない状態を保つ
- 開発の生産性は担保できるようにする
後者についてはいくら品質面が担保できていていも、例えば毎回コミットやPushの度に30分以上時間がかかってしまっては生産性が大きく損なわれてしまう。
そのため、実際に開発のワークフロー(CIの構築を含む)を作るときには単に品質面だけでなく、生産性とのバランスを考える必要がある。
ここで重要になってくるのがテスティングピラミッドの考え方で、基本的にサイズが大きくなるほどテストの実行に時間がかかる。時間がかかるテストを毎回実行していては生産性が損なわれるため、後回しにするなどの考慮が必要になる。
上記から考えると、開発フローの構築にあたっては
- プロジェクトや技術的な特質を加味した上で適切なチェックを適切なタイミングで実施し、適切なフィードバックを返す
ことが必要になると考える。
適切なチェックとは
適切なタイミングとは
適切なフィードバックとは
コードレビューまでに実施(Push時 or ローカルコミット前など)
- 静的解析
- 自動テスト(単体、結合)
- コード品質
- セキュアコーディング
マージ後(コードレビュー後)に実施
基本的にテストの対象はデプロイ後のリソース。
ステージング環境等にデプロイ後、システム全体の挙動に問題がないか確認する。
目的としては以下2点。
- 欠陥が挿入されてから検知するまでの間を短くするため
- より実際の環境(本番環境)に近い状態での検証を行うため
実例
実際に使用できる機能
フロントエンド(JavaScript(React))
テストの種類
SAST: Static Application Security Testing(静的セキュリティ検査)
ソースコード自体を解析・検査して脆弱性を見つけ出すもの
動くコードになる前の段階から使用できる
DAST: Dynamic Application Security Testing(動的セキュリティ検査)
動いているアプリケーションに対して様々な入力を与え、その結果をもとに脆弱性の有無を判断する
ブラックボックステストなので網羅性には欠ける
IAST: Interactive Application Security Testing
SASTとDASTの双方のメリットを兼ね合わせた手法
まずDASTで検査を行い、疑わしい部分をSASTで解析する
バックエンド(Python)
- flake8
- black
-
radon
- Cyclomatic Complexityなどのコードの品質に関するメトリクスを測定する
チェックの実施タイミング
テストの実行タイミングと同様に、適切なタイミングでチェックを実行することで開発の速度を向上させられる。
基本的な考え方としては可能な限り早期なタイミングで開発者にフィードバックを返せるようにすることで、速度を向上させられる。
例えば以下のような手順で開発が行われるとする。
- コードを書く
- 保存する
- ビルドする
- ローカルで実行する
- デプロイする
- デプロイ先で実行する
Pythonのような動的型付けの言語だとビルドがないが、静的解析ツールによるチェックがビルドに相当するとすれば、mypyやflake8によるチェックを自動で実行するフローを作れば、実行時(Runtime)にエラーが見つかるよりも早期に問題が発見でき、開発速度を向上させられる。
参考資料
リポジトリ管理
モノレポとマルチレポ
開発フロー
参考資料
モノレポについての誤解 - Misconceptions about Monorepos: Monorepo != Monolith を翻訳しました
Monolith→MultiRepo→MonoRepoでの
リポジトリ戦略
複数サービスのWebフロントエンドを運用する際のリポジトリ構成〜monorepoからmanyrepoへ〜
Organizing Serverless Projects
[GitLab CI] Monorepo(単一レポジトリ)で複数デプロイ可能なディレクトリがある場合の構成案
Configure Gitlab CI/CD for Monorepo
参考資料
計測
- チームの生産性を上げたい、ソフトウェアの品質を上げたい、顧客満足度を上げたいといった改善を行おうとするとき、まずは計測対象の値と測定方法を考え、何かしらのアクションを取り、効果を検証するのが基本的な流れ(測定できないと改善したか把握できない)
- ただし、データ分析等の文脈でもよく語られることだが、クオリテイティブ(定性的、Quantitative/定量的の逆)な側面も無視するべきではない
計測対象
- 作業の量
- ストーリーポイントを使って計測
- チームのパフォーマンスとしてベロシティを計測
- チームによっては進行中のプロジェクトに対して作業が追加されるペースを表すスコープベロシティも計測する
- 作業の品質
- 手戻り率を計測する
- 手戻りに投入する作業と新しい開発に投入する作業の割合を示す
- ストーリーを新しい作業か手戻り作業に分類することで、全体のストーリーポイントの総量から手戻りのストーリーポイントの総量で計算できる
- 手戻り作業にストーリーポイント割り当てないという方法を取ることもできる
- 手戻り率を計測する
参考資料
アジャイルにおける見積もり
要求の作成
アジャイルとシーケンシャルでの違い
アジャイルプロジェクトでは、プロジェクトの最初に各要求の本質的な部分だけを定義することが目標となる。細かな推敲作業のほとんどはジャストインタイムで行うために残され、場合によってはすべての作業がジャストインタイムで行うために残される。アジャイルプロジェクトでは要求をそれほど推敲しない、ということではなく、要求をあとで推敲する。
ストーリー
次のようなストーリー形式で表現する。
ストーリー自体はそのまま開発に入れるほど詳細なものではなく、対話を促進するためのもの。
プロダクトバックログ
ストーリーで表現したアジャイル要求を溜めておくためのコンテナとしてプロダクトバックログに置いておく。
ほとんどのチームは、現在のスプリント以外に、リファインメント済みのバックログアイテムがだいたいスプリント2つ分あれば、ワークフローのプランニングや技術的な実装をサポートするのに十分な情報を提供できると考える。チームのほとんどの作業がCynefinの複雑系で行われる場合は、プランニングの見通し期間が短いほうが現実的かもしれない。
上記に記載の通りプロダクトバックログには開発に入れるように要求事項の詳細化が実施されたものが一定数以上存在するようにすると効率よく開発を行うことができる。
要求の追加
- トップダウン
- ボトムアップ
ストーリーポイント
作業アイテムの大きさをストーリーポイントで計測する。
作業の見積もり、プランニング、トラッキングにストーリーポイントを用いる。
多くのチームではストーリーポイントの尺度として1〜13のフィボナッチ数列(1, 2, 3, 5, 8, 13)を用いる。
フィボナッチ数列を用いるのは細かなポイントの違いに時間を使わないように(5か6かのどちらであるかなど)
ストーリーポイントの尺度
それぞれのチームがそのチームで用いる大きさの尺度を定義する。
トラッキング
ストーリーポイントを使って見積もりを行った後は実際にその作業が完了するペースを割り出す。
アジャイルチームではイテレーションごとのストーリーポイントの数がチームのベロシティ(一つのイテレーションごとでチームがこなせるストーリーポイントの数)になる。
ベロシティはイテレーションごとに変化するため通常は意味を持たない。
重要なのは平均ベロシティの推移傾向。
ベロシティが安定してきたらチームはプロセスの試験的な変更を行なってベロシティにどのような影響を与えるか計測できる。
絶対時間と相対時間
ユーザーストーリーの分割
バーティカルスライス
参考資料
- More Effective Agile
- ストーリーポイントで見積もる現実的な方法 - Qiita
ユーザーストーリーの分割
- ストーリーが大きすぎて1つのイテレーションに収まらない場合
- 次のイテレーションでは他のストーリーが入っていて、ストーリーをそのままでは入れられない場合(分割すればはいる場合)
データ境界に沿って分割する
大きなストーリーはデータ境界に沿って小さなストーリーに分割すること
具体例
財務情報を収集するプロダクトの開発では以下のストーリーが1つだけ存在した。
- ユーザとしてバランスシートの情報を入力できる
実際には一言でバランスシートといっても入力可能な値は極めて多彩であり、2週間のイテレーションで開発するのは難しそうだった。
そこで、チームはユーザが入力するデータの種類に対応させてストーリーを分割した
最終的に以下のような10数個のユーザーストーリーに分割され、いずれも2週間というイテレーションの期間内にフィットする形になった。
- ユーザとしてバランスシートのデータをサマリで入力できる
- ユーザとしてバランスシートにカテゴリごとの入力ができる
- ユーザとして入力を間違えないように入力値のバリデーションがほしい
- ユーザとして貸付金の詳細を入力できる
- ユーザとして不動産の詳細を入力できる。
- ユーザとして現金の詳細を入力できる。現金には預金や小切手が含まれる
操作の境界で分割する
- 大きなストーリーはストーリーで行う操作にそって分割すること
- 大きなストーリーはCRUD操作に沿って分割すること
具体例
きわめて複雑な検索画面を開発している企業での話。
最初は検索画面全体で一つのストーリーになっていたが、以下の3つに分類した
- 第一イテレーション
- 最初のイテレーションでは検索結果が312件ありますと簡単に表示するだけにした
- 第二イテレーション
- データ表示用のグリッドを追加
- 第三イテレーション
- 残りの検索条件を入力する項目を追加
第一イテレーションの結果はあまり有益なものに見えないかもしれないが、プロジェクトステークホルダー全体にプロジェクトが進んでいることを確かめてもらい、フィードバックを得ることができる。
CRUD操作に沿って分割する例
チームはコーチとして、チームの選手を管理できるというストーリーに取り組んでいる
CRUD操作に応じて以下の3つのストーリーに分割する
- コーチとして、新しい選手をチームに追加できる
- コーチとして、チームの選手の情報を編集できる
- コーチとしてチームから抜けた選手を削除できる
要件の管理
ユーザーストーリー
通常アジャイルでの要求事項はユーザーストーリーの形式で表される。
ストーリー形式で表す目的はビジネスサイドとエンジニアサイドでの対話を促進するため。
プロダクトバックログ
アジャイルにおける要求はプロダクトバックログに配置する。
ただ、バックログに配置するのは要求だけでなく機能拡張、フィックスなどプロジェクトのスコープの残りの部分を定義するために必要な作業が全て含まれる。
つまり、新たな要求事項だけでなく、リファクタリング、障害対応やスパイク(技術的な調査)などもバックログとして管理する必要がある。
イテレーション
チームが一定期間で実施するタスクを管理するためのもの。
- チームとしてのアウトプットの量を測定し、生産性の向上や今後のリリース計画の見通しなどに役立てるため
- チームの一定期間内の予定を管理するため
プロダクト開発のフロー
- 獲得
- 分析
- 仕様
- 検証
獲得
要求事項や障害対応など、チームとして対応が必要になる事項をプロダクトバックログに入れる。
- ユーザ起点
- 追加機能の要望
- ユーザへの聞き取り
- 問い合わせ(障害等)
- 自社起点
- チーム内のアイデアから
- リファクタリング
- 既存バグの発見
分析、仕様
プロダクトバックログの内容を詳細化し、実際に対応に取り掛かれる状態にする。
このフェーズが終わればイテレーションの中で対応をすることができる。
プロダクトバックログの運用
- チームのスケジュールに影響を及ぼす対応であればプロダクトバックログに追加する
- 個別のバックログでリリースの状況などを管理する
- イテレーション単位でのリリースが難しいことを踏まえて、チームのアウトプットはバックログでは計測しない