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

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

コード=読みやすくあるべきという観点で見ると、書く際に気をつけるべきは命名と分割という話。

命名を意識するというのは次のような感じです。
例えばこんなコードがあったとします。
String orange = "Apple"; // これは論外
String info = "Some Information";
前者はそもそも書いてあることと中身が違うので、混乱をきたすどころか、バグでも起きた日には迷宮入りしかねません。後者は、結局なんの情報?という部分が欠落しているので、読み手は中身が正しいのかどうか判定できません。(前後の文脈で判断を仰ぐのは、時間の無駄になるので適切ではありません)
一方で、命名がしっかりしていれば、細かなロジックがわからなくても何をしているのか理解できる(ここが重要)はずなので、命名はコードを書く際に意識すべき要素だといえます。

分割を意識するというのは次のような感じです。
次のコードを見てください
void eatBreakfast() {
    while () {
        〜
    }
    while () {
        〜
    }
}
eatBreakfastの中で2つの処理が混在しています。これでもいいのでは?という意見はあると思いますが、これでは、ぱっと見た時に、eatBreakfast(朝ごはんを食べる)が2つのwhileループからなることはわかりますが、それが一体何をしているのかはわかりません。
(じっくり読めばわかるんだと思いますが、それをさせるのは良いコードではありません)

なぜわかりにくいのかというと、朝ごはんを食べる処理にはいくつか分割できる要素がある(eatBreakfastは抽象度が高い)のですが、それがそのまま(抽象度が高いまま)になっているからです。
そこでeatBreakfastが、実際には、「パンを食べる」と「コーヒーを飲む」から構成されていたとするならば、
void eatBreakfast() {
    eatBread();
    drinkCoffee();
}
となります。明らかにわかりやすくなりました。

命名と分割 、ぜひ意識してコードを書いて見てください。

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

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

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

サイトはいろいろ有りますが、有名どころだと
コーディングスキルチェック:
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";
}
いかがでしたでしょうか?意外と簡単な印象を受けていただけてたら嬉しいです。 もちろん、これ以外にも様々なことを気をつける必要は有りますが、まずはそれぞれのメソッドの目的を明確化して、きちんと名前付けするのを意識するだけでもだいぶ綺麗なコードが書けるようになるはずです。

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

↑このページのトップヘ