コードの可読性についてのプレゼンテーション紹介 vol. 1: “導入と原則” 編

はじめに

こんにちは。コミュニケーションアプリ「LINE」の Android クライアントチームの石川です。
先日、コードの可読性についてのプレゼンテーション (https://speakerdeck.com/munetoshi/code-readability) を公開しました。

今後、このプレゼンテーションについてのちょっとした解説を、本ブログ上で不定期に連載していきます。
今回は、このプレゼンテーションの概要と、最初の章 “導入と原則” についての解説を行います。

このプレゼンテーションについて

このプレゼンテーションは、コードの可読性を向上するためのアイディアをまとめたもので、以下の8つの章からなります。

  • 導入と原則: 可読性の高いコードの重要性、プログラミング原則
  • 命名: 名前の示す内容、文法、語の選択
  • コメント: ドキュメンテーション、インラインコメント
  • 状態: 状態遷移の管理、不要な状態の削除
  • 手続き: 関数やメソッドの流れの明示化や分離
  • 依存関係 I: 2つの型の間の依存関係の強さ
  • 依存関係 II: 依存関係の方向、重複、明示性
  • レビュー: コードレビュー依頼、レビューコメント

全章をまとめると、なんと700ページを超える分量になります。なぜこのような巨大なプレゼンテーションを作ったのかというと、私の所属しているコミュニケーションアプリ「LINE」の Android クライアント開発チームを、より “持続可能な開発ができる環境にしたい” からでした。

LINE は2011年に開発が始まって以降、よりよいユーザー体験を提供するために、絶え間ない機能開発や改善を行ってきました。そうして徐々にプロジェクトが成長した結果、Android クライアントのコードはモジュールを含めると150万行にまで膨れ、チームメンバーは50人を超える規模になりました。このような巨大なプロジェクトで開発を継続可能にするためには、コードの可読性を保ち、技術的負債を返済し続ける環境が必要です。

しかし、特定の誰かがリファクタリングをし続けるだけでは、そのような環境は実現できません。巨大なプロジェクトでは、”コードの可読性を保ち、技術的負債を返済し続ける” ことそのものをスケーラブルにする必要があります。つまり、開発に携わる人全員が、可読性と技術的負債を意識する必要があります。

可読性の高いコードを書くことは、単純に機能実装を行うことよりも困難なことが多いです。それには、どのようなコードが読みやすいのかという知識や、効率的にプログラムの構造を再構成する技術が求められます。そこで、それらの知識や技術を共有するため、コードレビューの指摘の典型例や、リファクタリング中に発見した可読性の低いコードの特徴をまとめたものがこのプレゼンテーションです。

第一章: 導入と原則

この章では、可読性の高いコードが必要な理由と、そのためのプログラミング原則の紹介をしています。

可読性の高いコードが必要な理由

前節の繰り返しになりますが、プロダクトの開発を持続可能にするために、コードの可読性を高く保つ必要があります。例えば、5分考えて変数名を工夫したり、適切なコメントを書くことで、他の開発者(未来の自分自身も含む)が1時間悩むことを防げるかもしれません。重要なのは短期的・個人的な生産性ではなく、プロダクトのライフサイクルの期間におけるチーム全体の生産性です。逆を言えば、そのコードの寿命が短かったり、使われる範囲が限定的である場合は、可読性について考慮する必要性は薄くなるでしょう。例えば、試験的な実装であったり、一度しか実行しないスクリプトがそれに該当します。

可読性を重視するべきかどうかの損益分岐点は、作業の時間のうち “コードを読んだり他の人にコードを解説する時間” と “コードを書く時間” のどちらが大きくなっているかがひとつの基準になります。ここで注意するべき点は、コードを書いている最中に他のコードを参照する場合や、コードレビューを行う場合なども “コードを読む時間” に算入するべきという点です。

プログラミング原則

頑健で可読性が高いコードを書くために、プログラミング原則に従うことは多くの場合に有用です。しかし、状況を考えずに原則を過剰に適用すると、かえってコードの可読性が落ちる場合もあります。例えば、第六章では command-query separation を過剰適用した際の悪影響について解説しています。この章では、コードの可読性を考える上で特に重要なだけでなく、仮に過剰に適用しても悪影響がそこまで致命的でないプログラミング原則を5つ選んでいます。

The boy scout rule

このルールは、ボーイスカウト運動の創始者 Robert Baden-Powell の格言を、Robert C. Martin がソフトウェア開発に適用したものです。 Robert C. Martin の主張は原義と文脈は異なりますが、コードの変更を行う場合はよりきれいにしようという主張です。この原則に従う例としては、あるコードを変更するついでに名前をわかりやすくしたり、コメントやテストを追加したり、使われていないコードを消すことが挙げられます。これは “汚いコードを更に汚くするな” と言い換えられます。例えば、巨大なswitchに新たなケースを追加することはこの原則に反しており、新たなケースを追加する前にストラテジーパターン等を使ってリファクタリングする必要があります。

YAGNI (You Aren’t Gonna Need It)

この原則は、機能・コードは必要になった時に実装されるべきで、将来必要になりそうという理由で実装されるべきでないと主張しています。現在必要ないコードの例としては、使われていないユーティリティー関数、実装が1つ以下の抽象化レイヤー、固定値しか渡されない仮引数などが挙げられます。このような将来のための機能・コードは、実際には使われない可能性が高いだけではなく、他の理由でのコードの変更が必要になった時の障害になりえます。もし、ある条件分岐を追加しようとした際、別の無駄な分岐があると、最終的な分岐構造はより複雑になることが想像できます。このことからも、将来の変更に対して柔軟であるためには無駄な機能実装を避け、設計を単純化することが重要だとわかります。

ただしこの原則は、コードの変更が容易であることを前提としています。変更が困難な例としては、外部公開する API やライブラリ、マイグレーション困難なデータベースのスキーマ等が挙げられます。この場合、将来どのように使われるかを考慮して設計・実装することが求められる場合があります。

KISS (Keep It Simple Stupid)

この原則の原義は、機器の整備を行いやすくするために設計を単純化するべきという意味です。これをソフトウェア開発に適用すると、 “機能・仕様を単純にする” や “実装手法を単純にする” といったことになるでしょう。特に実装手法に関しては、目的と手段を取り違えないよう留意するべきです。プログラミング原則やパラダイム、コードの美しさや一貫性、設計手法といったものは、コードの可読性や頑健性を向上させるための手段であるべきで、それ自体を目的にするとかえって可読性や頑健性を損ないかねません。例えばリアクティブプログラミングで、定数値を含むすべての値をobservableにすることは可能ですが、統一性の観点では “美しく” なる一方で、コードの可読性やバグの発見しやすさは悪化しえます。

Single responsibility principle

この原則は、SOLID と呼ばれるオブジェクト指向のための原則の中の一つで、定義を訳すと”あるクラスが変更される理由は、ちょうど一つであるべき” となります。例えば、ユーザーの情報の構造(名前、メールアドレス)とその集合(登録済みユーザーリスト)を一つのクラスで実装すると、このクラスを変更する理由が2つになります(ユーザーの情報の項目を変更したい場合と、ユーザーの登録方法を変えたい場合)。この場合、ある変更が別の機能に影響がないことを保証できなくなるため、一つのクラスの責任・関心の範囲は一つに絞るべきです。

Premature optimization is the root of all evil

この原則は、効果の小さい最適化はするべきでないと主張しています。コードが複雑になるような最適化は効果が大きいときのみするべきで、そのためにもプロファイリングや見積もりが重要になります。ただし、コードの可読性がよくなるような最適化はこの限りではないでしょう。例えば、ArrayListの要素をループで検索するコードをHashMapに置き換えることは、メモリの使用量は増えるかもしれませんが、計算量を減らす上にコードも簡潔になります。

おわりに

今回は “導入と原則” 編として、このプレゼンテーション全体についてと、第一章の内容を紹介しました。

次回は “命名とコメント” 編として、第二章と第三章の内容を紹介します。
公開いたしました

Related Post