エンジニアHubPowered by エン転職

若手Webエンジニアのための情報メディア

Rubyコミッター・Yuguiに学ぶ、コードに書くべき「適切なコメント」と「適切な場所」

Rubyコミッター・園田裕貴(Yugui)さんが、長年の経験で体得したソースコードに書くべき「コメントの技法」を教えてくれました。

プログラミングにおいて、どんな初心者でも書けるけれど、適切に書くのは上級者でないと難しいもの。それがコメント(=ソースコードに書かれている注釈やメモ)です。

不適切なコメントをつけても、プログラムの動作には影響しません。しかし、書き方の巧拙によって、コードの可読性や理解のしやすさには雲泥の差が出ます。良質なコメントが良質なコードをつくるのです。

今回はRubyコミッターでありgrpc-gatewayの開発者でもあるSupership株式会社の園田裕貴(Yugui)さんに、優れたエンジニアがどんな観点を持ち、どんなコメントを書いているのかを聞きました。

園田 裕貴(そのだ・ゆうき/@yugui
書籍『初めてのRuby』(オライリージャパン)の執筆者であり、Rubyコミッタ。スケールアウト(現Supership)の初期中心メンバーの一人として活躍をした後、Google Japan、Gengoを経てSupershipに出戻り、全社横断的な業務改善に取り組んでいる。

【コメントの技法1】外部との接点に書く

――園田さんはどんな箇所にコメントを書いているか教えてください。

園田:まず、外部との接点にはコメントを書くべきだと考えています。要するに、パッケージやモジュールなどの機能で、外から利用されることを想定しているもの。それが最初の候補です。

なぜかというと、プログラムがうまくモジュール化されているならば利用者はコードの内部を知る必要はないですが、呼び出すに当たり「どんな振る舞いをするのか」「何に気を付けるべきか」といった情報は知っておく必要があるからです。

例えば、引数が文字列型だとして「どんな形式の文字列であるべきなのか」までを言語仕様で制限できるものはそんなにないですよね。少なくとも、メインストリームで使われているプログラミング言語としてはすぐには思い当たりません。

パッケージやモジュールを外部から利用する人には、どんな形式の文字列を期待するのか情報提供しなければなりません。つまり、他者がそのコードを利用することを前提として、コードだけでは伝え切れない情報を付属的に伝える。これがコメントを書くべき箇所の基本的な考え方です。

――では、外部とのインターフェースには具体的に何を書くべきでしょうか?

園田:一般論として最初に検討するべき候補はあります。「(1)事前条件」「(2)事後条件」「(3)不変条件」「(4)入力の意味」「(5)出力の意味」「(6)副作用」「(7)計算量」です。要するに、利用する側が知っておくべきだけれど、コードの中身を見なければ容易には分からないものです。

##
    # Evaluates Jsonnet source.
    #
    # @param [String]  jsonnet  Jsonnet source string.
    #                  Must be encoded in an ASCII-compatible encoding.
    # @param [String]  filename filename of the source. Used in stacktrace.
    # @param [Boolean] multi    enables multi-mode
    # @return [String] a JSON representation of the evaluation result
    # @raise [EvaluationError] raised when the evaluation results an error.
    # @raise [UnsupportedEncodingError] raised when the encoding of jsonnet
    #        is not ASCII-compatible.
    # @note It is recommended to encode the source string in UTF-8 because
    #       Jsonnet expects it is ASCII-compatible, the result JSON string
    #       shall be UTF-{8,16,32} according to RFC 7159 thus the only
    #       intersection between the requirements is UTF-8.

yugui/ruby-jsonnetより引用。園田さんが挙げているような観点に基づき、コメントが記載されている

ただ、究極的な答えはどうしてもケースバイケースになってしまいます。例えば、モジュール化のためにパッケージを分けてはいるけれども、そのパッケージを自分しか使わない確信があれば、コメントは書かなくていい。

だから、ライセンス(利用許諾)やチーム体制など「プログラムがどんな人にどう使われるのか」も、コメントを書く書かないの判断材料になってくると思います。

【コメントの技法2】どんな読者が読むのかを考える

――ソースコードの処理内部でコメントを記載する箇所の候補を挙げるとすれば?

園田:候補を検討するに当たり考慮すべきは「どんな読者がコメントを読むのか」です。読者がどんなスキルを持っていて、何を知っているのか。それを踏まえることが重要になります。

f:id:blog-media:20180514142919p:plain

yugui/ruby-jsonnetのメインの処理を担う各モジュール(ext/jsonnet配下にあるもの)には、詳細なコメントはあまり書かれていない。ソースコードを読む読者が「Rubyの拡張機能を開発できる」「モジュールが実現したい処理の概要を理解できる」というスキルを持っていることを前提としているためだ

ここで言う想定読者とは、他のチームメンバーあるいは将来の自分です。その人たちに向けて「コードを日常的に読む人が知らなければいけない情報」を記載しておく必要があります。

――というと、具体的には?

園田:複雑なアルゴリズムにはコメントを書くべきでしょうね。ただ、どれだけ詳細に書くべきかはやはりケースバイケース。チームメンバーまたは自分自身の平均的なスキルレベルに依存すると思います。

例えば、私は以前あるプロジェクトでワーシャルフロイド法の実装が必要になり、コードを書いたことがあります。そのコメントに「ワーシャルフロイド法」と書き、Wikipediaへのリンクを貼りました。

なぜなら、私はそれほど競技プログラミングには強くないからです。半年後くらいに自分がそのコードを見たとき、何のアルゴリズムか一目では判別できない可能性があるだろうと考えました。

でも、競技プログラミングに強いメンバーがたくさんいる会社もありますよね。そういったエンジニアならばコードを見ればワーシャルフロイド法だと分かります。だから書く必要はないでしょう。

【コメントの技法3】コミュニティの方針に合わせる

――プログラミング言語・フレームワークの開発コミュニティのように「スキルの高いエンジニアが集まることが前提」という場合、記載すべきコメントの量も必然的に減りますか?

園田:そうですね。大切なのは「読者がプロジェクトに何を期待しているのか」を考えることです。

――例えば?

園田:プロジェクトの特定の箇所で「A」という方針でコードが書かれているならば、読者は他の箇所でも「A」という方針が貫かれていることを期待します。プロジェクト全体の一貫性を求めるわけです。

例えば、高いスキルや多くの知識を前提とするプロジェクトならば、最初から読者はその内容を勉強して参画するので、冗長なコメントは不要なはずです。にもかかわらず、くどいコメントがあると邪魔でしょう。頑張って書いても読者の害にしかならないのですから、書くべきではないですよね。

だから、どうコメントを書くべきかについてのもう1つの答えは、プロジェクトの一貫性を求めている読者のために「周り(コミュニティの方針)に合わせること」です。

f:id:blog-media:20180514143549p:plain

ruby/ruby参照。Ruby言語のメインの処理を担う各モジュール(ext配下にあるもの)は、どのソースコードを読んでもコメントの書き方に一貫性が保たれている

【コメントの技法4】会社やチームの慣習に起因する内容を書く

――他にコメントを記載すべき箇所は?

園田:会社やチームが持つ、固有の慣習に起因するものは書いておく方がいいと思います。なぜなら、新しいエンジニアが参加した際に「固有の知識や経験がないために正しい判断を下せない」というケースを避けなければいけないからです。

// You can learn more about gRPC API Service descriptions from google's documentation
// at https://cloud.google.com/endpoints/docs/grpc/grpc-service-config

grpc-ecosystem/grpc-gatewayより引用(該当モジュールのcontributorはStefan Hacker氏)。モジュールの実装に当たり知っておくと便利な「gRPC API Service」の知識が、Googleのドキュメントから学べることについて記載されている

――独特の慣習があり、業界知識が求められるパターンというと、金融業界もそれに当たりそうですね。

園田:そうですね。ただ、その場合はコメントを書く前にまず徹底すべきことがあります。業界知識という整理された知識体系を、コードの構造に反映させることです。体系を説明するための冗長なコメントを少なくできますから。

その上で、コードからこぼれ落ちてしまうような情報をコメントに書いておくといいでしょうね。

【コメントの技法5】検討したけれどやらなかったことを書く

園田:検討したけれどやらなかったことも、手法の概要と、うまくいかない理由をセットにしてコメントに書くべきです。あるいは、小さな問題を修正しようとするとコードが複雑になったり性能が落ちたりするので、あえて放置することもあります。

そんなときには問題の概要と放置する理由を書くべきでしょう。

やったことは全てコードに書いてありますが、試したけどうまくいかなかったアプローチはコードには表れません。その情報を記載しておくことで、他のエンジニアが不毛な努力をしてしまう可能性を回避できます。

文字のボリュームが多ければ、外部ドキュメントに書きリンクで飛ばしても良いでしょう。

// HasQueryParam determines if the binding needs parameters in query string.
//
// It sometimes returns true even though actually the binding does not need.
// But it is not serious because it just results in a small amount of extra codes generated.

grpc-ecosystem/grpc-gatewayより引用。あえて、小さな問題を放置した理由が書かれている

【コメントの技法6】デザインスキルが向上すれば、不要なコメントは減らせる

――書くコメントの内容は、過去と現在とで変わりましたか?

園田:変わってきましたね。昔は不適切なコメントの量が多かったと思います。

――それは何に起因していますか?

園田:まず、かつての私は不要なコメントをつけざるを得ないほどデザイン(設計)が下手だったからです。

例えば、過去に「○○の手順と△△の手順を踏んでから□□を呼び出す」というデザインのモジュールを作る際、呼び出し手順の情報をコメントに書いていました。

でも、どうしてもコメントを読み飛ばしてしまう人がいるので「動きません」という苦情が来ていたんです。であれば、そもそも初めから細かいことを気にせずに使えるインターフェースを提供しておくべきだった。コメントは解決策ではないという教訓を学びました

――「コメントは解決策ではない」とは象徴的なフレーズですね。

園田:もちろんコメントが解決策となるケースも多々ありますけどね。

もう1つは、今の自分なら「コメントを書かなくていい」と判断できるものでもそう断言できなかったり、逆に今の自分なら「これは書かなければいけない」と考えられるものをなんとかなると甘く見てしまっていたりしていました。

知識と経験によってデザインのスキルが向上したので不必要なコメントが減ったのと、経験によってコメントを読む読者の平均的なスキルを想定できるようになり、適切な判断を下せるようになりました。

――若手エンジニアがそうしたスキルを身に付けるには、どんな知識や経験が必要だと思いますか?

園田:もしかしたら古臭いと思う人もいるかもしれないですけど、知識の観点で言えば、デザインパターンをきちんと知っておくのは有効です。

一番有名なGoF(Gang of Four)などでは現代でよく用いられるプログラミング言語では不要になった手法も一定の割合含まれていますが、それらを上回るほど現代でも有益なパターンがたくさんあります。デザインパターンを用いることで、使用に注意がいるような不適切な設計を少なくできるので、注意喚起のようなコメントもなくせると思います。

それに、デザインパターンは共通言語であり、それにのっとった命名や構造にしておくことで普遍的にどんなエンジニアにも理解してもらえます。となれば、よりコメントの量は減らせます。

それからRubyのコミッターは「適切な名前を付けること」と「(Rubyの機能である)ブロックを適切に使用すること」をとても大事にします。

名付けにおいて最も気にするのは“一貫性”です。「標準ライブラリの○○という機能はこういう命名体系なのに、こちらは違う」となると、読者はわざわざそれを覚えなければいけなくなってしまいますから。

同じような振る舞いをするものには同じような名前を付けることで、読者が知っておくべき事前情報の量を減らすことができます。

それから、ブロックを使うとその範囲だけリソースが有効になりますから、解放するためのコードをプログラマ自身が書く必要がなくなります。そうすれば、解放を促すようなコメントは不要になりますよね。

各言語が持っているコードの安全性を担保するための機能を上手に使う。それがコメントの適正化のために重要だと思います。

――知識の話は納得のいくものが多いですね。経験としては、どんなことをすべきでしょうか?

園田:これは私の個人的体験をベースとした話になりますが、コーディングルールの意味を考えてコードを書くことが大事です。

思想を説明していなくても、「こういったコメントを書きなさい」といったコーディングルールの指定ってあちこちのプロジェクトであるじゃないですか。そのルールに沿って手を動かしているうちに「なるほど、こういう意図なんだ」と察しがつくようになりました。

それに、先ほども話したように、私自身も不適切な設計やコメントによって誰かを苦しめてきましたし、苦しんできたんです。そうした経験があったからこそ「良い設計とは何か。良いコメントとは何か」の知見を得てこられたんだと思います。

――深い知識と経験に裏打ちされたノウハウ、とても参考になりました。どうもありがとうございました!

取材・執筆:中薗昴(サムライト)/写真:鈴木智哉

関連記事