📘

社内のプロダクト開発でコメントを書くときの考え方

2022/08/21に公開

はじめに

私が社内のプロダクト開発で、コメントを書くときに考えていることをまとめようと思います。個人の主観を元に書くので参考程度に読んでください。

社内プロダクトとは、社内の1チームで開発しているプロダクトを指し、社内の他のチームや、社外の不特定多数の人から利用されるものではないとします。プロダクトはWeb APIを想定しています。

サンプルコードはGoで書いています。

コメントを書く目的

コメントを書く目的は、ソースコードから読み取れる情報を補足したり、誤読を防ぐことで、
ソースコードの可読性を高めるためだと思っています。

コメントを書くことでソースコードから読み取れる情報は増えるため、コメントを書くことはメリットしかないように思えますが、デメリットもあります。次にコメントを書くことのメリット/デメリットについて説明します。

コメントを書くメリット

ソースコードから読み取れない情報を補足することができる

私は社内のプロダクト開発で、ソースコードには表れない実装した理由を記述するためにコメントを書きます。実装した理由をコメントとして残しておくことで、ソースコードを変更するときに、変更して問題ないかどうかを判断する助けになります。

例外として、ソースコードには表れない実装した理由でも、チームで共通認識がとれている内容であればコメントを書かないです。コメントを書いても書かなくてもソースコードの可読性に影響がないからです。

ただし、共通認識が今後失われる可能性があるならコメントを書きます。共通認識が失われる場合、実装した理由をチームメンバーがわからない状態になるので、ソースコードを変更することが難しくなります。共通認識が失われる可能性があるかどうかを判断する方法は、例えば、以下の2つがあげられます。

  • 新しいメンバーが入ってきたときに必ずインプットする内容か
  • チームが解散したり、プロダクトを別のチームに移譲するときに引き継がれる内容か

コメントを書くデメリット

開発効率が落ちる

コメントをどの程度書くか判断しなければならない理由は、ソースコードで管理するものが増えるほど、管理コストが増え、開発効率が落ちるからです。

管理コストが増えるとは、例えば、ソースコードを修正するときにコメントも直したり、コードレビューでコメントの日本語が伝わるものかどうかを確認する、などの作業が増えることを意味しています。コメントを書くことで、ソースコードの可読性を高める一方で、このようなデメリットも発生します。

どれくらいコメントを書くかは、会社、チームでコメントを管理するコストをどれだけ支払えるかに依存します。例えば、会社の技術戦略として、コメントを管理するコストを支払ってでもソースコードの可読性を上げたい場合、ソースコードからは読み取れない実装した理由をより具体的に書いたり、実装した理由以外の内容をコメントとして書いても良いと思います。

ソースコードの可読性が落ちることがある

ミノ駆動さんの良いコード/悪いコードで学ぶ設計入門の10章でも言及されていますが、ソースコードと比較してコメントの保守は見逃されがちです。ソースコードを変更しだが関連するコメントを修正しなかった場合、ソースコードとコメントの内容が乖離するので、ソースコードの可読性が落ちます。

例えば、コメントを書いた当時はエラーを返していたが、その後ソースコードのみ修正され、エラーを返さなくなった関数があげられます。関数でエラーを返していないのに、コメントではどういうときにエラーを返すか説明しているので、ソースコードが読みづらくなっています。

// getUsersByIDsは、idを元にユーザー一覧を返す関数です。
// XXX という条件でエラーを返します。
func getUsersByIDs(ids []string) model.Users {
...
}

別の例として、コメントを書くルールが統一されておらず、各々が勝手にコメントを書いてしまうこともあります。

以下のサンプルコードでは、getUsers関数ではコメントで関数の説明を書いていますが、getUserByID関数にはコメントがありません。チームメンバーは、関数にコメントを書くかどうかを自分で判断しなければならないです。

基本的に関数の処理はソースコードを読めばわかることです。混乱の元になるので、コメントを書く方針が無いなら、不必要なコメントは書かないほうがよいです。

func GetUserByID(id string) *model.User {
...
}

// ユーザー一覧を返す関数です。
func GetUsers() model.Users {
...
}

コメントを書く例

設定値の根拠

アプリケーション固有の設定値をセットすることがあります。コメントを書かなければ値の根拠がわからないです。

以下の例ではNekochan APIへのHTTPリクエストのタイムアウト値の根拠をコメントで書いています。

// Nekochan APIへのHTTPリクエストが正常に実施される場合、5秒以上かかることがないため、timeoutを5秒にする。
ctx, cancel := context.WithTimeout(ctx, time.Second*5)

条件分岐の理由

特定の値だけ条件分岐で別の処理にすることがあります。コメントを書かなければ何のために別処理にしているのかわからないので、ソースコードからは読み取れない意図です。

func suppressValues(m map[string]string) map[string]string {
	var res map[string]string
	for k, v := range m {
		// nekochanの値には機密情報が含まれているので値の消し込みをする
		if k == "nekochan" {
			res["nekochan"] = "*****"
		}
		...
	}
...
}

エラーハンドリングしない理由

確実にエラーが返ってこない、エラーが返ることがない関数やメソッドがあるときに、エラーハンドリングをしないことがあります。コメントを書かなければエラーハンドリングしていない理由がわからないので、ソースコードを変更するときに、関数の使い方やアプリケーションの動作環境を調べる手間が発生します。

// time.LoadLocationでは、実行環境にAsia/Tokyoのzoneinfoが無いときにエラーが返ってくる。
// DockerコンテナでAsia/Tokyoのzoneinfoをセットしているため、エラーが発生することがないのでエラーハンドリングしない。
jst, _ := time.LoadLocation("Asia/Tokyo")

ソースコードから読み取れる情報を補足すること以外でコメントを書く例

ドキュメント生成ツールで利用する文章

Goのソースコードのコメントからドキュメントを生成するツールを使う場合、生成したいドキュメントの内容に従ってコメントを書くことがあります。

コメントからドキュメントを生成するツールの例として、Godocswagがあります。

実装方法の説明、関数やメソッドの利用方法

OSSのソースコードや、複数のチームで共通利用されるライブラリのように、自チーム以外から利用されるプロダクトを開発しているときは、具体的な実装方法の説明や、関数やメソッドの利用方法をコメントとして書くことがあります。

私は複数チームで利用されるGoのサンプルコードを提供していますが、よく使うhttp.Transportのいくつかフィールドについて、使い方の説明をコメントとして書いています。

var client = http.Client{
	Transport: &http.Transport{
		TLSClientConfig: &tls.Config{
			// リクエスト先のサーバーの証明書の検証をスキップする。
			InsecureSkipVerify: true,
		},
		// HTTPのKeep-Aliveを無効にする。
		// TCPコネクションを使いまわさずに、異なるユーザーがHTTPリクエストをする状況を再現する。
		DisableKeepAlives: true,
	}
}

上記のサンプルコードは以下のスライドで使ったものです。
https://speakerdeck.com/yuyu_hf/dmm-go-4-load-testing-first-release?slide=22

コメントを書かない例

ソースコードからは読み取れない実装した理由

ソースコードからは読み取れない実装した理由はコメントに書いておいてほしい情報ですが、別のドキュメントにすでに書いてある場合は書かなくてよいと思います。ドキュメントは更新するが、コメントの修正が忘れ去られ、ドキュメントとコメントの内容の乖離が起こりがちです。

例えば、アプリケーション上の実装とビジネス上の用語の対応付けです。

type Task struct {
    ID          string // ID
    Title       string // タイトル
    Description string // 説明
}

「説明」というビジネス上の用語を「Description」と表現し、コメントで「説明」と補足しています。ビジネス上の用語を「説明」から「詳細」に変更したときに、ソースコードのコメントを修正し忘れて「説明」が残り続けることがあります。

ドキュメントに書いてある内容をコメントとしてどれくらい書くかは程度の問題だと思っています。コメントの保守運用にどれくらいのコストを払えるかをチームや会社で決めて、何をどの程度コメントとして書くかを考えるとよいと思います。

ライブラリの使い方の説明

ライブラリの使い方は、ライブラリのドキュメントを読む、コメントとして書かない、でよいと思います。チームメンバーへの知識のインプットのために書いている、という意見もありそうですが、別のドキュメントを用意するとか、ペアプロする、で対応できます。アプリケーションコードに直接関係ない内容をコメントとして残しておくと、ソースコードの視認性が悪くなったり、コメントを管理するコストが発生します。

// time.LoadLocationは、実行環境のzoneinfoにセットされたロケーション情報を返します。
// 実行環境のzoneinfoに"Asia/Tokyo"がセットされていない場合、エラーを返します。
jst, err := time.LoadLocation("Asia/Tokyo")

TODOコメント

今後対応する予定をコメントとして残しておくことがあります。直近で対応するなら書いてもよいと思います。対応期限も決めず、残り続ける場合は、意味のないコメントになる可能性が高いです。ソースコードの視認性も悪くなるので、コメントを消して、GitHubのIssueやタスク管理ツールで管理するほうが良いです。

// TODO: あとでリファクタリングする。
func GetNekochans() model.Nekochans {
...
}

リファクタリングで対応できるとき

実装方法の詳細をコメントで補足している場合です。例えば、コメントで実装方法について説明している処理を関数やメソッドにすることで、コメントで補足する必要がなくなることがあります。以下のようにサンプルコードを書いてみました。

// プレミアムユーザーを抽出する。
for user := range users {
	if user.MostFavoriteAnimal == model.Nekochan || user.MostFavoriteAnimal == model.Inuchan {
		newUsers.append(user)
	}
}

猫または犬が最も好きなユーザーはプレミアムユーザーということがわかります。リファクタリングとして、処理をmodel.Usersのメソッドとして用意し、名前をつけてあげることで、コメントで処理の詳細を補足する必要はなくなります。

premiumUsers := users.PremiumUsers()
newUsers = append(newUsers, premiumUsers...)

よくある意見

Google本で述べられてるGoogleのコメントの書き方を真似したい

Google本とはGoogleのソフトウェアエンジニアリングのことです。本の10章で、Googleでのコメントを書くルールについて書かれています。一部抜粋して紹介します。

Googleでのコードのファイルのほぼ全てはファイルコメントを含まなければならない。
Googleでは、全ての自由関数(free function)、もしくはクラスの公開メソッドは、その関数が何を行うかを説明するコメントを含んでいなければならない。

私個人の意見ですが、Googleではコストをかけてでも可能な限りソースコードの品質を上げるという方針にしていると思います。Googleほどソースコードの品質を上げることにコストをかけることができる会社やチームは多くないと思うので、安易にGoogleの方針を正しいと信じて真似しないほうがよいと思います。会社やチーム、そしてプロダクトにとってコスパの良い方針を考えるべきです。

コメントは英語で書くべき?

コメントを書く目的はソースコードの可読性を高めるためです。チームメンバーが最も読みやすい言語で書くほうが良いです。

また、開発で利用するツールによっては、ソースコードに英語以外の文字列を含めることができないことがあります。その場合、英語でコメントを書く必要があります。

まとめると、コメントを英語で書くかどうかは、以下の2つのポイントを考慮して決めればよいです。

  • チームメンバーが最も読みやすい言語か
  • 開発で利用するツールに制約はあるか

まとめ

本記事では、私が社内のプロダクト開発で意識しているコメントの書き方について説明しました。コメントを書くことはメリデメがあります。私の意見が正解というわけではないので、会社、チーム、プロダクトにとってコスパの良いコメントを書く方針を考えてみてください。

参考

Discussion