このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。
Polyspace チェッカーを使用してソフトウェアの複雑度を低減する
ソフトウェアの複雑度とは、ソフトウェア モジュールまたはソース ファイルの、定量化が可能なメトリクスのことです。種類はさまざまで、行数、パス数、関数の数、関数呼び出しツリーの複雑度などがあります。このようなメトリクスがしきい値を超えると、Polyspace® ソフトウェア複雑度チェッカーが起動します。ソフトウェアの複雑度が高いことは、コードの読み取り、理解、デバッグが難しいことを示している可能性があります。複雑なプロジェクトを後からリファクタリングするのではなく、ソフトウェアの複雑度を開発中に許容可能なレベルに維持するほうが効率的です。ソフトウェア複雑度チェッカーを使用して、複雑なモジュールを開発サイクルの早期に検出することにより、後で行うリファクタリングの手間を減らしましょう。
すべてのファイルと関数に対してコード複雑度メトリクスの絶対値を計算することもできます。Polyspace を使用したコード複雑度メトリクスの計算を参照してください。
Hersteller Initiative Software 標準を使用したコード複雑度のチェック
コードのコード複雑度メトリクスが指定されているしきい値を超えると、ガイドラインのコーディング ルールが違反を報告します。既定では、Polyspace Bug Finder™ はしきい値を、Hersteller Initiative Software (HIS) コード複雑度標準によって指定されている値に設定します。コード複雑度メトリクスが HIS 標準で規定されている範囲内にあるかどうかを確認するには、[チェッカーの選択] ウィンドウを使用してガイドラインのコーディング ルールを有効にします。
[チェッカーの選択] ウィンドウを開きます。このウィンドウを開く方法は、ご使用の Polyspace 製品によって異なります。詳細は、以下を参照してください。
[ガイドライン] 、 [ソフトウェアの複雑度] に移動して、HIS 標準に対応するルールを有効にします。HIS コード複雑度メトリクスを参照してください。
HIS 標準に照らしてチェックする場合、ガイドライン チェックの既定のしきい値を変更する必要はありません。
カスタムしきい値を使用したコード複雑度のチェック
コードのカスタム コード複雑度しきい値を定義できます。最初に、自分のユース ケースのベスト プラクティスに応じて、しきい値の適切なセットを決定します。たとえば、新しいプロジェクトまたは新しく開発するコードを解析するときに、[goto ステートメントの数がしきい値を超えている] のしきい値をゼロに設定して、GOTO ステートメントの使用を減らすことができます。レガシ ライブラリを含むモジュールを解析するときには、しきい値を高い数値に設定するのが良い場合もあります。
しきい値のセットを定義したら、[チェッカーの選択] ウィンドウでこれらのしきい値を指定できます。
[チェッカーの選択] ウィンドウを開きます。このウィンドウを開く方法は、ご使用の Polyspace 製品によって異なります。
[ガイドライン] 、 [ソフトウェアの複雑度] に移動して、使用するルールを有効にします。
[しきい値] フィールドでカスタムしきい値を指定します。
ソフトウェアの複雑度の特定と低減
Bug Finder 解析を実行することによるソフトウェアの複雑度の特定
ソフトウェアの複雑度を特定するには、チェッカーのしきい値を構成します。たとえば、次の表に示されているチェッカーのしきい値を設定します。
| チェッカー | しきい値 |
|---|---|
コメント密度がしきい値未満 | 20 |
呼び出しツリーの複雑度がしきい値を超えている | 10 |
呼び出しの発生数がしきい値を超えている | 10 |
言語スコープがしきい値を超えている | 400 |
しきい値は、ソフトウェアの複雑度の許容レベルを示します。複雑度を高める可能性があるコード内の問題を特定するには、ソフトウェア複雑度チェッカーを構成してから、Polyspace Bug Finder 解析を実行します。次のコードについて考えます。
long long power(double x, int n){
long long BN = 1;
for(int i = 0; i<n;++i){
BN*=x;
}
return BN;
}
double AppxIndex(double m, double f){//Noncompliant
double U = (power(m,2) - 1)/(power(m,2)+2);
double V = (power(m,4) + 27*power(m,2)+38)/(2*power(m,2)+3);
return (1+2*f*power(U,2)*(1+power(m,2)*U*V+ power(m,3)
/power(m,3)*(U-V)))/( (1-2*f*power(U,2)*(1+power(m,2)*U*V
+ power(m,3)/power(m,3)*(U-V))));
}AppxIndex が複雑度を高くしているように思われます。複雑度を低減する方法ははっきりしません。ソフトウェア複雑度チェッカーが複雑度の原因の特定に役立ちます。Bug Finder 解析の後で、構成されたチェッカーが以下のように起動します。
コメント密度がしきい値未満:コード内の関数に説明コメントが含まれていないことを示します。呼び出しツリーの複雑度がしきい値を超えているおよび呼び出しの発生数がしきい値を超えている:関数定義の数と比較して、関数呼び出しが多すぎることを示します。一部の式を複数の関数にパッケージ化できることがわかります。言語スコープがしきい値を超えている:同じオペランドが複数回繰り返されていることを示します。一部の繰り返しを削減できます。たとえば同じ引数を指定して複数回呼び出されている、関数powerがあります。
これらのチェッカーは、関数 AppxIndex がコードの読み取り、理解、デバッグを難しくしている可能性を示しています。コードの複雑度を低減するために、報告されたチェックに対処します。
ソフトウェアの複雑度を低減する
特定された問題に対処することにより、コードの複雑度を低減します。この場合、報告されたチェックの根本原因は、関数 AppxIndex が 1 つのタスクを実行するのではなく、複数のタスクを実行していることです。たとえば、この関数は最初に U、その後 V を計算し、最後に U と V の両方を含む非常に長い式を評価します。この問題を解決するには、関数 AppxIndex をリファクタリングして、各タスクを別個の関数にデリゲートします。長い式は細かく分解できる場合があります。次に例を示します。
// This code calculates effective index of materials as described in
// the formula in 10.1364...
// power(x,n) returns the nth power of x (x^n)
// n is an integer
// x is a double
// return type is long long
long long power(double x, int n){//Compliant
long long BN = 1;
for(int i = 0; i<n;++i){
BN*=x;
}
return BN;
}
// CalculateU(m) calculates the first intermediate variable
// required to calculate polarization
// m is the relative refractive index
// return type is double;
double CalculateU(double m){//Compliant
return (power(m,2) - 1)/(power(m,2)+2);
}
// CalculateV(m) calculates the second intermediate variable
// required to calculate polarization
// m is the relative refractive index
// return type is double;
double CalculateV(double m){//Compliant
return (power(m,4) + 27*power(m,2)+38)/(2*power(m,2)+3);
}
// CalculateMid(m,f) calculates the large term present
// in both numerator and denominator
// of the effective index calculation
// m is the relative refractive index
// f is the fillfactor
// return type is double;
double CalculateMid(double m, double f){//Compliant
double U = CalculateU(m);
double V = CalculateU(m);
return 2*f*power(U,2)*(1+power(m,2)*U*V + power(m,3)/power(m,3)*(U-V));
}
//AppxIndex(m,f) calculates the approximate effective index
// m is the relative refractive index
// f is the fillfactor
//return type is double
double AppxIndex(double m, double f){//Compliant
return (1+CalculateMid(m,f))/( (1-CalculateMid(m,f)));
}コードに十分な数のコメントを付けてドキュメント化します。
AppxIndexが実行する大きく複雑なタスクを小さくて簡単なタスクに分割し、CalculateU、CalculateV、CalculateMidなどの個別の関数にデリゲートします。これで、関数powerの呼び出し頻度が少なくなりました。べき乗を計算する別の関数を後で実装し、現在の関数ではなく新しい関数を使用する場合、行わなければならない置き換えは少なくなります。1 つの特定のタスクを実行し、できるだけ機能のオーバーラップが少ない新しい関数を記述します。その結果、これらの関数に含まれる同じオペランドの繰り返しは少なくなります。
ソフトウェア複雑度チェックへの対処の詳細については、チェッカーのドキュメントを参照してください。
コードのリファクタリングができない場合、報告されたチェックにコード注釈で対処します。たとえば、複雑なライブラリを使用している場合、ライブラリで報告されるチェックに注釈を付けることができます。コードへの注釈付けと既知の結果または許容可能な結果の非表示を参照してください。ファイルまたは関数コード メトリクスに注釈を付けると、対応するソフトウェア複雑度チェッカーにも同じコメントで注釈が付けられます。