ロジック
リーダブルコードの目的である
HTML・コードは他の人が最短時間で理解できるように書かなければならない
を達成するために、コードの「ロジック」について説明していきます
※ロジックは各段落の内容が独立し、JavaScript の内容がメインになっています
処理の並び順
さて問題です。下記の並び順はどちらが読みやすいでしょうか?
if (count < 10) {}
if (10 > count) {}
どちらも同じ意味ですが、おそらく前者が読みやすいと思います。これは「10 がカウントより大きければ」より「カウントが 10 以下ならば」のテキストが日本語としてより自然であるからです。
「カウントが 10 以下ならば」の書き方は「ヨーダ法」と呼ばれる書き方ですが、現在は一般的に前者の読みやすい書き方が「自然」で良いとされています
上記に似た問題として「三項演算子」の可否もよく問題に上がります
三項演算子は行数を短くすることよりも、他人が理解するのに必要な時間が短くなることを意識して使用するか判断してください
また、if/else 文を書くときは最も一般的(処理回数が多い・処理が軽い・判定が早い・意味順)な処理を最初に判定・処理することで、コード全体を理解する時間を短縮し実行速度が早くする考え方が存在します
設問:if 文を並び替えてください
if (/* 特殊ケース */) {
// 長い処理
// 長い処理
// 長い処理
} else if (/* 上記と同じ頻度の特殊ケース */) {
// 軽い処理A
} else if (/* よくあるケースA */) {
// メイン処理
} else if (/* よくあるケースB */) {
// 軽い処理B
}
ネストを浅くする
次の問題です。下記の並び順はどちらが読みやすいでしょうか?
const A = getValue(a);
if (A < 100) {
const B = getValue(b);
if (B > 30) {
if ((A + B) < 100) {
return (A + B);
}
}
}
return 0;
const A = getValue(a);
const B = getValue(b);
if ((A >= 100) || (B < 30) || ((A + B) > 100)){
return 0;
}
return (A + B);
今回も結果は同じですが、前者より後者が簡単そうに見えますよね?
前者のコードではネストのスペースに最大 12 字も使用しています。今の主流のコーディング規約では 1 行あたり 80 ~ 120 文字とされていますが、文字数の 1/10 を使用しており完全に無駄ですね
ネストが深くなるのは初期構築のときだけでなく、寧ろ運用で「既存コードに新しく判定を追加したい」「一行 if 文を入れるだけで簡単だから」という場面でよく起きます
人間が知覚できる文字数を最大限に使用するために、if 文であれば「早期ガード」の書き方があります。メインの処理に入る前に return させることで、メインの処理を守り処理を高速化しネストを浅くできる、コードを書くうえで必須の書き方です
ネストの深さは罪の深さです。ネストが深くなりすぎたときはコードを見直してみましょう
説明変数/要約変数
ここからは見づらく大きくなりすぎたコードを短く、簡潔に書くテクニックを記載します
下記の式を見やすくするにはどうすればいいでしょうか?
if (text.indexOf('hoge') !== appearPosition) {}
if 文の中に判定が入っているため「if 文であること」「中身の判定」を同時に解釈する必要があります 上記のような場合は「要約変数」を使い、解釈する内容を 1 行ずつに分解します
const isHoge = (text.indexOf('hoge') !== appearPosition);
if (isHoge) {}
式の右辺が定数の場合は、「説明変数」を用いて下記のように書けます
const resulut = text.indexOf('hoge');
if (resulut !== -1) {}
if 文の判定が複雑になるほど、変数への置き換えが重要になっていきます。また「この判定を後で使うよ」と読む人間へ事前に伝えることができます
変数を削除する
式を変数で分割することでコードを読みやすくする方法を紹介しました。しかし変数が多すぎると逆に読みづらくなるため、使うべきでない場合があります
- 複雑な式を分解していない
- 変数にしなくても明確
- 一度しか使われず重複コードの削除に貢献していない
- 直接結果を利用すれば簡潔に書ける
できるだけコードは短いほうが良いです。短く書いた上で説明のために変数へ処理を分割するとキレイなコードになります
変数のスコープを縮める
短くコードを書く際に、できるだけ変数を使い回せるようにグローバルスコープの変数を作る人もいます
count = 0;
const fun1 = function () {
// 処理
for (i = 10 - 1; i >= 0; i--) {
count++;
}
}
fun1();
console.log(count)
// 10 ←!?
console.log(i)
// -1 ←!???
もしスコープを意識せずにロジックを書けば、意図せずに変数の混ざり合いが生じてバグの温床になります
(また、明らかな目的がない限り、グローバル変数は宣言してはいけません)
そのために、変数宣言 var / let / const はスコープを意識して正しく使いましょう
正しく使いましょうと言われても具体的なイメージができない人は「全ての変数を const で書く」書き方ができるかチャレンジしてみましょう。無駄な一時変数を減らし、要所だけを可変変数にすることでスコープを意識した書き方ができます。
設問:下記のコードをリファクタリングしてください
data = [14,21,73,43,9,45];
today = new Date();
num = [];
for (i = 0; i < data.length; i++) {
if (data[i] < 31) {
if (today.getDate() < data[i]) {
num.push(data[i]);
}
}
}
汎用コードを沢山つくる
怠惰なエンジニアの美徳として、「一度書いたコードを二度と書かない」ことがよく上げられます。処理を汎用化して切り出して再利用することで、コードの品質をあげメインの処理に集中することができます
ここで重要な考え方は「思いやり」で説明した「1 度に 1 つのことをする」です
まとめ
コードを書きプログラムを書く仕事をしていても、キレイなロジックを考えられるかどうかにコーダとエンジニアの違いがあると考えています
しかし現実には時間をかけられないため泥臭いコードを納品しなければいけない場面が多々あります。しかし普段から「とりあえず動くコードならいいや…」等の考え方をしていると未来に大きな負債を残します
どんな時でも余裕を持って優雅たれ の姿勢でコードを書けるようになりましょう