リーダブルコード 9章のまとめ

※編集中です

はじめに

会社で勉強の一環として、「リーダブルコード」をみんなで読むということを始めたので、そのためのまとめ

私のようなへっぽこプログラマーには願ったりかなったりなので頑張って勉強しています

なお。
9章(しかも途中から)以外はここではまとめていません笑

定義の位置を下げる

元々C言語では関数やブロックの先頭で変数を定義する必要があったので、
その名残で例えばPythonでもこんな書き方をする人がいる
(本当にいるのか…?)

良くない例

def ViewFilteredReplies(original_id):
    filtered_replies = []
    root_message = Messages.objects.get(original_id)
    all_replies = Massages.objects.select(root_id=original_id)

    root_message.view_count += 1
    root_message.last_view_time = datetime.datetime.now()
    root_message.save()

    for reply in all_replies:
        if reply.spam_votes <= MAX_SPAM_VOTES:
            filtered_replies.append(reply)

    return filtered_replies

うーん、確かに読みにくい

こういう書き方をする必要はもはや無いので
変数の定義は変数を使う直前に移動する

良い例

def ViewFilteredReplies(original_id):
    root_message = Messages.objects.get(original_id)
    root_message.view_count += 1
    root_message.last_view_time = datetime.datetime.now()
    root_message.save()

    all_replies = Massages.objects.select(root_id=original_id)
    filtered_replies = []
    for reply in all_replies:
        if reply.spam_votes <= MAX_SPAM_VOTES:
            filtered_replies.append(reply)

    return filtered_replies

はい、だいぶ読みやすくなりました

Cから入った人は、ここで挙げられている「良くない例」みたいな書き方をしたくなるんでしょうか…?

MATLABから入りPythonくらいしか書けるようになってない私は
そもそも最初にまとめて書こうとさえ思いませんでした笑

でも、きっとまとめたくなる場合もあるとは思います

追記
他の人の話を聞いたら、組み込みなど変数の開放が必要になる場合、宣言をまとめたくなるそうです
確かに、忘れないように1か所に固めるというのは分かりやすいですね

変数は一度だけ書き込む

「生きている変数」が多いとコードが理解しにくくなるらしい

それをさけるために、
「変数は一度だけ書き込む」ことを心掛けよという話
(耳が痛い話です)

例えば、

static const int NUM_THREADS = 10;

だと明確である
だって値が変わらないんだもの

でも、いつもそううまくいくものでしょうか?
というのがちょっと疑問に思ったところではありました

私はデータフレームにデータを追加したりクレンジングしたりと
ここでいう「変数を何回も操作」してしまっているような気がします…

また、同じ理由で、C++の場合はconstを使うべきらしいですね
Pythonを含めてstringなどの組み込み型は「イミュータブル」になっているそうなんですが、
基本的にイミュータブルの方がトラブルが起きにくいらしいです
(イミュータブルって何?だったので調べる…)

うーん、でも、C++だと

const int a=123;
a=456;            // コンパイルエラー(代入不可)

ですが、Pythonだと

a = 123
a = 456 # エラーにはならない

なのでエラーにはならないですよね、
これは本当にトラブル対策になっているのか…?

ただ、この節でいわれているポイントは
「変数を操作する場所を減らす」ことは間違いないでしょう

最後の例

以下のような入力フィールドがウェブページにあったとする

<input type="text" id="input1" value="Dustin">
<input type="text" id="input2" value="Trevor">
<input type="text" id="input3" value="">
<input type="text" id="input4" value="Melissa">

このとき、setFirstEmptyInput()という、以下の操作を行う関数を考える

  • 「文字列を受け取り、ウェブページにある最初の空の\<input>に入力する
  • 戻り値は更新したDOM要素(空の入力フィールドが無ければnullになる)

良くない例

var setFirstEmptyInput = function (new value) {
    var found = false;
    var i = 1;
    var elem = document.getElementById('input' + 1);
    while (elem !== null) {
        if (elem.value === '') {
            found = true;
            break;
        }
        i++;
        elem = document.getElementById('input' + i);
    }
    if (found) element.value = new_value;
    return elem;
};

一応動くがあまりきれいではない

ここで、変数に着目する

  • var found
  • var i
  • var elem
    については、何回も書き換えられている

まず「制御フロー変数」であるfoundを削除する

var setFirstEmptyInput = function (new value) {
    var i = 1;
    var elem = document.getElementById('input' + 1);
    while (elem !== null) {
        if (elem.value === '') {
            elem.value = new_value;
            return elem;
        }
        i++;
        elem = document.getElementById('input' + i);
    }
    return null;
};

関数から早めに返すことでfoundを削除できた

次にelemに着目する
elemはiに合わせてイテレートしているので、
whileをforに変更してみる

var setFirstEmptyInput = function (new value) {
    for (var i = 0; true; i++) {
        elem = document.getElementById('input' + i);
        if (elem === null)
            return null;   // 検索失敗。空の入力フィールドは見つからなかった。
        if (elem.value === '') {
            elem.value = new_value;
            return elem;
        }
    }
};

リーダブルコード内でも触れられていましたが、
forの条件にtrueとはあまり書かないと思います

というか、
forでtrueは危険すぎるとの意見でした
ですよね。。なんとなくそんな気はします

きゅうこん

きゅうこん

元メカ設計者、現なんちゃってAIエンジニア。実験データを分析しているうちにプログラミングとAIのスキルを習得(?)職業何ですか?と聞かれたときに何と答えるべきかを考える日々。 Qiita: https://qiita.com/kamome885

タイトルとURLをコピーしました