くそコードが無くなる日を目指して

実例はC++/Javaがメインです|良いコードは健康を増進します

Category: コーディング

コードを書いているときは目的の機能を早く完成させたくなるがゆえに、細かいとこに気がいきにくくなりがちですが、それは危険です。
よく言われることですが、最終的にそうして出来上がったコードはそのときだけ 動く、汎用性の低いものになっていて、次の機能を追加するときに問題(=バグ)を引き起こします。
もちろん無視してそのようなコードを書き続けてもいいですが、そのサイクルが続けば続くほど汎用性は下がり、どこかの時点で破綻します。

でも、決して汚くしようとしてしているわけではないのに、なぜ問題が大きくなるまで放置してしまうのでしょうか?
これは破綻が突然起きるのではなく、すごく小さなほころびの積み重ねが原因となっているからです。

ちょっと簡単な例を見ながら、どういったところがほころびなのか見てみましょう。

まず、次のような消費税込みの値段を計算するメソッドがあったとします。

class TaxCalculator {
    ...
    public int calculateTaxIncludedPrice(int price) {
        return price * 1.05;
    }
    ...
}
税率を5%としてみました。この時点ですでにほころびがありますが、未来永劫コードに変更がなければおそらく問題は起きません。
しかし、2014年から税率が8%になることがわかり、2014年以降の計算を変更しなければいけなくなったとします。
ここで、問題が発生します。なぜか、上のコードを見た人はきっと、
あー要するに2014年から1.05が1.08になるだけだよね。つまりこうでしょ!
class TaxCalculator {
    ...
    public int calculateTaxIncludedPrice(int price) {
        Calendar date = Calendar.getInstance();
        if (2014 <= date.get(Calendar.YEAR)) {
            return price * 1.08;
        }
        return price * 1.05;
    }
    ...
}
と、考える可能性が高いです。これでだいぶ問題が大きくなりました。
でも、最初の、ほころびが小さいので、これで何が、どうだめになったのかよくわからないかもしれません。

上のコードの問題点は、直接的には1.05、1.08という数字がハードコードされていることなのですが、根本的にはそもそも消費税込みの計算をするということがどういうことかきちんと考えられてない点にあります。
つまり、税込みの値段というのは本当は、
物の値段×税率
であるべきなのに、
物の値段×なんらかの数字
という表現がコード上されてしまっているのが問題です。

物の値段×税率という考え方が最初からあれば、上のコードたちはこうなっていたはずです。
class TaxCalculator {
    private static final float TAX_RATE = 1.05f;
    ...
    public int calculateTaxIncludedPrice(int price) {
        return price * TAX_RATE;
    }
    ...
}
class TaxCalculator {
    private static final float TAX_RATE;
    static {
        Calendar date = Calendar.getInstance();
        if (2014 <= date.get(Calendar.YEAR)) {
            TAX_RATE = 1.08;
        } else {
            TAX_RATE = 1.05;
        }
    }
    ...
    public int calculateTaxIncludedPrice(int price) { 
        return price * TAX_RATE;
    }
    ...
} 
もし、別になにも変化がないと思うようでしたら、世界中の様々な国の税率に対して計算をすることを考えてみてください。
前者では、計算式そのものの部分に変更が加わります、でも後者は国別に税率を設定するだけで済みます。
計算式の部分に変更がはいると、そもそも税率が変わるだけなのに、計算式をいじるという意味的なおかしさが生じる上、なんかのきっかけで掛け算が足し算に変わったり、各国ごとの計算があっているのかといった不要な不安を覚えることにあります。

コードを書くときは、そもそもこの計算は何なのか、何が目的なのかそういう意識をもって書くことを心がけてみてください。

自分だけなのかみんなもそうなのかわかりませんが、家にいると、コーディングがしたくないわけではないけど、かと言って特に作りたいものもないから、何もせず、あーでも何かしなきゃという妙な焦りだけがあって、ただ時間だけが過ぎてしまうことはないでしょうか?

そんなときに個人的におすすめなのが、コーディングスキルチェックサービスやいわゆる競技プログラミングのサイトにある問題を解くことです。

サイトはいろいろ有りますが、有名どころだと
コーディングスキルチェック:
CodeIQ
Paiza
競技プログラミング:
TopCoder
Codeforces
あたりがありますね。

おすすめは、PaizaとCodeforcesです。
Paizaは初心者でも解けるような問題(文字列の中からAの個数を数えるなど)から1時間以上かかる難しい物まであって、その日の時間的な余裕とバランスをとりながら楽しめる、CodeforcesはTopCodeに比べてサイトがシンプルでわかりやすいところが好きで、おすすめです。

解けたからといって、きれいなコードがかけるようにはあまりなれないかもしれませんが、
スピードと正確さが求められる中で、コードの品質も気にすることができれば、一歩先のレベルに行けるようになると思います。

是非、試してみてください。

それでは、良いコード日和を
 

前回、良いコードかどうかは相手に内容を伝えようとしているかどうかの違いといったことを書きました。

今回は実際のコードで実例を交えながら、説明したいと思います。

前回、カレーの例をお見せしましたが、そのときのA)をソースコード風に表現するとこんな感じになります
String menu() {
    String p = "p";
    String o = "o";
    String m = "m";

    Thread.sleep(5000);
    m += "c";

    Thread.sleep(1000);
    o += "c";

    String c = p + o + m;
    Thread.sleep(10000);
    c += "bl";
    return c;
}
問題は、いろいろ有ります。順番に前回のB)のレシピのようにしていってみましょう。

まず、pだのoだのが何を指し示しているかわかりません。
お見せした例が極端に見えるかもしれないですが、意外とめんどくさがられて省略された名前が放置されることはよくあるので、何が何を示すのか名前付けることは常に意識したほうが良いです。
今回はこんな感じになると思います
String menu() {
    String potato = "potato";
    String onion = "onion";
    String meat = "meat";
(以下略) }
これで、p、o、mがそれぞれ何を表しているかわかりやすくなりました。

でも、まだわかりにくいところは残っています。注目すべきは3回出てくるsleepです。
大抵の場合、このように同じような処理を何回もやる場合は、メソッドにくくりだして、それに適切な名前をつけるとわかりやすいコードになります。ここでは、次のようにします。
(よく、くくりだすことが強調されますが、それ以上に名前が重要です。後述します)
String menu() {
    String potato = "potato";
    String onion = "onion";
    String meat = "meat";

    meat = cook(meat, 5000);
    onion = cook(onion, 1000);
    curry = boil(potato + onion + meat, 10000);

    return curry;
}

String cook(String ingredient, long timeMillis) {
    Thread.sleep(timeMillis);
    return ingredient + "Cooked";
}

String boil(String ingredient, long timeMillis) {
    Thread.sleep(timeMillis);
    return ingredient + "Boiled";
}

どうでしょうか。だいぶ元のコードが改善されて、パッと見ただけでも何をしているかわかるようになっていないでしょうか?
ここでのポイントは、メソッドを分けた上で、さらにcookとboilの2つがあることです。
同じ処理構造をしている=まとめて一つのメソッド/関数にしてしまう。と、いったことをやりがちですが、個人的には目的が同じでなければ、このように、似ていても分けて、それぞれに意味のある名前をつけるべきだと思います。もし統一するのであれば、より抽象的な、「火にかける」のような名前にしますが、肉と玉ねぎとカレーの具を火にかけるは同じ作業なのか考える必要があります。
(炒めることと煮ることは違う作業ですよね)

これでだいたい終わりです(数字がマジックナンバーなのはまた別の日にでも)。最後にメソッドの名前を変えるのを忘れないようにしましょう。
しつこいですが、メソッドに、その中身がやっていることをなるべく正確に示す名前をつけることは重要です。
今回はカレーを作ったのでこんな感じでしょうか。
 
String prepareCurry() {
    String potato = "potato";
    String onion = "onion";
    String meat = "meat";

    meat = cook(meat, 5000);
    onion = cook(onion, 1000);
    curry = boil(potato + onion + meat, 10000);

    return curry;
}

String cook(String ingredient, long timeMillis) {
    Thread.sleep(timeMillis);
    return ingredient + "Cooked";
}

String boil(String ingredient, long timeMillis) {
    Thread.sleep(timeMillis);
    return ingredient + "Boiled";
}
いかがでしたでしょうか?意外と簡単な印象を受けていただけてたら嬉しいです。 もちろん、これ以外にも様々なことを気をつける必要は有りますが、まずはそれぞれのメソッドの目的を明確化して、きちんと名前付けするのを意識するだけでもだいぶ綺麗なコードが書けるようになるはずです。

それでは、良いコード日和を 

ソースコードって難しいですよね。
極論いうとif, for, whileあたりがわかれば誰でも書き始められて、
最近はAndroidやiOSの登場で、初心者でも気軽に簡単にアプリを作れてしまう。
作れてしまうがゆえに、コードの見た目はとりあえず脇に置かれてしまう。
で、気づいたらぐちゃぐちゃ・・・。

あー、もどかしい。

そもそも綺麗なコードってどんな感じ?
自分のはどうなのだろう?
とif, for, whileの使い方を教えてくれたあのサイト、あの本たちは
そういうことは何も教えてくれなくて全然わからないこともよくあると思います。
綺麗に書くのは、スーパープログラマーじゃないとできない。とすら、思ってしまうこともあるかもしれません。

でも、実は綺麗なコードを書くには、知識も特別な技術も本質的には要りません。
相手に伝えようとしているかどうかという、心構えが一番重要です。

良いソースコードは、料理のレシピのようなものです(たぶん)。
たとえば:

A)メニュー
じゃがいもとたまねぎをきりつつ、おゆをわかしながら、にくをいためて、そのごきったじゃがいもとたまねぎをいため、いためたらわかしたおゆをいれてにじゅっぷんくらいにる、じゃがいもがにえたら、かれーるーをいれてあじをととのえてかんせい

B)カレーの作り方
-じゃがいもは皮をむき、一口大に切る
-たまねぎも皮をむき、スライスする
-フライパンに油をひき、肉を炒める
-肉に火が通ったら、切った野菜を入れ、中火で炒める
-玉ねぎがきつね色になるまで炒めたら、鍋にお湯をいれ、炒めた具を煮る
-じゃがいもに串が通るまで煮えたら、カレールーを入れる。
-ひと煮立ちさせたあと味を整えれば完成

なにが言いたいかはなんとなくわかりますよね?
AよりBのほうがわかりやすくないでしょうか?
それはきっと、
・Bはカレーの作り方と書いてあるから、最初からその後にどんなことが書いてあるか想像できる
・順番になっていて、それぞれの手順が分割されている。Aはぱっと見なんだかよくわからない。(ひらがなだし・・・)
・Bは細かい指示(きつねいろまでとか)が書いてあるので、間違えにくそう。Aはどこまで炒めれば良いのかよくわからないので、初めてだと???となりそう
・そもそもAは伝える気があんのかよ!
というところにあると思います。

ソースコードもこれと同じです。今、何を、どのように、どこまで、したいか、それを説明するように書かれているかどうか、それが綺麗なコードと俗にいうくそコードの差です。
意外と単純な気がしてこないでしょうか?

今まさにこれに気づき、意識し始めたあなたは、もう綺麗なコードを書くプログラマーの仲間入りです。

長くなってしまったので、実例は次の記事からお見せしたいとおもいます。

では、良いコード日和を!
 

↑このページのトップヘ