はじめに
社内で CIツール(Jenkins)の標準化を進めており、ビルド時にインスペクション(静的コード解析)を導入しようかと検討しています。
そこでどんなツールがあるか調べてみてFindBugsを実際に試してみました。
インスペクション
インスペクションツールには実行しないのでコンパイルせずにコードを解析しバグの可能性がある個所や品質を下げるコードをピックアップしてくれます。
またコーディング規約に沿っているかチェックするのもインスペクションにあたります。
インスペクションツール
Javaに対応しているインスペクションツールとしては以下のようなものがあります。
- checkstyle
- 定義したコーティング規約に沿っているか検査してくれます。
- FindBugs
- FindBugsで定義されているバグパターンと一致するコードを検知してくれます。
- PMDにも同様の機能があるようですが、FindBugsの方がバグパターンが多いためこちらを使われることが多いようです。
- PMD
- コードの複雑性を検知してくれます。
FindBugsを試してみた
今回はIntelliJにプラグインをインストールして使用してみました。
インストール手順
- プラグインダウンロード
- https://plugins.jetbrains.com/plugin/3847-findbugs-idea から最新のプラグインをダウンロードします。
- (現在の最新バージョンは 1.0.1 です)
- プラグインインストール
- ダンロードしたファイルを解凍
- 解凍したファイルを /IntelliJ/Install/dir/plugin 以下にコピーする
- IntelliJを起動/再起動する
以上でインストール終わりです。
実際に使ってみる
使い方は簡単です。
1. IntelliJを起動しプロジェクトを開く
2. サイドバーのプロジェクトを右クリック
3. FindBugs->Analyze Project Filesを選択
4. 解析するか聞かれるので Yes を選択すると解析を始めます
解析結果の例 (定期決済のコードを解析してみました)
文字列結合に + を使っていたケース
以下ツールによって表示された詳細です。
このメソッドは、ループの中で + を使用して String を構築していると思われます。
各々の繰り返しにおいて、String は StringBuffer/StringBuilder に変換、追加され、String へ変換されます。
各々の繰り返しで文字列が再コピーされ、増大すると繰り返しの数で二次コストの原因になる可能性があります。
for (j = 0; j < kanaHanZenTbl.length; j++) { if (kana.substring(i).startsWith(kanaHanZenTbl[j][0])) { // 次の文字が濁点付き半角ならまとめる if (0 <= j && j <= 25) { str = str + kanaHanZenTbl[j][1]; i++; break; } else { str = str + kanaHanZenTbl[j][1]; break; } } } |
この問題については以下のような修正案が提示されました。
// This is bad String s = ""; for (int i = 0; i < field.length; ++i) { s = s + field[i]; } // This is better StringBuffer buf = new StringBuffer(); for (int i = 0; i < field.length; ++i) { buf.append(field[i]); } String s = buf.toString(); |
効率の悪いMapイテレータ
以下ツールによって表示された詳細です。
このメソッドは、keySet イテレータから取り出されたキーを使用して、マップエントリの値にアクセスしています。
Map の entrySet イテレータを使用したほうが Map.get(key) ルックアップを回避するのでより効率的です。
for (String key : requestMap.keySet()) { String value = (String) requestMap.get(key); if (key.equals("tien")) { //内容が長いため21桁以上の場合は、先頭20桁のみ出力します。 if (value == null || value.length() <= 20) { LOG.info(key + " = " + value); } else { LOG.info(key + " = " + value.substring(0, 20) + "…"); } } else { // キー項目のみINFOで出力 LOG.info(key + " = " + value); } params.add(new BasicNameValuePair(key, value)); } |
ツールによって表示された詳細については全てこちらに記載されています。
どんな項目をチェックしてくれるのかも確認することができます。
おわりに
初めて静的解析をしてみて、当初思っていたよりも簡単に解析できてしまったことにおどろきました。
Jenkinsにも静的解析のJobを追加して品質向上に役立てたいと思います。
ちなみにGradleやMavenなど主要なビルドつーるにはプラグインがあるようです。
この記事を書いた人
-
新卒3年目で脱新人を目指してます。
フロントに興味を持ち始めた今日このごろ。
趣味は 麻雀 プログラミング 音楽。
運動不足を感じているため、ダンスを始めようかと思っています。
最近書いた記事
- 2019.06.26コンテナイメージの縮小
- 2019.05.27Chromeのユーザ切り替えで複数のAWS環境の管理をわかりやすくする
- 2019.04.15ECRのライフサイクルポリシー
- 2019.03.29KongでOAuth2の認証手順