読みやすいコードって？① - if条件を書くとき

プログラミングをする際に良く耳にする「可読性」という言葉があります。
私はプログラミング未経験から縁があってIT企業に入社し今はSEとして働いていますが、
ほぼ独学で身につけたスキルのため、「可読性の高いコード」や「読みやすいコード」と言われても、正直どういうコードが読みやすいの？というのが分かりませんでした。

この記事では、具体的な例を挙げながら、なぜ読みやすいのか？なぜ読みにくいのか？について考えたいと思います。
「可読性ってどうやって考えたらいいの？」と思っている昔の私（今もですが・・）のような方の引き出しの一つに加えてもらえたら嬉しいです。

#具体例
例えば、映画のチケット料金を計算するプログラムを書く時、
以下のようなクラスがあったと仮定します。

* **上映映画クラス(MovieOnPlay)**・・・チケットを計算する元になる上映時間等を含んだ映画のクラス。
* **料金計算クラス(PriceCalculator)**・・・上映映画を引数にとって、上映映画クラスの情報を元にチケット料金を計算する。

```java:MovieOnPlay.java
/**
 * 上映映画クラス.
 */
class MovieOnPlay {
    /** 映画の名前. */
    private String name;
    /** 上映開始時間. */
    private LocalDateTime startTime;

    /** 上映開始時間getter. */
    public LocalDateTime getStartTime() {
        return thie.startTime;
    }

    // この下にgetter、setterが続く想定（今回の記事には関係ないので省略）
}
```

```java:priceCalculatro.java
/**
 * チケット料金を計算する.
 * @param movie 上映映画
 * @return チケット料金
 */
public Integer calculate(MovieOnPlay movie) {

    LocalDateTime now = LocalDateTime.now();

    // 引数で受け取ったmovieがnullの場合と、
    // movieの上映開始時間がシステム日付(now)より後だった場合は
    // RuntimeExceptionを投げるコードをここに記述する

    // 料金計算ロジック
    calculatePrice(movie);
}
```

## エラーチェックを行うコードを書くことを考えてみる

料金計算クラス(PriceCalculator)で、料金計算を行う前に以下のエラーチェックを行う場合を考えます。

* 引数に受け取った上映映画クラスがnullだった場合はエラー
* 料金計算しようとしている映画の上映開始時間が、現在の時間より前だった場合（すでに上映開始時間が過ぎている場合）はエラー

上記のチェックを行うコードを書く場合、以下の2つの書き方は同じ動きをします。

```java
// 書き方の候補①
LocalDateTime now = LocalDateTime.now();
if( !(movie != null && movie.getStartTime().isBefore(now)) ) {
    throw new RuntimeException("正しい上映映画が選択されていません。")
}

// 料金計算ロジック
calculatePrice(movie);
```

```java
// 書き方の候補②
LocalDateTime now = LocalDateTime.now();
if(movie == null || movie.getStartTime().isAfter(now)) {
    throw new RuntimeException("正しい上映映画が選択されていません。")
}

// 料金計算ロジック
calculatePrice(movie);
```

では、どちらが**”可読性が高い”**と言えるでしょうか？
実は**可読性が高いのは①**であると考えることができます。

## なぜ①の方が可読性が高いと言えるのか？
### エラーにならない条件から考えてみる
後から別の担当者がこのコードを見た場合、おそらく「どうしたらcalculate(movie)が実行されるのかな？」という観点で見ることが多いと思います。
RuntimeExceptionがスローされる条件より、calculate(movie)が実行される条件の方が、実際の業務においては重要だからです。

 * movieがnullではない
 * startTimeがnowより前である

上記の２つの条件を満たせば、ifブロックをスルーしてcalculatePrice(movie)を実行することができます。
逆に、”そうでない場合”はRuntimeExceptionをスローします。
それをそのままコードに落とし込んだのが①です。

```java
// movieがnullではない
movie != null
```

```java
// startTimeがnowより前である
movie.getStartTime().isBefore(now)
```

```java
// ”そうでない場合”はRuntimeExceptionをスロー
if( !(movie != null && movie.getStartTime().isBefore(now)) ) {
    throw new RuntimeException("正しい上映映画が選択されていません。")
}
```

上記の!( ) をはずした「movie != null && movie.getStartTime().isBefore(now)」を満たしたものがcalculate(movie)を実行できます。

### ②をもう一度見てみる
②をのコードを「どうしたらcalculate(movie)が実行できるか？」という観点で見てみます。
if分の中のコードに**”当てはまらない”**条件であれば実行できるのですが、
「movie == null」 の逆はすぐわかるとしても、「movie.getStartTime().isAfter(now)」でない条件とは何か？を考えた時に、少し時間がかかるのではないでしょうか？

```java
// 書き方の候補②
LocalDateTime now = LocalDateTime.now();
if(movie == null || movie.getStartTime().isAfter(now)) {
    throw new RuntimeException("正しい上映映画が選択されていません。")
}

// 料金計算ロジック
calculatePrice(movie);
```

そのため、①の方が可読性が高いと考えられます。

# まとめ
今回はif文でエラーチェックを行う際の”読みやすさ”について考えてみました。
実際の業務では上記のようなケースはよくありますし、私も仕事をしていく中でif文に”当てはまらない”条件を考えるのに苦労したことは何度もあります。

プログラミングを勉強していく中で、こういった考え方でコードを書けば後々わかりやすいのか！と納得したうちの一つだったので記事にしてみました。

プログラミングは奥が深いので必ずしもこの書き方が100%正しいとは言えないのですが、こういった考え方を知っていくことで少しでも”読みやすい”コードを書けるようになりたいなと思います。