355.PMD(5)
初回:2024/03/13
PMDのソースチェックに関しては、前回までで終了です。
P子「終わりなのに続いているの?」※1
今回は、PMDで出来るもう一つの機能『Copy/Paste Detector』を使ってみたいと思います。
1.PMD の CPD(Copy/Paste Detector) とは
P子「聞くまでもないと思うけど、一応説明して」
内容としては、コピー&ペーストされたコードを見つけるという機能です。ソースコードの作成において、同じようなコードが複数の箇所に分散している状態は、バグの温床になりうるという事です。
P子「温床という事は、まだバグにはなってないという事?」
重複コードの問題点は、修正が必要になったときに修正漏れを引き起こしたり、Aコードを修正後テストしてOKでも、Bコードも同様に修正した所、類似コード(つまり同じではない)ため、Aと同じ修正では、Bはうまく動かないにも関わらず、テストを行わないとか緩いテストになっていたりするかもしれません。
P子「そんなの修正するコードはきちんと検証しなきゃダメでしょ」
つまり、本来なら1か所だけ修正してAPIレベルで検証すれば済むところを、関連するソースコードをひとつ残らず見つけて修正して検証する必要があるので、その際にミスする確率が爆発的に増えます。それが、バグの温床と言われるゆえんです。
そもそも、完全重複コードではなく微妙に改変されている訳で、本来修正が必要な個所の特定だけでも時間がかかりますし、発見できない事もあります。発見に時間がかかり修正ミスの可能性も高まり検証も時間がかかるので、良いことは何一つありません。
P子「なのに重複コードがこんなに多いのはなぜ?」
簡単な事です。コピー&ペーストでプログラムを作るのが簡単だからです。
《参考資料1》
https://enterprisezine.jp/article/detail/10412
コードが美しくないために起きる問題を考える(前編)―重複のあるコード/誤読問題
「EnterpriseZine」(エンタープライズジン)
小野 和俊[著] / 有馬三郎[著]
更新日: 2018/03/05
2.PMD の CPD の実行
PMDの第一回で、ソースチェックのコマンドラインを書きましたが、同様に、CPD の実行コマンドラインを示します。
Javaのパスを通したうえで、help を実行してみましょう
bin\pmd.bat cpd -h
Usage: pmd cpd [-Dh] [--ignore-annotations] [--ignore-identifiers]
[--ignore-literal-sequences] [--ignore-literals]
[--ignore-sequences] [--ignore-usings] [--[no-]
fail-on-violation] [--no-skip-blocks] [--non-recursive]
[--skip-duplicate-files] [--skip-lexical-errors] [-e=]
[-f=] [--file-list=] [-l=]
--minimum-tokens=
[--skip-blocks-pattern=] [-u=]
[-d=[,...]...]...
[--exclude=...]... [-z=[,
...]...]... [...]
Copy/Paste Detector - find duplicate code
[...] Path to a source file, or directory containing
source files to analyze. Equivalent to using
--dir.
-d, --dir=[,...]...
Path to a source file, or directory containing
source files to analyze. Zip and Jar files are
also supported, if they are specified directly
(archive files found while exploring a directory
are not recursively expanded). This option can
be repeated, and multiple arguments can be
provided to a single occurrence of the option.
One of --dir, --file-list or --uri must be
provided.
-D, -v, --debug, --verbose Debug mode.
-e, --encoding= Specifies the character set encoding of the source
code files
Default: UTF-8
--exclude=...
Files to be excluded from the analysis
Default: []
-f, --format=
Report format.
Valid values: csv, csv_with_linecount_per_file,
text, vs, xml
Alternatively, you can provide the fully qualified
name of a custom CpdRenderer in the classpath.
Default: text
--file-list=
Path to a file containing a list of files to
analyze, one path per line. One of --dir,
--file-list or --uri must be provided.
-h, --help Show this help message and exit.
--ignore-annotations Ignore language annotations when comparing text.
--ignore-identifiers Ignore names of classes, methods, variables,
constants, etc. when comparing text.
--ignore-literal-sequences
Ignore sequences of literals such as list
initializers.
--ignore-literals Ignore literal values such as numbers and strings
when comparing text.
--ignore-sequences Ignore sequences of identifiers and literals
--ignore-usings Ignore using directives in C#
-l, --language= The source code language.
Valid values: apex, coco, cpp, cs, dart,
ecmascript, fortran, gherkin, go, groovy, html,
java, jsp, julia, kotlin, lua, matlab, modelica,
objectivec, perl, php, plsql, pom, python, ruby,
scala, swift, tsql, typescript, vf, vm, wsdl,
xml, xsl
Default: java
--minimum-tokens=
The minimum token length which should be reported
as a duplicate.
Default: 0
--[no-]fail-on-violation
By default PMD exits with status 4 if violations
are found. Disable this option with
'--no-fail-on-violation' to exit with 0 instead
and just write the report.
--no-skip-blocks Do not skip code blocks marked with
--skip-blocks-pattern (e.g. #if 0 until #endif).
--non-recursive Don't scan subdirectiories.
--skip-blocks-pattern=
Pattern to find the blocks to skip. Start and End
pattern separated by |.
Default: #if 0|#endif
--skip-duplicate-files Ignore multiple copies of files of the same name
and length in comparison.
--skip-lexical-errors Skip files which can't be tokenized due to invalid
characters, instead of aborting with an error.
-u, --uri= Database URI for sources. One of --dir,
--file-list or --uri must be provided.
-z, --relativize-paths-with=[,
...]...
Path relative to which directories are rendered in
the report. This option allows shortening
directories in the report; without it, paths are
rendered as mentioned in the source directory
(option "--dir"). The option can be repeated, in
which case the shortest relative path will be
used. If the root path is mentioned (e.g. "/" or
"C:\"), then the paths will be rendered as
absolute.
P子「難しそうね」
そうでもありません。必要なのは、実行するソースコードのフォルダと、検出条件となる 最小トークン数だけです。
call 《独自にJavaの環境設定を行うbatファイル》 set SRC_PATH=c:\src call bin\pmd.bat cpd --dir %SRC_PATH% --minimum-tokens=100 > pmd_cpd.txt
3.まとめ
重複コードの検出は、多人数での開発や委託開発時のチェックに有効です。さらに、自分自身でも知らず知らず...いや、確信犯的にコピー&ペーストで開発してしまう事もあります。
P子「納期が近い時とか、ついつい、やりがちね」
とはいえ、やはりきちんとオブジェクト指向で設計して開発することで、重複コードを『出来るだけ』排除すべきだと思います。
P子「デザインパターンにも重複コードを避けるパターンって多いものね」
そして、重複コードの検出ツールも多数存在します。それだけ闇が深いのでしょう。
PMDに関しては、今回で終了です。皆さん、お疲れさまでした。
ほな、さいなら
======= <<注釈>>=======
※1 P子「終わりなのに続いているの?」
P子とは、私があこがれているツンデレPythonの仮想女性の心の声です。