リーダブルコード

C#リーダブルコード #12_対象外の時はすぐに抜ける

今回は前回解説した「メソッドはできるだけ早く抜ける」の別のパターンとして,「対象外の時はすぐに抜ける」というお話をしていきたいと思います。

BAD:チェックを多用する

次のようにProduct型のオブジェクトを引数で受けているメソッドがあったとします。このproductのProductNameに対してSubstringを行いたい場合を考えます。Substringをする場合は,必要な文字数が無い場合は例外になってしまうので,例外を出さずに処理しようと思うと,次のように,ProductNameに必要なだけの桁数が存在するかをチェックする必要があります。さらには,それ以前の問題として,productやProductNameもnullの可能性がある場合は,それもチェックが必要です。その場合,必要な条件を満たしているかをチェックするif文を書くと,次のようになります。

//メソッドはできるだけ早く抜ける2
//BAD:チェックを多用する
private bool チェックを多用する(Product product)
{
    if (product != null)
    {
        if (product.ProductName != null)
        {
            if (product.ProductName.Length > 2)
            {
                if (product.ProductName.Substring(2, 1) == "A") //①
                {
                    //BAD:チェックが多くてネストが深い
                    return true;
                }
            }
        }
    }

    return false;
}

実際にやりたいことは①の3文字目が”A”なのかどうかを判定したいのですが,そこにたどり着くまでに,いくつものif文が必要となり,かなりネストされた状態になります。このように,多くのif文があると,すべてのif文を脳みそに覚えながら読まないといけないし,階層が深くなり,コードが右にずれていき,物理的に読みづらくなります。

GOOD:対象外の時はすぐに抜ける

ネストが深くならないようにする対処法としては,対象外の時はすぐに抜けるということです。都合が悪いケースを排除するという考え方です。

前述したif文の階層が深くなる書き方は,やれる条件を目指してコーディングしていたのですが,やれないときは抜けるということにフォーカスをしてコーディングすると,次のようになります。

//GOOD:対象外の時はすぐに抜ける
private bool 対象外の時はすぐに抜ける(Product product)
{
    if (product == null) //①
    {
        return false;
    }

    if (product.ProductName == null) //②
    {
        return false;
    }

    if (product.ProductName.Length <= 2) //③
    {
        return false;
    }

    if(product.ProductName.Substring(2, 1) == "A") //④
    {
        return true;
    }

    return false;
}

前回同様④の判定を行いたいのですが,そのために不都合な状態の場合は,さっさとメソッドを抜けるという書き方です。それが①から③のif文です。④のチェックができない要素はすべて排除されるように,不都合な場合はメソッドを抜けています。④のチェックが整っている場合のみ,④までたどり付きます。このようにすれば,トレースする際も,productがnullの場合は,以降のコードを読まなくてもよいので,以前解説した通り,読み手に考慮した記述となります。このように,if文のネストを深くして,必要な状態にたどり着くのではなく,不都合な場合はすぐに抜けるということを意識してみてください。

書き方の変更

ちなみに, Substringの部分は,そのままboolで返却できるので,さらにスマートに,そのまま返却することもできます。

//GOOD:対象外の時はすぐに抜ける
private bool 対象外の時はすぐに抜ける(Product product)
{
    if (product == null)
    {
        return false;
    }

    if (product.ProductName == null)
    {
        return false;
    }

    if (product.ProductName.Length <= 3)
    {
        return false;
    }

    return product.ProductName.Substring(2, 1) == "A";
}
リーダブルコードC#

#01_はじめに

#02_プロジェクトの作成
#03_右に長いコードを書かない_隣のとなりまでしか訪ねない
#04_隣のとなりまで_右スクロールより縦スクロールの方がいい
#05_IFとELSEがある時は肯定系をIF否定形をELSEにする
#06_比較する時は変数を左_定数を右にする
#07_複数の比較を1回のif文でやらない
#08_booの比較でTrueやFalseを書かない
#09_否定の否定はしない
#10_型チェックはasを使う
#11_メソッドはできるだけ早く抜ける_返却する値を無駄に変数に入れない
#12_対象外の時はすぐに抜ける
#13_都合が悪いケースはガードする
#14_必ずやりたい処理はfinallyを使う
#15_比較演算子はできるだけクラスにさせる
#16_ifの中括弧の省略はしない
#17_if文のリーダブルコードまとめ
#18_名前の付け方
#19_意図が明確な名前を付ける
#20_名前は素直に付ける_連想ゲーム的な名前を付けない
#21_1つの事しかしていなければ短い名前でも理解できる
#22_長いクラス名の扱い方
#23_単数形と複数形で表現する
#24_対になる言葉の組み合わせを決めておく
#25_業務で使う名前は統一する
#26_名前を統一するための辞書ツール作成
#27_メンバー変数にアンダーバーを付ける
#28_ハンガリアン記法を使わない
#29_メソッド内の変数をメソッド最初に全部宣言しない
#30_メソッド内の変数は直前に宣言する
#31_ループの変数はループ内で宣言する
#32_変数を使いまわさない
#33_boolの戻り値はどちらがTrueかをわかるようにする
#34_解放が必要なオブジェクトにはusingを使う
#35_varを推奨する場合
#36_メソッド名の付け方
#37_voidとFunctionを意識する
#38_インテリセンスを意識した名前にする
#39_生成メソッドはCreate_型変換はToを使う
#40_無駄に変数に入れて返却しない
#41_重複をなくす
#42_リージョンで区切らない
#43_アクセス修飾子とsealedを付ける
#44_クラス名はソリューションエクスプローラーで並べることを意識する
#45_クラス名は名詞か名詞句で命名する
#46_クラス名で継承元や特性を表現する
#47_メソッド内にコメントを書かない
#48_分かりづらい部分はメソッド化をしてメソッド名で想いを伝える
#49_コードを読んだ人が「えっ?」と思うことが予想される場所にだけコメントを付ける
#50_コメントで悪いコードを取り繕うことはできない
#51_未実装機能はTODOコメントを書く
#52_リーダブルコードまとめ