「読みやすいコードのガイドライン」出版記念特別企画!「読みやすいコメント・読みやすい関数とは? CODE READABILITY LECTURE」レポート
LINE株式会社 石川宗寿さんが「読みやすいコードのガイドライン」を出版されました。その内容を元に開かれた「CODE READABILITY LECTURE」のレポートを質疑を中心にお送りします。
こんにちは。
エンジニアHubを運営しておりますエン・ジャパン株式会社のデジタルプロダクト開発本部(デジプロ)で、VPoEをしております、こざわと申します。
さる10月22日に、LINE株式会社の石川宗寿さんが技術評論社より書籍「読みやすいコードのガイドライン」を上梓されました。
実はこちらの本、石川さんがコードの可読性について社内講義された[プレゼンテーションスライド]が元になっています。
当時LINEに在籍していたこざわも、それを受講したうちの一人なのですが、講義があまりによい内容だったので、「これは社内講義ではもったいないので、ぜひ本にしましょうよ」と石川さんに持ちかけて、そこから長い道のりを経て本になった経緯がございます。感無量であります。
さて、いよいよ本になりますというタイミングで、「出版に合わせてエンジニアHubでもこの本を広めるために何かできないかしら」と話をしたところ、石川さんのご厚意で、エン・ジャパンのエンジニアやインターン生向けに社内講義を組んでもらい、そのレポートを、できるだけ本を買って読みたくなるようにまとめて記事にしてみてはどうか、ということになりました。それがこちらの、書籍をプロモーションする記事となります。
講義は全八回で組まれているのですが、そのうちの二回分、「コメント」と「関数」についての回を講義してもらうことにしました。ではそのレポートをお送りします。
【書籍プレゼントキャンペーン】※終了いたしました
本講義の書籍「読みやすいコードのガイドライン -持続可能なソフトウェア開発のために」を10名様にプレゼント!
記事の最後にある「キャンペーン情報」をご確認のうえ、奮ってご参加ください!
一時間目「コメント」
書籍では第三章にあたり、第二章の「命名」とともにコードに現れる自然言語記述として取り扱われています。スライド版では[こちら]からになります。
コメントには大きく二種類、ドキュメンテーションとしてのコメントと、非形式的なコメントがある、という分類の元、それぞれに対して、どのようにあるべきかが話されました。
ドキュメンテーションコメント
ドキュメンテーションコメントは、コードを読まなくても中身が分かるようにするためのコメントです。Javadocなど、クラスや関数などの定義や宣言に対して、決まった書式で説明を行うコメントであり、ドキュメントツールを使うことでAPIドキュメントを生成したりすることもできます。対して、非形式的なコメントはコードの様々な場所に書かれ、コードを読むスピードを上げたり、正確に理解する助けになるコメントです。
「ひな形として作られたドキュメンテーションコメントをそのまま放置する」など、それぞれのコメントについてのアンチパターンが紹介されましたが、弊社にも身に覚えのあるエンジニアが多数いました。
ドキュメンテーションコメントは、コードを読まずとも理解できるようにするためのものですから、コードの要約がまずありきで、それを補足するオプショナルな詳細が加わります。要約についてはどのように重要な部分を見つけ出すか、共通部分を括りだして抽象化するか、といった技法を説明してもらいました。詳細については、そもそもどのような詳細を説明するべきか、どのようにすれば誤解が減るかを話してもらいました。
非形式的なコメント
非形式的なコメントについては、大きなコードに対するコメント、複雑・非直感的なコードに対するコメント、ワークアラウンドを含むコードに対するコメントを、それぞれのコード例を挙げて説明してもらいました。
レクチャーの所々で、石川さんから受講エンジニアたちに、質問が投げかけられる形で進みました。いくつかをピックアップしてみます。
石川:
コメントを書くことで、コードの意図を示したり、注意点を挙げることでミスを防止したりするほかに、リファクタリングをしやすくすることもできます。コメントを書くとリファクタリングしやすくなる理由は?
エンジニアA:
検索しやすくなるから?
石川:
それも一つの理由です。他には、コードに対してドキュメントがやたらと長くなってしまう場合に、コードが良くないというシグナルとして働くからという理由もあります。リファクタリングすることで、コードが分かりやすくなり、コメントが短くできる場合があります。そうして短くできたコメントは、名前を付け直すヒントになる場合もあります
---
石川:
fun setSelectedState(isSelected:Boolean): Boolean
というコードがあった場合、戻り値のBooleanは何を意味するか?
エンジニアの回答:
セットが成功したかどうか…?
セットの結果かな?
引数で受け取ったstateに更新をできたかどうか
セットした後の値
セットする前の値
石川:
何であるかはコードだけでは分からない、というのが出題の意図でした。それを分かりやすくするには、コメントで戻り値に説明をする必要があります。(詳しくは書籍p.79を御覧ください。)
講義後のコメント・感想
エンジニアB:
コメントが大事だとは思っていたが、石川さんの話を聞いてコメントをナメまくっていたことがわかった。十分に見やすくわかるだろうとコメントを書かなくて、未来の自分が全然すんなり読めなくてちょっとイラっとしたり、ドキュメンテーションを全て同じ粒度で揃えて書かないといけないという妄想に取りつかれて、本質的ではない理由でドキュメントを書きまくって、書いた後に冗長で気持ち悪いな、これはなんだ?と感じたこともあった。アンチパターンに一個一個あてはめて考えるとなぜかがすごくよくわかりました。
石川:
ドキュメンテーションは形式的なので、フォーマット自体や、内容の粒度や、レイヤーについこだわりがちになってしまいます。実際にドキュメンテーションを書き、その数か月後に見るのを繰り返さないと、どういう風に書いたらよいのか習得しにくいので難しいところではあると思います。
エンジニアB:
必要な情報だけに疎ろにしたほうが、逆に適切な情報量になることがあるとわかりました。
---
インターン生C:
これまでひとりで開発をしていて、作ったものがTwitterのBotなどということもあってドキュメンテーションというものを知らなかった。ドキュメンテーションと非形式的なコメントとの違いが知れてすごく有意義な時間でした。ありがとうございます。
石川:
インラインコメントとかの説明はいろんな記事や書籍で説明されているとは思いますが、ドキュメンテーションはあまり無かったりするので、書き方に困る人が結構多いと思います。アプリケーションコードなど、ライブラリを使う側だけを作っていると、ドキュメンテーションの経験が中々積めなかったりします。
しかし、ライブラリなどを作りだすと、とたんに必須のスキルになります。外部公開するライブラリだけではなく、一つの組織内で自分のコードが使われる立場になったときにも結構大切になる感じです。ドキュメンテーションと非形式的なコメントの違いを意識して書いてくださると嬉しいです。
エンジニアD:
APIドキュメントを読むことはみな結構多いと思いますが、その元になるのが、コードに書かれているドキュメンテーションとしてのコメントで、それを加工して作ることが多いわけです。
二時間目「関数」
書籍では第五章、スライドでは[こちら]にあたります。
読みやすい関数とは
読みやすい関数とは、「振る舞いが予測可能」な関数です。コメントの章とも関連しますが、ドキュメンテーション、特にその中でも要約が書きやすい関数は振る舞いが予測しやすい関数です。そうでなければ予測しづらい関数になっていて、コードが良くないシグナルだと言えます。
振る舞いを予測可能にするためには、関数の責任と流れを明確にするのが有効です。
関数の責任を明確にするテクニックとして、関数の分割と、その中でも重要なコマンド・クエリ分離の原則を、そしてそれを使うときの注意点について紹介してもらいました。
コマンド・クエリ分離の原則
石川:
a,b,cの値は何になるのが期待されるか
val a = IntList(1,2) val b = IntList(3,4) val c = a append b
エンジニアA:
a=[1,2], b=[3,4] , c=[1,2,3,4]
エンジニアB:
a=[1,2,3,4] b=[3,4] c=[1,2,3,4]
エンジニアC:
下記だったらまた変わってきますね。
val c = a.append(b)
石川:
コマンドクエリ分離の原則が守れていたら
a=[1,2]
ですが、崩れていたら、
a=[1,2,3,4]
となる実装があり得ますね。でもこのコマンドクエリ分離の原則についても使いすぎがよくない場合もありまして…(詳しくは書籍p.132を御覧ください。)
関数の流れを明確にする3つのテクニック
続いて、流れを明確にするテクニックとして、「定義指向プログラミング」「正常系に焦点を当てる」「対象による分割」の三つを紹介してもらいました。
「定義指向プログラミング」 はこの本で石川さんが名付けた手法です。制御構造だけでなく引数・関数・クラスも含めてのネストや、関数呼び出しのチェーンを減らすために、説明変数を定義してそこに部分式を代入したり、コード断片を関数として抽出して定義することで、それらにどんどんと名前を付けていくものです。これにより、動作の理解に重要なコードを一か所にまとめ、コードを「斜め読み」することが可能になります。
「正常系に焦点を当てる」テクニックとしてはアーリーリターンを取りあげ、その効用と、過剰適用の害について例示してもらいました。どんな手法に対しても、それに対して良くない使い方、過剰な使い方があり、使いどころと使う程度を適切にしないといけないというのは、この本全体を通して流れる裏テーマだとのことです。
「条件でなく、対象による分割」については、条件として「有料アカウントか無料アカウントか」、操作対象として「背景画像とアイコン画像」とがあり、2×2で4つの場合分けをコードとして書かなければいけないときに、まず条件で関数を分割してその中で個々の操作対象を列挙するか、それとも先に操作対象毎に関数を分割してその中で条件分岐するか、どちらが良いかについて論じられました。人間がコードを書くときの直感としては、条件で分割しがちで、それが自然な思考の流れです。しかし、読むときには、操作対象で分割されている方がよいというのが趣旨となります。詳しくは書籍 p.160を御覧ください。
質疑応答コーナー
既存コードに対してコメントを追加していくテクニック
エンジニアE:
ドキュメンテーションについて、Kotinは静的型付け言語なので、データ型などから情報が得られたりすると思うんですけど、いま実際開発してる現場だと動的型付け言語でデータ型とかが定義されてなかったりする。
PHPなのでPHPdocを補完していかないといけないんだなっていうのはありつつも、返り値として返すようなデータ型とかも結構ふわっとしてたり、実装がなんか何やってんだろうこのメソッドは?みたいなのが結構あったりするんですけど、こういったものに後付けでコメントとかをつけていく場合は例外とかの記載ばかりになり大変になりそうだなというイメージがある。既存コードに対してコメントを追加していくテクニックやどういう風に整理したらよいかを教えてほしいです。
石川:
既存コードにコメントを追加する上で、特に動的型付けの言語の場合、まず最初におそらく必要なことが『コーディング規約でドキュメンテーションのフォーマットを定める』ということです。JavaScript とかでも例えば Closure Compiler というものですと、ドキュメンテーションとしてコメントを、あるフォーマットで書くことで静的型付けのようにチェックすることができたりします。
型のチェックはしなかったとしても、そういったフォーマットをまず定義して、開発者がドキュメンテーションを読むことで使い方やエッジケースを理解できるようにすべきかなと思います。
例外ケースが増えて、実際のドキュメンテーションと挙動が違うことがあることについては、結構血を流しながらコメントを書く必要があるかなーっていう感じはします。
私が経験したいくつかのプロダクトで、何をやってるかわからないものに対して徐々にリファクタしないといけないことがありました。その場合、わかってる範囲についてだけでも書いた上で、TODOコメントなどで『この部分はよくわからない』とかをもし明記できるなら、それもいいと思います。わかっていない点があるならば、そのこと自体を表明するのも一つのテクニックになります。
実際に思い込んでたものと挙動が エッジケースで違うみたいなのは、テストを書いたり、ドキュメンテーションを実際に書いて、それによってバグを引き起こして…という風に結構血を流す作業にどうしてもなってしまうかなっていうのはあります。
なので、まずフォーマットを決めてそれをみんなで統一して『これで行きましょう』というのを決めるのと、分からないところはもうわからないと言ってしまい、わかってる範囲だけでもとりあえず書いていく。そして残りは泥臭い作業になりますっていう感じですね。
エンジニアE:
ありがとうございます。いまのコードの状態がよくない状態だったりして、リファクタリングは進めないといけないと感じています。ファーストステップとしては、コメント・ドキュメンテーションの指針を立てるのがよいんですかね?
石川:
それはスタイルにもよると思います。例えばまずテストを書くというスタイルも当然あると思います。私が経験したプロダクトだと、テストを書くためにはリファクタが必要で、リファクタするにはテストが必要という状態がありました。その場合の私の解決策は、『壊します』と宣言して『ここからここまでは壊れる可能性があるので覚悟してください』と、いろんな人に、QAでも企画者でもみんなに伝えて、実際壊しながらリファクタするっていうのが必要になっていました。
もしドキュメンテーションを書いたり、テストを書けるような状態でしたら、それらを先にやったうえでリファクタするのが理想です。
理想でリファクタできるとは限らないので、その場合は『悪影響は何があるか・悪影響があってもどうしてリファクタしないといけないのか』を説明する簡単なプロポーザルを書いて、『それでこれやりますからみんな覚悟してくださいね』という合意をとるのが必要になるかなと思います。
エンジニアE:
ありがとうございます。たくさん血を流さないといけなさそうな気がしています(笑)
石川:
それは頑張ってください(笑)。血を流す作業をひとりでやろうとすると、つぶれてしまうので、みんなを巻き込むのが良いと思います。
エンジニアE:
ありがとうございます。皆さん頑張りましょう(笑)
---
エンジニアB:
今の話はめちゃくちゃ実践的で、リファクタリングするときの理想だけがあるけど、みな踏み込めないところがあって、デグレるのも怖いしっていうところで今の話はすごい実践的で良かったです。ありがとうございます。
石川:
ありがとうございます。立場によっては、当然今後の開発速度が下がってでも、いまの動いているのは触らないでくれという人もいます。その立場ではそう言うのは正しいので、『どうして必要なのか?』の説得力を持たせることが必要になります。『これをやらないと次の機能 featureX の実装ができない』など何かモチベーションとして十分に説明可能なものを用意するのは、プロポーザルを作る時に重要になるかなと思います。
エンジニアB:
ありがとうございます。コードのレベルだけでなくて、アーキテクチャの部分や運用でもリファクタリングが必要になる中で、いまよりも不便なほうに一回行くかもしれないみたいなことは絶対起きると思います。
石川:
はい。おっしゃる通りです。
エンジニアB:
プロポーザルで人に納得感を持っていただくっていうところ、合意するための材料をきちんと用意して人をいろんな人を巻き込みながら頷かせるというのが大事だと改めてわかりました。ありがとうございます。
エンジニアE:
大変ためになる勉強会で書籍もこのあと読み込んで、しっかり自分のものにしていこうと思っています!最後に話してもらった実務ベースの話もすごくためになって、これからのモチベーションにもつながるところもありました。これからも頑張っていこうと思っています。
レクチャー後の感想
レクチャー後、社内Slackなどで感想を募ってみました。いくつかをピックアップして掲載します。
エンジニアAさん:感想
読みやすいかどうかの基準が感覚や経験則に頼ることが多かったのですが、それらが言語化されていて非常に理解しやすい内容でした。 言語化できているということは、自身の実装だけでなく、コードレビューにも活かせる訳で、チーム全体のスキルを引き上げるのに、この書籍の内容を実践していくことが非常に良いアプローチだと感じているので、是非活用させていただきます。
また、最後の方でお話しいただいたリファクタリングの実践的なところで、既存のコードとどのように戦っていくのか実体験も交えお話しいただけて、大変参考になりました。
今後のリファクタリング指針とし、ドキュメンテーションベースで実施していくという選択肢が出来ただけで大きな一歩です。
関数の講義では定義思考プログラミングの注意点の話(可読性を上げるために行ったつもりが、かえって損なう抽出を行ってしまう)がなんでも定義的に当てはめる罠の話として印象に残りました。
エンジニアBさん:感想
コメントについての講義で、ドキュメンテーションと非形式的コメントと区別した使い方を、それぞれどういう意図で使い分けるのかについて知れたのが勉強になりました。
関数の講義では定義思考プログラミングの注意点の話(可読性を上げるために行ったつもりが、かえって損なう抽出を行ってしまう)がなんでも定義的に当てはめる罠の話として印象に残りました。
エンジニアCさん:感想
過去に感じた悩みや違和感の数々が、言語化されていて目から鱗でした。話す言葉の解像度も高く、考え抜いたことがわかり、素直に尊敬しました。自分でも何度も噛み砕いて、自然に武器として使えるようにしたいです。
質疑応答で、テストとリファクタリングどちらも必要な場面で、コードベースによっては必ずしも安全にリファクタリングできるとは限らず、そういった血を流すほかない場面では、全員で「ここからここまでは壊れる可能性があります」と腹をくくるということも必要になってくるという話。
そして各所を説得できる納得のいくプロポーザルを用意することも必要になってくるという石川さんの経験に基づいた話は、本当にためになりました。アーキテクチャや運用をリファクタリングする際にも、まったく同じことが言えると思います。
エンジニアDさん:感想
コメントの時間では、ドキュメンテーションと非形式的なコメントの違いと書き方が勉強になりました。 特に、文法的に、こういうふうに書くといいよ、という簡単な提示と具体的な例についての説明が、すごくわかりやすかったです。
個人的に、インターンを開始してから文章の書き方や、伝え方が苦手だと実感することが多かったので、コード内のコメントだけでなく、普段のテキストコミュニケーションでも意識していきたいです。 コードを書く上で、要約する、というのが、自分の思っている以上に色々な方向から見た時に役に立つのをお話を聞いて感じたので、心がけたいと思いました。
関数の部分では、特に「書きやすいコードと読みやすいコードの違い」のお話が印象的でした。
読みやすさや、メンテナンスのしやすさ、伝えやすさなど、書きやすさよりも優先するべきことの軸をはっきり知ることができたと思います。
だからと言ってすぐに網羅して書けるわけではないですが、よく言われる「読みやすいコード」の本質を知れた気がします。
どの説明においても、簡単にポイントを提示してくださったので、自分がどう気をつければいいかイメージを持つことができました。
さらに本を読んで、書きやすいコードではなく、「読みやすいコード」を書けるように意識していきたいです。
キャンペーン情報
キャンペーン規約
-
▼応募方法
会員登録後、このページの下部にある「応募するボタン」を押す -
▼応募期間
2022年12月22日(木)18:00 ~ 1月12日(木)23:59(終了いたしました。) - ▼賞品
書籍「読みやすいコードのガイドライン -持続可能なソフトウェア開発のために」 10名 - ▼当選メールの送信日
1月下旬予定 - ▼当選について
厳正な抽選を行い、ご当選者様へはサイト上のスカウトメッセージにてご連絡をさせていただきます。
注意事項
- キャンペーンへのエントリーはお一人様1回のみ可能です。
- スカウトを公開していない場合、当選メッセージの受信が出来ませんのでご注意ください。
- ご登録内容に不備がある場合、当選の権利を無効とさせていただく場合がございます。
- 当選の権利はご当選者本人のみ有効で、家族を含む第三者への譲渡、あるいは換金をすることはできません。
- 商品の発送は日本国内に在住の方に限らせていただきます。
- 抽選結果に関するご質問の受付は行っておりません。