エンジニアのためのJavadoc再入門講座

エンジニアのためのJavadoc再入門講座 現場で使えるAPI仕様書の作り方

エンジニアのためのJavadoc再入門講座 現場で使えるAPI仕様書の作り方

JavaDocで一冊本が書けるのか!?という驚き半分、興味半分で読んでみました。私の知り合いでJavaDoc厨と呼ばされている人がいて、その人に色々教えてもらったことを整理して本にした感じで、非常に良くまとまっているし現場で使えるTIPSばかりです。

いくつか例をまじえてご紹介

「メソッド名の日本語訳」はいらない!

例えばこんなのやつ。

/**
 * 従業員を検索します。
 */
List<Emp> findEmpAll(String id);

こんなJavaDocはまったく意味がない。むしろ書かない方がよい。本書には以下のように記述されています。

このメソッドに与えられたドキュメンテーションコメントは、実際にはドキュメンテーションコメントではありません。これはただ単に、メソッド名を日本語に翻訳しただけの文字列です。このようなドキュメンテーションコメントは、コード上に表現された内容以上の情報をいっさい提供しません。したがって、書くだけ無駄と言えます。

ただしこれには例外があって、フレームワーク等を利用した上で必須となるな単なる定義クラス類は対象外となること。例えばStrutsでいうとActionFormなんかがこれに該当する。このあたりはあらかじめプロジェクトでこのパッケージ、またはクラス群は「メソッド名の日本語訳」でもよいといった運用ルールを決めておくとよい。

では一部例外を除いて、通常はどんな内容を書く必要があるのか?

ドキュメンテーションコメントの基本

詳しい説明は本をよんでいただくとして、メソッドに対するドキュメンテーションコメントの基本をちょっとだけ説明します。メソッドに対するドキュメンテーションコメントの基本は以下の4つで構成されます。

  • 主説明
  • 引数の説明
  • 返却値の説明
  • 例外の説明

主説明は後に置いといて、まずは引数。引数に書くべき内容でもっとも優先すべきなのはメソッドの取り得る値の範囲を明確にすることです。例えば引数にnullは許容するのか?数値の場合であれば整数値、0、負の値が特別な意味を持つのか最小値、上限値は存在するのかと言ったようなことを記述します。あとは受け取ったオブジェクトの状態が変更されるか等。

次に返却値です。返却値で一番大事なことは値域を明確にすること。引数と基本は一緒です。nullを返すときがあるのか?はたまたbooleanの返却値ならば、どのような場合にtrueを返すのか?です。だめな例で良く見るのが、例えばオブジェクトのロック状況をbooleanで返す場合

/**
 * ...
 * @return ロック状態
 */ 

こんなJavaDocを書いていいのは小学生までです♪正しい大人は次ぐらいには書きましょう。

/**
 * ...
 * @return このオブジェクトがロック中の場合は {@code ture}
 */ 

また返却値のドキュメンテーションはもう一つ大事な側面があります。それはこのAPIを呼び出す側時に呼び出し元より参照されるドキュメンテーションになるということです。あたりまえのことを言っているようですがこれがとても大事で、よく至る所でnullチェックをするようなプログラムをみたりしますが、このようなドキュメンテーションを記述しておくことで呼び出し側でどのようなチェックを行えばよいかを容易に判断できるようになります。ちゃんとソースコード読めばそんなのわかるだろ!って言う話もありますが、これは担当者が分かれていた場合など非生産性的である現実的には無理です。特にこのようなドキュメンテーションは、Eclipse等のIDEとも非常に相性が良く、コードを書きながらJavaDocを表示させることによりリズムにのってコーディングできるといった効果も生み出します。

次は例外です。例外はどのような状況下でその例外が発生しうるかを記述します。またフレームワーク全盛期のこの時代、非検査例外をよく使うことがあります。非検査例外は本来、よほどの理由がなければ呼び出し側でハンドリングすべきものではないですが、場合によってはHibernateExceptionなどtry-catchの煩雑さを解消するために意図的に非検査例外にしているものもあります。つまり非検査例外においても呼び出し側でハンドリングする価値のある非検査例外も存在するということです。このような非検査例外はドキュメンテーションに記述すべきです。

最後に主説明です。主説明は主に、引数の説明、返却値の説明、例外の説明に書けない内容を記述します。たとえばそのメソッドが何を行うものなのかやメソッドを呼び出す上の前提条件はないか?またそのメソッドを呼び出したことによる副作用がないか?といったことを記述します。

可視性

まず始めに一言。

「privateに対するドキュメンテーションコメント」は不要

この理由は2つあって、1つはprivateは外部に公開されるものではないので書く必要がない。もう一つの理由はprivateは内部の実装であるため、頻繁にリファクタリングによって処理内容が変わったり、メソッド統合/分割が行われるため現実解としてドキュメンテーションコメントの維持管理難しいという問題があります。リファクタリングの話はここでは言及しませんが、リファクタリングは通常必然的に行われるものであり、リファクタリングを行わないという答えは基本的にあり得ません。

またprivate意外でもか可視性という意味でpublic、protected、interfaceに書くドキュメントテーションコメントの意味が異なりますので、誰のためのドキュメンテーションコメントであるか?を強く意識して記述する必要があります。

アノテーションを活用しよう

あまり活用していない人が多いような気がします。メジャーどころの@author、@param、@return、@throwsといったところはEclipseがデフォルトで自働生成するJavaDocに含まれるということでよく見ます。ただこれ以外に@deprecated、@code、@link、@see、@since、@inheritDocといったような非常に便利なアノテーションが用意されていますので積極的に活用しましょう。

@authorの個人的なこだわりとしては@authorにはきちんと自分の名前を記述しろ!というところです。よく自分の会社名とか納品先の会社名とか書く人がいるのですが、特別な指定や制限がないかぎり@authorには自分の名前を記述すべきだと思っています。これは本書に書かれていることとは反対のこと言っています。なんでかというとプログラマーは自分の書いたコードに誇りと責任を持て!以上。あ、あとここはSVNとかのアカウントと同じものを使うと、アカウント名が統一できてわかりやすかったりします(同じものにしたからと言って何か連携ができるわけではないですが。もしかしたら何かある?)。

運用の話

ポイントはいかに機械にチェックさせるかです。この手のJavaDocの記述というのはコーディング規約で規定されてたりしますが、たいがい異常な長さで、よくある最悪のパターンでは結局読まれないでコーディング規約無視というような話もあります。最後に人間の目でチェックするというのも考えもので、どう考えてもコストに対するメリット(価値)は得られないでしょう。

で、どのように機械化させるかというと以下の三つを使います。

一つ目と2つ目はEclipseに依存してしまうことになりますが、まぁJava開発においてEclipse以外を使うことも少ないかと。コードフォーマットはEclipseソースコードの整形を行うときの設定です。JavadocでいうとJavadocは整形対象にするか?@paramでパラメータ名以降は改行するか等の設定を行います。基本はCheckstyleで規定したコーディング規約に沿う形でコードフォーマットを作るのがいいじゃないかと思っています。こうしておくことで、Eclipseの3.4からの機能である、ソースコードの保存時に自動的に整形するという機能と組み合わせて使えるようになり、ソースコードの保存時にCheckstyleで規定したコーディング規約に沿う形の整形を行うことが可能になります。

コードテンプレートはEclipseソースコードの生成時や、コメントの生成時のテンプレートを作成することが出来ます。Javadocに関係するのはコメント生成時のテンプレートの部分です。余談ですがテンプレートに著作権のコメントとか設定しておくとEclipseで新しく.javaのファイルを生成したときに自動的に著作権を挿入できるので便利です。

なぜコードテンプレートを使うのかというとコードフォーマット、Checkstyleだけでは不十分だからです。実際にあったコードですが以下のようなものがありました。

/**
 * .
 * @param hoge .
 * @return .
 */
public int hoge(String hoge) {
  何かの処理
}

ちょwww おまwww という感じですが、あ、ちなみに言っておくと、JavaDocに書いてある「.」は何かを省略しているわけではありません。こういう人のためにコードテンプレートを活用します。例えばメソッドのコメントでは以下のように設定しておきます。

/**
 * ${todo} for ${user}
 * 
 * ${tags}
 */

こんな感じで書いておくとEclipseJavaDocを生成したときに

/**
 * TODO for yamkazu
 * 
 * @param hoge
 */

みたいなコードが生成されます。心理的にアカウント名でTODOとか書かれるとJavaDocを書きたくなる率はあがるんじゃないでしょうか?CIのXFDに通じるものがありますね。ついついちゃんと書きたくなる症候群に陥りますね。ちなみにTODOと書いておくとEclipseでも一覧として参照できますし、MavenやHudsonといったツールでも一覧を取得できます。簡単に言うと見える化です!あ、念のため言っておくとJavaDoc生成時にEclipseのショートカットで自働生成させていないような人は私はプログラマーとして認めません!

このように、コードフォーマット、コードテンプレート、Checkstyleを組み合わせると効果的に機械にチェックさせることが出来ます。

どのように設定を共有するか

やり方は2つあります。

  • 設定ファイルをエクスポートして配布し、開発者のEclipseにインポートしてもらう
  • .settingsディレクトリ等のeclipseの設定ファイルを含めた形でプロジェクトを構成管理する

はじめは前者の方でやっていたのですが、問題として、設定ファイルを配っても適用してくれるか保証されない(実際設定してませんでしたとかある)。また再配布時/再設定に多少手間がかかるということです。後者の.settings方式はEclipseのプロジェクト保存形式のまま管理されるため、それはSVN等で管理しておけばプロジェクトをダウンロードした時点で自動的にこれらの設定が適用されますし、再配布の際も開発者にsvn updateをやってもらうだけなので運用が楽という利点もあります。なんてと言えばIDEEclipseに固定されてしまところでしょうか。また余談になりますが、FindBugsの設定がエクスポートできないというの制約があるため、.settingsで共有する方が色々ご利益がある気がします。

ただ.settingsにも問題があってEclipseのworkspace共通といった設定には関与できないというところで。例えば、Eclipseではpublic protectedといった修飾子、メソッド、フィールドといったものを整形するときにソートするという機能がありますが、これはプロジェクトごとに設定が行えずworkspace共通の設定になるため、.settingsで共有するといったことが出来ません。

その場合は、その部分については諦めるというのが一つの手です。というのは機械でチェック(設定)出来ないなら、必ずしも開発者が正しく設定してくれる保証もないですいし、最終的に必然的に人の目で保証しなくていはいけなくなる場合があるので、コストがとたんに高くなります。もし、どうしてもそのようなworkspace共通設定といったものにも、制約を持たせたいといった事がある場合は、事前にwiki等でコーディング前に共通の設定変更として作業をまとめておくといった運用が良いかと思います。

まとめ

大事なことなので2度いいますが、コストに対するメリット(価値)を良く考えてプロジェクトでルールを定めてください。最近JavaDoc厨と呼ばれる人もいますし、実際JavaDocを書き始めると楽しくて、ついついpirvateメソッドにまでJavaDocを書いてしまったり、徹底的にコーディング規約に準拠させたいがために人間の目によるチェックをやったりと、どう考えても価値のない(低い)作業に力を入れる事だけはさけましょう。CIでも良くいっているのですが、機械に出来る事、機械が得意な事は積極的に機械にまかせ、人間は人間にしか出来ない事にもっと注力しましょう。