『Clean Code』 ノート(1)
クラシックの一冊、Robert C. Martin氏のClean Codeを読んでみようと思います。クリーンコードのために何ができるか、ヒントになれるはずです。ここは本の1と2章の内容となります。
なぜクリーンコードが必要なのか
混乱なコードだと会社を壊滅させることも可能です。特に自社商品開発の会社にとって、沼(wading)にハマってしまうと、生産性が0に近くなり、競争に負ける運命は定められています。クリーンコードは効率・生産性を高めるためだけでなく、生存に関わる重要な位置付けだと。
プログラマーがマネージャーからのスケジュールのプレッシャーの前に、とりあえず動くコードを書く、という謎の落とし穴に陥ってしまいがちです。そのせいで、時間をかけて設計を洗練することを諦めることがしばしばあるでしょう。
これは、患者が医者に、手術の前に手を洗わないでください、時間の無駄だから、と言っていると同然で、医者は当然断るでしょう。なぜなら、医者が患者より感染のリスクを熟知しているからです。もし患者のいう通りにすると、専門性の欠けた態度となります。同じく、プログラマーが混乱のリスクを負いながらも、とにかくスケジュールに追われていることを優先することも、「プロ」らしくない判断です。感染が病気を悪化させることと同じく、混乱なコードがスケジュールに間に合うことになんの役にも立ちません。むしろ開発者を遅らせるだけです。
そのため、スケジュールに間に合う唯一の方法というのは、終始クリーンコードを保つことです。
どんなコードが「クリーン」なのか
これは絵を描くことと似ていて、多くの人は、絵が上手かどうかを判断できるが、上手に描くことがプロでない限りできまい。綺麗なコードと、汚いコードの分別も大半のプログラマーにはわかるが、綺麗なコードを描くことがそうにいない。
クリーンコードを描くために、様々なスキルとテクニックを習得・使用することが必要。このプロセスは、アーティストになるための道なりとも考えられるでしょう。
何がクリーンなコードなのかについて、C++の発明者、Bjarne Stroustrup氏が次のように述べています:
私は優雅と効率的なコードが好きだ。コードのロジックは直接的で、欠陥が隠れないであるべき。依存関係をできるだけ減らし、メンテナンスに役立つだろう。ある種の層を分ける策を元に、エラー処理のコードを改善する…クリーンコードは一つの仕事だけを熟す。
他にもいろんな数十年の開発経験を持つ超ベテラン開発者から意見が挙げられていて、まとめてみると:
- 本人と他の開発者に読みやすいコード
- シンプル、直接的、コード意図がわかりやすい
- 依存性が低い(凝集度が高い)
- ユニットテストのある・パスできるコード
- できるだけ小さい(短い)コード
- 重複のないコード
読みやすさの重要性について、もう一つの例が挙げられている:コードを書くというよりも、実際に開発中コードを書くと読む時間の比例が1:10ないし以上。古いコード、ネットで検索したコードなどを含めて読む時間が圧倒的に多い。この時間を楽にさせるためにも、読みやすさを常に優先した方が良いでしょう。
有意義な命名
ネーミングは開発の中に充満しています。ファイルの名前、クラスの名前、関数の名前、変数の名前などなど。この章は良いネーミングのルールを列挙しています。
- 名前でwhat/why/howが分かる
良い名前の存在だけで、何をするものか、その中身が分かるはず。ここはJavaの慣習で割とverboseなネーミングの例が挙げられていますが、目的が伝わるとの意味で良いと思います。
- 誤解を招かないように
専用名詞の略語、ビルトインのキーワードなどを使わない。数字1とl、数字0とO、というようなキャラクタを避けようと。
- 意味のある分別をする
a1, a2 ... anのような数字系列の名前が正確な情報を提供していなく、コードの意図も見えません。また、意味の近い言葉で別々のクラス・関数などを作らない。
さらに、variableは変数の名前に出ること、tableがテーブルの名前に出ることなど、無意味な蛇足は無用。
- 読める名称を使う
記憶を促進するために、読めることが非常に大事なこととなる。自分で勝手に言葉を作らないこと。genymdhms
のような言葉は絶対に避けるべき。
- 検索しやすい名称を使う
例えば変数名sとsumを比べると、今時のIDEとエディターにはabsolute検索はできるでしょうが、sumの方が意図も分かり、検索するときも出てきやすい。また、定数を使う場合は定数に名前を付与した方が良い。
- preとpostはいらない
データタイプを名前に入れない。
m_とかを変数名の前(後も含む)につけることも不要。クラスと関数を小さく分割することで語尾・語頭へのニーズを消すことができるはず。
- 翻訳する必要のある名称を使わない
ここの翻訳というのは、例えばa, b, cのようなキャラクター一つの変数名、そのままではなく、人が読むときに何か別の言葉に変化させないといけないことを避けるべき。
- クラス名
クラス名は名詞、もしくは名詞のプレーズ・組み合わせ・動詞は避けるべき。
- メソッド・関数名
動詞または動詞のフレーズ。一部は慣習に従って、get, set, isなどを前につける。
- 冗談は止せ
冗談半分、ユーモアをアピールための命名は避けるべき。言葉そのままの意味が伝われば良い。
- 一貫性を持つ
近い意味を持つ言葉、例えばget, fetch, retrieve、delete, remove, destroy、これらを終始統一にすること。
- 一つの単語の目的も一つ
同じ単語を違う目的の関数とかに使わない。これは一貫性を持つ原則の補足でもあり、一貫性を保つためにあえて違うことを同じ単語で命名すると逆効果となります。
- 専門領域の名称を使おう
コードを読むのはプログラマーですから、専門用語を大胆に使えば良い。Visitorデザインパターンが分かると、AccountVisitorの命名に意味があるし、JobQueueとかが分からない開発者もいないでしょう。
- プロジェクトの関わる領域の名称を使おう
上記の補足として、もし専門用語が使えないのであれば、プロジェクトの関わる領域の名称・用語を使おう。
- コンテキスト・文脈を意識しよう
一つの名称のみで全てを説明できることは珍しい。むしろ、ネームスペース、クラス、関数などの文脈全体を考慮した方が良い。そもそも、preの語頭とpostの語尾はその手段の一つとして使われていますが、良い文脈を提供していると、preとpostも不要となるでしょう。
16. 文脈の蛇足注意
例えばGas Station Deluxeとのアプリを開発しています。それで全てのクラスの前にGSDを語頭としてつけてしまうと、蛇足になってしまいます。
経験的に、「これ以外に可能性がない」文脈はいらないものです。
命名については以上合計16個くらい羅列されています。本にはいろんな例も上げているのでできれば原作を一度読んだ方が良いでしょう。
最後に
自分なりの感想で、重なる部分もありますが、
- 意味の合っている英単語を使う(辞書で随時調べて、スペリングもチェックしよう)
- 慣習=共通認識の略語を使う(自分しか分からない略語を作らない)
- ネームスペースを利用して文脈を作る(ネームスペースでわかるものをクラス名などに入れない)
- 意味が多岐に渡る・言語とフレームワークによく使われている単語を避ける(修飾語を加える)
要するに、精確に伝わるのが何より。
では今日はこれで。
Discussion