C#リーダブルコード #03_右に長いコードを書かない_隣のとなりまでしか訪ねない

当サイトではアフィリエイト広告を利用しています。

リーダブルコード
Subway Station in Munich, Germany. Train coming in. Strong Motion Blur on Train and People, no recognizable Persons.

まずは基本的な話からやっていきたいと思います。最初の項目は「右に長いコードを書かない」というテーマです。

右に長いコードを書かない

先ほど作成したReadableCodeクラスにメソッドを作成します。メソッド名は「右に長いコードを書かない」です。

//基本
private void 右に長いコードを書かない()
{
}

日本語のメソッド名には違和感があるかもしれませんが,メソッド名が解説と関係ない場合は,ReadableCode01Aなどとするよりは,どういった解説のためのコードかを理解してもらうためにも,日本語で内容を一言で示したメソッド名の方が,後で観た場合にわかりやすと思うので,日本語にしています。もちろん,後述する,メソッド名の命名の仕方や,メソッド名に意味を持たせる場合は,英語で適当な名前を付けますが,メソッド名に意味がない場合は,日本語のメソッド名にしていきたいと考えています。

それでは「右に長いコードは書かない」の話をしていきたいのですが,その前に,コードから呼び出すためのクラスやメソッドが無いと,サンプルコードを記述することができないので,準備として,次のようなクラスを事前に作成します。

Productクラスの作成

新しいクラスのファイル「Objects.cs」などを作成し,そこに次のようにProductクラスを作成します。

public sealed class Product
{
    public Product(int productId,
                    string productName,
                    int price,
                    int stock)
    {
        ProductId = productId;
        ProductName = productName;
        Price = price;
        Stock = stock;
    }

    public int ProductId { get; }
    public string ProductName { get; }
    public int Price { get; }
    public int Stock { get; set; }
}

ProductDtoクラスの作成

続いてProductDtoクラスを作成します。

public sealed class ProductDto
{
    public ProductDto(Product product)
    {
        ProductId = product.ProductId.ToString();
        ProductName = product.ProductName;
        Price = product.Price.ToString();
        Stock = product.Stock.ToString();
    }

    public string ProductId { get; }
    public string ProductName { get; }
    public string Price { get; }
    public string Stock { get; }
}

先ほど作成したProductクラスを全部stringで保持するクラスです。これは後程Productクラスの変換のために使用します。

Productクラスのリストを返却するクラスの作成

続いて,Productクラスのリストを返却するクラスを作成します。

public static class ProductSqlServer
{
    public static IEnumerable GetProducts()
    {
        var result = new List();
        result.Add(new Product(10, "p10", 100, 2));
        result.Add(new Product(20, "p20", 200, 6));
        result.Add(new Product(30, "p30", 300, 4));
        return result;
    }
}

これはSQLServerに接続してProductクラスのリストを返却するようなクラスのイメージにしてありますが,今回の解説では,実際にSQLServerには接続するコードまでは書かないので,ダミーの値を返却する形で実装しています。

右に長いコードを書かないメソッドにコードを追加

ここまでで,サンプルコードを記述する準備が整ったので,ReadableCodeクラスに,コードを書いていきます。

private void 右に長いコードを書かない()
{
    var dtos = new List();
    ProductSqlServer.GetProducts().Where(x => x.Price > 100).ToList().ForEach(x => dtos.Add(new ProductDto(x)));
}

 

紙面の都合上折り返されていますが,実際には改行コードなしでコーディングされていると考えてください。これはあえて右に長くなるように,たくさんドットをつけて,無理やり長くなるように記述しました。このように右に長いコードを書くと,行数としては1行で書けるかもしれませんが,右にスクロールしながら,さらに,いくつものオブジェクトと処理を記憶しながら読んでいくことになり,初めてコードを読む人や,作り手以外の人が読む場合は特に,読むのがしんどいコードになります。

少ない行が良いコード?

コードは短い方がいいということを誰かに教わっているせいか,少ないコードが良いコードだと思っているプログラマーの方がいます。確かにコード量を減らすことは良いことではあるが,1行で書いたからコード量が減っているということではない,ということがご理解いただきたいと思います。それに,1行が長くなると,横スクロールが発生しますね。スクロールはマウスホイールで行う関係上,横にスクロールするよりも縦にスクロールする方が断然楽です。横スクロールはカーソルをスクロールバーに合わせて左右にスクロールしなければいけませんが,縦スクロールはマウスホイールを使って一瞬でスクロールできますよね,なのでコードが右に長くなるくらいなら,縦に長くなる方が,よほど読みやすいということになります。

何行で書くかではなく何秒で読めるか?

コード量を減らすことにとらわれて,コードの行数を減らそうとして,前述のような右に長いコードが読みづらいことは解説した通りですが,ポイントは,何行で書くかではなく何秒で読めるか?ということです。行数を減らすのではなく,初めてコードを読んだ人が,何秒で理解できるか?ということを意識してコードを書くことが,読みやすいコードを書くことにつながります。ですので,コードの行数が減ったかどうかではなく,理解に必要な秒数が減っているかどうかをチェックしてみてください。

隣の隣まで

もう一度右に長いコードを確認してみましょう。

private void 右に長いコードを書かない()
{
    var dtos = new List();
    ProductSqlServer.GetProducts().Where(x => x.Price > 100).ToList().ForEach(x => dtos.Add(new ProductDto(x)));
}

このコードを読む場合,何が読みづらいかというと,頭の中,つまり,コードを読む人間の脳みその中に貯めておかないいけないことが多いということが問題です。まずProductSqlServerGetProducts()に対してWhereを行って,Price100より大きい値で,それをListに変換して,ForEachで回してDTOに変換してdtosにAddしている。という感じで,いくつものオブジェクトや処理を読みながら,頭に記憶しておかないといけません。人間が一度に認識できる数は,数字は7つ,文字は6つ,単語は5つと言われています。それ以上のことを頭に入れると,覚えていたことが1つ抜けていくということです。これも個人差があるので,値は前後するので,基本的に,コードの記述は「隣の隣まで」くらいがストレスなく読めるコード量だといえます。要するに,ドット(ピリオド)の数が2つになる程度が適当だといえます。もちろん,ドットの数は少なければ少ない方が読みやすいのですが,長くなっても隣の隣くらいまでが良いでしょう。今回のケースであれば,ProductSqlServerから始まるコードなので,隣のGetProduct(),その隣のWhereくらいまでが適当です。

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

これ以上続くと,最初に何をしていたかを忘れ始めて,結局前後しながら読むことになり,余計に時間がかかります。ということでこの「右に長いコードを書かない」という項目をBADコードとして記述しておきます。

private void 右に長いコードを書かない()
{
    var dtos = new List();
    //BAD:右に長いコードを書かない(隣のとなりくらいまでにする)
    ProductSqlServer.GetProducts().Where(x => x.Price > 100).ToList().ForEach(x => dtos.Add(new ProductDto(x)));
}

このようにコメントにBADやGOOD,NOTBADを記載することで,後で見たときにわかりやすいと思うので,こんな感じで直接コードに書いていきます。本書の最終版をチームに新人が入ってきたタイミングで,全部読んでもらえば,チーム全体で統一した考え方でコーディングができる等の使い方もできると思います。もちろん,すべて私の考えに従っていただく必要はないので,考えが異なる箇所は,書き換えた状態で,全員に共有すればよいと思います。

コードの評価

コードの評価は前述した通り,次の3つです。

  • BAD:良くない書き方
  • NOTBAD:別に悪くはない
  • GOOD:いい書き方,推奨

BADとGOODはそのままですが,NOTBADは,複数の書き方がある場合等,どちらで書いてもいいということもあったり,さほどいい書き方ではないが,BADというほどではない場合もあるので,NOTBADという評価も含めています。

今後はこんな感じで,コードを評価しながら解説を進めていきます。