はじめに
先日、こんなエントリを書きました。
上の記事の中で、僕は「きれいなコードだけではすんなりコードが理解できないこともある」というような話を書きました。
もちろん、ある程度の規模になってくるといくらがんばっても「すんなり」では済まない場合も増えてくるけど、それでも最初に挙げた特徴を兼ね備えたコードとそうでないコードでは、開発効率に雲泥の差が出てくる。
僕が考える「良いコード」 - give IT a try
きれいなコードを書くことはいつでも大事ですが、きれいなコード「だけ」では大きなコードを理解するのは難しいです。
そこできれいなコードを書くことに加えて、僕が意識しているコードを理解しやすくする工夫について書いてみようと思います。
ただし、ここで書く内容はあくまで僕が普段心がけていることです。
現場の文化やコードの規模や歴史、開発チームのスキルや人数、開発しているソフトウェアのジャンル等によっては、「そんな方法は採れないとか」「そんなことはやっても無駄」とか、いろんな意見が出てくるかもしれません。
人にはヒトの、現場には現場の文化やルールがあるのは理解しつつ、ここではあくまで「僕はこうやってます」というスタンスで書いていくことをあらかじめご了承ください。
それでは以下が本編です。
【もくじ】
大前提として
「きれいなコードを書くこと」に加えて大事なことは、未来の開発メンバー(未来の自分自身を含む)に、なぜこんな仕様にしたのか、なぜこんなコードを書いたのか、という意図や背景を残しておくことです。
感覚としては未来の自分へ向けて書いたメッセージをタイムカプセルに入れて、土の中に埋めこむようなイメージです。
何年後かに自分が書いたコードを読む開発者が出てきたとして、その人が「はて?」と思ったときに、「僕はこういう意図でこのコードを書いたんですよ」という何らかの手がかりを残しておくわけです。
以下の内容はそんな「手がかり」を残す方法のあれこれです。
テストコードとセットでコードを書く
当たり前と言えば当たり前ですが、新しい機能を追加したり、仕様を変えたりしたときは、それを検証するテストを書きます。
そのとき、単にテストコードを書くだけではなく、RSpecのit
やcontext
にはテキストで「どういうときにどんな挙動になるのか」を詳しく書きます。
it
やcontext
に書き切れないときはテストコード内にテストの観点をコメントとして書きます。
アプリケーション側のコードだけでは「このコードはいったい何がしたいの?」とか「どういうときにどんな結果を返そうとしたの?」とか「この条件分岐ってもしかして不要じゃないの?」といった疑問が湧いた場合でも、テストコード上で具体的なユースケースを明記しておけば「なるほど、このコードにはちゃんと意味があったんだ」「このコードはこんなふうに動くんだ」と、未来の開発メンバーに理解してもらうことができます。
コミットの粒度に気を付ける(blameしやすいコミット粒度にする)
「このコードはなんでこんなことやってるんだ?」と首をかしげたとき、僕はgit blameをよく使います。
git blameしたときのコミットが適切な粒度でまとまっていて、そこにわかりやすいコミットメッセージが書いてあれば、「あー、当時はこういうことをやろうとしてたのね」と書き手の意図を理解できます。
反対に、blameで調べた結果が雑なコミットになっていると「なるほど、わからん」という結果になりやすいです。
なので、コミットをするときは「将来blameされたときに、このコミットが調査の役に立つかどうか」を意識しています。
コミット粒度に関する参考文献
なお、コミットの粒度については昔Qiitaに記事を書いたことがあります。
RubyConf 2018でTekin Suleymanさんが発表したBranch in Timeという発表も、理想的なコミットのお作法を学ぶのに良い資料だと思います。
開発チケットへのURLをコミットメッセージに残す
上のコミット粒度の話にも関連しますが、コミットメッセージに開発チケットへのURLを含めておくと、git blameしたときに素早く当時の開発チケットにアクセスできるようになります。
もちろん、開発チケットには求められている要件やプログラムの仕様、その要件が出てきた背景や具体的なユースケースなどが書かれている必要があります。
(必要であれば)コードにコメントを書く
「読めばわかるコード」にコメントを付ける必要はありません。以下は不要なコメントの例です。
# 日曜日だったらギターを弾く if date.sunday? play_guitar end
また、わかりにくいコードはまず、わかりやすくなるように書き直すべきです。
コメントを書いて逃げるのではなく、コードをわかりやすくする努力をしましょう。
しかし、実務では「わかりやすくしたいが、要件が複雑すぎるのでどうしてもこれが限界」と感じることもときどき発生します。
そんなときは躊躇なくコメントを書きましょう。
未来の開発メンバーが自分のコードを読む光景を想像しながら、「さすがにこのコードは複雑すぎて読みづらいよね」とか「なんでこんな奇妙なアプローチにしたのか、絶対想像が付かないよね」と思うようなコードを書いてしまったら、「こんなコードを書いてごめんね🙏」と心の中で手を合わせながらコメントを残してください。
それは不要なコメントではなく、必要なコメントです。
解説ドキュメントを書いてそのリンクを載せる
もし、伝えたい情報がコードにコメントを書くぐらいでは伝えきれないボリュームなのであれば、別途ドキュメント(GitHubのwikiページでも可)を書いた方がいいでしょう。
未来の開発メンバーに向けて「こういうコードを書くに至った理由」や「コードを理解する上で押さえておきたいポイントや全体的なアーキテクチャ」等をドキュメントにまとめて、そのURLをコード内のコメントやREADMEファイルに載せておきましょう。
コード説明会を開いてその動画のリンクを載せる
僕が大きくて複雑な機能を作ったときは、完成後に開発メンバーを集めてコード説明会を開くことがあります。
僕はリモートワーカーなので、コード説明会は毎回ビデオ会議です。そして、そのビデオ会議は最初から最後まで録画します。
動画であれば話し手の表情や声のトーンも伝わりますし、画面共有をしながら「ここのコードは〜」とコードを指し示したり、その場でコードを動かしてプログラムの動きを見てもらったりすることもできます。
ドキュメントを書くよりもずっと多くの情報が残せますし、説明会で話した時間=動画を作成する時間なので、ドキュメントを書くよりも手間がかかりません。
また、参加者からの質問にも随時答えられるので、作成した動画にFAQ的な役割を持たせることもできます。
作成した動画はクラウド上に保存してリンクURLを生成しましょう。
コード内のコメントやREADMEファイルに動画のURLを残せば、「動画版・開発者によるセルフライナーノーツ」のできあがりです。
書き手の意図が伝わるきれいなコードを書く(reprise)
繰り返しになりますが、上で挙げたようなテクニックを使ったからといって、コードの美しさをないがしろにして良い、ということにはなりません。
可能な限りコードで書き手の意図を伝えようとする努力は常に行うべきです。
きれいなコードを書くことは必須条件とした上で、それでも意図が伝わりにくい場合はどうしたらいいか、というテーマで僕はこの記事を書いています。
Q. コードの美しさなんて主観に過ぎないので意味がないのでは?
もちろん何を美しいと判断するのかは最終的には各人の主観となります。しかし、チーム内でコードレビューを繰り返せば、どんなコードが良くてどんなコードがダメなのか、という共通認識が徐々に出来上がっていきます。レビュアーとレビュイーで意見が食い違うときはチーム内でどういうコードが望ましいのか、議論するのが有効です。
こうした作業を繰り返していき、開発メンバー全員が一定の共通基準を持つようになれば、コードの美しさは「単なる主観」ではなくなっていくはずです。
番外編:なるべく退職者を出さない
未来の開発メンバーのためにコードの意図や背景を残しましょう、という話をあれこれ書いてきましたが、もしかすると一番よくやるパターンは、git blameで「このコードを書いたのは誰か」を調べたあと、そのメンバーをつかまえて「ねえ、ちょっといい?」と質問することかもしれません(苦笑)。
そのためにはその開発メンバーがすぐにつかまること、より具体的にいえばその開発メンバーが社内に在籍してもらうことが条件になります。
ですので(いち開発者の努力だけでは限界があると思いますが)、なんとか退職者を出さずに「何かあればすぐに質問できる状態」を維持し続けたいものです。
幸いなことに僕が勤めているソニックガーデンは離職率がかなり低いので、「ねえ、ちょっといい?」がいつでもしやすい環境です😄
逆に離職率が激しい会社では「なんでこんなコードになってるのか全然わからん」というお悩みが発生しやすくなりそうです。
番外編その2:不要なコードやデータベースのテーブルやカラムは消す
システムを長期間保守していると、不要になった機能もときどき出てきます。
ある機能が削除されると、以下のようなものが不要になります。
- アプリケーションコード
- テストコード
- データベースのテーブルやカラム
- その機能で利用していた外部ライブラリ
不要になったコードやテーブルは適宜削除していきましょう。
そうしないと、未来の開発メンバーが「このメソッドはどこからも参照されていないようだけど、はて?」と首をかしげてしまいます。
ちなみに、Ruby on Railsであればデータベースのカラムを物理削除する前に、ignored_columns
で論理削除することができます。
class Project < ActiveRecord::Base # schema: # id :bigint # name :string, limit: 255 # category :string, limit: 255 self.ignored_columns = [:category] end
ActiveRecord::ModelSchema::ClassMethods
データベースのテーブルやカラムは間違って物理削除すると復旧が大変なので、こういった便利機能をうまく活用していきましょう。
まとめ
というわけで、このエントリではきれいなコードの次に意識すべきこととして、書き手の意図やコードの背景を残す方法のあれこれをまとめてみました。
ここまで書いてみて思ったのは、結局のところ開発の仕事というのはコードを通じた開発者同士のコミュニケーションだ、ということです。
第一段階として「コードだけで伝わるコミュニケーション」を心がけ、それでもダメな場合は、次の段階としてこのエントリで紹介したような方法を用いてなんとか他の開発者とコミュニケーションできるようにする、といった感じです。
きれいなコードであれ、それ以外のアプローチであれ、いずれの方法もコミュニケーションのための手段です。
なので、具体的な方法にあまり捕らわれすぎず、「どうすれば自分の意図が伝わるか(うまくコミュニケーションできるか)」という目的を明確に持った上で、それを実現する手段を考えるといいんじゃないかな〜と思います。
自分の創意工夫をみんなで共有し合おう
また、こういった創意工夫について、プロジェクト内の開発メンバーや社内のプログラマで議論してみるのも面白そうです。
議論してみると「なるほど、その発想はなかった!」というような意外なtipsが見つかったりするかもしれません。
冒頭にもちらっと書きましたが、有効なアプローチは現場によって変わってきそうなので、現場単位で「これはMUST」「可能であればこれも」というような合意を形成しておくと、より開発しやすいコードベースができあがりそうです。
以上、このエントリがみなさんの参考になれば幸いです!