かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

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

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

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

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

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重ループと同じです。

要約すると

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