Galileo Figaro

常に初陣!

ドキュメンテーションコメントスキル向上 - 外から見えないもので説明しない

ドキュメンテーションコメントとは

ドキュメンテーションコメントは、 よく型定義やメンバなどの直前に書かれるコメントで、 その型やメンバの仕様を説明するものである。 ここで重要なのが、 「実装」ではなく「仕様」の説明であるということだ。

基本的には、その型やメンバの「利用者」に向けた仕様説明だと思った方がよい。 「実装者」に向けた説明ではないのだ。 もちろん実装者がその実装の過程で、 ドキュメンテーションコメントを参考にすることもあるだろう。 しかしそれは「このメソッドってどういう仕様だっけ」というような、 仕様を確認するために見るぐらいだろう。

外から見えないもので説明しない

前述のように、ドキュメンテーションコメントは 利用者に向けた仕様説明である。 そのため、実装者しか見えないプライベートな要素を使って 説明するのはよろしくない。

例えば、private なメンバの名前や、 ローカル変数の名前が、説明文中に登場するのはよろしくない。

例1

private bool hasValue = false;

/// <summary>
/// hasValue が true の場合に名前を返す。
/// false の場合は空文字列を返す。
/// </summary>
public string Name => hasValue ? name : string.Empty;

hasValue というフラグ名が説明文中に登場する。 どうやら、hasValue というフラグによって振る舞いが変わるようだが、 そのフラグは外部からは見えず、 利用者にとっては謎のフラグだ。

利用者に見せている要素のみで説明すると、 例えば下記のようになる。

/// <summary>
/// コンストラクタで名前が与えられていればその名前を返す。
/// そうでなければ空文字列を返す。
/// </summary>
public string Name => hasValue ? name : string.Empty;

あるいは、そのフラグを外部に見せてしまうという手もある。 その場合、フラグにもドキュメンテーションコメントを記載し、 true や false になる条件を書こう。

/// <summary>
/// コンストラクタで名前が与えられていれば true、
/// そうでなければ false。
/// </summary>
public bool HasValue { get; } = false;

/// <summary>
/// <see cref="HasValue"/> が true の場合に名前を返す。
/// false の場合は空文字列を返す。
/// </summary>
public string Name => hasValue ? name : string.Empty;

例2

private const int userNumMax = 999;

/// <summary>
/// 新しくユーザーを追加する。
/// </summary>
/// <exception cref="InvalidOperationException">
/// すでに userNumMax 人登録されている場合。
/// </exception>
public void AddUser(User newUser)
{
    // ...
}

どうやらこのクラスには、登録できるユーザ数に上限があって、 それを超えると例外を発生させるようだ。 ただ、userNumMax が外部から見えないので、 利用者は何人なら登録できるのか分からない。

上限人数が分かるように、

/// <exception cref="InvalidOperationException">
/// すでに 999 人登録されている場合。
/// </exception>

のように書いてもいいが、それだと「999」という数字を コード中の 2 カ所に書くことになり、DRY の原則に反する。 さっきよりマシではあるが。

なので、上限人数を利用者が見えるようにしよう。

/// <summary>登録できる上限人数</summary>
public int UserNumMax => 999;

/// <summary>
/// 新しくユーザーを追加する。
/// </summary>
/// <exception cref="InvalidOperationException">
/// すでに <see cref="UserNumMax"/> 人登録されている場合。
/// </exception>
public void AddUser(User newUser)
{
    // ...
}

余談だが、上限人数を外部に見せることはなにかと便利である。 例えば、ユーザーが見る画面に「最大○人まで登録できます。」というような 文言を表示するのにも使える。

例3

private readonly System.Timers.Timer timer = new System.Timers.Timer(1000);

/// <summary>
/// バックグラウンドで定期処理を開始する
/// </summary>
/// <exception cref="InvalidOperationException">タイマーが既に実行中の場合</exception>
public void StartPolling()
{
    // ...
}

このメソッドは、定期処理をタイマー (System.Timers.Timer) を使って実現している。 具体的なメンバ名 (timer) こそ出ていないものの、 「タイマー」という語は利用者にとっては初出だし、何のことか分からないかもしれない。

また、タイマーを使っているのは内部の事情であり、利用者にとっては関係のないことである。 定期処理を、タイマーで実現しようが無限ループで実現しようが、 利用者にとってはブラックボックスだ。

内部の要素を使わずに説明するとなると、 例えば、下記のようにするとよいだろう。

/// <exception cref="InvalidOperationException">定期処理が既に開始されている場合</exception>