コードの最低品質を底上げする為のルール的なアレ。

何となくまぁ、話題になったので、とりあえず書いておくます。
ルールなのだけど、常に例外的状況は存在しるます。
その例外的状況を適切に把握しているのであれば、どの様にコード書いても良いです。
自分の中で一定のルールを持ってコーディングすると、
そもそも自分がミスをし易いパターンを把握し易いのと、
自分のコードの最低品質がある程度担保されるので、良いかな…と思うマス。


要は、みんな俺様ルールを作って、
それをある程度意識しながらコーディングすれば良いと思うよ、って話。

考え方の基本。

  • 自分の能力が最も発揮されない状況を想定する事。
    • 疲れている、やる気ない、気になる事が他にある、等々…
  • 頭を使う時間は計測するのが難しいが、タイピングしている時間は、ある程度簡単に計測可能である事。
    • 「考えている時間」は、貴重なリソースだけど、見積もりが難しいのだよねぇ…。すごく。
      この位の時間考えれば答えが出る筈だ、みたいな事を見積もりすんのは、結構難しいと思う。
      一方で、10000文字タイピングする時間は、何度か計測すれば、見積もり出来る様になるですだよ。
  • ちょっと考えた上で、訓練すれば誰でも出来る事。
    • まぁ、つまり、これから書く事は、結構しょうもない事ですよ、と。

実際のルール

  • 一つのスコープの中に収める変数の数をギリギリまで減らす。理想的かつ具体的には7つ。
    • Magical Number of 7って奴です。どこが出元なのか知らないけど、人間は、平均すると7つ位までの事象を同時に認識出来るらしいでつ。
    • ちなみに、僕の場合は、脳のメモリが少ないので3〜5くらい。賢い人は、10でも20でもいけるかもしれないけどもさ。
  • 1つのメソッドまたは関数が、開いているエディタで一画面に収める。収まらない時は、無理にでも分割する。
    • 画面のスクロールしながら、コード読むとコード読む作業に加えてマウスをスクロールするので、純粋にコード読む事に集中出来なくなるのが良くないのでつ。
    • 調子が良い時は、特に気にならないだろうけど、特に疲れている時には、脳の中を一つのタスクに集中させる方が良いと思うですだ。
    • 使ってるフォントサイズやら、モニタの枚数やら解像度やらで、全然違ってくるので、具体的な数字を挙げるのは難しいのだけどね。
  • 使用する比較演算子を絞る。Javaなら、<と==。
    • 僕が<を選んでいるのは、一般常識として、左が小さくて、右が大きいと思っているから。後、=の位置が<の右なのか左なのか忘れるから。
    • 比較演算子は、大抵のプログラミング言語で、<、<=、!=、==、>、>=が少なくともある筈。C#だと、もっとあるけど。
      このルールによって、比較対象となる数値についてのみ考えれば良くなります。色んな比較演算子を使う事を前提にすると、それだけで、考えるべき事が単純に4倍以上になるので、しんどい。
    • 多分、このルールを導入すると、this.hoge < value && value < this.hoge みたいになって、最初結構気持ち悪いのだけど、慣れまつ。
  • 条件分岐は、if文のみを使う。
    • 具体的には、switch文を使わない。if else で代替可能だし。
    • 特にJavaのswitch caseは、breakが必要だし、case毎のスコープになっていないので、構文として余り良くないのでつ。
    • 使う構文を絞る事で、条件の内容だけに集中出来る様になる事が重要でつ。
  • if文で、!(エクスクラメーションマーク)を使わない。具体的には、if(cond)もしくは、if(cond == false)と書く。
    • モニタのドットピッチにもよるのだけど、まぁ、細くて見逃し易いから。
    • 印刷してコードレビューすると、大概見落とす。読まないといけない量が多かったりすると、間違いなく見落とす。
    • if(cond == true)とは書かない所がポイントだったりする。対称性が無いので、論理的根拠に欠けるのだけどね。
    • 使ってるのは、IDEでもテキストエディタでも良いんだけど、少なくともeclipseでは、falseは強調表示されるけど、!は強調表示されない。
      他の環境でも似たようなもんじゃないかなぁ…
  • ループは、for文のみを使う。
    • javaなら、拡張for文は、積極的に使う。
    • while文は、変数のスコープが大きくなりがちなのと、殆どの状況でfor文を使う事が可能だからでつ。
    • よって、こういう気持ち悪い書き方も許容する。for(boolean cond = false;cond;) {}。
  • 再帰を使わない。末尾再帰で簡単に代替可能なら、そっちを使う。
    • もしくは、使う状況を予め限定する。僕の場合は、Treeとか、Nodeとか、そういう木構造っぽい名前を持ったクラスに対する処理を書く時だけ再帰しるます。
    • 加えて、再帰処理は、それだけを行うメソッドまたは関数とし、それ以外の処理は、切り出す。つまり、Visitor使う。
  • 変数名の長さと、スコープの広さに対応関係を作る。
    • 具体的な数字を挙げる事はしないけど、特定のスコープの中で、最も広いスコープの変数が、最も長い変数名になる様にする。
    • つまり、ローカル変数で、スコープが特に短いモノに、iとかmとか一文字の変数を使う事や、長いメソッドで、そのメソッド全体で使う変数を、idxみたいな謎の省略名にする事を許容する。
  • 戻り値の変数名を常に「result」にする。
    • 変数名考えるのは結構難しいでつ。自動的に決められるものはいつも同じにするのが良いと思いまつ。
  • 各メソッドのreturn文を一か所だけにする。
    • これによって、if文のネストが飛躍的に深くなり易くなりまつ。
    • 但し、return文が複数ある時よりも、飛躍的にデバッグし易くなりまつ。
    • 1つのメソッドを画面内に収めるルールとの併せ技で、if文のネストが深くなる事を防げます。
  • try catchは実質的にgotoである事を強く意識する。
    • 濫用は、ダメ、ゼッタイ。
  • メソッドやメンバ変数のスコープは、とりあえず「protected」にする。
    • ここは、間違いなく意見が分かれるトコロなのだけど、既に動いているコードをHackし易くなるます。
    • 更に、変数のスコープを短くするべき、と言うルールとはある意味矛盾している。
  • publicメソッドがあるクラスは、interfaceを定義する事を考慮する。
    • これも拡張性を簡単に得る為の技術でつ。
    • 実装継承を前提にするより、interfaceと移譲による多重継承を使う方が、コードを再利用し易くなりまつ。


なんか他にもある様な気がするけど、すぐに思い出せないので、そんなに重要なルールじゃないって事でしょう。