若手SEを救いたい社畜の手記

わかすくしゅき

プログラミングにおいてJavaDoc/コードコメントの効果的な書き方について

2021年1月15日

このページに書いてあること

このページでちょろっと書いた、「意味のないコメント」についてさらに啓蒙が必要だと思ったので追記します。対象はJavaDocとコードコメントの両方です。

自分もハッピー、以後メンテナンスする人もハッピーになるためにプログラムを書く人の助けになれば。

ちなみにコードレビュアーからの目線となります。

つまり、後からコードレビューをした時に「これいらないでしょ・・・」とか「これ何してるかわからないな〜」という観点での記事です。

NGだと思う例2つと、こんな感じでどうでしょうという提案1つです。あくまでも、正解を提示とか大それた内容ではないので候補の1つとしてご検討くだされば。

  • NG例
    1.最もやばいと思うJavaDoc=詳細設計書パターン
    2.書かなすぎて何しているかわからない問題パターン

最もやばいと思うJavaDoc=詳細設計書パターン

ソフトウェア開発をやっているとたまに(否、結構)見かけるパターンです。

Javaのコード1行1行をJavaDocで書くという地獄のパターンとなっております。以下がその例です。
こういうJavaDoc見たことある方いませんか?クラス設計なんていう名目でこういうのが出てくることがあります。

	/**
	 * 処理を実行し、結果を返します。<br>
	 * <ol>
	 * <li>引数チェック<br>
	 * 引数をチェックします。
	 * <ol>
	 * <li>引数がnullでない場合<br>
	 * 処理を継続します。
	 * <li>引数がnullの場合<br>
	 * "false"を返して処理を終了します。<br>
	 * </ol>
	 * <li>ユーザー情報検索<br>
	 * {@link SampleLogic#search(String)}によりユーザー情報を検索します。<br>
	 * <ol>
	 * <li>ユーザー情報の検索が成功した場合<br>
	 * 処理を継続します。
	 * <li>検索結果がnullの場合<br>
	 * "false"を返して処理を終了します。<br>
	 * </ol>
	 * <li>結果返却
	 * @param str 文字列
	 * @return 処理結果
	 */
	public String execute(String str) {

		//引数がnullの場合
		if (str == null) {
			//"false"を返す
			return "false";
		}

		//ユーザー情報検索
		SampleLogic sml = new SampleLogic();
		str = sml.search(str);
		//検索に失敗していたら
		if(str==null) {
			//falseを返す
			return "false";
		}

		//trueを返す
		return "true";
	}

この時、以下のようなJavaDocが出てきます。見た目的にはまぁ普通ですね。

やばいポイント

まぁいくつかありますが・・・・

  • 作業量がエグい
  • コードを少し直しただけで,コードの日本語版であるJavaDocも直さないといけなくなる(修正量が2倍)
    コードを直すのが億劫になる。
  • そもそもこれを見たところでコードが正しいのかがわからない

こんなのが代表的だとおもいます。

でもこれって、大抵の場合時間がかかるくせに価値を産みません。

なぜなら、設計というのはどう実現するかを書くべきものであって、どう実現されているかを書くものではないからです。

先程の粒度のJavaDocはコードを書く前には記述することができません。ではどのタイミングで書かれているかというと、大抵の場合はコードを書いた後にコードに沿って書くことになります。
そうすると、設計の後にコーディングがくるという順序が守られていません。

コーディングの前に書けない設計になっているということは、それは設計書ではなということです。

このようなコメントは時間ばかりかかるくせに、作った瞬間からゴミになります。次の改修ではコードと乖離するでしょう・・・・

書かなすぎて何しているかわからない問題パターン

コーディングに自身のある人がやりがちなイメージです。(バージョン管理とかをあまり気にしないような人とか)
※あくまで私の周りでの傾向です。

例は非常に単純で、Oracle Javaに標準でついているJavaDocをイメージしていただけると近いです。

どれだけ複雑な処理をしていても、「●○をします」みたいな一言のJavaDocで終わらせてしまいます。

先に出した例程度のコードなら気にならないのですが、本当の業務システムでは業務処理本体の行数などはどうしても多くなります。その時に一言JavaDocだと大変なことになります。

	/**
	 * 処理を実行し、結果を返します。<br>
	 * @param str 文字列
	 * @return 処理結果
	 */
	public String execute(String str) {

		if (str == null) {
			return "false";
		}

		SampleLogic sml = new SampleLogic();
		str = sml.search(str);
		if(str==null) {
			return "false";
		}
		return "true";
	}

やばいポイント

これのやばさは、初回の開発では問題にならないところにあります。

例えば、複雑な処理をしているコードがあったとして、それのコメントが1行だけだったらどうですか?
どこで何をしてるのかの解析に時間がかかりませんか?

そうです。

改修を担当することになった時に辛いんです。この手のコメントは。

ただそれだけです。どう使っていいのかがわからないし、何をしてくれるのかがわかりません。

個人的に思う、こういうコメントを書いて欲しい

あくまで業務システムでの話です。

業務システムというのは、顧客の業務を代行するためのシステムであり、通常は基本設計を行って何を実現するのかを厳格に規定します。

つまり、Javaのコメントには基本設計で実現しようとしている機能のどこを担当しているのかということを書いて欲しいのです。

誰か他の人が改修をすることを前提として、そのためのコメントを書いて欲しいという話ですね。書きすぎも良くないし書かなすぎも良くない。

例えば、基本設計書に処理フローが書いてあることが多いと思うんです。
で、この時処理フローは次のように書かれていないでしょうか。
Sampleというコントローラークラスとかがあったとしましょう。

こういう設計があったとき、設計のこの機能はJavaのここでやってますということを明示してあげると後から見た時にすごく修正がしやすくなります。

あくまで一例ですが、以下のようなコメントはどうでしょうか。

	/**
	 * 処理を実行し、結果を返します。<br>
	 * <ol>
	 * <li>リクエストチェック<br>
	 * <li>データベース検索<br>
	 * <li>結果返却
	 * </ol>
	 * @param str 文字列
	 * @return 処理結果
	 */
	public String execute(String str) {

		//■リクエストチェック
		if (str == null) {
			return "false";
		}

		//■データベース検索
		SampleLogic sml = new SampleLogic();
		str = sml.search(str);
		if(str==null) {
			return "false";
		}

		//■結果返却
		return "true";
	}

ポイントは基本設計書とのマッピングです。基本設計書に出てくる言葉を使ってJavaDoc(=詳細設計書)を記述していきます。そして重要なのは、ソースコードにもそのコメント書いて基本設計書とマッピングさせるということです。
※ただし、コードコメントには処理の番号を書かないでください。HTML表記のJavaDocでは自動採番されますが、コードコメントは手動です。番号を入れてしまうと、間に1つ処理が入った時に地獄です。それ以降全部書き直さないといけません。
※※処理の詳細を説明するコードコメントと区別するために、JavaDocとマッピングしたコードコメントは先頭に目印の記号でも入れておきましょう。例の場合は「■」にしました。

少なくともこの辺にあるような「業務部分」に当たる処理・クラスはこのように書いておくと良いです。
で、実際のリクエストチェックの処理については特にそちらのクラスに委譲する。失敗した時などの処理は書く必要はありません。ここに書いても誰も見ないからです。

業務というのは常に変更が加えられていくものであり、その際基本設計書を真っ先に修正すると思います。この書き方をしておくと、基本設計書を修正した時に詳細設計書を見ればコードのどこを直せばいいかがすぐにわかります。また、詳細設計書の記述がソースコードにも1行ずつあらわれているため、ソースコードのどこをいじればいいかも一目瞭然です。

反対に「仕組みの部分」はこのような記述は不要で、もっと簡潔で大丈夫です。
なぜなら「仕組みの部分」は細かい設計を書かなくとも伝わることが非常に多いからです。

例えばHTTPS通信を実行するような場合、その手続きはもはや定型と言えます。

  1. 接続先のURLを定義して
  2. コネクションをオープンして
  3. ボティ電文を書き込んで
  4. 送信して
  5. レスポンスを受信して
  6. コネクションをクローズして

この流れになります。これはWebAPIにJSONを投げる場合も、POST電文の場合も、GETやDELETEの場合も、SOAP通信ですら同じです。つまりこの部分は業務を変更する場合でも改修の可能性が低いと言えそうです。

このような「仕組みの部分」はOracleのJavaDocと同じような感じで書いておけば十分でしょう。中身を見てコードの修正を行うことはないからです。

まとめ

JavaDocとコードコメントについて書きました。
基本設計書に登場する言葉を使って詳細設計やコードを記述することにより、無駄を省いてメンテナンス性を高めることができます。
この「登場した言葉を使っていく」というのはドメイン駆動設計などに通ずる考え方となります。

そうすると今後の改修の時に大幅に楽になります。
ただし、これを実現するためにはクラス設計がSOLID原則に基づいてOOPでいい感じになっている必要があります。
ちなみに、手続き方などで汚いコードになってしまっていると、このようなコメントは書けなくなることが多いです。
SOLID原則の概要はこちらの方が詳しく説明していただいてました。

つまり、クラス設計をSOLID原則に基づいて実施することは詳細設計やコーディングに非常に良い効果を生むということが分かりますね!

  • B!