CheckstyleとJava。 自動コード検査は役立ちますか?





最近、コードレビューの自動化と最適化、コードインスペクション、および大規模プロジェクトのコードを適切な形式で維持するその他の方法に関する記事 (例えば、 記事1記事2記事3 )がHabréで顕著に頻繁になりました。



定期的な読者は以前の投稿( firstsecond )に既に出会っていて、同僚がJavaライブラリCheckstyleの使用について話し、その拡張に関する共同の経験を共有したと思います。



Checkstyleの追加チェック(チェック)を記述するためのチームの最新の取り組みは、Eclipse CheckstyleプラグインEclipse-cssevntu-checkstyle 1.5.3 、2012年9月4日)のアドオンの新しいアセンブリに含まれていました。



Javaコードを記述する段階でエラーの検索を自動化する実験を続けています。 Checkstyleの独自の小切手を書くのは簡単であるか、むしろかなり簡単であることを確認しました! 開発において真にユニークで有用な小切手を書くことはより困難です(さらに、新しい小切手を共有することについて開発チームのすべてのメンバーと後で合意することはさらに困難です)。 この投稿では、Checkstyleの新しいチェックを開発する方向でのチームの最新の成果について説明します。 また、以下では、Checkstyleライブラリ、Eclipse Checkstyleプラグイン、およびアドオンの操作原理、有用性、制限について少し強調したいと思います。



開発には、プログラマーの多大な努力と注意が必要です。 時間は止まりません。顧客の希望は変わり、プロジェクトは肥大化し、プログラムコードは開発者によって安全に忘れられ、時間とともに時代遅れになります。 コードを共同で構造化し、常に適切な状態に保つようにしなければなりません。 これには、可能なすべての手段が使用されます。コードのレビュー、リファクタリング、メトリックによるオウムのコードの「特性」の測定など。このようなチェックとコードの再編成には多くの時間と開発者からの神経細胞が必要です。 一方、肯定的な点があります。開発会社に定期的なコードレビューが存在するため、「良い」および「正しい」コードを記述するための一般的なルールが出現し、統合されます。 これらのルールのほとんどは、会社で一般に受け入れられている標準になります。多くの場合、企業で新入社員に最初に教えられるのは、会社のルールとコード作成標準です。



Joshua BlochのEffective JavaやJava Puzzlersなど、「良い」および「安全な」コードを書くことをテーマに多くの本が書かれています。 これらの本には、「正しい」プログラミングの長年の経験が含まれており、これらの本のヒントのほとんどは、企業標準になる価値があります。



しかし、「有能な」プログラミングの標準とルールがどれほど普遍的で良いものであっても、それらをすべて学び、覚えて、常に念頭に置くことはほぼ不可能です。 さらに、「良い」コードを書くためのすべてのルールを暗記していても、プログラマーは常に間違いを犯す権利を持っています(または標準ルールに対する彼自身のビジョン)。 初心者の開発者は単に無知で「悪い」または安全でないコードを書くことができ、経験豊富なプログラマーは時間の不足のために急いで標準を簡単に忘れることができます。



基準と「祖先の経験」を順守しなかった場合、結果が異なる可能性があります。 コードのスタイルに関する規則に従わないと、コードを理解するのが難しくなります。 これは修正可能ですが、ほとんどの場合、開発者は単純に長い記述のコードに戻り、すべての標準に従ってリファクタリングすることを望みません。 古代のプログラミングの原則は、「すべてがうまく機能する場合」や「修正が気に入​​らない人」などのように機能します。=)コードの残りのエラーは、特に大規模なプロジェクトでは検出が難しい場合があります。 ここで、Checkstyleライブラリは、開発者のヘルプにアクセスする必要があります。これは、事前に構成されたプログラミング標準とのエラーおよび矛盾を示し、場所だけでなく、コードの各問題領域の問題の原因も表示します



ほとんどの場合、Checkstyleは、開発者がコードのスタイルを維持し、潜在的に危険な状況を特定するのに役立ちます。 また、Checkstyleを使用して、ソフト(またはソフトではない)形式で、Java開発者に特定の標準および規則に準拠するコードの記述方法を指示することができます。 「標準と規則」には、ブラケットとインデントの配置方法から潜在的に危険な状況まで、ほぼすべてを含めることができます。 さらに、Checkstyleによってチェックされる「問題のある」セクションとシチュエーションのセットは、Javaプログラミングで長年確立され、一般に認識されている「適切な形式」のルールに対応しています。



コードでエラー/スタイリングの問題を検出すると、Checkstyleは設定によって異なる動作をする場合があります。 「ソフト」設定では、ライブラリは存在するエラーのみを警告し、最も深刻な設定では、プロジェクト内のすべてのCheckstyle警告が修正されるまでビルドに失敗します。



Checkstyleには、デバッグ済みの構成がいくつか付属しています。そのうちの1つは、Sun Code Conventionsに従って最大限に構成されています。 これにより、すぐにCheckstyleを使用できます。 ただし、真剣かつ永続的にCheckstyleを使用する場合は、独自の構成を作成し、チェックを1つずつ設定することを含めて、徐々に適切な設定にすることをお勧めします。 これにより、ライブラリの機能を理解しやすくなり、含まれる各チェックが本当に役立つことを確認できます。 さらに、初心者のJava開発者である場合、Checkstyleをゼロから設定することは、Javaプログラミングの「良い形」を学ぶ良い経験になるでしょう。



特定のニーズに合わせて、Checkstyleに独自のチェックを追加することもできます。 私たちのチームは長い間小切手を書いてCheckstyleを追加してきましたが、開発では常に既製の小切手の多くを使用しています。 例:当社では、java.lang.NullpointerExceptionオブジェクトを作成することは不適切なフォームと見なされます。 どのプロジェクトにもNPEのインスタンス化がないことを確認するために、プラグインのEclipse Checkstyleプラグインセットに独自のチェックを追加し、特定のクラスのオブジェクトの作成を禁止し( ForbidInstantiationCheck )、チェックが「呪われる」 NPEをインスタンス化します。



独自のチェックを作成し、Checkstyleを改善する際に、Checkstyleエンジンのコードとチェック自体が高品質でわかりやすい方法で作成されることが非常に役立ちます。 )。Checkstyleの可能性を拡張し、Javaで記述された独自のチェックを追加するか、既存のチェックを変更する簡単な機会があります。 独自の小切手を作成してCheckstyleに追加するのは簡単です。 これを行うには、CheckstyleプロジェクトWebサイトおよびwiki指示に従って新しいチェック用のコードを記述し、 アドオンを使用して最新のCheckstyleアセンブリに追加します。 結果は、IDEのCheckstyleプラグイン、Maven Checkstyleプラグインなどにフィードできる、再構築されたCheckstyle jarアーカイブになります。 既存のチェックの中から、独自のサンプルを作成する良い例を見つけるのは簡単です。そのため、初心者のプログラマーでも、Javaの経験がなくてもCheckstyleのチェックを作成できます。



他のソフトウェア製品と同様に、Checkstyleには長所と短所があります。 利点は単純です。カスタマイズの利便性と柔軟性、多数のさまざまなルール(チェック)のサポート、独自のチェックを記述する機能、およびライブラリへの組み込みの容易さです。



ライブラリの主な欠点は、すべてのCheckstyleチェックが単一のJavaファイルの制限を超えることができないことです。 また、チェック中に、Checkstyleはすべてのコメントを省略しますが、これは、私見では致命的ではありません。



Javaコードの検証は、次のスキームに従って、常にChecktyleによって実行されます。
  1. LL文法に基づいて、Checkstyleで使用されるANTLRエンジンは、使用されるJavaのバージョンの仕様に一致するJavaパーサーを生成します。
  2. 結果のパーサーを使用して、Javaコードは抽象構文解析ツリー(Abstract Synthax TreeまたはAST)の形式で表現されます-1つのJavaファイルに対して1つのツリー。 受信した各構文ツリーの構造は、ほぼ次のとおりです。

  3. 各ツリーの各頂点は、含まれるすべてのチェックによって処理されます。チェックでは、対応するタイプの頂点が入力として示されます。 構文ツリーの頂点を処理する順序は、コードを読み取るときのシーケンスの実際の順序(左から右、上から下)に対応します。
  4. 見つかったすべてのエラーについて、適切な警告が生成されます。


サプリメントについて少し



2年間のプラクティスを通じて、数人のチームがCheckstyleの機能に精通し、Checkstyleの既存のチェックの数を増やしました。 それらのほとんどを「SevNTU-Checkstyle」という別のプロジェクトに持ち込みました。 (参照:SevNTU-セヴァストポリ国立工科大学、私たちのチームのほとんどは、この大学の元学生または現在の学生であり、Reveredata LLC会社のセヴァストポリオフィスのJava開発者によって監督されています。プロジェクトの本質は、チェックのセットCheckstyle新しいチェック(および実際のプロジェクトでリアルタイムにテストする)は、Checkstyleプロジェクトの所有者に各チェックを送信する必要なく、公式のチェックセットに受け入れられるのを待機しません。 過去に見てきたように、Checkstyleプロジェクトの創設者は非常に忙しく、高品質のコードのアイデアを共有していません(各修道院には独自の憲章があると言われています)。したがって、ほとんどの場合、彼らは新しい提案に応じず、独自のパッチトラッカーで修正し、Checkstyleに品質テスト済みのチェックを追加しないこともあります。一般に、Checkstyleの機能を拡張したり、ニーズに合わせてチェックを変更したりする場合、これはもはや障害ではありません。



約1年前(11/09/11)、私たちのプロジェクトはEclipse Checkstyleプラグインの一部となり、 Eclipse-csの 「拡張機能」になりました。 Eclipseの他のアドオンと同様に、更新サイトから簡単にインストールできます。 インストールプロセスは、2つの簡単なポイントで構成されています。



  1. Eclipseを開きます。
  2. 更新サイトの[ヘルプ]-> [新しいソフトウェアのインストール] URLであるeclipse-cs.sourceforge.net/update/にアクセスし、両方のdaws、つまり -Checkstyle-plugin自体の実際のインストールとそれに追加するものを選択します。


さらに、リンクを手動で入力しなくても、 Eclipse Marketplaceからアドオン(およびEclipse-cs自体)をインストールできます。



Eclipseを再起動し、新しいCheckstyle-configuration(Window-> Preferences-> Checkstyle-> New ...)を作成した後、25の追加チェックを持つグループがCheckstyle設定に表示されます。





付録に含まれる25のチェックのほとんどは、「コードスタイル」をチェックしませんが、潜在的な危険を探します(もちろん、これは、Checkstyleを使用して問題を明確に特定できる場合にのみ当てはまります:バイトコードを分析せずに複数のJavaファイルを一緒にチェックする)。



サプリメントの各チェックの簡単な説明はページにありますので、そのうちのいくつか、より正確にはコードを個人的に作成または編集したものについてのみ詳しく説明します:



ChildBlockLengthCheck-ネストされた演算子のサイズの割合をチェックするチェック(演算子の本体が占める行数を比較します)。 ネストされた演算子の本体サイズが1レベル上の演算子のサイズのN%を超える場合、このチェックは警告を表示します。 チェックは、ネストされたステートメントがm行を超える場合にのみ警告を表示します。 これは、画面に完全に収まらず、親ブロックの行を多く占有しているブロックを見つける必要がある場合に便利です。



avoidModifiersForTypesCheck-指定されたタイプのオブジェクトに対して、静的、最終、一時、揮発性の4種類のキーワードの1つ以上の使用を禁止できます。 パラメーターとして、4つのキーワードのそれぞれに対するこのチェックにより、目的のタイプの名前形式を指定する4つの個別の正規表現を指定できます。



AvoidModifiersForTypesCheckの使用例:ULCグラフィックライブラリオブジェクト(ULCComponents)は静的であってはなりません: link 。 したがって、Checkstyleでは、クラス名が「ULC」などで始まるすべてのオブジェクトへの「static」キーワードの割り当てを禁止することは非常に合理的です。



CauseParameterInExceptionCheck-開発者に、独自の例外であるクラスの少なくとも1つのコンストラクターのパラメーターとしてExceptionまたはThrowableを指定することを強制できます(カスタムExceptionコンストラクターのパラメーターの1つとして必要な原因)。



独自の例外を表すクラスは、クラス名で検索されます(入力パラメーターとして指定された正規表現を使用)。



また、チェックでは、一部のクラスを名前で無視する可能性があります-再び正規表現を使用します。



ForbidsCertainImportsCheck-正規表現による特定のパッケージ/タイプのインポートを禁止するチェック(このチェックは対応するSonarチェックに似ています)。



ForbidInstantiationCheck-指定されたタイプのオブジェクトのインスタンス化を禁止するチェック。 使用例:プロジェクト全体のレベルでjava.lang.NullPointerExceptionオブジェクトの作成を禁止する必要があるとします(当社では、NPEオブジェクトの作成は不適切なフォームと見なされます)。 パラメーターとして、チェックはインスタンス化が許可されていないクラスへの修飾パスのコンマ区切りリストを受け入れます。



«java.lang.NullPointerException, your.custom.Class, etc.»







ReturnCountExtendedCheck-メソッドとコンストラクターのreturnキーワードの数をチェックするチェック。 チェックには柔軟な無視設定があり、その助けを借りて、n個以上のreturnステートメントを持つメソッドの書き込みを禁止することはできません。 このチェックでは、「return」ステートメントの「カウント」のみが可能です。 また、このチェックにより、正規表現を使用して、名前によって一部のメソッドを無視できます。



AbbreviationAsWordInNameCheck-連続する大文字の数についてクラス名をチェックするチェック。 つまり -このチェックは、「MDCContextListener」などのJavaクラスの命名を禁止することを目的としており、名前を「MdcContextListener」に変更することを提案します。 クラス名を標準化するだけでなく、同様のチェックが必要です。 入力パラメータの助けを借りて、例外となる略語の名前をチェックするように設定できると便利です。



OverridableMethodInCtorCheck-コンストラクターからの再定義されたメソッドの呼び出しを禁止するチェック(NetBeansに存在するものと同様のチェック)。 ご存じのように、Javaでは、コンストラクターからオーバーライド可能なメソッドを呼び出すと、プログラムの動作が不明瞭になる可能性があります(このようなコンストラクターを呼び出すときのメソッドの結果は、予想とは異なる場合があります(例として、StackOverflow の問題に関するこの議論を見ることができます)。また、定義できないメソッドを呼び出すこともできます別の呼び出し、今回は既に再定義されたメソッド-この場合も、プログラムの「奇妙な」動作が開始される可能性があるため、再定義の禁止はJavaコードで「良いトーン」と見なされます コンストラクターから呼び出されるメソッド(およびコンストラクターのように機能するclone()およびreadObject()メソッド)これを行うには、コンストラクター(およびclone()およびreadObject())から呼び出される非静的メソッドにfinalキーワードが割り当てられます。 、またはスコープ修飾子private。



チェックの作成プロセスで見たように、Javaコードには、メモリ内のいくつかのファイルを開いている間にバイトコードを直接分析しないと検証が困難または不可能な状況が多くあります。 Checkstyleはこれを行う方法を知らないので、OverridableMethodInCtorCheckは完全にはほど遠いと言えます(主にCheckstyleの制限のため)。 一般に、Checkstyleではなく、コンパイルされたバイトコードで動作するPMDまたはFindBugsで、コンストラクターから再定義可能なメソッドへの高品質の呼び出しを検索することをお勧めします。



PS Eclipse Checkstyleプラグインが有用であり、アドオンが見つかることを願っています。 私たちが書いた一連のチェックはテストで十分にカバーされており、私たち自身のプロジェクトでテストされています。 ただし、バグを見つけた場合や新しいチェックのアイデアがある場合は、 githubリポジトリで問題を作成してください。可能な限り迅速に検討します。



それだけです、見てくれてありがとう)






All Articles