リファクタリングすべきか・してよいかの判断基準

 リファクタリングは、設計やコードを綺麗に保つという普遍的に求められる活動の一要素です。常識的な習慣として推進すべき活動です。

 ただ、有効性の理解を得られないままリファクタリングを行って物議を醸す場面も存在します(例えばここのはてなブックマーク等で巻き起こった議論などです)。
 実際、リファクタリングは、以降の保守作業をサポートしてこそ価値がでるものであり、考えなしにいつでも一律実施すればよいというものではありません。リファクタリングの対象やチームの状況によって、リファクタリングをすべきかどうか、線引きがされます。

 このリファクタリングをすべきかどうかの基準ですが、一言でまとめると「妥当な保守性の実現を、妥当な費用対効果で実現できるか」になります。今回はこの基準を構成する「妥当な保守性の実現」と「妥当な費用対効果」について、それぞれ解説します。

リファクタリングで妥当な保守性を実現できるかの基準

 まず「妥当な保守性の実現を、妥当な費用対効果で実現できるか」の前半を構成する、「妥当な保守性を実現できるか」は、リファクタリングが必要となる、有効な保守性要求を満たしているか、というものになります。

 例えば、特定のライブラリの置換が予定されているならば、「そのライブラリ置換を安全に行いたい」という保守性の要求が発生します。その保守性を充足するリファクタリングならば、妥当な保守性を実現できる、と判断できます。
 また、特定のコードの保守作業でミスが頻発しているならば、「ミスを予防する設計構造を実現したい」という保守性の要求が発生します。その要求を満たすリファクタリングも、妥当な保守性を実現する活動です。

 一方で以下に該当するようなリファクタリングは、何かしら有効な保守性要求を充足するものではなく、妥当な保守性を実現していない、と判断されがちです。

  • 十分に枯れていて、今後保守作業が発生する見込みのないコードに対するリファクタリング
  • 独りよがりのこだわりの押し付けで、誰かにとっての保守作業をサポートしないリファクタリング

 このリファクタリングが必要となる、有効な保守性要求についてですが、大きく次の3つに分類できます。

計画上求められる保守性

 計画している保守作業をサポートする保守性の要求です。
 例えば次のような保守性要求が該当します。

  • ソフトウェアアップデートによる機能追加を計画しており、機能追加がしやすいように、設計・コードの変更性を確保したい
  • 自動テストの大規模導入を計画しており、自動テストが導入しやすいようにテスト容易性を確保したい

 このカテゴリの保守性要求に基づくリファクタリングは、開発計画の具体化の中で必要性を識別できます。

リスクマネジメントとして求められる保守性

 プロジェクトリスク・プロダクトリスクの対策として求められる保守性の要求です。

 これは例えば次ような保守性要求が該当します。

  • リソース開放ミスについてリスクが高く、解放忘れを防止する設計を行いたい
  • セキュリティリスクが高い(脆弱性を悪用された時の被害が大きく、かつ脆弱性リスクが高いプロダクトを扱っているなど)ため、脆弱性を埋め込みにくいように設計やコードを改善したい

 このカテゴリの保守性要求に基づくリファクタリングは、リスク分析を通して必要性を識別できます。

日々の開発で求められる保守性

 自分たちが今まさに手掛けている開発作業を支えるための保守性の要求です。
 自分たちチームが開発をしやすいように、自分たちが必要と考える保守性を実現します。テスト駆動開発におけるリファクタリングはここに分類されます。

 このカテゴリの保守性要求に基づくリファクタリングは、自分たちの実感を通して必要性が認識されます。

妥当な費用対効果でリファクタリングできるか

 次に「妥当な保守性の実現を、妥当な費用対効果で実現できるか」の後半を構成する費用対効果についてです。

 保守性の要求があったとしても、その対応の費用対効果がマイナスの場合は、リファクタリングは避けるべき事が多いです。例えば次のような場合です。

  • 自動テストが書かれておらず、リグレッションテストのコストが高くなっている状態では、保守性要求があったとしても費用対効果がマイナスになることがあり、リファクタリングが不適切な場合がある
  • 保守性要求があるとしても、それが独りよがりで有効な要求でなかったら、効果が望めないということで費用対効果がマイナスになる。それに対応するリファクタリングは不要と判断される

 費用対効果は、リファクタリングの費用を安くできるか、リファクタリングの効果が十分かを重視します。これらは、チームやリファクタリング対象の状態を見て判断します。
 例えば対象の自動テストの充実度、自動テストのテスタビリティの高さは、リファクタリングの費用削減に直結します。コードの保守性を日頃から維持・向上するチームの習慣づけができているかも、リファクタリングのとっつきやすさにつながり、費用削減につながります。総合的なプログラミング能力も、費用対効果に連動します。
 これら要素の評価を通して、リファクタリングの費用対効果を評価します。

リファクタリングの必要性をチームに理解してもらうためには

 自分のためのリファクタリングならば、自分が必要・有効だと感じるリファクタリングを個人の習慣として推進するのが基本的な姿勢になります。

 一方でチームとしてリファクタリングを推進した方が良い場合もあります。そこでリファクタリングの必要性をチームに理解してもらうには、前述した保守性要件の分類ごとに応じたアプローチが有効です。次のようなアプローチです。

  • 計画の立案・精査を通して、「計画上求められる保守性」を識別し、それに基づくリファクタリングを推進する
  • プロジェクトリスク・プロダクトリスク分析を通して「リスクマネジメントとして求められる保守性」を識別し、それに基づくリファクタリングを推進する
  • チームの活動を確認したり、レトロスペクティブなどの機会を利用して「日々の開発で求められる保守性」を識別し、それに基づくリファクタリングを推進する

 上記に該当しない保守性要求に基づくリファクタリングは、理解が得られない可能性があり、注意が必要です。具体的には、計画上不要で、リスクコントロールとして求められておらず、開発当事者外の視点から投げかけるようなリファクタリングです。

 なおリファクタリングの必要性をチームに理解してもらう場合での注意点として以下があります。

  • 開発のライフタイムの認識の違い。保守期間を短く考えている人(例えば短期案件として開発にかかわる外部要員等)は、保守期間を長く考えている人と比べて、保守性要求を重視しないことがある。その場合、長いライフタイムで求められる保守性要求を明示化して製品要件として実現を要求する、といった工夫が求められる
  • 必要なコードの保守性の認識の違い。コードの保守性をないがしろにしている人は、そうでない人と比べて、保守性要求の必要性を認識しないことがある。その場合、チームのプログラミングレベルの向上といった啓蒙が求められる

レビューのレバレッジ性・ピンポイント性を確保する開発プロセス設計

 一定以上の規模のプロジェクトでは、開発プロセス設計において、テックリードなど有識者による横断的なテクニカルレビューをどうするかが課題になります。
 そこでは、次の課題への対応が求められます。

  • レビューのレバレッジ性の確保。少数のレビューアの影響力を全体に発揮させる。
  • レビューのピンポイント性の確保。多数の業務作業の中で、有識者の力が求められる作業に集中してレビューを設ける。

 このレビューのレバレッジ性・ピンポイント性の確保のためには、開発プロセス設計において、レビューのレバレッジポイント(少ないリソースで大きな影響を発揮できるポイント)を設け、そのレバレッジポイントにレビュー工程を確保するアプローチが有効になります。

レビューのレバレッジポイント

 レビューの代表的なレバレッジポイントに以下があります。有識者によるテクニカルレビューの力を引き出したい場合、これらに対しレビュー工程を設けるのが、有効な開発プロセス設計のアプローチとなります。

立脚点が妥当かレビューする

 ステークホルダの識別に漏れがないか、要求源の識別ができているか、スコープの理解が妥当か、特定のモデル(例えば品質特性)の観点で抜け誤りがないか、レビューします。
 そうした活動の立脚点に問題があると、以降の大きな成果物の誤りや欠落を誘発します。それを防げる点で、レビューのレバレッジ性を確保しやすいです。

方向づけが妥当かレビューする

 要求に対する対応の方向づけをレビューします。
 例えばセキュリティをしっかり確保するように一貫づけられている、特定の非機能性能を向上できるように各所に配慮がされている、保守性の確保が全体にわたって配慮されている、といったものを確認します。
 そうした方向づけをレビューで正しておけば、成果物全体の傾向に影響力を発揮できます。

難易度の高い課題対応が妥当かレビューする

 テックリードなど有識者でなければ対応が難しい課題対応を、ピンポイントでレビューします。例えば複雑なハードウェア制御のアルゴリズム設計といったものを確認します。
 これは、多数の業務作業の中で、テクニカルレビューで見るべきポイントに対するレビューのピンポイント制の確保につながります。

影響力の大きい判断が妥当かレビューする

 プロジェクト、チーム全体を横断するような、全体方針の判断をレビューします。例えばプロダクト全体の実装形式に影響するフレームワークの選定、開発プロセスのテーラリングといったものがそれに該当します。
 こうした全体に影響する判断のレビューは、レビューのレバレッジ確保につながります。

レバレッジポイントを確保するプロセスの動的なメカニズム

 レバレッジポイントの確保アプローチに、プロセスの動的なメカニズムが有効な場合があります。
 例えばその代表例にDRBFMがあります。
 DRBFMは、レビュー観点に故障モードを用います。この故障モードは、開発活動を通して蓄積・整理することで、レビューの適切性を高めていきます。
 そこでは、有識者はレビューを通してこの故障モードを作りこみチーム全体に展開することで、有識者がいないレビューでも、有識者の配慮・工夫を活用できるようにします。すなわちレビューのレバレッジ性の確保に故障モードを活用できます。

開発の高スピードと高品質を支えるテストアプローチについて講演

先日、開発生産性 Conference 2024のSpecial Sessionにて、「高品質と高スピードを両立させるテストアプローチ」と題して講演をさせていただきました。

https://speakerdeck.com/goyoki/test-approach-that-improves-quality-and-agility-together speakerdeck.com

2000人弱の参加者で緊張する登壇でしたが、準備を通して最近の経験や学びを体系的に整理でき、良い機会になりました。
声をかけていただいた運営の方々、参加者の方々、大変ありがとうございました。

モデリングは目的と観点による方向づけが不可欠

モデリングの対象が同一でも、何をどうモデリングするかには無数の選択肢があります。
そこであるべきモデルを方向づけするのが、次の目的と制約です。

目的について

まず目的についてです。例えば「机のモデリングをしたい」という場合でも、目的によってモデリングの方向性が変わります。
例えばその目的が「机が入口を通り抜けられるか知りたい」のならば、モデリングの対象は「机の幅・高さ・奥行」になります。一方「机を提供部品で組み立てたい」という目的があるならば、モデリングの対象は「机の部品構成、組み立て手順、完成図」になります。

制約について

制約は、モデリングのスコープややり方を制限するものを指します。具体的には次のようなものになります。

  • 技術制約 :プロジェクトでの技術的な実現性の制約
    • 例)技術的に実現不可能な設計モデルは許容されない
  • ビジネス制約 :ビジネスの成否にかかわる制約
    • 例)コストがかかりすぎる設計モデルは許容されない
    • 例)チームの開発リソースを超える設計モデルは許容されない
  • モデリング制約 :モデリング作業やその成果物管理の制約
    • 例)モデル作成者が管理できないほど膨大なモデルは作れない

こちらもモデリングの方向づけに影響します。

モデリングは目的ありき

そもそもモデリングは「目的を達成するために、対象の特定の特質を、特定の形式で表現する」活動です。それは、抽象化する、削る、行動化する、関係づける、分割する、形式化する、というアプローチで構成されます。
目的無く対象をそのまま模写するやり方では、この情報を削ったり抽象化したりするアプローチになりません。モデリングは目的があって成立するアプローチと言えます。

注意点:目的や制約が同じでもモデルにはバリエーションが発生する

注意点として、モデリングは不確定要素があり、同じ目的・制約下でもモデラーや状況によってモデルにバリエーションが生まれます。主な不確定要素に以下があります。

  • モデラーの能力・指向
  • 入力の不確定要素
  • 解決策が複数ある

モデリングのプロセスやアプローチは様々ありますが、それらが提示する手順通り進めればモデルが完成、というわけではありません。言い換えると、モデリングをシステマティックに進められる場面は多くありません。

実際、現場のモデリングは探索的です。モデラーの能力を活かしながら、様々な観点で分析し、ゆさぶりをかけ、フィードバックで洗練させ続けることで、優れたモデルを生み出せるようになります。

モデリングと目的・制約をつなぐ観点

目的・制約と、具体的に何をモデリングするかをつなぐのが観点です。
観点は、着目したい特質や側面の方向性を示す言葉です。

目的・制約や、それをブレークダウンした目標・課題から、どういう分析・設計を行いたいか検討する過程で、観点が生まれます。

例えば前述の机の例ですと、「机が入口を通り抜けられるか知りたい」という目的があれば、「机の大きさ」という観点と、「入口の大きさ」という観点が導かれ、その観点ごとにモデリングすることになります。

観点は、モデルの種類に紐づいています。例えば「高さと幅の大きさ」という観点ならば、二次元モデルが紐づいています。内部構造ならば、クラス図やブロック図が紐づきます。そして観点に基づいた分析・設計成果物は、観点に紐づくモデルの種類に従ってモデリングしたモデルになります。

その関係性を示したものが以下の図になります。


参考文献

speakerdeck.com

ソフトウェアプロダクトライン開発でのテストアプローチ

ソフトウェアプロダクトライン開発とは

ソフトウェアプロダクトライン開発(SPLE:Software Product Line Engineering。ソフトウェア製品系列開発)は、複数の類似した製品群(プロダクトライン)の開発についての開発手法・テクニックです。プロダクトラインで共有する資産を効果的に運用して、プロダクトラインの価値を高めたり、開発生産性を高めたりすることを目指します。

ここでいうプロダクトラインは次のようなものです。

  • 仕向け地ごとといった複数のバリエーションのグループ
  • 異なるグレード群のグループ

SPLEは、複数の製品で共有する共通資産をソフトウェアプラットフォームとして開発し、それを使って個別のソフトウェアプロダクトの開発の効率化を目指します。

ここでいうソフトウェアプラットフォームは、コンポーネントといったソフトウェアの部品だけでなく、その要件、設計、テストといった開発情報も含まれます。

このソフトウェアプラットフォームを整備し、複数のプロダクト群に共通資産として展開することで、次の恩恵を確保します。

  • 開発リードタイムの短縮。既存の共通資産を活用することで個別プロダクトの開発リードタイムを圧縮する。
  • 開発費用の低減。既存の共通資産を活用することで、複数のプロダクト群を開発する場合の総コストを削減する。
  • 品質の向上。品質を作りこんだ共通資産を活用することで、その作りこみの恩恵を個別プロダクトでも享受する。
  • 顧客価値の向上。上記のリードタイム短縮やコスト削減、品質向上の帰結として、顧客価値を向上する。

また上記以外の副次的な恩恵として、製品群の保守のサポートや、アーキテクチャの複雑化対応といったものも実現します。

ソフトウェアプロダクトライン開発のプロセス

SPLEは、ソフトウェアプラットフォームを開発するドメイン開発プロセスと、個別プロダクトを開発するアプリケーション開発プロセスの二つのプロセスを独立で運用します。

ドメイン開発プロセスでは、プロダクトマネジメントの活動で、プロダクトライン(製品系列)のマーケティング、企画、ポートフォリオ管理を行います。プロダクトマネジメントは、プロダクトラインの製品ロードマップをドメイン開発プロセスに対し出力します。SPLEの製品ロードマップは、将来にわたってのプロダクトラインの共通フィーチャ、可変フィーチャの要件の情報を含みます。
そしてプロダクトマネジメントの結果に従って、ドメインの要求開発、設計、実現(Realisation。詳細設計と実装)、テストをインクリメンタル・反復的に実施して、ソフトウェアプラットフォームを蓄積・整備していきます。

アプリケーション開発プロセスでは、通常のプロダクト開発を行います。要求開発では、ドメイン要求とアプリケーション要求を両方分析し、ソフトウェアプラットフォームの活用が増えるように要件定義を行います。以後の設計、実現、テストについても、ソフトウェアプラットフォームの資産を活用して、開発生産性を高めていきます。

ソフトウェアプロダクトライン開発を支えるテストアプローチ

SPLEにおいてソフトウェアテストは重要な役割を果たします。
特にソフトウェアプラットフォームに対するテストは、次の二方面から開発生産性を支えます。

  • プラットフォームの品質確保を支え、それによってプロダクトラン全体の生産性向上を支える。
  • 資産として共有されることで、アプリケーションに対するテストを効率化する。

一方で、SPLEのような共通資産を活用するアプローチでは、可変性の管理、可変性への備え、共通資産と個別プロダクトの連携といった、様々なテストアプローチの工夫が求められます。
以降に、SPLEに求められるテストアプローチを解説します。

全体最適が得られるようにドメインテストとアプリケーションテストを分担させる

ドメインテストとアプリケーションテストの分担の適切さは、プロダクトライン全体の生産性に影響します。

特に定番の課題となるのが、プラットフォームに対し、ドメインテストをどの程度詳細に実施するかです。

まずドメインテストは簡易的な確認しかせず、必要なテストの責務をアプリケーションテストのみで対象仕様とすると、個々のプロダクトごとに大きなテスト期間・リソースが必要になり、プロダクトライン全体での効率化を悪化させます。

逆にドメインテストで詳細なテストをして、そのプラットフォーム部分のテストをアプリケーションテストでは省略するアプローチでは、次のような要因でコストが過剰にかかることになります。

  • ドメインテストで多種多様な変異体のテストをしなくてはならない。
  • アプリケーションの実行環境や依存コンポーネントが存在しない状態でテストしなければならない場面が増える。Test Doubleで代替できることもあるが、SPLEがフィットする大規模な組込み製品といったタイプでは現実的でないことが多い。

上記のような制約があることから、ドメインテストとアプリケーションテストは、無理なく共有資産化の効果を得られる分担のバランス取りが求められます。具体的には次のような方針で分担する必要があります。

  • ドメインテストは次の方針に従う。
    • コードレベルのテスト(例えばユニットテスト)は網羅的に作成する。
    • 共通部分に対しテストを作成する。プロダクトごとの可変部分については、テストがやりやすいように、再利用可能なテスト資産をアプリケーション開発に対して提供する。
  • アプリケーションテストは、資産として提供されたドメインテストを再利用する形で、アプリケーション固有のテストを作成する。

ドメインテストは段階的に育て洗練させる

前述で少し触れましたが、ドメインテストは、アプリケーションの実行環境や依存コンポーネントが存在しない状態でテストしなければならない場合があります。これは複雑な製品ではTest Doubleによる対応が難しい制約があります。
この制約に対応するため、ドメインテストは次のような段階的な洗練を行う必要があります。

  • 【最初のアプリケーション開発初期】ユニットテストや、小中規模の仮想環境でのテストといった、限定的なテストを実施する。
  • 【最初のアプリケーション開発中記】アプリケーションのプロトタイピング環境を流用し、それを使って共通部分に対するテストを充実させる
  • 【最初のアプリケーション開発後期、次のアプリケーション開発開始期】最初のアプリケーションの環境をベースに、テストを充実させる。

テストをプロダクトコードのパラダイムに合わせる

SPLEのプラットフォームは共通化の促進のため、特別なパラダイムを適用する場合があります。この適用は、プラットフォーム全体に適用することもあれば、プラットフォームとアプリケーションの境界レイヤに限定して提供する場合もあります。
適用されるパラダイムを以下に示します。

  • ジェネレーティブなコード。コード生成ツールやモデル駆動開発ツールを使って、アプリケーションに合わせたコードを自動生成する。
  • メタプログラミング。高位ロジックでアプリケーションに合わせたコードを実現する。
  • プリプロセス。プリプロセッサ処理でアプリケーションにあわせたコードを実現する。

プラットフォームのテストは、プラットフォームのコンポーネント資産とセットで利用されるため、そのテストは、プラットフォームと同じパラダイムに遵守するのが基本です。

例えば様々なアプリケーションに柔軟に対応するため、プラットフォームの資産をジェネレーティブにすることは珍しくありません。その際は、テストもジェネレーティブにしなければなりません。すなわち、プラットフォームを生成できるようなパラメータ設定を、テストにも適用できるようにする必要があります。

可変性はプロダクトマネジメントの管理下に置く。テスト単独で対処しない

SPLEは、可変性をプロダクトマネジメントの管理下に置く必要があります。具体的には、プロダクトライン全体の視座でフィーチャや可変性を把握し、それに基づいてプラットフォームの可変性を開発する必要があります。
これは、際限のない無数の選択肢・バリエーションを、費用対効果に見合う可変性スコープに絞り込むためです。

テストでは、品質リスクに基づいてテストを作ることから、プロダクトマネジメントのスコープ外の可変性をテスト使用する場面が出てきますが、これは不吉な兆候です。

もしスコープ外のテストを作らなければならない理由が、プロダクトマネジメントの不備ならば、プロダクトマネジメントを立て直して、ドメインの要件分析、開発、テストと一通りのドメイン開発プロセスをまわすのが妥当です。プロダクトマネジメントの不備をテストでごまかすと、プロダクトライン開発全体に悪影響を及ぼすリスクを高めます。

一方、プロダクトマネジメントが適切なのに、スコープ外のテストを作ろうとする場合も問題を起こします。その場合、根拠が不明なテストが生まれ、アプリケーション開発を阻害するためです。

なおスコープが曖昧になりがちなポイントに、時間軸の可変性があります。これは、将来追加される可能性のある可変性です。ただこういったものも、基本的にプロダクトマネジメントの管理下におくべきものになります。

自動化されたリグレッションテストおよびテスト自動化容易性を充実させる

ドメイン開発でもアプリケーション開発でも、ユニットテスト結合テストにて、自動化されたリグレッションテストを満遍なくコンポーネントに配備することが重要です。
というのも、SPLDではドメイン開発プロセスとアプリケーション開発プロセスが独立で動くことで、変更の割り込みがよく発生するためです。例えばプロダクトラインの複数のプロダクトを並行開発しているときに、あるプロダクトでプラットフォームのバグが見つかり、プラットフォームのデバッグと、プラットフォームを共有している他のアプリケーションへのデバッグの取り込みが発生する、といったことは珍しくありません。プロセスが独立で動いていることから、この変更の割り込みはリリース間際でテストが十分に行えないタイミングで発生することもあります。

そこで重要になるのが、自動化されたリグレッションテストをプラットフォームにもプロダクトにもいき渡しておくことです。そのテストがあると、変更の割り込みの受け入れが容易になります。

また、自動化されたリグレッションテストをいきわたらせるために、テスト自動化容易性をいきわたらせるのも重要です。それにより、プラットフォーム側から十分なリグレッションテストを提供できなくとも、アプリケーション開発の中でリグレッションテストを構築できるようになります。

テストのモジュール性とトレーサビリティを確保する

テストの再利用を容易にするためには、テストのモジュール性の改善が必要です。保守がしやすいよう責務割り当てが適切で、外部に不必要な依存性を持たないモジュール性設計をテストコードでも推進することで、プラットフォームのテストを共有するのも、アプリケーションのテストをプラットフォームに取り込むのも容易になります。

また、テストのインプットとなっている要件や設計とのトレーサビリティの明確化も重要です。可変性設計、変異性設計ではフィーチャを単位としますが、フィーチャごとにテストを紐づけることで、フィーチャの取捨選択においてどのテストを選出すればよいか明確になります。

持続可能なテストウェアやテストシステムを利用する

SPLEのプラットフォーム資産は、持続可能な状態にして長く共有できると費用対効果が高まります。そのためプラットフォーム資産を構成するテストウェアやテストシステムを構築するのが重要です。

例えばSPLEのような共通資産化戦略で良く問題になるのが、依存しているプラットフォームやフレームワークの転換です。使用しているフレームワークが廃れ別のフレームワークに主流が入れ替わるというのような状況はフロントエンドを中心に珍しくなく、それによりフレームワークに依存する資産がまとめて陳腐化する、といった状況は複数見てきました。資産化戦略では、枯れて安定した技術スタックを選ぶべきなのと、変化が起きるの当たり前として資産化戦略を組む必要があります。

また本質的にSPLEと紐づいた要素ではありませんが、SPLEで使用するツールの維持コスト・ライセンスコストで悩まされる現場も見てきました。例えばSPLEのプラットフォームにモデル駆動開発を導入している場面で、そのモデル駆動開発ツールのライセンス料が高額かつロックインが協力なため、時がたつほどSPLEの費用対効果が目減りしていく状況に遭遇したことがあります。SPLEでは、長いライフサイクルで費用対効果を評価し、技術スタックを構築すべきです。

アプリケーションごとのテストの集積でなく、プロダクトラインに対する包括的なテストを設計する

SPLEでのテスト設計アプローチに、アプリケーションごとのテストを集めて、プラットフォームのテストとするものがあります。このテスト設計アプローチは弊害が多く、保守を阻害するテストの重複が多数発生するほか、テスト対象とテストのトレーサビリティ構造がツリーでなくセミラティスとなり、トレーサビリティの維持が難しくなります。

そのため、SPLEのテスト設計アプローチは、変異性を包含するプロダクトラインに対してテスト設計するのが無難です。
なお個々のアプリーケーションでないと実現できないテスト条件(環境条件など)が発生するのは少なくありません。その際は、プロダクトラインに対する包括的なテストを、チャンピオン的なアプリケーションに対するテストで実現しつつ、そこでカバーできない個々のテスト条件を、それぞれのアプリケーション条件でテストすべきです。

保守性が高まるように内部可変性を設計する

SPLEでは外部可変性の設計が解説されることが多いのですが、内部可変性の設計も重要です。特にプロダクトコードについてはテスト容易性が高まるように内部可変性設計を行い、テストコードではテストの保守が容易になるように内部可変性設計を行うのが重要です。

共通資産固有のテスト観点を使う

SPLEのプラットフォームに対するテストでは、共有資産なりのテスト観点が求められます。
具体的には次のようなものを追加のテスト観点として分析する必要があります。

  • プラットフォーム資産とアプリケーションを紐づけるアダプターやジェネレータのテスト
    • 例えばプラットフォーム資産をジェネレーティブ人するならば、ジェネレータのテストをよく考える必要があります
  • 可変性制約に対するテスト。
    • 選択しないフィーチャ、選択できないフィーチャが存在しないことのテストや、可変性制約を実現不能にする仕組みのテストが求められます。

テスト設計コンテストU-30クラス審査委員長業の振り返り

社外のコミュニティ活動として、2017年からテスト設計コンテストU-30クラスの創設とその審査員長を続けていたのですが、立候補あり今年度から大段さんに引き継ぐことになりました。良いタイミングなので、今回振り返りながら、自分の審査委員活動の総括をできればと考えています。

テスト設計コンテストとは

テスト設計コンテスト(テスコン)は、文字通りテスト設計の良否を競うコンテストです。

https://www.aster.or.jp/business/contest.html

テスコンは、指定の仕様書に対してテスト設計を行い、それを審査基準に従って点数化して順位を競います。(1回だけ中止がありましたが)2011年から毎年開催してきました。現在はNPOソフトウェアテスト技術振興協会の活動として、有志の運営委員、実行委員の手で運営されています。

自分がファウンダー&審査委員長をやっていたのは、このコンテストの一部として、途中から派生したテスト設計コンテストU-30クラスという部門です。こちらも形式は派生元(U-30クラスと区別するために、Openクラスと呼ぶようになりました)と大まかに同じですが、30歳以下という年齢制限を追加で加えています。
以下、このU-30クラスのコンテストについての自分の審査委員長としての活動を時系列で振り返っていきます。

U-30クラス創設のきっかけ

U-30クラスの創設は、テスコンをはじめ、ソフトウェアテストのコミュニティを下支えしていた吉澤さんから声をかけられたのがきっかけでした。
そこで求められたのが、主にテスコンの参入障壁を下げて、若手や初学者にもテスト技術の啓蒙やテスト設計の楽しさを広げたい、という要求です。

というのも、当時のテスコンは成果物の品質と規模が急激に高まり、参入障壁が一気に上がっていった時期でした。
その背景としては、何回かの開催を通してテスト設計方法論を使いこなすチームが増え、成果物の品質が一気に上がっていった要因がありました。またテスコンの人気により、予選として各地域で絞り込みをしないと本戦の審査ができないほどチームが増え、競争率が高まっていた背景もありました。

この傾向はテスト技術の普及・発展の点で良い事なのですが、反面、テストの初学者や若手が安易に参加しにくい参入障壁が生まれていました。そこで年齢を若手に限定するクラスを設けることで、若手や駆け出しにもテスコンに参加いただき、テスコンによるテスト技術の普及・発展を促進しようという話が生まれました。

U-30クラス審査委員チームの構築

創設にあたっては、まず審査委員チームの構築に着手しました。
そこでは審査委員を、当時のテストコミュニティで精力的に活動していた方の中から、テスト設計コンテストの出場経験のある方、高いテスト設計技術を持った方を選び、個人的にお声がけしていきました。当時の自分はWACATEというテスト技術の勉強会合宿を中心にテストの人脈を広げていた影響で、結果的にWACATE関係者がチームの主体となりました(WACATEは若手の成長を意識したイベントのため、その関係者が母体となったことにより、後述する教育特化志向につながりました)。
そこに他の方がお声がけして推薦いただいた蛭田さんを加え、テスト設計コンテストU-30クラスの審査委員チームが完成しました。

初年度のコンテスト活動の開催

U-30クラスの始動にあたっては、思いや理念あるNPO活動ということで、ミッションやビジョンを審査委員間で共有して、それに沿ってU-30クラスを形作っていこうと考えました。

具体的には、審査委員メンバーで、創設のきっかけとなったテスコンの実行委員・審査委員の想いを具体化しながら、次の目的を設定しました。

  • テスコンに若い人を参加しやすくする/テスコンのすそ野を広げる
  • テスト設計の大切さに気付いてもらう
  • テスト設計の面白さ、他人のテスト設計と比較する面白さを体験してもらう
  • 本人の次のステップアップに役立てる/新人・中堅社員教育を支援する/仲間を増やす
  • 新しいテスト設計(観点・技法・方法論)を開発する



次にコンテストの建付けを具体化してきました。
初年度は、参加者の方々に本家のテスコン:Openクラスのこれまでの蓄積(チュートリアル資料、参加チームの成果物等々)を参考にして学んでいただこうという考えで、審査基準やルールはOpenクラスをそのまま踏襲しました。またテストベースについても、スタンドアロンの組み込み製品で規模が小さい、Openクラスで何年も使われていて資産が蓄積しているという理由で、SESSAMEの話題沸騰ポットを採用させていただきました。
一方、それとは別に、初学者でも方向性が考えやすくなるように、テストの計画・アプローチにある程度の制約を指定する、U30専用の補足要求書を新設しました。

最初の開催後

初開催では、学生や新入社員といった初学者・入門者に複数参加いただき、テスコンの参加障壁を下げようという目標は一定レベルで達成できたと感じています。

ただ反省点として、コンテストの競争を重視しすぎて、目的としていた教育方面の貢献が弱くなっていました。
例えばフィードバックについては、客観的な問題点の指摘が中心であり、スキルアップにつながる改善提案や今後の動機づけができていませんでした。特に点数の低いチームについては、問題指摘が沢山羅列されるだけのフィードバックを返してしまう形になり、テスト設計初心者のためという目的とは逆行して、委縮させてしまう恐れも出ていました。

U30はミッションを持つクラスということもあり、振り返りと問題改善に当初から注力していたのですが、そこで上記問題を細かく把握・評価し、次年度への改善につなげるようにしました。

二年目以降:教育的側面を志向する

初期の反省を踏まえて、U30クラスのテスコンは、コンテストの競争よりも、参加者の成長やスキルアップを伸ばす、教育重視のイベントを試行するようにしました。

まず審査員全員で、目的のほか、目的達成のアプローチを具体化して共有し、活動の方向性を固めました:

  • 【2020】テスト設計コンテストU-30クラスの目的
    • テスコンに若い人を参加しやすくする/テスコンのすそ野を広げる
    • テスト設計の大切さに気付いてもらう
    • テスト設計の面白さ、他人のテスト設計と比較する面白さを体験してもらう
    • 本人の次のステップアップに役立てる/新人・中堅社員教育を支援する/仲間を増やす
  • 【2020】目的達成のアプローチ
    • 改善を促すようなポジティブなフィードバックを心がける
    • 適切に伝えつつ、傷つけないようにする
    • 参加チームに気づきを促すような、わかりやすいコメントにする

そして、前年度のふりかえりと、上記のアプローチに沿って、以下の改善を実施しました:

参加者の成長につながるようなフィードバックの充実

コンテスト参加チームには、問題点を指摘するフィードバックコメントを個別に返すようにしています。
従来は問題点や点数の根拠の羅列のみを返す形になっていました。改善後から、激励屋応援の言葉と、問題点をどう改善すればよいか・どう勉強すればよいかを、丁寧に説明するフィードバックを行うようにしました。
これにより1チーム当たり3ページ程度だったフィードバックコメントが、1チーム当たり十数ページの改善提案書となるようになりました。

コンテストの作業をより現場に寄り添わせるよう、テストベースを拡張

テスコンは工数などの制約がなく、テスト技術の優劣に特化してテスト設計を行う傾向がありました。
一方現場では様々な制約(人数、工数、コスト)へのフィットが求められ、その過程でリスクベースドテストや各種テスト効率化手段が要求されます。
U30では、このギャップを埋めるよう、工数上限やチーム体制の指定を行うようにしました。

三年目以降:さらに教育志向を強化する

毎年の開催での振り返り・問題改善を通して、U30は更に教育的側面の強化を志向するようになりました。
まず、コンテストの目的では、具体的なターゲットのイメージと、自分たちが何をしたいのかを、審査委員皆で協議し、同意を形成しました:

  • 【2021~】テスト設計コンテストU-30クラスのビジョン
    • ◼ターゲットとする参加者
      • テスト初心者(業務で触れているがテストの全体感・本質論に関われていない) ★メインターゲット
      • 純粋なテスト初心者(一年未満、学生) ★次のターゲット
      • テスト設計中堅、コミュニティ参加常連
    • ◼参加者にどうなってもらいたいか
      • テスト開発をやり切れる
      • テスト設計の大切さに気付いてもらう
      • テスト設計の面白さ、他人のテスト設計と比較する面白さを体験してもらう
      • 本人の次のステップアップに役立ててもらう
      • テスト技術を高めあう仲間を増やしてもらう
      • 学生教育、新人・中堅社員教育に役立ててもらう
      • テスト技術についての成長を実感してもらう
    • ■審査員がどうありたいか
      • テスコンに若い人を参加しやすくする / テスコンのすそ野を広げる
      • テストを分析設計から行うことを周知する/テストエンジニアに対する教育の機会を提供する
      • より良いテスト設計を考え続けるきっかけを提供する

そして、上記を達成するためのアプローチについても、審査委員全員で協議し、共通認識として同意しました:

  • 【2021~】テスト設計コンテストU-30クラスのアプローチ
    • ◼大会外のアプローチ
      • 初心者・経験の浅い人でも気軽に参加できるようにする
      • 初心者向けチュートリアルの開催
      • 初心者参加を促す宣伝
    • ◼大会内のアプローチ
      • 一通りのテスト設計作業を経験する機会を設ける
      • 具体的なお題でテストを考える機会を提供する
      • 三者からステップアップにつながるフィードバックをもらえる機会を提供する
      • 参加チームに気づきを促すような、わかりやすいコメントにする
      • フィードバックを無理なく対応できるようにする
      • フィードバックコメント、直接の対面コメント含め、ポジティブなコメントを充実させる
      • 書類審査のコメントで、適切に伝えつつ、傷つけないようにする
      • 発表/他の参加者の成果を知る機会を提供する

そしてこれらの目的とアプローチに沿って、コンテストの活動を強化していきました。

まずフィードバックコメントを返すだけではなく、審査委員と参加者が直接話し合って、対話や質疑応答で改善点やアドバイスを共有する、フィードバック会を追加で開催するようにしました。
また、フィードバックコメントについては、前年度の方針転換で量が爆発して弊害が出るようになっていたことから、上記アプローチに沿って洗練させてフィードバックするようにしました。
さらに審査基準についても、普遍的に現場で重視される「テストが目的・制約に沿っているか」「そもそもテストが妥当か」のテスト妥当点を新設し、良いテストは何か、どうテストすべきかを考えていただく仕組みを追加しました。

なお自身の仕事の繁忙期の体制面のリスクから、このころから山崎さんにも共同審査委員長に参入いただきました。

これからについて

社外活動とはいえ、自分自身としてもかなり気づき・成長の得られる貴重な五年間でした。誘っていただいた吉澤さんや、協力・支援いただいた審査員・実行委員の方々、参加者の方々、大変ありがとうございました。

なお現在のU-30クラスのテスト設計コンテストは、教育重視の目的とアプローチを定義し、一貫してそれに沿った運営・改善を継続することで、参加者の成長や教育につながるイベントとしてかなり充実してきたと感じています。
自分のスキルを伸ばしたいという若手にはぜひ参加いただきたいですし、ベテラン方がテスト設計について成長やスキルアップに課題意識を持っている若手を見つけたら、ぜひ参加を促していただけると幸いです。

リグレッションテストの方針立て

リグレッションテストの方針の重要性

ソフトウェアに変更を加えた際に、意図せず変更とは関係のない所で故障が発生したり潜在的なバグが顕在化したりしたものは、リグレッション和製英語デグレードとも)と呼称されます。
リグレッションテストは、このリグレッションが発生していないか確認するテストです。このリグレッションテストは通常、変更前後でテスト成功状態が維持されることを確認して、意図しない変化がソフトウェアに発生していないか確認するアプローチをとります。

このリグレッションテストをどう方針立てするかは、テストの方針にとって重要な課題です。

というのも、ソフトウェア開発では仕様や設計の変更がありふれていますし、デバッグによる変更がリリース間際まで続きます。そこでは一般的に変更の度にテストを全てやり直すほどの期間やリソースがないため、絞り込んだ限定的なテストケースでリグレッションテストを構成せざるを得ません。このテストの絞り込みは変更内容によって大きく変わるため、その場その場で、プログラマやテストエンジニアが判断することになります。
そこで事前のリグレッションテストの方針立てが重要になります。適切な方針を提示できていると、その場その場のリグレッションテストを適切な方向に誘導できます。逆に方針立てがないと、好き勝手な判断で、不適切なリグレッションテストが行われる可能性を高めます。

リグレッションテストの方針立ての難しさ

ただ重要であっても、リグレッションテストの方針立ては次のような難しさから、具体化しにくい事情もあります。

  • リソースや期間が不足するのが当たり前
    リリース間際でテストの期間・工数が確保できない状況下でもデバッグで変更され続ける状況がありふれている。また仕様変更は全テストのやり直しを考慮してまで行われるのは稀である。そのため、本来必要なリソース・期間が確保できない状況が珍しくない。
  • リグレッションリスクの十分な識別は困難
    ソフトウェアの影響範囲は、直接的な結合のほか、DBや実行環境、ブラックボックスフレームワーク等を介して広く波及する。影響の程度も、非同期処理などではテスト条件が膨大で全容把握が困難。変更の影響範囲をそもそも正確に特定できない。

このように不十分なリソースで、特定困難なリスクに対応するため、そもそもリグレッションテストは、テストチームのテストだけでは対応不能な場面も少なくありません。

なお、重要であることからテスト計画に関わる標準やプロセス、テンプレートの多くは、リグレッションテストの方針立てを計画段階で要求しています。ただこの難しさから、適切な方針立てをあきらめ、以下のような記述で形骸化させてしまう場面を複数見ます。

  • 現場と乖離して実現困難な方針を立てる。極端な例では、全ての再実施を要求するなど
  • 空虚で実質的に何も影響を及ぼさない方針をたてる。「影響範囲をテストする」の一文で済ませるなど

こうした形骸化を防ぐためには、前述のリグレッションテストの難しさに向き合う必要があります。

リグレッションリスクは様々な手段で対応する

リグレッションテストの本来の目的は、リグレッションリスクのコントロールです。具体的にいうと、テストでリグレッションリスクの顕在化を確認し、許容できない品質リスクがあればデバッグを通してリスクをリリースできるレベルまでコントロールすることを目指します。

この「リグレッションリスクのコントロール」ですが、当然手段は手動のテストだけではありません。他の特に有効な手段として次のようなものがあります:

開発者による変更レビュー

例えば、DRBFMなど変更に対する設計レビュー、PRレビューといったコードレビューです。
これら開発チーム内のレビューは、あからさまな開発ミスによるリグレッションの流出防止に有効です。
注意として、変更範囲が大きいと人間のレビューでは影響範囲が追いきれなくなるため、細かい粒度で習慣的にレビューを実施するのが重要です。

自動化されたリグレッションテスト

自動テストは再実行が容易なため、絞り込みすることなく、変更ごとにフル実施しやすいメリットがあります。そのため、リグレッションの網羅的な確認を効率よく安定してこなせます。一般的に、リグレッションテストの主力となる手段です。
注意として、手動のリグレッションテストは全て自動化することはできません。自動テストでは探索的テストの強み(微妙な品質の異常の確認や、探索的な意地悪な操作の試行など)を再現しにくいデメリットがあります。
そのためリグレッションテストを自動テストのみで済ませられない場面も多く、その際は手動のテストによる補完が必要になります。

Cover & Modify

これは、開発者判断で、リグレッションが発生しそうな箇所に自動テストを書き、変更前後でそのテストが合格状態であることを確認するプログラミングアプローチです。前項の自動リグレッションテストの応用例の一つです。

このアプローチでは、開発者が怪しいと思う箇所(不吉な臭い)にリグレッションテストが配備されるため、開発者の知見や思考を活用してリグレッションリスクを軽減できます

リグレッションリスクを局所化する設計の工夫

ソフトウェアの変更性を高める設計の工夫です。具体的には、コンポーネント間の結合度を下げる工夫を実施し、変更する際の影響範囲やリグレッションリスクを局所化する対策を推進します。
例えば、金銭や個人情報を扱うといったハイリスク機能は、特定コンポーネントアーキテクチャ設計的に隔離してトラストバウンダリを設けて、それ以外の変更時のリグレッションリスクを軽減するといったアプローチが典型例になります。
反面教師として、変更性の悪い設計(全体が複雑に結合し、変更影響を限定できない設計)の場合、変更の際のリグレッションリスクが極大化して、何が起こるかわからなくなります。そうした場合では、リグレッションテストの絞り込みが困難になります。

高頻度で小規模なリリース

なるべく高頻度に細かくリリース・デプロイして、一回の変更の規模を抑えるアプローチです。
リリースの粒度が大きいと、それだけ変更範囲が大きくなり、対応すべきリグレッションリスクが広く・高くなります。これではリグレッションテストの絞り込みが困難になりますし、前述した変更レビューや設計の工夫などのプラクティスも効果を発揮しにくくなります。
そのため、開発のリードタイムを高めて、リリースは高速に済ませられるように体制、プロセス、技術力を整備しておくことは、変更のリグレッションリスク軽減に寄与します。

リグレッションテストの方針

リグレッションテストの基本方針は、上記の有効な手段で十分にリグレッションリスクを軽減したうえで実施する、という形になります。これによりリグレッションテストに必要なリソースや期間を、実現可能なレベルまで軽減します。

この基本方針に基づくリグレッションテストの作り方のアプローチは次のようになります:

  1. 設計、コードを見て(変更性を高め、コンポーネント間の結合度を下げるアーキテクチャバウンダリを確認して)、リグレッションリスクの確認範囲を絞り込む
  2. 変更レビューなど変更アプローチと、開発者テスト、自動テストを見て、自分たちのリグレッションテストまでに残留しているリグレッションリスクを評価する
  3. 残ったリグレッションリスクに基づいて、テストケースを絞り込み実行する。

以降のリグレッションテストは、基本的にリスクベーステストになります。変更をレビューし、そこから想定されるリグレッションリスクを識別して、対応が必要なものにかかわるテストをピックアップします。

リグレッションテストの方針は、上記のようなアプローチを具体化して定義するのが、妥当なものの一つになります。