非機能要件と向き合おう！：第1章「非機能要件の難しさ」


# はじめに

https://qiita.com/wolfmagnate/items/d9a2570d239edd2a8daa

今回は、我々が向き合おうとする非機能要件とは具体的にどのような問題で、どうして難しいのかについて明確な理解を得ることを目指します。

**いいね、ストックをよろしくお願いします！**

# 非機能要件の定義
非機能要件とは、機能要件ではない要件、という定義です。
機能要件以外の全てを示している、広い言葉です。開発の現場で使われる代表的な非機能要件を簡単にリストアップしてみました。
- パフォーマンス
- UX
- 信頼性
- セキュリティ
- 価値（ソフトウェアがユーザーの課題を解決しているか？）
- 保守性

# 品質測定の困難さ
これらの特徴は共通して**達成してるかが測定しにくい**という問題を抱えています。
ざっと次のような質問が考えられます。

<details open><summary>非機能要件の品質測定の質問例</summary>

- ユーザーにとって必要なパフォーマンスはどのぐらいですか？
- ユーザーが十分に使いやすい画面とはどのようなものですか？
- ユーザーはどの機能でどの程度の障害を許容してくれるでしょうか？
- セキュリティが完全であることはどのようにして判断できますか？
- ユーザーが「本当に必要だったもの」とプロダクトの距離はどのぐらいですか？
- あなたは普段、どのぐらい読み書きしやすいソフトウェアを開発していますか？
</details>


これらは、各種要件を満たす上で本質的な問いです。それにもかかわらず、答えるのが難しいです。
例えばユーザビリティは、長い間使ってみて「なんとなく使いやすい」と感じるだけです。

:::note alert
**非機能要件の品質測定の困難**
- 測定に時間がかかる
- 測定内容の数値化・言語化ができない
:::

# 目標設定の困難さ

品質測定が困難であるため、通常は**品質に相関する測定可能・言語化可能な目標**を立てて対応します。例えば、次のように対処します。

<details open><summary>品質に相関する目標例</summary>

- ユーザが満足するパフォーマンスとして、ユーザー登録処理にかかる時間を500ms以内とする
- ユーザーにとって使いやすいシステムとして、基礎的なユースケースシナリオを3画面以内に完了できるようにする
- ユーザーが許容する障害として、98%の可用性とする
- セキュリティ度合いを判断するため、毎年脆弱性診断を実施する
- ユーザーの価値に繋げるため、ユーザー課題をリストアップ・言語化する
- 保守性の高いソフトウェアにするため、関数を読みやすくする
</details>

しかし、非機能要件では、このような目標はあくまで品質に相関するだけで、目標を達成したところで品質が確実に改善するとは限りません。
また、これらの目標は人間がなんとなく関連しそうだと考えて作っただけで、品質から必然的に導き出されたものではありません。

:::note alert
**非機能要件の目標設定の困難**
- 目標と品質はあくまで相関するだけ
- 目標と品質の相関はあくまで単なる予想
:::

# 目標達成手段の設定の困難さ

非機能要件の困難はこれだけではありません。開発者は、**目標を達成するため、具体的なアクションをとります**。例えば、次のようなものです。

<details open><summary>目標達成のための手段の例</summary>

- DBキャッシュを導入してユーザー取得を高速化する
- ボタンのサイズを大きくして目立たせる
- アラートを設定して障害に気づきやすくする
- 内部ネットワークの通信でもTLSを利用する
- ユーザー課題に基づき、機能を考案する
- 読みやすさを意識した関数の命名を行う
</details>

このような手段は、目標達成のために作られたものです。しかしながら、非機能要件は複雑です。測定される数値・状況は、ソフトウェアに関連するあらゆる要素が複雑に絡み合った結果です。したがって、手段がどの程度目標に寄与したのかはわかりにくいです。さらに、手段が目標達成に役立つかどうかは確実にはわかりません。

:::note alert
**非機能要件の目標達成の手段設定の困難**
- 手段を実施しても目標が達成できるとは限らない
- 適切な手段は目標からはわかりにくい
:::

# 非機能要件の困難さの全体像
ここまでで説明してきた内容を図にまとめましょう。

![1-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1412657/a800b47c-7ea9-4138-b230-8a98730b5bae.jpeg)

この図からも分かる通り、非機能要件が抱えている本質的な困難は、次のようにまとめられます。

:::note alert
**非機能要件の困難の本質**
- 直接的に品質に関連するほど、測定・言語化が困難
- 直接的な数値・行動に繋がるほど、品質との関連性があいまい
- 品質・目標・手段の関連性が弱い
:::

# 派生的な困難
このような本質的な困難から、その他の困難も発生してしまいます。

まず、その複雑性から、**品質が外部環境に影響されやすく、不安定**ということです。大抵、放置していると勝手に劣化します。

<details open><summary>外部環境の影響を受ける例</summary>

- ユーザー数の増加に伴い、SQLのクエリの性能が悪化する
- 機能が追加されていくごとにメニューのボタンが増え、分かりにくくなる
- 同一ネットワーク上で動作するシステムが増えると、それに起因する障害が増える
- 新規サービスの提供は攻撃者に新しいアタックサーフェイスを提供することになる
- 競合プロダクトが便利な機能を提供し、ユーザーが一部の機能を使わなくなり、ユーザー課題が変化する
- コードが勝手に予想外の場所から再利用され、変更可能性が下がる

</details>

:::note alert
**非機能要件はプロダクトの外部の環境の変化により、勝手に品質が変化・悪化する**
:::

非機能要件は測定の困難さから、**コミュニケーション上の断絶を生みやすい**です。

- 直接的に関わりのない人間からは意味のない工数に見える
- 直接取り組んでいる人間からすると、価値が理解されない。さらに、他人の行動は無自覚に品質の自然劣化を招く

この現象も、各種非機能領域の分野で発生しています。

<details open><summary>非機能要件に起因するコミュニケーションの断絶の例</summary>

- パフォーマンスは見えづらいため、よく知らないビジネスアナリストが分析のために作ったクエリがシステムに負荷をかけてしまうインシデントが発生し、その後は開発チームの承認が必要になる。アナリストは承認の意味を知らないので無駄な待ち時間に見える
- UXは主観的なために、デザイナーが提案した繊細なアニメーションやレイアウトの微調整を、エンジニアが技術的な制約や実装優先度の違いから十分に反映せずに勝手に実装し、デザイナーが不満を持つ
- 信頼性は見えづらいため、開発チームからすると、運用上の面倒なチェック項目は無駄に見える。しかし、運用チームからすると、開発チームは自分たちが好き勝手に開発して、その結果発生する保守問題を押し付けてくるように見える
- セキュリティは見えづらいため、従業員が個人で勝手にITシステムを使いシャドーIT問題が発生し、面倒な研修や禁止事項が増え、従業員の不満が溜まる
- ユーザーの価値は分かりにくいため、開発チームがユーザーの声を聞くことなく、想像で機能を追加し、ユーザーから使いにくいシステムになる
- 保守性は測定しにくいため、チーム外の人間にリファクタリングの工数をとる理由を説明しにくく、結果として読みづらいコードが放置されやすい

</details>

:::note alert
**非機能要件は効果が説明しにくいため、機能要件に比べて置き去りにされ、対立を生みやすい**
:::

# コラム: 機能要件との違い
機能要件では、要件を分解することが可能です。例えば、ユーザー登録機能を作りたいなら、DBスキーマを作って、APIエンドポイントを作って、ユーザー認証機能を作って…という複数のサブ機能を作り、それらを統合すれば確実に機能を完成させることができます。

:::note
**機能要件の特性**
- 「できる」or「できない」なので品質を満たすかの判断が容易
- 要件を確実に分解でき、分解した要素を全部完成させると、全体も完成する
:::

## 用語の整理
- **品質**: 本当に達成したいもの。概念的で直接言語化・測定することは困難な特性
    - **品質が高い**: 非機能要件をよく満たしていること
- **目標**: 品質を高めるために設定される、**測定可能**な指標。測定方法+達成の判断基準の組み合わせ
    - **目標を達成する**: 設定した指標よりも良い値を得ること
- **手段**: 目標達成のための具体的な施策。**測定可能かつ実施可能**な行動

もちろん、この用語は大まかに区切ったものです。中間的な指標・特性も考えられます。

- 「保守性という品質を達成するために、関数の読みやすさを実現する」では、多少具体的になったが、それでもなお測定が難しく、品質と目標の中間地点と言える
- 「関数を読みやすくするため、サイクロマティック複雑度の平均を5以下に維持する」は、少なくとも測定は可能なので目標ですが、具体的な行動としてはコードベース全体を見て適切な場所を補修する必要があるため、具体的な手段としてはさらに考える必要があり、目標と手段の中間地点と言える

# 非機能要件と向き合う手法
この記事で提案した非機能要件の困難性モデルをもとに考えれば、非機能要件の改善テクニックをより抽象的な観点から理解することができます。

## 本質的な困難と向き合う

次の図を見れば分かるようにう、非機能要件の本質的な困難を倒す方法は、次の**二種類**しかありません。

![1-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1412657/8b2fa702-1afa-4752-a1f6-1abfae173d2a.jpeg)

:::note
**非機能要件の本質的な困難への対策**
- **目標を品質に近づける**: 達成することで本当に欲しい品質が改善するような目標を立てる
- **手段を目標に近づける**: 実施することで本当に目標達成に近づくような手段を作成する
:::

実は、様々な非機能要件に関するベストプラクティスの多くは、この二種類のどちらかと言えます。いくつかの具体例を挙げておきましょう。

- パフォーマンスにおける「推測するな・計測せよ」は最適化の前に、その最適化が本当に効果のあるボトルネックなのかを調べるということであり、手段を目標に近づける手法である
- アジャイル開発における「ふりかえり」は一定期間に行ったプロダクト開発・チームの改善が効果的だったかを判断するということであり、目標を品質に近づける・手段を目標に近づける、の両方を含む手法である

## 派生的な困難と向き合う

外部環境からの影響を排除することは困難です。なぜなら、チームの知識・権限の範囲外の問題や、他の機能との意図しないトレードオフなどは、事前に予想することも難しく、仮に予想できたとして制御することも難しいからです。

したがって、対策は後手に回らざるを得ません。変化を受け入れて、対応するという枠組みが必要です。具体的には、次の二つのステップを継続的に実施します。

:::note
**外部環境からの影響への対策**
1. **外部環境によって変化した差分を理解する**
2. **自然に劣化した分だけ手段を実施する**
:::

非機能要件の分かりにくさによって、コミュニケーション不足が発生しやすい問題については二種類の解決策を取ることができます。

:::note
**コミュニケーションの断絶への対策**
- **コミュニケーションを改善する**：チーム全体が非機能要件の改善の取り組みを理解する
- **非機能要件の分かりにくさを改善する**：目標を利用してコミュニケーションを取る
:::

これらの対策方針に基づいて、次章以降でより詳細な方法を解説していきます。

# おわりに

ソフトウェア開発において、非機能要件は様々な種類のものが様々な場面で現れます。しかし、本質的には、測定しにくい・行動につなげにくいことが問題になっており、多くの共通点があります。

https://qiita.com/wolfmagnate/items/221dac21240b9c5068ad