コメント概論

こんにちは、K.Y(HN Rerurate_514)です。
今回、リーダブルコードを読んでので読書ログなんですけど、コメント文の書き方について知見を得たので共有しようかなと思います。

概要

コメントとは、基本的にコードを詳しく説明してはならない。
コメントは、コードの可読性を著しく下げることを常に留意するべきである。

実論

不要なコメント

例えば、以下のコメントはいかなる場合においても役に立つことはない。

//これはUserクラスを定義している。
class User(){
	//名前を格納する変数
	var name : String
	
	//パスワードを格納する変数
	var passward : Passward
	
	//コンストラクタ
	constructor(name : String, passward: Passward){
		this.name = name
		this.passward = passward
	}
	
	//これは名前を出力する関数である
	fun printName(){
		//名前の出力
		print("name = $name")
	}	
}

このコメント文は、クラスメンバそれぞれにコメントしている。
しかし、特に何かを説明しているわけではなく、そして新しい情報を得られるわけではない。

Success

見ればわかるようなものにはコメント文を付けない。

関数を代弁するコメント

関数の動作を示すコメント文は基本的にはつけてはいけない。
関数は名前でその動作を表すべきである、という考えからきている。

//これは与えられた値をpropertyによって制限を課す関数である。
//valueはpropertyに与えられたRange型によってvalueを編集する。
//例;0 < x < 100
fun editValue(value: Int, property: EditProperty){
	
}

このような関数はコメント文を書くより先に、関数名を見直す必要がある。
制限を課すという意味のenforce limitsという英単語を使用する。

fun enforceLimitsFromProperty(value: Int, property: EditProperty){
	
}

Success

コメントは、良いコード > 良いコメント + 悪いコードなので、関数の自己文書化を進める。

コメントは”考え”を記録する

コメント文は、情報を与えるように努める。

//このコードは、自作関数よりライブラリの関数を使用したほうが20%程度早かった。
//自作関数での計算回数が多いようだ。

コードが汚い理由を示してもよい。

//このクラスは汚くなってきている。
//サブクラスを作ったほうが良いかもしれない

このコメントはコードが汚いことを認めている。そして、修正も促している。このようなコメント文がなければ汚いコードは見ようとも思えない。

欠陥にコメント文を使用する

コードは絶えず進化していて、必ず欠陥が生まれてくる。
それを記録するのもコメント文の役割である。
ただし、注意してほしいのは欠陥の「履歴」を残すものではない。

以下によく使われる記法を記す。

記法概要
TODOあとでやること
FIXME既知の不具合があるコード
HACKあまりきれいじゃない解決法
XXX致命的なエラー
//TODO この関数を抽出したサブクラスを作成する
 
//FIXME 1が期待されるのに2が返ってきている
 
//HACK 線形探査で解決している。
 
//XXX NPEの可能性

定数を説明する

定数を定義する際には、必ず定数を作成した背景が存在する。
この背景を説明することで、この定数を詳しく理解することが出来る。

const IMAGE_QUALITY = 0.75    //0.75だとユーザは画質とファイルサイズの面で妥協しやすい

定数には、コメント文が必要ないと思われるかもしれないが、実はコード理解に大いに役立つ場合が多い。

何故この処理なのかを説明する

他のプログラマがこのコードを見た際に、「なぜこれはこうなんだ?」と思えるコードにはコメントで補足しておくのが望ましい。
そうしていない場合、意図せずして修正が加えられて欠陥が発生する可能性があるからである。

//このクラスはトランザクションの関係で一つしか存在させてはいけない。
//そのためシングルトンにしている。
object DataBaseController {
	fun create(){}
    fun read(){}
    fun update(){}
    fun delete(){}
}

Dartのシングルトン

前もって告知しておく

作成したコードに存在する「罠」を示しておくのもコメント文の役割である。
このコメント文があることによって、いきなりエラーが発生してしまった時でもある程度の予測がつく。

//この関数は1分でタイムアウトする
fun requestAPI(){}

全体像の把握

例えば、ソースコードを読んだだけでは伝わってこないシステムがある。
そういう、コードとコードのつながり(interfaceやオブザーバ)や、全体像に関わるものはより高レベルなコメントに記す。

//このクラスは複雑だが、やっていることは単なるキャッシュである。
 
//このクラスはファイルのパーミッションを扱う便利な関数が含まれています

Success

後からやってきた担当者にソースコードだけでは得られない情報を記しておく。

要約のコメント

例えば、イテレータの複数あるコードでは、コードを見ている最中にこんがらがってしまうかもしれない。
そうした場合は、コメント文で簡単に処理を記述する。

//顧客の購入した商品を取り出す
customerBoughtList.forEach{ productList ->
	productList.forEach{ sale ->
		
	}
}

まとめ

コメントすべきでないこと

  • コードからすぐにわかること。
  • ひどいコードを補うコメント。

記録すべきこと

  • 何故このやり方なのか
  • コードの欠陥をFIXMETODOによって示すこと。
  • 定数の設定された経緯

読み手の立場になる

  • コードを使用した際に、使用する側が驚いてしまう、予期できなさそうな操作がある場合は記録しておく。
  • クラスなどは、全体像を記しておく。

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

ほとんどの言語には、ドキュメンテーションコメントが存在している。
ドキュメンテーションコメントとは、インテリセンスに表示される内容を記すものである。
ただし、可読性を著しく下げてしまう場合もある。

/** * /

KotlinやTSなら/** */を使用する。

/**
* このクラスは、音楽再生にまつわるクラスです。
*/
class AudioPlayer{
 
}

ちなみにこの記法だと、引数や返り値を詳細に記述することが出来る。

/**
* この関数は与えられた二つの引数を足して返すものです。
*
* @param1 x 足される数
* @param2 y 足す数
*
* @return 二つの数の合計を返す
*/
fun calculatePlus(x: Int, y: Int): Int{
 
}

summary

C#なら/// <summary>を使用する。

/// <summary>
/// このクラスは、音楽再生にまつわるクラスです。
/// </summary>
class AudioPlayer
{
	
}

///

Dartなら///を使用する。

///このクラスは、音楽再生にまつわるクラスです。
class AudioPlayer{
 
}