XMLでのCheckstyleコーディング標準のカスタマイズ
Checkstyle構成ファイルの中身は、ソースコードの検証に使用される一連のモジュールを定義する標準のXMLファイルです。各モジュールは、1つの特定の種類のコーディング標準またはベストプラクティスに対応します。
モジュールは階層構造です。ルートモジュールは常にCheckerモジュールで、ここに他のモジュールが含まれています。モジュールは、サブモジュールを含むこともできます。有名なTreeWalkerモジュールもこの形式に倣っています。TreeWalkerモジュールはJavaソースファイルを解析し、サブモジュールで解析ツリーの各種要因を検証します。実際、Checkstyleモジュールの大部分はTreeWalkerモジュールのサブモジュールです。単純なCheckstyle構成ファイルの抜粋を以下に示します。
<module name="Checker"> <module name="TreeWalker"> <module name="JavadocMethod"/> <module name="JavadocVariable"/> <property name="scope" value="protected"/> </module> <module name="AvoidStarImport"/> </module> <module name="PackageHtml"/> </module>
モジュールの動作は、プロパティを使ってカスタマイズできます。各モジュールには一連のプロパティがあり、既定値が設定されています。プロパティをオーバーライドするには、モジュールタグの本文にプロパティタグを追加します。例えば、LineLengthモジュールの場合、最大行長の既定値は80文字です。80文字ではなく、70文字を超える行をチェックするには、次に示すようにmax
プロパティを設定します。
<module name="LineLength"> <property name="max" value="70"/> </module>
severity
プロパティは任意のモジュールに適用でき、表示されるメッセージの種類を決定します。例えば、モジュールを無効にするには、severity
プロパティをignoreに設定します。
<module name="LineLength"> <property name="severity" value="ignore"/> <property name="max" value="70"/> </module>
大部分のモジュールは、既定の設定で適切に動作します。JavadocTypeモジュールは、クラスとインターフェイスのJavadocコメントをチェックします。このモジュールを既定値で有効にするには、構成ファイル内でモジュールを宣言します(TreeWalkerモジュール内でネストする必要があります)。
<module name="JavadocType"/>
既定では、@author
タグは必要ありません。プロジェクトや会社によっては、これが必須の場合もあります。その場合は、次に示すように、このモジュールに対してauthorFormat
プロパティも定義します(この例の場合、NULL以外の文字列が該当します)。
<module name="JavadocType"> <property name="authorFormat" value="\S"/> </module>
命名規則をはじめ、多くのモジュールで正規表現が使用されます。例えば、パッケージ名では小文字の英字と数字のみを使用しなければならないという厳密なパッケージ命名規則を、以下に示します。
<module name="PackageName"> <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/> </module>
多くの会社やプロジェクトでは、標準のファイルヘッダー規則を使用します。Checkstyleには、これを実現するための多くの方法が用意されています。単純なケースでは、ヘッダーテンプレートを作成できます。このテンプレートは、一部の行は固定であり、開発者が変更できる行もあります。会社の標準で、以下に示すように、下部に著作権情報を記載するボックススタイルのコメントが課せられているものとします。
//////////////////////////////////////////////////////////////////// // My Project Title // A description of this file goes here. // // Copyright (C) 2006 My Company ////////////////////////////////////////////////////////////////////
これを簡単に実現する1つの方法は、上記のテキストから成る「java.header」という名前のヘッダーテンプレートを定義し、どの行を修正するかを指示することです。
<module name="Header"> <property name="headerFile" value="java.header"/> <property name="ignoreLines" value="2, 3, 4"/> </module> Suppose that all you need to do is to put a copyright line at the top of each file: // Copyright (C) 2006 MyCompany // All rights reserved
しかし、年は毎年変更する必要があります。このためには、以下に示すように、RegexpHeaderモジュールを使って行内の正規表現を定義します。
<module name="RegexpHeader"> <property name="header" value="^// Copyright \(C\) \d\d\d\d My Company$\n^// All rights reserved$"/> </module>
より複雑な正規表現を使用するために、ヘッダーを外部ファイルで定義することもできます。例えば、会社またはプロジェクトの標準で、ソース構成システムに基づく次のような動的要素を含むファイルヘッダーが必要であると仮定します。
//////////////////////////////////////////////////////////////////// // My Project Title // File: $Id$ // A short description goes here // // Last modified $Date$ by $Author $ // Copyright (C) 2006 My Company ////////////////////////////////////////////////////////////////////
これは、RegexpHeaderモジュールおよび外部ファイルテンプレート(この例の場合はjava.header)を使って設定できます。
<module name="RegexpHeader"> <property name="headerFile" value="java.header"/> </module>
この場合の「java.header」ファイルは、次のように指定されています。
^//////////////////////////////////////////////////////////////////// ^// My Project Title ^// File: \$Id.*\$$ ^//.*$ ^// ^// Last modified \$Date.*\$ by \$Author.*\$$ ^// Copyright \(C\) \d\d\d\d My Company ^////////////////////////////////////////////////////////////////////
この他にも、多くのモジュールを有効化し、構成できます。詳細については、Checkstyleのドキュメントを参照してください。
Checkstyleテストの抑制
場合によっては、正当な理由から、特定のコードセクションでコーディング標準に違反することがあります。例えば、次のコードは、各百分位の生徒のリストを抽出します。
for (int i = 1; i < 100; i++) { List<Student> students = extractCentile(i, examResults); ... }
このコンテキストでは、例えば値100の使用は明白であり、これをONE_HUNDREDという定数に置き換えてもほとんど意味はありません。Checkstyleでは、さまざまな方法でこの問題に対処できます。こうした特殊ケースに対処する最も簡単な方法は、SupressionCommentFilterモジュールを使用することです。このモジュールによって、あるセクションのコードに対するCheckstyleが無効になります。
// CHECKSTYLE:OFF - 100 is not a "magic number" in this case for (int i = 1; i < 100; i++) { // CHECKSTYLE:ON List<Student> students = extractCentile(i, examResults); ... }
XML構成ファイルに関連するSuppressionFilterを使用する方法もあります。この方法の場合、より詳細な抑制を指定できます。この方法は、大きなコードブロックや、複数のクラスにわたってルールを無効にするときに便利です。
<module name="SuppressionFilter"> <property name="file" value="docs/suppressions.xml"/> </module>
上記のコードは、「suppressions.xml」を呼び出しています。これは、特定のクラス、または特定クラス内の特定行に対する特定のチェックを無効にするために作成する必要があるファイルです。次の例では、すべてのJavadocチェックがCatalog
クラスの先頭の50行で無効になり、MagicNumberCheckがすべての単体テストクラスで無効になります。
<!DOCTYPE suppressions PUBLIC "-//Puppy Crawl//DTD Suppressions 1.0//EN" "http://www.puppycrawl.com/dtds/suppressions_1_0.dtd"> <suppressions> <suppress checks="Javadoc*" files="Catalog.java" lines="1-50"/> <MagicNumberCheck(suppress checks=" files="*Test.java"/> </suppressions>
この方法の場合、「suppression.xml」ファイルを最新の状態に維持するために、余分な保守作業が必要です。また、開発者はワイルドカードを使いたがりますが、これは、CheckStyle監査の効率を低下させてしまいます。実際、この方法はあまり使用すべきではなく、他の方法を考慮し、他に方法がない場合に限って使用してください。
ビルドプロセスへのCheckstyleの統合
コーディング標準を定義し、同意したら、これを日常の業務に統合する必要があります。各開発者のマシンのIDEにCheckstyleプラグインを統合するのもよいでしょう。ただし、コーディング標準は、実際にはプロジェクト全体で組織的に実行され、検証されることが必要です。毎晩のプロジェクトビルドがこれに適しています。
CheckstyleはAntタスクと共に配布され、HTMLフォームのレポートを生成できます。Mavenは、Maven Checkstyleプラグインを通じて、Checkstyleレポートをそのまま統合します(図6を参照)。どのようなビルドツールを使用する場合でも、Checkstyle監査はプロジェクト全体で少なくとも1日に1回は実行して、プロジェクトのWebサイトで結果を公開します。
プロジェクトのCheckstyle構成ファイルをプロジェクトのソース管理下に置き、開発者の作業環境とビルドツールの両方から同じファイルを参照するとよいでしょう。こうすることで、開発者のマシンとビルドプロセスに同じ標準が適用されます。
コーディング標準の導入
ソフトウェアプロジェクト管理における他の多くのものと同様、スタッフの適切なスキルは、新しいコーディング標準の実装の成功につながります。
まず、プロジェクトの一番の優先順位を明確にすることが必要です。管理者(プロジェクトマネージャと上級管理者の両方)は、コーディング標準が重要であることを開発者に理解させる必要があります。そうでなければ、コーディング標準は決して実行されません。コード監査を自動的に生成すること(および公開すること)と、これを開発者の日常業務に組み込むことは別物です。ここでは、個々の教育や指導が役立ちます。プロジェクトミーティングで、コードの監査結果を検討する方法もあります。使用する方法にかかわらず、開発者の賛同を得続けることが重要です。
コーディング標準とコードレビュー
自動的なソースコードの監査が、コードレビューに代わることは決してないことに注意してください。コードレビューは、適切に使用すれば、ソフトウェアの品質を向上する強力なツールです。コードレビューは本質的に人間による作業であり、効率的であるためには人間の判断に大きく依存します。
しかし、Checkstyleレポートでは、さまざまなコーディング標準を構成する多数の面倒なチェックが自動的に行われるため、コードレビューが簡単化され、高速化されます。これにより、コードレビューアはより高度な問題に集中できるようになりますし、コードの簡潔性と可読性が向上するため時間の節約にもなります。
コーディング標準を適用すると、最初のうちは、開発者が新しい作業方法に慣れるまで少し時間的なロスが出ます。この点については、開発者と管理者の間であらかじめ話し合っておく必要があります。コーディング標準はプロジェクトと会社のマネジメントに大きく貢献すると開発者が感じれば、コーディング標準は、開発作業の一部にすぐに組み込まれます。開発者がコーディング標準を完全に実践するようになれば、最小限の負担で、明らかなメリットを得ることができます。