リーダブルコード

C#リーダブルコード #04_右に長いコードの対処

前回は「右に長いコードは書かない」というお話をしました。では右に長いコードになってしまうときはどのように対処していけばいいのか,というお話を今回はしていきたいと思います。

改行しても右に長いコードには変わりない

改行した場合

まず最初に考えられる対処法は,改行するということですね。前回の右に長いコードを改行してみましょう。

//改行しても右に長いコードには変わりない
ProductSqlServer.GetProducts()
    .Where(x => x.Price > 100)
    .ToList().ForEach(x => dtos.Add(new ProductDto(x)));

ただ,改行しても左から右に読んでいく量は同じなので,読んでいく量,脳みそに覚えておかないといけない量は特に変化がなく,大した改善にはなっていませんね。まぁ改行しないよりは,している方がマシ程度です。ですので,改行したから右に長いコードではなくなったということにはなりません

どこかで切る

対処法としては,どこかで切る必要があります。例えば,ToList()まででいったん切ります。次のように,ToList()までの結果をproducts1に受けて,その後,products1.ForEach・・・とします。

var products1 = ProductSqlServer.GetProducts().Where(x => x.Price > 100).ToList();
products1.ForEach(x => dtos.Add(new ProductDto(x)));

こうすると,いったんToList()が終わった段階で思考を切ることができますね。いままでは,ProductSqlServerをGetProducts()して,Whereで100より大きいやつをListにして,それを回してProductDtoにする・・・とすべてを脳みその中に放り込んでいたものを,「Priceが100より大きいリストがproducts1」ということで,ここで思考を切ることができ,脳みそは,いったん忘れて,次のForEachに移ることができます。こういった感じで,思考をいったん切ることで,読みやすさは大きく変わります。

ToListが冗長

先ほどはToListの部分で切ることで,思考を切ることができて,右に長いコードがある程度改善しました。ただ,この例でいうと,このToList()自体が,冗長なので,その部分も解説しておきます。

//ListのForEachをするためにToListするのは冗長
var products1 = ProductSqlServer.GetProducts().Where(x => x.Price > 100).ToList();
products1.ForEach(x => dtos.Add(new ProductDto(x)));

このToListがForEachするために変換しているとすれば,非常に冗長です。要するに,products1.ForEachのForEachは,List<T>にだけ存在するメソッドなので,Whereを取得されたIEnumerable<T>をList<T>に変換していますが,ListのForEachではなく,通常のforeach文を使えば,Listに変換する必要がなくなるので,ToListをする必要がありません。ですので,List<T>のForEachをするためだけにToListを呼び出しているのであれば,これも無駄に右に長くしているコードの元凶になっているので,あえてToListする必要はありません。

隣のとなりまでしか訪ねない

①のようにToListをやめて,Whereの結果をproduct2に受けていったん切ります。

//GOOD:隣のとなりまでしか訪ねない
var products2 = ProductSqlServer.GetProducts().Where(x => x.Price > 100);//①
foreach (var product in products2) //②
{
    dtos.Add(new ProductDto(product));
}

次に②のように通常のforeach文を使用してproduct2をぐるぐる回してdtos.Add・・・の部分を実施すれば,結果は同じになります。こうすることで,ProductSqlServerから始まる文は,GetProductsのWhereの部分でいったん完結しているので,ProductSqlServerの隣の隣に収まっているといえます。そこまで完結させておいて,次はそれをぐるぐる回す,②の部分に移るので,脳みそで覚えておくことは,格段に少なくなっているといえます。隣のとなりまでしか訪ねないということを目安にして,うまく文を切っていくことを検討してみてください。

ラムダを覚えても右に長くしない

今回解説した通り,右に長いコードになる場合は,どこかで切れないかを考えてみてください。ラムダ式等を覚えたり,新しい書き方を覚えたりすると,使いたくなって,つい右に長いコードを書きがちです。新しい書き方がすべてにおいて正義ではないし,最初に言った通り,何秒で理解できるかが大事なので,新しい書き方だからOKという感じではなく,総合的に判断して使っていただいた方がいいと思います。

右に長くなるという事はクラスをうまく分割できていない

最後に余談ですが,本書はオブジェクト指向に関しては触れずに,シンプルに書き方を解説することを目的としていますが,右に長くなるコードの原因の1つとして,うまくクラスが分割できていないという可能性があります。例えば今回の例でいえば,ProductSqlServerのGetProductsでPriceの引数を受ける関数があれば,

ProductSqlServer.GetProducts().Where(x => x.Price > 100)

の部分を,

ProductSqlServer.GetProductsByPrice(100);

とすることもできます。これだとお隣さんに尋ねるだけなので,大変シンプルに読むことができます。今回はオブジェクト指向やデザインパターンの話はしないので,クラス分割にはあまり言及しませんが,そういった部分も原因としてはあると思うので,本書以外にも,そういった部分を勉強していただいてもいいかと思います。

リーダブルコード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_リーダブルコードまとめ