Keecom's Yuruyuru Outputs

興味のある事をゆる〜くアウトプットしていきます

良いコードを目指して ~分岐・繰り返し~

分岐や繰り返し処理にもコードを見やすくする方法は多くあります。

基本的な概念が多いかもしれませんが、改めて再認識することで”良いコード”を目指していきましょう。

分岐する上での注意点

コードを書いていれば、Dtoクラスなどでない限りほとんどのファイルに分岐処理は存在するでしょう。

分岐処理で良いコードを意識すれば、全体的な読みやすさは変わるはずです!

条件はなるべく肯定的に

分岐処理は、必ず条件を伴います。

特に指定がなければ、条件部の条件はコーディングする人が考えると思います。

その際に、肯定系/否定形どちらでも実装可能な場合、特別な意図がない限りは肯定的な意味合いにしたほうが読み手側にとって楽になります。

実例を書いていきましょう。

エラーチェックの結果、エラーとなる場合にはreturnする処理を考えます。

否定的な意味合いの場合、以下のようなコードになります。

    ・・・
    if(!clearFlg){
        return false;
    }
    ・・・

上記の例はシンプルなのでそこまで読みにくさはありませんが、「クリアフラグがTrueじゃない」=問題がある というように否定のニュアンスを考えてしまいます。

また、否定形の場合だと読み間違えてしまう(!を見落としてしまう)可能性もあるでしょう。

そうではなく、例えば上記の場合だと「errorFlg」を条件部にするとそのまま読んでいけるし、読み間違える可能性は低くなります。

全ての条件分岐を肯定的にすることが正しい訳ではありませんが、どちらでも実装可能な場合には特別な意図がなければ肯定的な条件にしましょう。

比較変数の配置

これは恐らく無意識でやられている方も多くいるかと思います。

条件分岐をする際に、変数を変数or定数と比較する場合は必ず左側に比較したい対象を置きましょう。

    ・・・
    if(1000 < salesSum){
        // 処理
    }
    ・・・

上のコードを見たら、なんかむず痒いと感じる人は多いのではないでしょうか。

実際にこれが見やすさと直結するかどうか調べてみましたが、どうも英語の用法と同じだそうです。(比較級とかのやつ)

比較する変数は必ず左側に配置しましょう!

三項演算子の多用は避ける

皆さんはコードを書くときに三項演算子を使うことはありますか?

三項演算子を使うことでよりコードが見やすくなることがあります。

例えば、未成年かどうかを判断して文字列で情報を保持する場合、以下の2パターンが考えられます。

// パターン1 通常分岐
if(age < 20){
    userDto.category = "minority";
}else{
    userDto.category = "adult";
}

// パターン2 三項演算子
userDto.category = (age < 20) ? "minority" : "adult";

見てわかる通り、パターン2のほうがコードとしてすっきりしています。

このように、三項演算子を使えば分岐処理を綺麗に整えることができます。

しかし、三項演算子はシンプルな分岐処理の場合は可読性が上がりますが、少しでも複雑な処理をしてしまうと読みづらくなってしまいます。

私は以前こんなコードに出会いました。

・・・
***Dto.status = (inputSum > 20) ? ( (inputSum > 40) ? 2 : 1 ) : 0;
・・・

少なくとも、1度目を通しただけで理解した人は少ないと思います。

上記は入れ子になっているので当然読みづらさがありますが、真偽それぞれの場合の評価式が複雑になると読みづらくなるため、よく考えていない多用は避けましょう。

繰り返し処理をする上での注意点

繰り返し処理は私が一番勘違いしていた部分です。

以前の私は"良いコード"とは、効率の良いコードというシンプルな考えでした。

1つのfor文の中で、できることは全てぶちこむという事を良い考えとしてコードを書いており、結果プログラムの可読性は下がっていたと思います。

そうならないように、注意点を書いていきたいと思います!

なるべく処理はシンプルに

先にも書いたように、for文の中であれもこれも、と処理を乱雑に書いてしまうとコードの可読性はさがります。

for文などは、シンプルになるように繰り返し処理の目的が達成したら閉じましょう。

また必要になったら極端な話、再度for文を書いてしまえば良いのです。

私も最初は、これのほうが良いのか?と疑問を抱いたのですが、実際利点を書き出してみると、確かにそうだと感じました。

  • for文の中で余計な他の処理をしていないので保守しやすい
  • コードが読みやすい(データの状況が理解しやすい)
  • 数百行以下のループなら処理速度は微々たるものしか変わらない

ループ処理を行う件数が多い場合は影響が大きいかもしれませんが、想定される件数が多くない場合にはfor文をフェーズ毎に分けても良いかと思います。

但しこのあたりは感覚的な部分も多く、まとめたほうが見やすい方もいらっしゃると思うので、自分が見やすいと思う方で書きましょう。(笑)

ネストは浅く

これはif文・for文に共通することですが、ネストは浅くしましょう。

ネストが深くなれば、どの段落で分岐・繰り返し処理が終わるのかがわかりにくくなります。

ではどのようにネストを浅くしていくかですが、不要な分岐や繰り返しをなくす事を考えましょう。

実例を書いていきます。

for(EventDto dto : eventDtoList){
    //Eventステータスが公開の時に処理**を実施
    if(dto.status == 'public'){
        // 処理A
        ・・・
    }
}

上記の例だとif文自体を消すことはできませんが、ネストが深い部分を短くすることができます。

for(EventDto dto : eventDtoList){
    //Eventステータスが公開でない場合は処理**を実施しない
    if(dto.status != 'public'){
        return false;
    }

    // 処理A
    ・・・
}

if文の条件を変えて早めにreturn処理をすることで、for文の中の主処理はインデントが1つ減りました。

こういった早めのreturnなどは読みやすく且つ保守もしやすくなるので是非活用してください!

但し、後続処理やその他諸々でできない場合もあると思うので、そこは適宜対応して行きましょう。



この記事の内容は、基本的なことも多いですが全てにあてはまるものではないと思います。

こういう考え方もあるということを知った上で、皆さんの思うようにコーディングしていくことが大切だと思います!!