2024/02/13 22:13:39

Perl コードのメトリクス測定

コードを静的解析する

メトリクス解析ツール

Perl コードのメトリクス解析には Perl::Metrics::Lite やコマンドラインツールの App::plmetrics を使用します。

plmetrics

App::plmetrics モジュールにはコマンドラインでメトリクス解析を簡単に行う plmetrics が含まれています。

$ plmetrics --module Encode
/usr/lib/perl5/5.8.8/i386-linux-thread-multi/Encode.pm
.---------------------------------------------------.
|       | avg   | max | min | range | sum | methods |
+-------+-------+-----+-----+-------+-----+---------+
| cc    |  7.69 |  18 |   1 |    17 | 100 |      13 |
| lines | 17.92 |  94 |   4 |    90 | 233 |      13 |
'-------+-------+-----+-----+-------+-----+---------'

リモートの git リポジトリを対象に解析することも可能です。

$ plmetrics --git git@github.com:bayashi/Statistics-Swoop.git
lib/Statistics/Swoop.pm
.--------------------------------------------------.
|       | avg  | max | min | range | sum | methods |
+-------+------+-----+-----+-------+-----+---------+
| cc    | 3.00 |  10 |   1 |     9 |  18 |       6 |
| lines | 8.67 |  28 |   1 |    27 |  52 |       6 |
'-------+------+-----+-----+-------+-----+---------'

metacpan の tar.gz もいけます。

$ plmetrics --tar http://cpan.metacpan.org/authors/id/B/BA/BAYASHI/Statistics-Swoop-0.02.tar.gz
lib/Statistics/Swoop.pm
.--------------------------------------------------.
|       | avg  | max | min | range | sum | methods |
+-------+------+-----+-----+-------+-----+---------+
| cc    | 3.00 |  10 |   1 |     9 |  18 |       6 |
| lines | 8.67 |  28 |   1 |    27 |  52 |       6 |
'-------+------+-----+-----+-------+-----+---------'

集計は --result オプションで指定します。

$ plmetrics --tar http://cpan.metacpan.org/authors/id/B/BA/BAYASHI/Statistics-Swoop-0.02.tar.gz --result method
lib/Statistics/Swoop.pm
.----------------------.
|         | cc | lines |
+---------+----+-------+
| minimum |  1 |     1 |
| _calc   | 10 |    28 |
| maximum |  1 |     1 |
| average |  1 |     1 |
| new     |  4 |    10 |
| result  |  1 |    11 |
'---------+----+-------'

詳細は --help で。

    plmetrics [--module=<module> | --file=<file> | --dir=<dir> | --git=<git_repos> | --tar=<tar_url>] [--result=<result>] [--sort]

    OPTIONS:

        --module     local module name
        --file       local file path
        --dir        local directory path
        --git        git repository
        --tar        URL of tar.gz

        --sort       sort result table
        --result     kind of result(module*|methods|cc|lines|files) *default

measureperl-checkstyle

Perl::Metrics::Lite に同梱されている measureperl-checkstyle は、オプションで計測値の閾値を渡して解析結果を XML で受け取ることができます

$ measureperl-checkstyle --max_sub_lines 60 --max_sub_mccabe_complexity 10 --directory /home/bayashi/dev/_modules/WWW-Pastela/lib
<checkstyle version="5.1">
  <file name="/home/bayashi/dev/_modules/WWW-Pastela/lib/WWW/Pastela/App.pm">
  </file>
  <file name="/home/bayashi/dev/_modules/WWW-Pastela/lib/WWW/Pastela.pm">
    <error line="23" column="1" severity="error" message="'paste' method cyclomatic complexity is 25" source="com.puppycrawl.tools.checkstyle.checks.metrics.CyclomaticComplexityCheck"/>
  </file>
</checkstyle>

という感じで、閾値を超えたファイルがレポートされます。

Jenkins さんに食わせるのに便利ですね!

Test::Perl::Metrics::Lite

Test::Perl::Metrics::Lite を使用して、メトリクス測定結果を testing することができます。いわゆる xt などに入れて活用すると良いと思います。

perl_metrics.t

use Test::Perl::Metrics::Lite (-mccabe_complexity => 10, -loc => 100);
all_metrics_ok();

という感じです。簡単ですね!

ディレクトリ単位やファイル単位で計測から除外することもできます。

use Test::Perl::Metrics::Lite (
    -mccabe_complexity => 10,
    -loc => 100,
    -except_dir  => [
        'some/dir/path',
        'some/dir/foo/path',
    ],
    -except_file => [
        'lib/Hoge/Foo.pm',
        'lib/Hoge/Bar.pm',
    ],
);
all_metrics_ok();

どうしても無視リストに加えて切り抜ける場合は、理由をコメントで添えると吉。

数値の意味

解析表示される数値の意味は、以下のようになっています。

File Metrics

項目名 意味
loc サブルーチンの行数
subs 関数の数
packages パッケージの数

Subroutine Metrics

項目名 意味
loc 行数
line_number ファイルでの行番号
mccabe_complexity 関数の複雑度

重要なのは loc と mccabe_complexity です。

loc は単純に関数の行数です。50~60行程度におさえるのを目安として、最大でも100行は超えないようにした方が良いでしょう。

mccabe_complexity は関数の__循環的複雑度__のこと。

循環的複雑度(英: Cyclomatic complexity)とは、ソフトウェア測定法の一種である。Thomas McCabe が開発したもので、プログラムの複雑度を測るのに使われる。プログラムのソースコードから、線形的に独立した経路の数を直接数える。

個人的にいろいろ計測してみたのと、読みやすさ、やり過ぎない程度を勘案して、以下のような基準で運用してみると良いのではないでしょうか。

10 シンプルでテスタビリティも高いはず。しかし、意図的に関数を分割しすぎて全体の処理が見えにくくならないように注意が必要
11 - 15 通常はこの範囲に収まる。また、テストカバレッジを高く維持するにはこの程度でないと厳しい
16 - 20 ぱっと読んでちゃんと動くかな?というレベル。一部テストがまともに書けない状態になってくる
21 - 25 さらりとは読めない。できれば分割したいところ。おそらく細かいテストはもはや書けない
26 - 黒歴史化確定。といいつつも、処理内容によってはこの程度のものはありえます

たまに計測をして、リファクタリング対象をあぶりだすか、Test に組み込んで必ずクリアするようにするかは、ものによるかと思います。 ビジネスにおけるプロダクト(特に一般ユーザ向けのウェブアプリケーション)では、リリースのスピードをもとめられると思うので、その点も考慮しなければならないでしょう。 ただし、複雑度の高さが、やがてプロダクトの改修の足を引っ張るということは常に意識しておかないとただ計測するだけに終わってしまいます。

静的解析が、快適で楽しいコーディングの一助になれるといいですね!

サイト内検索