かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

なぜプログラムのコードは複雑になっていくんだろう。

いろんなソースコードを見ていると、すんなり頭に入ってくるものと、そうでもないものに分かれてくる。個人的にすんなり頭に入ってくるもものは、大体以下のような形になってるんだなぁと思ったのでメモっておく。

ネストを深くしないために最初にいらないものは捨てる

メソッドとかで、本来したい処理と、そうじゃない値のチェック処理とかが混ざってると何がしたいのかわからなくなる。たとえばこんなの?

void Foo(int arg1, string arg2)
{
  for (int i = 0; i < 10; i++)
  {
    if (arg1 != 0 && i % 2 == 0)
    {
      if (arg2 != null)
      {
        // やりたいこと
      }
    }
  }
}

極端な例ですが、こんなのです。下手したら、やりたいことが複数個所に散らばってることもよくあります。これは

void Foo(int arg1, string arg2)
{
  if (arg1 != 0)
  {
    // arg1が0だとそもそも何もしない
    return;
  }

  if (arg2 == null)
  {
    // arg2がnullだと何もしない
    return;
  }

  for (int i = 0; i < 10; i++)
  {
    // やりたいこと
  }
}

こんな感じに書き直せると思います。(コンパイルもしてないし寝る前の頭なので、あまり自信はない)事前になるべく本来やりたいこととは関係ないことを切り捨てる。というのは大事だと思ってます。

コレクション処理だと

コレクションに対する処理だと、もっとひどくなります。ループしながらフィルタリングして、さらにフィルタリングして、何かのメソッドを実行した結果がOKだったら外部メソッドを呼び出すみたいな・・・。

var collection = ...何かのクラスのIEnumerable<T>...;
foreach (var item in collection)
{
  if (item.Foo == "Hoge")
  {
    var r = HogeHoge(item);
    if (r.Execute())
    {
        continue;
    }
    service.DoSomething(r.Property1);
  }
}

いらんものは先に捨てる。

var collection = ...何かのクラスのIEnumerable<T>...;
var targets = collection.Where(i => i.Foo == "Hoge")
  .Where(i => i.Execute());
foreach (var item in targets)
{
  service.DoShomething(item.Property1);
}

LINQみたいなのが無いときは、データのフィルタリングをするループと、そうじゃないメインの処理をやりたいループで2重ループになって無駄だとかいうのがありましたが、LINQは、ちゃんと書けば遅延実行なので、1重ループと同じです。

要約すると

情報はあらかじめ、処理しやすいように整理整頓してからメインのロジックにとりかかりましょう。ということでした。はい。 ねむいので、変な文章になってたらすいません。