アジャイル開発の浸透で、顧客やステークホルダーとの対話に応じて臨機応変な対応が可能になり、大きな手戻りは減ったかもしれません。それでも、なお、ソフトウェア開発の本質的な複雑さや不確実性は、分割されたと言えるものの、誰もが満足できる状態で解決された、とは言えなさそうです。それでもプロセス改善の探求を繰り返していくなかで、私たちは「ロバストネス分析」にたどり着きました。単なる懐古主義ではなく、実際に以下のような問題への解を見出すことができましたので、その事例を紹介します。

ロバストネス分析を導入した経緯

私たちは、VisionalのHRMOS事業部で新規プロダクトを開発しているエンジニアチームで、私、水谷はその一員です。非常に仲の良いチームで、コミュニケーションも十分円滑ですが、それでも新規プロダクトを開発する限り、それに対してのイメージに齟齬が発生してしまうことは避けられませんでした。

それに、アジャイルであることによる開発スピードの速さ、及びそのサイクルの短さから、「以前開発したプロダクト」についてステークホルダーと話すとき、そのディテールについて思い出して説明するために、かなり頭を回転させなければなりませんでした。

これらは改善するべき課題点だとチームは認識していましたが、快刀乱麻を断つ処方箋はなかなか見つからず、大小さまざまな手法を開発プロセスに取り込んでトライアンドエラーを繰り返していました。そこで、ひときわ大きな効果を実感できたのが、ロバストネス分析でした。

ロバストネス分析はICONIXプロセスに含まれる開発手法で、最近はあまりその名前を聞かなくなっていたものでした。しかし、この「ユーザー要求を解釈して、実装すべき要素へと分解する」予備設計の手法(詳細は後述します)は、意外にもアジャイル開発にも適応するどころか、想定外の嬉しい効果ももたらしました。具体的には以下のようなものです。

この記事の前半では、私たちが導入したロバストネス分析とは何か、について具体例を交えながら紹介し、後半では、ロバストネス分析の具体的なメリットと、それをより効果的に扱うための幾つかのTIPSを提示します。

「何をやりたいか」から「何を作りたいか」を抽出するロバストネス分析

ロバストネス分析 (Robustness Analysis) は、スウェーデンのコンピュータ科学者 Ivar Hjalmar Jacobson によって1999年に『Use Case Driven Object Modeling with UML: A Practical Approach』で提唱されました。ユースケース記述が特定できた後、それに分析を加え、ドメインモデルを更新します。誤解を恐れずに言えば、「何をやりたいか」から「何を作るのか」を抽出するプロセスです。この分析においては、ロバストネス図 (Robustness Model) がその産物として特徴的です。ロバストネス図は以下のようなものです。

一般的なロバストネス図の例

各記号の意味を説明します。

アクター

アクター Actor は操作主体を意味します。例えば「管理者」や「ユーザ」「システム」「バッチ」などです。

バウンダリ

バウンダリ Boundary はアクターが相互作用する要素を意味します。例えば「提出ボタン」や「詳細画面(へのアクセス)」などです。

エンティティ

エンティティ Entity はソフトウェアの中で半永久的に管理されるデータ、あるいは中間生成物を意味します。例えば「アンケートの回答情報」や「ユーザとアンケートの回答を結びつけたデータ(クラス)」などです。

コントロール

コントロール Control はバウンダリとエンティティ、あるいはエンティティとエンティティを繋ぐシステムの処理を意味します。例えば「アンケートの回答情報のユーザIDとユーザ情報を結びつける」「回答情報を組織構造に従って集計する」などです。

基本的にロバストネス分析というプロセスは、ロバストネス図を構築していく作業そのものです。この図を作成する過程で、私たちが、あるユースケースを満たすために必要な以下のような要件を明確にします。

この流れを詳細に見ていきましょう。なお、私たちがロバストネス図を作成する際の一例であり、必ずしも原義と一致しないことを書き添えておきます。

ロバストネス図を作成する

1. ユースケースを確定しプロダクトの機能(仕様)を書き下す

プロダクトの機能の例
プロダクトの機能の例

スクラム開発では通常、プロダクトオーナーが責任を持つプロダクトゴールが決定しています。様々な流儀が存在すると思いますが、私たちの場合は、微細な顧客体験が価値につながると考えているため、プロダクトオーナーと共に事前に細かなユースケースを確定させることがあります。そこで、私たちはユースケースから改めて、作成するプロダクトを明確にし、その機能を書き下します。この部分については別のプラクティスが存在しますので他の記事でご紹介する予定です。これによって、基本的な仕様が決定します。

2. インプットとアウトプットを確定する

仕様からインプットとアウトプットの形を決定することができます。例えば、人事管理者がサーベイを選択し、その回答率を閲覧したいという機能なら、以下のようになります。

input
顧客が選択したサーベイIDをブラウザからシステムに送る
output
送られたサーベイIDに対して保存している回答データから回答率を計算してブラウザに送る

上記を決定すれば、最初と最後のクラス定義を考えることができるので、私たちは多くの場合、擬似コードをロバストネス図にエンティティとして付しておきます。以下のようなものになります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
/** 顧客が選択したサーベイID */
class RequestedSurveyParam (
  surveyId: String,
)

/** 回答率データ */
class SurveySubmissionRate (
  surveyId: String,
  targetted: Int,
  submitted: Int,
  submissionRate: Double,
)
インプットとアウトプット

3. アウトプットを構成するための材料をリストアップする

インプットとアウトプットが決定した場合、アウトプットを実現するためにインプットされた情報のほかに集めなければならない情報が確定します。システムで永続化されている情報は、私たちのチームが扱うものの場合、データベースに保存されているものと一致するので、どのテーブルにアクセスしなければならないかが分かりますから、それをロバストネス図に加えます。先程の回答率の場合は以下のようになります。

組織情報を同期する場合は、以下のようになるでしょう。

上記をエンティティとしてロバストネス図に擬似コードと共に記しておきます。データベース接続部分やAPI接続部分に関しては、クラス定義を既に考えられるはずです。以下のようになります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
/** データベースから取得できるサーベイの回答対象者データ */
class SurveyTargetUser (
  surveyId: String,
  userId: String,
)

/** データベースから取得できるサーベイの提出された回答データ */
class SurveySubmisssion (
  surveyId: String,
  userId: String,
  answers: Array<SurveyAnswer>,
)

/** 回答データのうち、一つの質問あたりの回答データ */
class SurveyAnswer(
  questionId: String,
  optionId: String, //ここでは選択肢の種別
)
アウトプットの材料

4. アウトプットを構成するための方法を考える

取得すべき情報が出揃ったならば構成する方法が考えられます。先程の回答率で言えば、情報を取得したあと、あるサーベイの回答データの数を対象者の数で割って、それをブラウザにレスポンスとして返せばよいはずです。外部の企業情報を保存するなら、情報を取得したあと、データを自分が保存したい情報のみに削ぎ落としたり加工したりして、データベースに保存する必要があるでしょう。

ここで初めて具体的なシステムの「処理」が確定します。私たちは普段、この段階でそれらの処理を担当するクラスやメソッド名を与えてコントロールとしてロバストネス図に付しておきます。大抵の場合、データは途中で加工された状態を持ち、その場合は擬似コードを付したうえでエンティティとして書き加えます。以下のようなものです。

1
2
3
4
5
6
/** あるサーベイに対する回答対象者データと提出データの一覧 */
class SurveyTargetUsersAndAnswers (
  surveyId: String,
  targetUsers: Array<String>,
  answers: Array<SurveyAnswer>
)
アウトプットの構成法

5. 補足情報を書き加え、チェックリストで検査し、必要に応じて仕様を更新する

次に補足情報を書き加えます。例えば、暗黙的になされるソートであるとか、APIのURLであるとか、アクセスできる権限や、できない権限など、書くべきことは多くあります。これらは本来のロバストネス分析に現れるものではないかもしれませんが、多くの場合役に立つので、付箋などで忘備録的に付与されます。

補足情報

その後、もう一度、機能の要求要件が満たせるか確認すれば、完成です。以下のようなものになります。

ロバストネス図の全体

ロバストネス分析の3つのメリット

前述の通り、ロバストネス分析を導入した動機は、事前設計として、作るものを明確にしたいというものでしたが、事前には想定していなかったいくつかのメリットが発見されました。幾つか列挙したいと思います。

作業分担が容易になる

作業分担

ロバストネス図という一つの図があることによって、作業の分担が極めて容易になりました。例えば、先述のサーベイの回答率集計機能であれば、

がバックエンド側の作業として考えられますが、この分担をひと目で誰がどこまでするのか把握することができます。また、疑似コードを貼り付けているおかげで、最終的にこの形にして次の人物の担当部分に渡せばいい、前の部分が完成したらこの形になる、というのが予め理解できるので、並行で作業を進めることができるようになりました。

以前までは、データを加工した結果どのような形になるのか、実際に完成するまで分かりづらかったり、あるいは自分が担当している作業はどこからどこまでなのか明確ではないことがあり、手戻りが発生することがありましたが、それがなくなりました。もちろん、これに関しては経験とチームワークで何とかできるものではありましたが、このような共通言語の誕生で齟齬がなくなったのは、チームメンバーが変更した場合でも安心です。

共通理解が容易になる

共通理解

チームメンバーがどのようなものを作ったか、あるいは過去の自分たちがどのようなものを作ったかがひと目で分かるようになりました。コードを見なくてもロバストネス図を見れば、どのテーブルを触って、どのように加工しているのかを知ることができます。

これは作業の並行性を保ちつつも、チームメンバー同士でフォローに回れたり、あるいは巻き取ったりするのに役立ちます。意外なところではレトロスペクティブでの振り返りにも役に立ちます。お互いがお互いの作成したものについて理解が容易なので、「今回のプロダクトの問題点」などの話題でもわざわざ説明する必要がなく、図のこの部分の話では、と切り出すことができます。また、プロダクトオーナーなどに仕様を確認する際、「この部分でこの情報が必要になるが、ないことがあって」と実際のものが完成する前に、機能についてグラフィカルな議論を交わすことができます。

見積もりが容易になる

見積もり

事前に全く想像できなかった点として、ロバストネス図は見積もりに役に立ちます。

簡単そうな機能でも裏側での処理が複雑なため、工数がかかってしまう、というのはよくあることだと思いますが、ロバストネス図はそれをグラフィカルに反映します。複雑な処理であれば、その処理の数だけコントロールが存在し、図そのものが大きくなります。

このことは、実際にコードを触らないステークホルダーにその機能がどれだけ複雑でどれだけ時間がかかりそうか、というのを根拠を示しながら説明するのに役立ちます。また、実際にコードを書いているわけではなくロジックを整理しているものですので、実際のプログラムに明るくない人物でも、この図をある程度詳しく読むことは可能ですし、これは他のチームと連携して機能を作成する際にも役に立ちます。

結果として見積もりは正確になり、ベロシティは安定します。チームメンバーも納得して作業を行うことができます。

ロバストネス分析を更に良くするTIPS

ロバストネス分析を行うにあたり、色々と実験と変更を加えながら私たちはそれを活用してきました。その一例を紹介しようと思います。

一つ前のスプリントで用意しておく

ロバストネス図はスプリントプランニングの前に書かれているのが望ましいです。スプリントプランニングの前に実際に作るものに対して時間を投資することは「するかどうか不確実な仕事」の場合はただ時間がかかるだけですが、大体は「いつかするが順番は決まっていない仕事」のことが多いですし、しなかった場合でもその意思決定に根拠をもたせることができます。

このことから、何らかの新しい機能を開発することが見込まれる場合、私たちはロバストネス図をスプリントの最後に書いています。これは先述の「見積もりが容易になる」ことにも役に立ちますし、スプリントプランニングで作業を分解する際に、大抵はロバストネス図の「この部分」「この部分」と転記をするだけですみます。

修正はロバストネス図から

開発の途中で、新たに考えなければならないことを思いつく、というのはままあります。その際に、ロバストネス図に変更が現れる場合なら、ロバストネス図を修正します。その修正の大きさに応じて、どのラインの関係者まで共有するかは変わってきますが、いずれにせよ具体的な変更を加えるまえにロバストネス図を修正します。

このルールを加えることで、ロバストネス図が常に正しく実装を反映している図として扱うことができます。誰かがある機能がどう実装されているかを知りたくてロバストネス図を見る時、それは常に正しいことが保証されています。昔の機能についてバグを修正したり、あるいは他のチームが変更を加えたい時に、この状況は大きく役に立ちます。

ロバストネス図の追加や編集を気軽にできる状態にしておく

ロバストネス図テンプレート

先程の節の影響とスクラム開発であることが重なり、ロバストネス図は常に変更されるもので、開発の様々な段階でアップデートされる余地があります。よって、私たちはロバストネス図を見れば自分が作るものが何なのかを把握できるように、図で表現できない情報についても、自由に図に貼り付けることにしています。これは使用しているツールがmiroであることも大きく関係していて、特定のフォーマットを持たず、仮想的なホワイトボードとして利用できることが大きいです。

よって、使うことのできる部品は先述のコントロールやバウンダリなどに限らず、エラーであったり、権限であったり、あるいはデザインのスクリーンショットなどが貼り付けられていきます。単純に見た目がにぎやかでモチベーションも向上します。それに、特定の厳密なフォーマットを持たないことは、新メンバーや習熟していない人物がロバストネス図に変更を加えることの心理的なハードルを下げ、結果としてそれは図の正しさを保証することにつながります。

ロバストネス分析、たのしいよ!

記事のまとめ

ロバストネス分析を導入することで、私たちは、実際にコードを書く前に自分たちが作るものを明確にでき、そのおかげで周囲との認識のすり合わせが可能になり、結果として全体の作業が早く、またストレスも少なく済ませることができました。

技術的な内容に自信がない新しいメンバーでも、視覚的なロバストネス図を間にはさむことで、シニアメンバーの思考をトレースできたり、時にはより深い議論へと入っていくことができることも、非常にありがたいです。

細かなトイルが取り除かれることで、プロダクトを考えて作るということに集中できるので、結果として開発が楽しくなる、といっても過言ではないかもしれません。過言かもしれません。

終わりに:私たちのこれから

私たちは、ロバストネス分析、中でもロバストネス図にはさらなるポテンシャルがあると考えています。時間を管理できる機能をもたせたり、あるいはデザインに役立たせることができたり、いろいろな改善策を試しているところです。

これからも様々な手法を忌憚なく取り入れ、必要に応じて外部に共有、あるいは広めていこうと考えています。私たちは本当に良いものを作るためにはどうすればよいのか、常に考え意見を集めています。より詳細を知りたかったり、あるいは「これは間違っている、我慢ならない、もっと良い方法がある」という方は、是非お気軽にご連絡をください!チームメンバー全員でお待ちしております!

水谷 和寿
水谷 和寿

HRMOS 事業部のエンジニア。猫とペンギンとスズメが好きです