こんにちは、Sansanプロダクト開発部 プロダクトグループの清水です。 直近で非機能要件の定義について頭を悩ませられる事もあったので、改めて非機能要件の定義について記事にしてみました。
非機能要件とは?
ビジネス目的を果たす事に成功するソフトウェアには、どのように振舞うかという機能以外にも重要な要素があります。 いわゆる非機能要件とよばれるものです。非機能要件が満たされない場合、機能的には十分だったとしても結果としてソフトウェアがビジネス目的に対して良い成果をもたらせない事になるケースがあります。
例えば、機能要件としてユーザ一覧を表示させる画面を持つWebシステムがあったとします。たとえユーザ一覧を表示できたとしてもレスポンスが極端に遅かったり、何回か表示させるとエラーが返ってくるなど期待する品質が満たせてなかったりすると、ユーザにとってはWebシステムを利用する事に非常にストレスがかかり、結局利用されなくなってしまうなどの事態を引き起こしてしまいます。このような事態を避けるためにソフトウェアの振る舞い以外に期待されるソフトウェアの品質属性 (Quality Attributes) *1を決定する事が非機能要件の殆どを占めます。非機能要件は設計やアーキテクチャに大きな影響を与える可能性が高いので、プロジェクトの後半で追加する事になると大きなコストを払う事になります。
品質属性 (Quality Attributes)
非機能要件として扱われる品質属性には大きく分けて外部品質と内部品質に分けられます。外部品質は実際にソフトウェア実行時に関連する品質であり、ユーザにとって重要なものとなります。一方の内部品質はそれ以外のものとなり、開発者や運用者などにとって重要なものとなります。具体的にどういった品質属性があるかは分類の仕方にもよりますが、代表的なものを以下の表に例示します。 *2
分類 | 品質属性 | 概要 |
---|---|---|
外部 | 可用性(Availability) | システムが完全に稼働するように計画された稼働時間の指標。システムの稼働時間と稼働停止時間の合計に対する稼働時間の割合で測る事ができる。定期保守などの周期性などにも影響を受ける。 |
外部 | 完全性(Integirty) | 情報の損失防止やシステム内のデータの正確さを保証する指標。予定外のファイルの損失や複数データを上書きをする場合の整合性など。 |
外部 | 相互作用性(Interoperability) | システムが容易に外部のシステムとデータを交換できるかを示す指標。インポートやアウトプットするデータの形式などもここで定義する。 |
外部 | 性能(Performance) | ユーザがどの程度の応答性で望んだ結果を得られるかを示す指標。他にもスループットやデータを保持できる容量、同時実行可能数や、機能低下時の振る舞いなどもこの指標に含まれる。 |
外部 | 信頼性(Reliability) | 特定の期間、障害なしでソフトウェアを実行できる確率を示す指標。可用性との違いは可用性がシステムが利用できる時間の割合に対して、こちらは障害の発生しにくさを示す。 |
外部 | 堅牢性(Robustness) | 無効な入力や、接続したソフトウェアやハードウェアの欠陥、外部からの攻撃や予定外の稼働状況に直面してもシステムが正常に稼働できるかなどを示す指標。 |
外部 | 安全性(Safety) | システムが人に対する危害や資産に対する損傷を与えるのを防ぐ。ソフトウェアがハードウェアを制御する場合に定義する事が多い。 |
外部 | セキュリティ(Security) | システムの機能またはデータに対して権限の無いアクセスなど悪意ある攻撃から保護する。 |
外部 | ユーザビリティ(Usability) | 使いやすさについて扱う。システムの入力から操作、出力を解釈するまでの作業工数などが指標となる。 |
内部 | 効率性(Efficiency) | システムがCPUやディスク容量、メモリー、ネットワークを上手く活用できてるかを示す指標。システムリソースを過剰に消費すると性能低下に結びつく。 |
内部 | 修正可能性(Modifiability) | ソフトウェア設計とコードの修正がどのくらい簡単にできるかを示す。指標として機能追加や問題の修正に必要な平均時間、正しく行われた修正の割合などがある。 |
内部 | 移植性(Portability) | ある稼働環境から別の稼働環境へソフトウェアを移行する為に必要な作業工数など。国際化やローカライズする能力を含めるケースもある。 |
内部 | 再利用性(Reusability) | ソフトウェアコンポーネントを他のアプリケーションで利用できるように変換する容易さを示す。指標としては相対的な作業工数を使う。 |
内部 | 拡張性(Scalability) | アプリケーションが成長しても性能や正確性に影響を及ぼすことなく、多くのユーザやデータなどに対応できるかを示す。 |
内部 | 検証可能性(Verifiability) | テスト可能性(Testability)とも呼ばれる。コンポーネントや結合されたシステムに対して期待された通りになっているかどうかを示す。 |
このように品質属性は様々な分類がありますが、実際にプロジェクトで注意深く検討する必要があるものは、殆どの場合一部のみとなります。 例えばBtoCで外部に多く公開されるようなシステムではユーザビリティが利用者数に響きビジネスとして利益に直結する事が多く重視される一方で、特定の少人数が利用する社内向け業務システムなら最低限は必要ですが、そこまで高いユーザビリティは求められません。なのでこれらの品質属性からプロジェクトにとって重要なものを決定し、非機能要件として明示する事がプロジェクトを成功させる鍵となります。
非機能要件定義のステップ
当然品質は良いに越したことは無いのですが、一般的に性能とセキュリティは相反する事が多かったりなど各品質属性のトレードオフがあります。また現実的に全てを満たす事はコストなどの制限によって不可能となります。そのためプロジェクトを開始する上でどれを優先するかを決める必要があります。
まずは検討対象となる品質属性をリストアップしていきます。上記に示したような一覧もありますが、IPA(情報処理推進機構)が用意している非機能要求グレードなども参考になります。非機能要求グレードでは大項目6つ、中項目35に分類してます。
リストアップした中からプロジェクトにとって重要な品質属性をピックアップしていきます。その際外した品質属性について何故外したのかも明記しておくと後で混乱を生みずらくなります。またこの時、開発者や保守担当社などの内部品質に関するステークホルダーも評価に入って貰う事が望ましいです。外部品質を重視するステークホルダーと違う点を重視する事が多いためです。
ピックアップした各品質属性の優先度をつけます。優先度を決める事で後のステップの要求を引き出す際の時間を、どの程度その品質属性に対してかけれるのかが明示されますし、また品質属性がトレードオフになった場合にどちらを優先すべきなのかも明示されます。これを早いうちから決めておくことで後からトレードオフが発覚しても対処が楽になります。
優先度の決まった各品質属性に対して具体的に期待する事は何なのかをステークホルダーから引き出します。その際ほとんどのケースで「期待する可用性は何か?」と聞いても答えは返ってこないかと思われます。なのでこちらで期待を引き出す質問を用意し、ステークホルダーには「画面を表示するのにどの程度の時間なら受け入れられるのか」や、「利用するユーザ数想定はどのくらいか」、「時間あたりに期待される処理量はどの程度か」などと言った質問を投げる事で具体的に何が期待されるのかを決めるために必要な情報を得ます。この時逆に受け入れられない基準は何なのかをステークホルダーに確認するのも有効な手段となります。たとえば「データを10万件処理するのに1週間かかる」「権限の無いユーザがファイルを削除できる」などです。これがなされてしまうとどう問題になるのかを確認する事で、どの程度なら許容できるのかを確認する事ができます。
前段で引き出した情報から具体的な品質要件を定義します。品質要件を書く際には目標設定法であるSMARTの則したものが適しています。つまり具体的(Specific)で測定可能(Mesurable)で達成可能(Attainable)で関連性(Relevant)があり、時間を意識する(Time-sensitive)なものです。各ステークホルダーにとって理解可能なように具体的でなければならないですし、測定可能でなければ満たしているかのテストができません。また現実的に実現可能でなければ絵にかいた餅になってしまいますし、プロジェクト目的にとって関連性が薄いようならその要件に投資する価値は無いでしょう。
筆者の直近の案件における適用
筆者は直近でインフラエンジニアの運用工数削減のため、APIサーバーをサーバレスに置き換えるプロジェクトを担当する事になりました。 そのAPIは以下の特性を備えておりました。
- サービスの成長にアクセス数が比例する
- 平日業務時間にアクセスのほとんどが集中する
- 変更回数は少なく年に数回程度しか行われない
- 社内向けで外部に公開されたものではない
- 他部署からリクエストが送信される
そのプロジェクトを実施する際にピックアップした品質属性と定めた非機能要件は以下になります。
品質属性 | ピックアップ理由 | 非機能要件 |
---|---|---|
相互運用性 | 目的が既存APIを置き換えるものであり極力変更はするべきではない。 | 既存APIの受け付けるリクエストと返すレスポンスと同様な事 |
性能 | 目的が既存APIを置き換えるものであり同程度は担保されるべき。 | 既存APIの一日あたりに捌いてるリクエスト数Xを一日で捌ける事 |
拡張性 | サービスの成長に比例してリクエスト数が増加する性質があるAPIなので担保すべき。 | 5年後想定されるリクエスト数Yを捌ける事 |
セキュリティ | 既存APIで担保されていたセキュリティは担保されるべき。 | 既存APIと同様の認証方式が利用できる事。また既存同様にIpアドレス制限がかけられる事 |
相互運用性は既存APIからの置き換えであり、内部とはいえ他部署からのリクエストを受け付けていた事から極力調整不要なように同じものを受付け返す事に、またロールバックを容易にできる事も、この要件により担保する事ができました。性能に関しては既存APIのログなどから現在一日で捌いてるリクエスト数を割り出し、それと同様の数が捌き続けれる事を定めました。リクエスト数がサービスの成長に比例する事から、その性能がある程度の将来に渡って担保できるのかも定義し、成長傾向から割り出したリクエスト数を捌ける事を要件としました。ここが定義されないと拡張性が担保できないシステムになる可能性が発生し、すぐにリプレース検討をする破目に陥ってしまうでしょう。内部利用のみとはいえセキュリティも以前と同程度担保される要件が無いと、想定外のリスクを被る事になるかもしれません。
このプロジェクトは目的に対して現在の組織で扱ってる技術要素などからある程度利用できるアーキテクチャは既定されていたのですが、そのアーキテクチャが上記の要件を満たす事ができなければそもそもプロジェクトを中止するという話もありました。しかし事前に要件が定まった事で、利用予定のアーキテクチャの制限や担保事項が、その要件に対して満たしている事が確認でき、プロジェクトを開始し無事に完遂する事ができました。
まとめ
システムを作る際に要求として明らかになりやすい機能要件に比べて暗黙的になりやすく定義しづらい非機能要件ですが、明示的に定義する事でそのシステムが本当に目的を達成できるものになる可能性が高まります。またアーキテクチャ設計のような後から大きく変更しづらいものに大きく関わってくるため、例えアジャイルのような小さなイテレーションで要件を実装していくスタイルの開発だったとしても、後のイテレーションで追加する事は難しくプロジェクトの初期に定義しておく必要があります。特にシステムライフサイクルの長いシステムの場合はここを怠ると、後になって問題を起こし高いコストを払う事になります。近年はWebサービスのような事業が続く限り運用されるような長いシステムライフサイクルのものをアジャイルで開発している事が多いと思いますが、非機能要件の重要性は以前にも増してるかと思います。なのでプロジェクトを始める際は一度、非機能要件について検討をしてみる事をおすすめします。
参考
buildersbox.corp-sansan.com
buildersbox.corp-sansan.com
buildersbox.corp-sansan.com
*1:品質特性と呼ばれる事もある
*2:出典:ソフトウェア要求 第3版