俺の名はケンヤ。難事件をいくつも迷宮入りさせたニート。しかし ある時謎の組織に入社し薬を飲まされ身体が縮んで Braian になっちゃった。
「面白いコードと読みやすいコードは違う」
「コードは理解しやすくなければいけない」
「コードは他人が最短で理解できるコードでなければならない」
「コードは短い方がいいが、"理解するまでにかかる時間"を短くするほうが大切」
名前に情報を詰め込む
明確な単語を選ぶ
例えばGetではなく、状況に応じてFetchやDownloadなどを使う.
tmpやretvarなどの汎用的な名前をさける
ただし、明確な理由があれば話は別。
具体的な名前を使って、物事を詳細に説明する
ServerCanStart()よりもCanListenOnPort()のほうが明確だ。
変数名に大切な情報を追加する
ミリ秒を表す変数名には、後ろに_msをつける。これからエスケープが必要な変数名には、前にraw_をつけるなどの工夫をする。
スコープの大きな変数には長い名前をつける
スコープが扱う画面に及ぶ変数に1〜2文字の短めの暗号めいた名前をつけてはならない。短い名前はスコープが数行の変数につけるべきだ。
大文字やアンダースコアなどに意味を含める
例えば、クラスのメンバ変数にアンダースコアをつけてローカル変数と区別する。
プロジェクに新しく入ってきた人でも理解できるようにする
後からプロジェクトに入ってくる人はもちろん、一人での開発なら半年後自分で見直しても理解できるようにする
限界値を含める時はmin、maxを使用する
範囲を指定する時はfirst、lastを使用する
包含・排他的範囲にはbegin、endを使用する
ブール値ではis、hasを使用する
複数の名前を検討する
名前を決めるときは複数の候補をだして、最終的にどの名前が一番誤解を招かないのかを判断する
最善の名前とは読み手が誤解を招かないこと。
すぐれたコードは目に優しいものでなければいかない
①読み手が慣れているパターンと一貫性のあるレイアウトを使用する
②似ているコードは似ているように見せる
③関連するコードをまとめてブロックにする
一貫性のある簡潔な改行位置
メソッドを使った整列
縦の線をまっすぐにする
一貫性と意味のある並びにする
宣言をブロックにまとめる
コードを段落に分割する
個人的な好みと一貫性
最終的には個人的な好みになってしまうが、重要なのは一貫性を保たせること。
間違ったスタイルを使用しているプロジェクトに参加した際もプロジェクトの規約に従うことがきれいなコードをかくことに繋がる
コメントの目的は、書き手の意図を読み手に知らせること
①コメントすべきでは「ない」ことを知る
・コードからすぐに摘出できること
・ひどいコードを補うコメントはコードの名前を変える
②コードを書いているときの自分の考えを記録する
・なぜコードが他のやり方でなくこのやり方になっているのか
・コードの欠陥をTODOやXXXの記法を使用する
③読み手の立場になって何が必要になるかを考える
・コードを読んだ人が「えっ?」と思うことを予想してコメントをつける
・読み手が驚くような動作は文章化しておく
・ファイルやクラスには「全体像」のコメントをかく
・読み手が細部に捕われないように、コードブロックにコメントをつけて概要をまとめる
コメントすべきでは「ない」ことを知る
コードから"すぐに"読み取れることをコメントに書かない
コメントのためのコメントをしない
ひどい名前はコメントをつけずに名前を変える
「優れたコード > ひどいコード + 優れたコメント」
自分の考えを記録する
優れたコメントとは自分の考えを記録するためのものである
「監督のコメンタリー」を記録する
作品がどのように作られたのかを理解するのに役立つ
コメントにはコードに対する考えを記録しなければいけない
コードの欠陥にコメントをつける
例: TODO: もっと高速なアルゴリズムを使う
記法 TODO: あとで手を付ける
FIXME: 既知の不具合があるコード
HACK: あまり綺麗じゃない解決策
XXX: 危険!大きな問題がある
読み手の立場になって考える
質問されそうなことを想像する
・関数やクラスを文章化するときには「このコードをみてびっくりすることは何だろう?」と自分に問いかける
ライターズブロックを乗り越える
プログラマの多くはコメントを書きたがらない。コメントをうまく書くのは大変だと思っているからだ。
コメントを書くjことによって品質が次第によくなっていくことを理解する。
コメントは正確で簡潔に
コメントは領域に対する情報の比率が高くなければいけない
あいまいな代名詞を避ける
代名詞は物事を複雑にしてしまう可能性がある。
はっきりと主語をつける
歯切れの悪い文章を磨く
関数の動作を正確に記述する
入出力のコーナーケースに実例を使う
コードの意図をかく
情報密度の高い言葉をつかう
まとめ
・複雑なものを指す可能性がある「それ」や「これ」などの代名詞を避ける
・関数の動作はできるだけ正確に説明する
・コメントに含める入出力の実例を慎重に選ぶ
・コードの意図は、詳細レベルではなく、高レベルで記述する
・よくわからない引数にはインラインコメントを使用する
・多くの意味が詰め込まれた言葉や表現を使って、コメントを簡潔にかく
制御フローを読みやすくする
条件やループなどの制御フローがあるとコードがよみにくくなってしまうことがある。
条件やループなどの制御フローはできるだけ「自然」にする。コードの読み手が立ち止まったり読み返したりしないように書く。
条件式の引数の並び順
if/else ブロックの並び順
・条件式は否定形よりも肯定形を使う。
・単純な条件式を先に書く。ifとelseが同じ画面に表示されるので見やすい。
・関心を引く条件や目立つ条件を先に書く。
三項演算子
do/while ループを避ける
do/whileはif文、while文、for文などの条件と違い「下から上」に読まなければならないので不自然
関数から早く返す
return を早く返してあげることで読みやすくなることがある
ネストを浅くする
単純にネスとの深いコードは読みにくい
ネストが増える仕組み
変更する時にはコードを新鮮な目でみる。
早めに返してネストを削除する
ネストを削除するには「失敗ケース」をできるだけ早めに関数から返せばいい
ループ内部(多重ループ)のネストを削除する
早めに返すのをループ内部で使用する場合はcontinueを使用する
巨大な式を分割する
説明変数
式を簡単に分割するには説明変数を用いても良い
ド・モルガンの法則をつかう
「notをくくりだす」と覚えればいい
短絡評価の悪用
プール演算子は短絡評価を行うものが多いので注意
「頭がいい」コードに気をつける。あとで他人がコードを読むときに分かりにくくなる
より優雅な手法を見つける
複雑なコードは「もっと簡単なコードがあるはずだ」と考える
巨大な文は分割をする
巨大な文は理解するのが難しくなってしまうため分割することを検討する
変数と読みやすさ
①変数が多いと変数を追跡するのが難しくなる
②変数のスコープが大きいとスコープを把握するのに時間がかかる
③変数が頻繁に変更されると現在の値を把握するのが難しくなる
変数を削除する
コードが読みやすくならない変数を削除する
中間結果を削除する
制御フロー変数を削除する
グローバル変数は避ける
グローバル変数はどこでどのように使われるのか追跡するのが難しい。
また「名前空間を汚染する」(ローカル変数と衝突する恐れがあること)から避けたほうがよい。
変数のことがみえるコード行数をできるだけ減らす
「生きている変数」が多いとコードが理解しにくくなる
変数は一度だけ扱う(できるだけ)
変数を操作する場所が多くなると、現在値の判断が難しくなる
まとめ
・邪魔な変数を削除する
・変数のスコープを小さくする
・一度だけ書き込む変数をつかう
コードの再構成
①プログラムと主目的と関係のない「無関係の下位問題」を抽出する
②コードを再構成して、一度に一つのことをやるようにする
③最初にコードを言葉で説明する。その説明を元にキレイな解決策を作る
④コードを完全に削除できる状況について説明する。また、コードを書かずに済ませる状況についても説明する(コードを理解しやすくするにはコードを書かないのが一番)
エンジニアリングとは、大きな問題を小さな問題に分割して、それぞれの解決策を組み立てることに他ならない。この原則をコードに当てはめれば、堅ろうで読みやいコードになる
無関係に下位問題を積極的に見つけて中秋すること
①関数やコードブロックをみて「このコードの高レベルの目標は何か?」と自問する
②コードの各行に対して「高レベルの目標に直接的に効果があるのか?あるいは、無関係の下位問題を解決しているのか?」と自問する
③無関係の下位問題を解決しているコードが相当量あれば、それらを抽出して別の関数にする
凡庸コードをさくさんつくる
凡庸コードはプロジェクトから切り離して考えられるので扱いやすい
このプログラミングはトップダウン?ボトムアップ?
トップダウンプログラミングとは、先に高レベルのモジュール関数を設計してから、それらをサポートする低レベルの関数を実装していく方式だ。
ボトムアップとはプログラミングとは、先にすべての下位問題を解決してから、それらを利用する高レベルのコンポーネントを実装していく方式だ。
プロジェクトに特化した機能
抽出する下位問題というのは、プロジェクトから完全に独立したものであるほうがいい。ただし、完全に独立していなくても、それは問題ない。下位問題をのぞくだけでも効果がある。
既存のインターフェースを簡潔にする
「理想とは程遠いインターフェースに妥協することはない」
自分でラッパー関数を用意して汚いインターフェースを覆い隠すのも綺麗なコードをつくるための手法
やりすぎ
小さな関数を作りすぎても逆に見にくくなってしまう。
「無関係の下位問題を積極的に見つけ抽出する」ことは目的だが、やりすぎて見にくくなってしまうのには注意が必要
まとめ
プロジェクト固有のコードから凡庸コードを分離するということ。
ほとんどのコードは凡庸化できる。
一度に一つのことを
一度に一つのことをするコードは理解しにくい。例えば、オブジェクトを生成して、データを綺麗にして、入力をパースして、ビジネスロジックを適用しているようなコードだ。
これらのコードがすべて絡みあっていると、「タスク」が完全に個別に完結しているコードよりも理解するのが難しい。
コードは一つずつタスクを行うようにしなければならない
一度に一つのタスクをする
①コードが行っている「タスク」をすべて列挙する。この「タスク」
という言葉はユルく使っている。「オブジェクトが妥当かどうかを確認する」のように小さなこともあれば、「ツリーのすべてのノードをイテレートする」のようにあいまいなこともある。
②タスクをできるだけ異なる関数に分割する。少なくとも異なる領域に分割する。
オブジェクトから値を抽出する
「一度に一つのタスク」を適用する
まとめ
「一度にひとつのタスク」を行う
読みにくいコードがあれば、そこで行われているタスクをすべて列挙する。そこには別の関数(やクラス)に分割できるタスクがあるだろう。
それ以外は関数の論理的な「段落」になる。
タスクをどのように分割するかよりも、分割するということが大切。
コードに想いを込める
おばあちゃんがわかるように説明できなければ、本当に理解したとは言えない
アルバート・アインシュタイン
誰かに複雑な考えを伝えるときには、細かいことまで話すぎると相手を混乱させてしまう。自分よりも知識が少ない人が理解できるような「簡単な言葉」で説明する能力が必要だ。自分の考えを凝縮して、最も大切な概念にすることが必要になる。これは誰かに理解してもらうだけでなく、自分の考えをより明確にすることにもなる。
コードもこれと同様で読み手が理解できるように「簡単な言葉で」書くべきなのだ
①コードの動作を簡単な言葉で同僚にも分かるように説明する。
②その説明の中で使っているキーワードやフレーズに注目する
③その説明に合わせてコードをかく
ロジックを簡単に説明する
短いコードを書く
プログラマが学ぶべき大切な技法というのは、コードを書かないときを知ることなのかもしれない。自分で書いたコードであれば、すべての行をテストして保守しなければならない。
ライブラリの再利用や機能を削除することで、時間を節約したり、コードを簡潔に維持したりできる。
最も読みやすいコードは何も書かれていないコードだ!
その機能の実装について悩まないで、きっと必要ないから
プロジェクトを開始するときには、これから実装するかっこいい機能のことを考えて興奮するものだ。そして、プロジェクトに欠かせない機能を過剰に見積もってしまう。その結果、多くの機能が、完結しないか、全く使われていないか、アプリケーションを複雑にするものになってしまう。
プログラマというのは、実装にかかる労力を過小評価するものでもある。プロトタイプの実装にかかる時間を楽観的に見積もったり、将来的には必要となる保守や文章化などの「負担」時間を忘れがちになる。
質問と要求の分割
すべてのプログラムが、高速で、100%正しくて、あらゆる入力をうまく処理する必要はない。要求を詳しく調べれば、問題をもっと簡単にできることもある。そうすれば、必要なコードも短くて済む。
キャッシュを追加する
コードを小さく保つ
ソフトウェアプロジェクトを始めるときには、ソースファイルは一つや二つしかない。しかし、プロジェクトが進んでいくと、ファイルが増えていく。ディレクトリを分けてファイルを整理しなければならなくなっていく。どの関数がどの関数を呼び出しているのか分からなくなってくる。バグを見つけるのもだんだん面倒になってくる。
最終的には、いろんなディレクトリにファイルが散らばることになる。プロジェクトは巨大になって、すべてを把握できる人もいなくなる、新しい機能を追加するのが苦痛になってくる。コードを扱うのが厄介になり楽しくなくなる。
あらゆる協調システムは成長する。それらを結びつける複雑さはもっと速い速度で成長する。
つまり、プロジェクトが成長しても、コードをできるだけ小さく軽量に維持するしかない。
そのためにやること
①凡庸的な「ユーティリティ」コードを作って、重複コードを削除する。
②未使用のコードや無用の機能を削除する
③プロジェクトをサブプロジェクトに分割する
④コードの重量を意識する。軽量で機敏にしておく。
身近なライブラリに親しむ
「ライブラリを熟知して、実際に活用することが大切」
たまには標準ライブラリの全ての関数・モジュール・型の名前を15分かけて読んでみよう!
標準ライブラリとはAPIや組み込みモジュールのことだ。
ライブラリの再利用はなぜいいことなのか
統計ではあるが、平均的なソフトウェアエンジニアが一日に書く出荷用のコードは10行なのだそうだ。
嘘だと思えるが、大切なのは"出荷用"という言葉だ。成熟したライブラリコードの裏側には、膨大な設計・デバッグ・修正・文書・最適化・テスト・が存在する。このダーウィンの進化を生き延びてきたコードには価値があるからだ。
まとめ
・不必要な機能をプロダクトから削除する。過剰な機能はもたせない。
・最も簡単に問題を解決できるような要求を与える。
・定期的にすべてのAPIを読んで、標準ライブラリに慣れ親しんでおく