この記事では
「リーダブルコード」の第4章ー美しさを読んで自分が理解したことを噛み砕いで記述します。
現場で使用する言語がJavaのため、コード部分はJavaで記述しています。
※あくまで個人の感想です
タイトル「美しさ」
筆者は「美しさ」と表現しているが実際どのような状態のことを美しいというのだろうか?
逆に美しくない=汚い状態とはどういう状態なのだろうか?
以下の2つは1〜100の数字を並べてみました。
例えば76という数字がどこにあるか探してみてください
汚い状態
8 31 49 65 96 99 32 86 81 88
12 60 52 27 58
36 72 3 6 11 50 64 100 2 42 97 73 25
87 38 53 74 61 78 56 55 7 40 34
80 98 69 10 45 71 66 9 82 54 46 95 62 63
24 26 68 84 51 18
37 48 93 41 47 19 43 77 94
21 22 92 89 59 57 4 16 17 29 67 23 35 76
5 33 90 28 83 20 30 70 39
79 14 44 91 75 13 85 15 1
美しい状態
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90
91 92 93 94 95 96 97 98 99 100
美しい状態だと探したい数字がすぐに見つかり
・わかりやすい
・見やすい
といった気持ちになったと思うが、そのような状態のことを「美しい」と表現しているんだと思いました。
1節「なぜ美しさが大切なのか?」
上で示した通り、美しいと以下のような利点があると思う
・探している記述がすぐ見つかる
・何かを追加するときにどこに追加すれば良いか明白
上記の例だと101を追記したければ改行してから先頭に
プログラミングの大半の時間はコードを読む時間なので、
美しいコードの方がプログラマに優しい
2節「一貫性のある簡潔な改行位置」
ここからは「美しい」状態にするために、どんな方法があるか紹介されている。
この説ではタイトルが改行位置とあるが、
筆者の伝えたいことは「シルエットを同じにする」ことだと感じた
例えば以下のような生徒の各教科の成績を保管するクラス
public class Score {
// フィールドは省略
public Score(int japanese, int math, int english, int science, int society) {
// 省略
}
}
汚い状態
Score okaAiSan = new Score(89, 55, 77, 93, 87);
Score hirabayashiShuichiroKun
= new Score(86, 89, 97, 100, 34);
美しい状態
Score okaAiSan
= new Score(89, 55, 77, 93, 87);
Score hirabayashiShuichiroKun
= new Score(86, 89, 97, 100, 34);
上のコードだとシルエットが違うため、ぱっと見では違うことをしているように見える。
下のコードだと同じ位置(=の前)で改行しているため見やすい。
ただこれだとそれぞれの数字が何を表しているか
Scoreクラスを確認しないとわからない// Score(japanese, math, english, science, society) Score my = new Score( 89, 55, 77, 93, 87);
このように引数に関するコメントをつけるとすぐわかる。
クラスの定義を見れば分かるとも思うが、このコメントの使い方は斬新だった
3節「メソッドを使った整列」
以下は2節のScoreクラスを使用してDBにデータを登録することを想定したコード。
汚い状態
Score okaAiSan
= new Score(89, 55, 77, 93, 87);
try {
dao.insert("okaAiSan", okaAiSan);
} catch (Exception e) {
// 例外処理
}
Score hirabayashiShuichiroKun
= new Score(86, 89, 97, 100, 34);
try {
dao.insert("hirabayashiShuichiroKun", hirabayashiShuichiroKun);
} catch (Exception e) {
// 例外処理
}
美しい状態
insert("okaAiSan", 89, 55, 77, 93, 87);
insert("hirabayashiShuichiroKun", 86, 89, 97, 100, 34);
public void insert(String name, int japanese, int math, int english, int science, int society) {
Score score
= new Score(japanese, math, english, science, society);
try {
dao.insert("name", score);
} catch (Exception e) {
// 例外処理
}
}
上のコードでは、シルエットは揃っているものの、try-catch句があり処理の全体感がつかみにくい。
下のコードのようにヘルパーメソッドを定義すると以下のメリットがある。
・重複を削除できる
・コードを追加するのが簡単になる
・try-catch句のような本当にやりたい処理以外の記述を隠すことで大切な部分を強調できる
4節「縦の線をまっすぐにする」
Scoreクラスから点数をそれぞれ取得するコードで見てみる
汚い状態
int japanese = score.getJapanese();
int math = scorre.getMath();
int english = score.getEnglish();
int science = score.getScience();
int society = score.getSociety();
美しい状態
int japanese = score.getJapanese();
int math = scorre.getMath();
int english = score.getEnglish();
int science = score.getScience();
int society = score.getSociety();
空白を使って整列したことでまっすぐ縦に目線を移動できるようになった。
こうするとtypoも見つけやすくなる。
下のコードだと縦に同じ単語が並ぶのでtypoがすぐ見つかります
(が言いたくてtypoはわざと仕込ませています)
空白の個数が変わるときは行数分修正する必要があるが
矩形選択を上手く使えばそれほど手間ではなさそう
Intellijでは「Option → Option + 矢印」もしくはOptionを押しながらドラッグ
5節「一貫性と意味のある並び」
汚い状態
Score hayashi = new Score(/* 省略 */);
Score satou = new Score(/* 省略 */);
Score aoki = new Score(/* 省略 */);
Score yagushi = new Score(/* 省略 */);
Score kimura = new Score(/* 省略 */);
Score koike = new Score(/* 省略 */);
美しい状態
Score aoki = new Score(/* 省略 */);
Score kimura = new Score(/* 省略 */);
Score koike = new Score(/* 省略 */);
Score satou = new Score(/* 省略 */);
Score hayashi = new Score(/* 省略 */);
Score yagushi = new Score(/* 省略 */);
コードの正しさが変わらないのであれば、並び替えた方が探しやすい。
並び順には例えば以下のようなものがある
・HTMLのinputフォームを同じ並び順にする
・アルファベット順や五十音順にする
6節「宣言をブロックにまとめる」
5節の例だと行が増えてきたときに以下の様にブロックで分けると探しやすい
美しい状態
// あ行
Score aoki = new Score(/* 省略 */);
Score ueda = new Score(/* 省略 */);
Score endou = new Score(/* 省略 */);
Score ootani = new Score(/* 省略 */);
// か行
Score katsuta = new Score(/* 省略 */);
Score kimura = new Score(/* 省略 */);
Score kuriyama = new Score(/* 省略 */);
Score koike = new Score(/* 省略 */);
…
ブロックで分けることによって不要な部分を飛ばして読むことができる。
7節「コードを段落に分ける」
Scoreクラスでテストコードを書いてみる
汚い状態
int japanese = 88;
int math = 89;
int english = 90;
int science = 91;
int society = 92;
Score score
= new Score(japanese, math, english, science, society);
assertThat(score.sum()).isEqualTo(450);
assertThat(score.average()).isEqualTo(95);
美しい状態
// パラメータ
int japanese = 88;
int math = 89;
int english = 90;
int science = 91;
int society = 92;
// テスト対象
Score score = new Score(japanese, math, english, science, society);
// テスト
assertThat(score.sum()).isEqualTo(450);
assertThat(score.average()).isEqualTo(95);
段落で分けることによってコードの全体感を掴みやすくなる
8節「個人的な好みと一貫性」
どんなに美しさが改善しそうでもコーディング規約があればそっちを優先しようねという話。
きっと優先順位は
「現場のコーディング規約 > 世間一般フォーマット(インデントとか) > 個人的な好み」
コーディング規約を無視してしまうと、他のコードと見た目が異なってしまうため、美しくなくなってしまう。
まとめ
コードを読んでいて、「見にくいな」と思ったら改善の余地がありそう。
実装しているときは機能について脳のリソースが使われているから、
一通り実装が終わった後に見やすさの観点で整形すると良さそう!