https://qiita.com/jun1s/items/5f60bbb886626d897abc?utm_source=Qiitaニュース&utm_campaign=eddbec1c54-Qiita_newsletter_505_03_09_2022&utm_medium=email&utm_term=0_e44feaa081-eddbec1c54-34388437#メソッドを宣言的に書く

コードが意図をそのまま表しており、バグの入り込む余地がありません。

これまでのような宣言的なコードの書き方をしていくと、メソッドも宣言的に書けるようになっていきます。

メソッドの中身がreturn文だけになる感じです。

public class Logic1
{
    private List<Uriage> _list;

    public Logic1(List<Uriage> list)
    {
        _list = list;
    }

    public decimal GetUriageByItemCd(string itemCd)
    {
        return _list
            .Where(uri => uri.ItemCd == itemCd)
            .Sum(uri => uri.Value);
    }
}

上記のような形まで宣言的に書ける場合、もっと省略して、メソッド自体を => を使って次のように書けます。

public class Logic1
{
    private List<Uriage> _list;

    public Logic1(List<Uriage> list)
    {
        _list = list;
    }

    public decimal GetUriageByItemCd(string itemCd) =>
        _list
            .Where(uri => uri.ItemCd == itemCd)
            .Sum(uri => uri.Value);
}

なんだかかっこいい感じですが、慣れるまではぎょっとしてしまうかもしれませんね。

副作用が処理の主目的なケース

ループの中でDBにINSERTしているケースなど、「最終的な副作用自体が処理の主目的」であるケースがあります。 このような場合はもちろん、全てを宣言的に書くことはできません。

しかし、INSERTする前のデータの集計や整形処理などは宣言的に書き、最後にループを回してINSERTする部分だけforeachで書くなど、可能な限り宣言的に書く対応をした方が良いでしょう。

副作用がある部分以外の処理を宣言的に書いておく

// 絞り込み・グルーピング・集計処理
var list = listInput
    .Where(row => 絞り込み条件)
    .GrupBy(row => グルーピング条件)
    .Select(group => 集計処理)
    .ToList();

// DB保存用の写像変換
var listForDB = list.Select( row => DB用写像変換 ).ToList();

// DBへの保存
foreach (var row in listForDB)
{
    InsertToDB(row);
}

上記のように目的ごとに段階を踏んで宣言的に記述しておくと(これをパイプ処理と言います)、もしこの後「DBに保存する際の変換処理に変更が入った」場合でも、その影響範囲を特定しやすくなります。

また、上記の処理と同時に帳票出力を行いたい場合でも、既存の処理に影響を与えずに処理を書くことができるでしょう。

帳票出力処理を後から追加

// 絞り込み・グルーピング・集計処理
var list = listInput
    .Where(row => 絞り込み条件)
    .GrupBy(row => グルーピング条件)
    .Select(group => 集計処理)
    .ToList();

// DB保存用の写像変換
var listForDB = list.Select( row => DB用写像変換 ).ToList();

// DBへの保存
foreach (var row in listForDB)
{
    InsertToDB(row);
}

// 帳票出力用の写像変換
var listForReport list.Select( row => 帳票用写像変換 ).ToList();

// 帳票出力
foreach (var row in listForReport)
{
    OutputReport(row);
}

もしDBへの保存処理の中に絞り込み処理とDB用写像変換を全部ループで書いていたら・・・と考えると、ぞっとしませんか?

もしループで書いていたら…ここに帳票出力処理を追加してください