綺麗で読みやすいソースコード、書きたいですよね。
読みやすいコードを書けるか否かはプログラマーにとって死活問題であり、私自身、仕事でコードを書くようになってから、その重要性を強く意識するようになりました。
本記事では、良いコードを書くための指南書の名著『リーダブルコード』と『プリンシプル オブ プログラミング』の中で、印象的だった部分を引用しながらリストアップしていきます。
コードは理解しやすくなければならない。本書はこの原則を日々のコーディングの様々な場面に当てはめる方法を紹介します。名前の付け方、コメントの書き方など表面上の改善について。コードを動かすための制御フロー、論理式、変数などループとロジックについて。またコードを再構成するための方法。さらにテストの書き方などについて、楽しいイラストと共に説明しています。
質の高い(バグが少なく、メンテナンス性が高い)プログラミングをするための、一生使える原理原則を、「なぜそうなるのか」「どうやって使えばいいのか」やさしく解説。脱・初心者を目指す入社3年目までのプログラマーのステップアップに最適のガイドブックです。
コーディングの大前提(?)
- 最も読みやすいコードとは何も書かれていないコードである。
- コードを理解しやすくするにはコードを書かないことが一番であり、コードを書かないことがパフォーマンスを上げることに貢献する。
コーディング一般
- 常に「このコードは理解しやすいだろうか?」と自問自答する。
- シンプルなコードは、「素人っぽく」見えることもある。経験を積んだプログラマは、経験を積んだなりの高級なコードを書きたくなるもの。その誘惑に負けないようなメンタリティを持つことが必要。
- プログラミングにおける1つ1つの判断は「そのコードが変更される」前提で行う。
- コードは1つずつタスクを行うようにしなければいけない。そのタスクは小さくなるように分割する。
- コードをたくさんの小さい部分に分割する(関数などが長くなったら分割して短くする)。
- やみくもに高尚な処理をしようとしない。自分のタスクを解くのに十分な要求を定義すればいい。(例えば、店舗検索システムを作るとして、「任意のユーザの緯度経度に対して、最も近い店舗を検索する」という要求があった場合、日付変更線をまたいでいるときの処理やその他色々高尚な処理が必要。しかし、自分のアプリケーションが特定の地域しか扱わないなら、そのような処理は不要。)
- プログラミングにおいては「今日単純なことをして、明日変更が必要になった時に、変更のコストを支払う」方が「今日複雑なことをして、結局使わない」よりも良い結果を生む。
- たまには標準ライブラリのすべての関数やモジュール、型の名前のドキュメントを読んでみる。ざっくり知っておけば、いつか役立つかも。
- 既存のインターフェースが汚い場合は、自分でラッパー関数を用意して、覆い隠すといい。
- 問題を声に出して説明するだけで、解決策が見つかることがある。(通称ラバーダッキング)
- より賢い手法を考えるなら、問題を反対から解決しようと試してみる。例えば配列を逆順にイテレートしたり、データを後ろから挿入するなど、とにかくいつもと反対のことをやってみる。
コメント
- コードを理解するのに役立つなら何でも良いからコメントを書く。(ただし、コメントには画面の領域をとられるし、読むのに時間がかかるので、簡潔なものでなければいけない。)
- ソースコードのコメントに「なぜそれをしているか」を書く。
- コメントで曖昧な単語を使わない。(例えば「行数を返す」だと空ファイルは0行なのか1行なのか分からない。そうではなくて、「改行文字(\n)を数える」のようなコメントにする。)
- 定数の値を決めたときに頭の中で考えていたことを記録する。
// 合理的な限界値。人間はこんなに読めない。
cont int MAX_RSS_SUBSCRIPTIONS = 1000;
- コードの欠陥にコメントをつける。
TODO: もっと高速なアルゴリズムを使う
- 変数の単位は以下のようにコメントに残すと簡潔でわかりやすい。
public class PerformanceTester {
// TcpConnectionSimulator(throughput, latency, jitter, packet_loss)
// [Kbps] [ms] [ms] [percent]
変数名や関数名の命名
- 名前を短いコメントだと考えて、長くなりすぎない程度に多くの情報を詰め込む。(ただし変数のスコープが小さいときは、名前に情報を詰め込む必要はない。)
- tmpやretvalのような情報の無い名前をつけるのは基本的には避ける。
- 変数の意味を間違えるとバグにつながりそうなときは、変数名に重要な属性を追加する。hoge_utf8みたいに文字コードを明示する等。
- 名前に含まれる単語を削除しても情報が全く損なわれない場合は、不要な単語を削除する。(例えばconvert_to_string()はto_string()にしても必要な情報は損なわれないからconvert_の部分を削除してしまう等。)
- 名前が他の意味と間違えられることはないだろうかと自問自答する。
- 名前を否定形にするのは避けた方が良い。(例:"disable_ssl = false" → "use_ssl = true")
- ブール値の変数名にはis, has, can, shouldなどの接頭辞を使う。
- 上下の限界値を決めるときには、max_やmin_を前につけるといい。包含的範囲であればfirst_, last_を使う。
- イテレータ(ないしはforループなどの繰返し処理)が複数あるときは、インデックスに明確な名前をつけるといい。(例えばインデックスを3つ使いたい場合はi, j, k ではなく、hoge_i, fuga_i, piyo_iみたいな感じにする。)
変数宣言や関数呼び出し
- 変数の定義は、変数を使う直前に行う。最初から全部定義する必要はない。
- 同じ変数には一度だけ書き込むようにする。
- 呼び出される関数の側で、渡された引数の調整をしてはいけない。関数を呼び出す前に、呼び出し側で調整する。
- まずデフォルト値で変数を宣言して、処理ごとに変数に代入するのは一つのやり方。
制御
- 条件やループなどの制御フローがないコードは読みやすい。処理の分岐を少なくし、処理の流れを直線的に読めるコードを書く。
- ネストの深いコードは、読み手の精神的スタックに条件をプッシュしなければならず、理解しにくい。
- ネストを削除するには失敗ケースをできるだけ早めに関数から返せばいい。関数から早く返すのはいいこと
- ifなどの条件式では、変化する値を左に、より安定した値を右に書く。
if (age >= 18)のほうがif (18 <= age)より読みやすい。(「もし君が18歳以上ならば」は自然だけど、「もし18歳が君の年齢以下ならば」は不自然。) - 式を簡単に分割するには、式を表す変数を使えばいい。
例えば、
if line.split(':')[0].strip() == 'root':
ならば
username = line.split(':')[0].strip()
if username == 'root':
と書けば読みやすい。
テスト
- テストするときは、コードを完全にテストする最も単純な入力値の組み合わせを選択しなければいけない。
- テストには最もきれいで単純な値を選ぶ。
- コードを検証する完璧な入力値を1つ作るのではなく、小さなテストを複数作るほうが、簡単で、効果的で、読みやすい。
- テストに使う関数は、他のコードから呼び出されないので、長くなっても構わない。テスト関数の名前はコメントだと思えばいい。
- テストのカバレッジを100%にすることに拘らない。テストの時間対効果を考える。ユーザーインターフェースやどうでもいいエラーケースの部分はバグのコストが高くないのでテストが割に合わない可能性。
- テストが開発の邪魔になってはいけない。あくまでもテストはプロジェクトの一部。時間対効果を意識する。
まとめ
長くなってしまいましたが、本記事では綺麗で読みやすいコードを書くためのヒントをリストアップしていきました。たくさん挙げましたが、
一貫性のあるスタイルは「正しい」スタイルよりも大切
PEP8(Pythonコーディング規約)
という言葉もありますので、神経質になり過ぎず、少しずつ読みやすいコードを目指していきましょう。
最後に、その他のヒントや分かりやすい説明は以下の書籍を参考にして頂ければと思います。
コードは理解しやすくなければならない。本書はこの原則を日々のコーディングの様々な場面に当てはめる方法を紹介します。名前の付け方、コメントの書き方など表面上の改善について。コードを動かすための制御フロー、論理式、変数などループとロジックについて。またコードを再構成するための方法。さらにテストの書き方などについて、楽しいイラストと共に説明しています。
質の高い(バグが少なく、メンテナンス性が高い)プログラミングをするための、一生使える原理原則を、「なぜそうなるのか」「どうやって使えばいいのか」やさしく解説。脱・初心者を目指す入社3年目までのプログラマーのステップアップに最適のガイドブックです。
最後までお付き合い頂きまして、ありがとうございました。
コメント