以下の記事に「LINQ 可読性」っていう検索流入があるんで、そのはなし。

初めてLINQという記法を見た人にはなんのこっちゃわからんだろう。
※LINQという名前を冠してはいるが、別に特別なことをしているわけでは無い。だから「LINQという記法」という言い方は正しくない。「LINQのクエリ式」だけが記法として独立している。

結論から言えば、LINQは読みやすい。ただ、学習コストがあるのはある。お前が最終的に達成すべきは顧客満足であって、そのためにLINQの「学習コスト」「開発工数」「保守工数」について考えねばならんだろうな。

◆LINQは何をしているのか

さっきの「使い方のはなし」を読み込んでもらえりゃわかるんだけど Too Long なのでポイントをば。

  • LINQは「引数に関数を受け取る」処理である。
  • LINQは列挙(リスト、コレクション、集合)に対して使用されるメソッド群である。別段特殊なメソッドではない。メソッド群に「LINQ」という名前を付けただけ。
    ※from in where selectだののクエリ式という書き方もある。あれは普通に読みづらいと思う。読んで理解が出来ない。
  • LINQのほぼ全てのメソッドは「新しい列挙を作成する」「元の列挙に影響を与えない」

◆宣言的

LINQを使わない場合に使用されるのはループであるから、それとの対比が重要となるだろう。C#で言えばループは「for」「foreach」ですよね。

実のところ、自由度で言えば foreach のほうが高い。何でもできる。だから foreach は読みづらい。

ループ処理っていうのは、ある列挙に対して何らかの操作をするものだな。LINQはその何らかの操作を各要素に分解したものだ。

たとえば Select メソッド。これは「列挙を読み込んで新しい列挙(射影)を作成する」機能である。それ以外のことはできない。

  • 元の列挙の中身をいじることができない。
  • 出来た射影の要素数は元の列挙の要素数と一致する。増減しない。元の列挙と一対一で新しい要素が生成される。

なぜにSelectには「Selectで出来ること以外の機能」がないのか。機能を削ったら何が起きるのか。それは、可読性が上がる。

どういうことかって、Selectでは射影を作ることしかできないからだ。foreach では、その中に書かれている手続きを読んで理解するまで列挙に何が起きたのかを知るすべはない。でもSelectであれば「とにかく射影を作っていて、それ以外のことはしていない。」という事が即座に理解できるな。

Where メソッドでは、列挙の要素の内容によって判定をし、フィルタリングする(抽出)以外のことはできない。つまり要素が減る/減らない以外のことは起きない。

だから、「出力したリストの要素数がゼロになっちゃってる」という不具合があった時にSelectの変換処理を疑う必要はないし、「変換の結果がおかしい」時はWhereのフィルタリング処理を疑う必要はない。問題の発生個所の特定が早まる。

列挙に対して何を実施するかを、「Select(Map処理)します」とか「Where(Filter処理)します」みたいに、まるで宣言しながら書いているな。それが「宣言的」であるということ。foreachだとそういう「なにをするか宣言」を伺い知ることはできない。一行ずつ読んで意味を理解し、最終的にどうなるのかをシミュレートしないといけない。

更に言えば、LINQでも内部的にはループが回っているわけだけど、それを意識する必要はない。コードの示す意味・意図で考えるなら「ザン!」ってな感じに変換結果が取得されていると捉えてもいい。foreachみたいな「ぐるぐるぐるーぺろぺろぺろーん」じゃない。

LINQにもForEachっていうメソッドがあるんだけど、使う意味ない。宣言的じゃないから。要素の内容が書き変わるから。うまあじが無いし逆に紛らわしい。だから単なるforeachで書けばいい。

◆LINQでどう書くか

発想を変える必要があるわな。

とにかく、やりたいことを分割すること。SelectとかWhereやらの操作単位にまで落とし込め。オメーが指示したいその一連の処理がつまり何なのかってことを考えろ。

また、Selectも一度で済ませる必要ない。SelectのあとにWhereして、それをもっかいSelectしたっていい。そうするだけの意味があるならな。

上手くいかない理由は、お前の知能がチンパンジーであることか、あるいは扱おうとしているデータ構造がそもそもおかしいか。

◆学習コスト

やらねぇほうがいいことはある。たとえばLINQのメソッドチェーンの外にある変数を書き換えたり。foreachで書いた処理に引きずられるとそうなるな。

でもその程度の学習コストはプログラミングって活動にはいつだってついて回るものだ。添え字で配列を読むforが基本だっただろ。そこからList作ってforeachな世界になった。foreachのほうが便利だからforeachの使い方を勉強したでしょう?そうだし、JavaScriptEcmaScript)だのでもリスト操作関数が揃っている。LINQの考え方はC#だけでのみ通用する概念じゃない。もっと普遍的な理論をベースに敷いている。

そんな感じ。

LINQは場合により処理パフォーマンスが出ない。適宜foreachで書け。ただ、コンパイラくんが最適化している場合もあるんで、ヤバそうなメソッドチェーンでも処理コストがそこそこに収まったりもする。SelectのあとにSelectつなげてもパフォーマンスは無事です。コンパイルしたらループ一回に変換されてます。

◆メタいはなし

無能な上司に逆らってはいけない。聞いちゃくれないから。「使うな」と言われたら、ちょっとくらい詰めてもいいけど、それよりも転職することを考えるべき。LINQすら使えないプロジェクトとか、そもそも未来が無いから。

どうすんの。Git使えないとかパブリッククラウド使えないとかコンテナ使えないとかコンテナオーケストレーションシステム使えないとかVS Code使えないとか好きなPC使えないとか.NET Core 3.1(C# 8.x)使えないとか。そもそも.NET Core使えないとか。

便利なものを便利に使えないって、それ世の中に追いつくためには残業するしかないじゃん。それはお前の負担だし、顧客の負担になる。お前はGit使わずにぶん殴ってSVNのコンフリクト解消を頑張るけど能力は伸びない。

論理的な上司は世の中に沢山いるわけだから、カイゼンのカの字も無いような人に付くことないよ。「LINQで書いたとして、メンバーは読めないぞ。お前が全部保守するのか?」とか言われたんでしょ?

もう辞めちまえよ。音楽性の違いってやつだぁそれは。

良くなるためには変化が必要で、変化にはいつでもコストとリスクが付きまとうものだ。そこをマネージする気のない組織にとどまるんじゃねぇよ。腐るから。エンジニアで良かったよな。引く手あまただぜ。だからコンテナとクラウドのエッチな関係を勉強をしやがれと、そう言いたい。

◆結論

LINQの可読性は高いよ。