本番システムでの再利用と回帰テストのコストに関連するソフトウェアエンジニアリングの原則はありますか?


12

私は年金と投資の面倒を見る銀行の大規模な金融取引システムに取り組んできました。15年間の機能変更後、手動回帰テストのコストはリリースごとに20万ドルに上昇しました。(1,000,000 LOC、1日あたり1,000万ドルの取引)。また、このシステムは、多くのデータを移動する社内の19の他のシステムと連動します。このシステムはJavaで実装されました。

ただし、「再利用」を行うほど、回帰テストのコストが高くなります。(理由は、「タッチするコードをテストする」必要があるためです。また、再利用/共有コードは、タッチされたときに多数の場所に影響を与えます。したがって、「DRY-Do Not Repeat Yourself」 -コードをコピーして貼り付ける金銭的なインセンティブを確認します。これは、回帰テストに大きな影響を与えるため、共有できるコードを変更したくないため、回帰テストのコストを削減するためです。

私の質問は、再利用と回帰テストのコストの関係を説明するソフトウェアエンジニアリングの原則があるかどうかです。

私がこの質問をする理由は、システムをテスト対象のより小さな部品に分解することには、おそらくコスト上のメリットがあるからです。

仮定:

  1. 「回帰テスト」とは、「受け入れテスト」を意味します。つまり、環境やデータのセットアップなど、ビジネスに代わってシステムに対して新しいテストを作成したり、古いテストを再利用したりする別のグループです。

  2. 大きなリグレッションテストコストに対する大胆な反応は、「より自動化されたテスト」です。これは良い原則です。この環境では、いくつかの課題があります。

    (a)自動テストは、システムが高い自動テストカバレッジを持たない限り、システムの境界を越えてあまり有用ではありません。(影響範囲の課題)。

    (b)システムが既に大きく複雑な場合、プログラマーの時間や高い自動化されたテストカバレッジへの資本投資に勢いをつけることは文化的に困難です。

    (c)自動化されたテストの維持コストはプロジェクトに隠されているため、プロジェクトレベルで簡単に破棄されます。

    (d)これは銀行で働くことの文化的現実にすぎません。

    (e)私はこの問題を別の方法で解決しようとしています(分解)。


2
「再利用」を行うほど、[受入]テストのコストが増加するという[…]を観察するという手振りの声明を作成します。受け入れテストは、継承階層などの実装の詳細にとらわれず、代わりに、たとえば使用シナリオを再生するべきではありませんか?
アモン

2
あなたの質問は興味深いですが、「再利用はオブジェクト指向の結果です」または@amonが言及した部分のような非常に偏った仮定が含まれています。あなたのコアな質問はプログラミング言語やオブジェクト指向プログラミングから独立しているため、「OO」部分を完全に削除することをお勧めします。そして、どの種類の「再利用」を念頭に置いているのかはかなり不明です。「再利用」は広義の用語であり、コピーと貼り付けの再利用はコンポーネントまたはライブラリの再利用とは異なります。
Doc Brown

感謝します。OOへの参照を削除し、共有コード(または共有コードになるコード)に触れるという考え方を拡張しました。
ホーキー

1
現在の形式では、私はあなたの質問に「いいえ、そうは思わない」と答えると思います-あなたにはあまり満足できないと思います。または、自作の再利用可能なコンポーネントを使用してあなたのような大きなシステムを構築する際に、実際にテストコストを削減するための原則と実践に興味がありますか?
Doc Brown

回答:


11

共有される可能性のあるコードを変更したくないのは、それが大きな回帰テストの影響を引き起こすからです

上記は私にとって正しいことです。コードが重要であるほど、コードが共有されるほど、品質要件は高くなり、が変更された場合により品質保証が必要になります。

システムはJavaで実装されているため、Java標準ライブラリ(JDK)で上記の例を見ることができます。そのメジャーリリースはまれであり、非常に労力のかかるテストを伴います。マイナーリリースでも非常に包括的な JCKテストスイートを、回帰がないことを確認します。

これは共有コードの進化を何らかの形で抑制していると思われるかもしれません。コードの変更に伴う影響とリスクが大きいほど、コードの変更に注意を払うほど、そのリリースのテストにより多くの労力が必要になります。

理想的には、広く共有されているコードのリリースの品質は、大きな変更をまったく必要としないようなものである必要があります(まれな機能強化のために保存します)。この考え方は、ジョシュアブロッホの有名な引用に反映されています

ダイヤモンドのようなパブリックAPIは永遠に存在します。あなたはそれを正しくするチャンスがありますので、最善を尽くしてください。


ただし、上記で述べたように、あなたが説明する問題の一部は、共有コード開発の非効率的な戦略が原因であるように見えます。特に、再利用されたコードについては、このコードを複製するか、「コア」共有ライブラリにすぐに含めるかの2つのオプションしか考慮されないことが特に面倒です。

これらの2つのオプションだけに制限する必要はありません。繰り返しますが、使用するJDKでそれをどのように改善できるかの例を見つけることができます。java.util.concurrentパッケージ(JSR 166)を見てください-Java 5リリースまでは、これらは別個のライブラリであり、コアJDKリリースの一部ではありませんでした。

考えてみてください。これは見落とした3番目のオプションであり、かなり実用的なオプションであり、新しい共有コードの「開始」時に考慮する必要があるオプションです。2-3個のコンポーネント間で共有できるコードを考えただけでは、システムのコアAPIにすぐにそれを含める必要はありません。

この「未熟な」共有コードは、Javaコンカレントユーティリティに対して行われたように、個別のライブラリとしてパッケージ化してリリースできます。この方法により、使用できるコンポーネントは比較的少量で済むため、完全な回帰テストの必要がなくなります。その結果、この共有コードを変更および改善し、本番環境でどのように機能するかをテストする余裕があります。

ライブラリが成熟して安定し、ライブラリ内のさらなる変更が発生する可能性が低いと確信できるようになったら、システムのコアライブラリに含めることを検討できます。


頻繁に再利用されるコードの変更にどれだけの労力(テストを含む)が関与する可能性があるかについての具体的な例は、JDKにも記載されています。リリース7u6ではStringsubstringパフォーマンスの変更を伴う内部表現を変更しました。Redditの機能開発者のコ​​メントは、この変更にどの程度の労力がかかったかを概説しています。

最初の分析は2007年にGCグループから出されました...

内部的に、オラクルのパフォーマンスチームは、パフォーマンスの変化を評価するために使用する代表的な重要なアプリとベンチマークのセットを管理しています。この一連のアプリは、サブストリングへの変更を評価する上で重要でした。パフォーマンスの変化とフットプリントの変化の両方に注目しました。必然的に、重要な変更の場合と同様に、一部のアプリでリグレッションが発生し、他のアプリでゲインが発生しました。パフォーマンスがまだ許容でき、正確さが維持されているかどうかを確認するために、回帰を調査しました...

私の返事は網羅的であることを意図していませんが、ほぼ半年間の献身的な仕事の非常に短い要約です...


...我々の両方が同様の考えの多くと、並行して答えに働いているようだ
ドク・ブラウン

ええ@DocBrown、それは質問が形に編集された後、我々はまた、約一時間、ほぼ同時に答えたことは興味深いです
ブヨ

9

「回帰テストのコスト/ビルドされた再利用コードのLOC」を計算するためのメトリックが存在するとは思わない。そして、同じ「ビッグ」システムを2回構築するためにそれほど多くの時間とお金を投資した人はいないと思います。

しかし、私はあなたのような再利用に起因する問題を見てきました。そして、おそらくあなたはこれをもっとうまく処理する方法についてのいくつかの考えに興味があります。

まず、実際に問題となるのは再利用ではなく、独自の再利用可能なコンポーネントを構築し、システム全体で使用する試みです。あなたはあなたの問題が発生しない大きなソフトウェアパッケージの多くの再利用をしていると確信しています:あなたが使用しているJavaスタック全体、または多分いくつかのサードパーティのコンポーネントを考えてください(あなたはそのコンポーネントに満足していると仮定します)。しかし、Javaライブラリなど、そのソフトウェアの違いは何ですか?独自の再利用可能なコンポーネントによって、非常に多くの回帰テストコストが発生していますか?以下は、異なる可能性があると思われるいくつかのポイントです。

  • これらのコンポーネントは非常に成熟していて安定しています

  • それらは完全に異なる組織によって開発され、単独で完全にテストされます

  • それらを(再)使用するために、それらを変更する必要はありません(実際、ソースコードを保持していないため、それを希望してもできませんでした)

  • 毎日新しいバージョンを入手するのではなく、マイナーアップデート(1か月あたり最大)、または1年ごとのメジャーアップデートのみを取得します。

  • ほとんどの更新は、特に下位更新と完全に下位互換性があるように設計されています

したがって、独自の再利用可能なコンポーネントをより成功させるには、上記の一部を独自の開発に適合させる必要があります。

  • 再利用可能なコンポーネントについては、保守を行う明確な責任を持ち、問題が発生した場合、コンポーネントを再利用するすべての人がすぐにバグ修正を確実に取得できるようにします。

  • 厳密なバージョン管理とリリースポリシーを確立します。再利用可能なコンポーネントを進化させるときは、毎日「全員に」リリースしないでください(少なくとも、システム上で20万ドルの完全な回帰テストを実行することを意味する場合を除く)。代わりに、新しいバージョンは時々のみ公開され、そのコンポーネントのユーザーが新しいバージョンへの変更を延期できるメカニズムを提供します。

  • コンポーネントが再利用される頻度が高いほど、安定したインターフェイスと下位互換性のある動作を提供することが重要になります。

  • 再利用可能なコンポーネントを分離してテストするには、非常に完全なテストスイートが必要です。

これらの多くは、コンポーネント自体を構築するコストが増加することを意味しますが、回帰の失敗によって引き起こされる変更のコストも削減します。


0

より多くのテストが必要なため、「目に見える」コストの上昇があるかもしれませんが、そのタイプのリファクタリングは通常、システムの技術的負債を減らすため、将来コードをより保守しやすくします。

これにより、将来のバグが減り、新しい機能や既存の機能の変更が実装しやすくなることが期待されます。

簡単に言うと、時間がかからないため、コストも安くなるはずです。

ここでは、Reduce、Easy、およびLessはすべて曖昧な用語であり、将来の(またはむしろ保存を希望する)保存はまだ行われていないため計算できません。

特に大規模なシステムの場合、コードベースが単純であれば、新しい従業員、またはプロジェクトに移る既存の従業員がより早くスピードアップすることができます。

また、既存のプロジェクトメンバーの士気が向上する可能性があるため、スタッフの離職率が低下する可能性があります。

もちろん、これらのメリットが得られることは保証されていませんが、これらは測定可能なコスト(テストの増加など)と一緒に考慮する必要があるものです。

実際、記述内容により最初の増加があったとしても、より良いコードは最終的にはテスト費用を徐々に削減するはずです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.