カレー作りの隠し味にコードは入れるべきか？

肉とジャガイモと玉ねぎと人参があれば他に何もいらない。(ルウはどうした？


### こんにちは、Javaおじさんのシキムです。


40才目前で、プログラム工学に興味を持ったので本や記事で読んだ難しい話を
咀嚼して簡単な言葉で語りたいと思います。

-----

今回は、カレー作り番外編 **「カレー作りにコード入れたくなかった」** というものについてです。


https://qiita.com/sikimuOji/items/668190ee35a64da899fc

ということで、カレー作りを先に読んでからのほうがいいかもしれません。

読んでもらえました？

では、さっそくカレー作成装置(コード版)を作りましょう。
※前の記事とは若干変えております。
----

```java:CurryMaker
Curry makeCurry(Carrot 人参, Potato ジャガイモ, Onion 玉ねぎ, Pork 豚肉){

    //野菜の皮を剥く
    PeelCarrot 皮むき人参 = 人参 - 皮;
    PeelPotato 皮むきジャガイモ = ジャガイモ - 皮;
    PeelOnion 皮むき玉ねぎ = 玉ねぎ - 皮;

    //野菜を切る
    PrepareCarrot 下ごしらえ人参 = 皮むき人参 / 一口大;
    PreparePotato 下ごしらえジャガイモ = 皮むきジャガイモ / 一口大;
    PrepareOnion 下ごしらえ玉ねぎ = 皮むき玉ねぎ / 一口大;

    //肉を切る
    PrepareMeat 下ごしらえ肉 = 豚肉 / 一口大;

    //鍋に具材を入れる
    Pan カレー鍋 = new Pan(下ごしらえ人参, 下ごしらえジャガイモ,下ごしらえ玉ねぎ,下ごしらえ肉);
    カレー鍋.煮込む();
    
    CurryRoux ルウ;
    generation 世代 = 自分.世代取得();
    if(世代 == 10代){
        ルウ = 甘口ルウ;
    }
    else if(世代 == 20代){
        ルウ = 中辛ルウ;
    }
    else{
        ルウ = 辛口ルウ;
    }

    カレー鍋.add(ルウ);
    カレー鍋.煮込む();

    return カレー鍋.get中身();
}
```
どうでしょうか？
日本語でも、

　　　人参の皮をむき、ジャガイモの皮をむき、玉ねぎの皮をむき、
　　　人参を切り、ジャガイモを切り、玉ねぎを切り、肉を切り
　　　鍋に入れて煮込み、カレールーを入れて、カレーを渡す。

と、それなりに長い文章でしたが、Javaコード風に書くと、さらに長くなってしまい。
バグを見つけたりすることが、困難になることが予想されます。



では、今回も単一責任の原則を意識して装置(コード)を新たに作りましょう。
----

```java:人参の下ごしらえメソッド
PrepareCarrot preparedCarrot(Carrot 人参){

    PeelCarrot 皮むき人参 = 人参 - 皮;
    PrepareCarrot 下ごしらえ人参 = 皮むき人参 / 輪切り;
    return 下ごしらえ人参;
}
```

```java:ジャガイモの下ごしらえメソッド
PreparePotato preparedPotato(Potato ジャガイモ){

    PeelPotato 皮むきジャガイモ = ジャガイモ - 皮;
    PreparePotato 下ごしらえジャガイモ = 皮むきジャガイモ / 乱切り;
    return 下ごしらえジャガイモ;
}
```

```java:玉ねぎの下ごしらえメソッド
PrepareOnion preparedOnion(Onion 玉ねぎ){

    PeelOnion 皮むき玉ねぎ = 玉ねぎ - 皮;
    PrepareOnion 下ごしらえ玉ねぎ = 皮むき玉ねぎ / 半月切り;
    return 下ごしらえ玉ねぎ;
}
```

```java:肉の下ごしらえメソッド
PreparePork preparedPork(Pork 豚肉){

    PreparePork 下ごしらえ肉 = 豚肉 / 一口大;
    return 下ごしらえ肉;
}
```

```java:ルウの選択メソッド
CurryRoux selectルウ(Generation 世代){

    CurryRoux ルウ;
    if(世代 == 10代){
        ルウ = 甘口ルウ;
    }
    else if(世代 == 20代){
        ルウ = 中辛ルウ;
    }
    else{
        ルウ = 辛口ルウ;
    }
    return ルウ
}
```

```java:CurryMaker
Curry makeCurry(Carrot 人参, Potato ジャガイモ, Onion 玉ねぎ, Pork 豚肉){
    
    //下ごしらえをする
    PrepareCarrot 下ごしらえ人参 = preparedCarrot(人参);
    PreparePotato 下ごしらえジャガイモ = preparedPotato(ジャガイモ);
    PrepareOnion 下ごしらえ玉ねぎ = preparedOnion(玉ねぎ);
    PreparePork 下ごしらえ肉 = preparedOnionPork(豚肉);

    //鍋に具材を入れる
    Pan カレー鍋 = new Pan(下ごしらえ人参, 下ごしらえジャガイモ,下ごしらえ玉ねぎ,下ごしらえ肉);
    カレー鍋.煮込む();
    
    Generation 世代 = 自分.世代取得();
    CurryRoux ルウ = selectルウ(世代);

    カレー鍋.add(ルウ);
    カレー鍋.煮込む();

    return カレー鍋.get中身();
}
```
やりました！真カレー装置(コード版)の完成です。
----
どうでしょうか、それぞれのメソッドが下ごしらえやルウの選択の責任を持つことでコードとして見やすくメソッドごとに確認もできるので修正も容易になったったと思います。
やっぱり、コードで書いた方がしっかり書き方がわかっていいですね。

一応、前と同じように分割しすぎの例も出しておきましょう。
(ちょっと無理があるのは、致し方なし)
----

```java:甘口なら甘口取得メソッド
CurryRoux select甘口ルウ(Generation 世代){

    if(世代 == 10代){
        return 甘口ルウ;
    }
    return null;
}
```
```java:中辛なら中辛取得メソッド
CurryRoux select中辛ルウ(Generation 世代){

    if(世代 == 20代){
        return 甘口ルウ;
    }
    return null;
}
```


```java:メソッド
CurryRoux selectルウ(Generation 世代){

    CurryRoux ルウ = select甘口ルウ(世代);
    if(ルウ == null){
        ルウ = select中辛ルウ(世代);
    }

    if(ルウ == null){
        ルウ = select辛口ルウ(世代);
    }

    return ルウ
}
```

どうでしょうか？ルウを選ぶという責任が３つに分かれてしまっているのでバラバラにし過ぎで、
単一責任と言えないのではないでしょうか？
以上が、コード版カレー作りでした。

**皆さん！このコードを参考にぜひ素晴らしいプログラミングをしてください！**


と、盲目に信じないでほしい。
----
プログラマーは、習性として良いと思ったコードをそのまま使ってみたい習性がある生き物だと思っています。もしかして、こう思ってませんか？

**このコードを参考に、同じように分割すれば必ずいいコードになる。単一責を維持するにはこうなるんだ。**

でも、責任って人によって捉え方は違います。
  ・甘口を選ぶことは１つの責任だ。
  ・下ごしらえは４つ合わせて責任だ。
  ・皮を剥くことと、切ることは別の責任だ。

わからなくなってきたところで、今回この記事を書く発端となったツイートをご紹介したいと思います。
----

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">此のスレッドで書いたんですが、以下が禁止されてまして。<br><br>if のネスト<br>switch<br>let, var<br>for, while, do-while<br><br>此のルールに対するエンジニアの反応は、「コードを書く」「レビューする」「テストを書く」と云う視点のどれが強く意識されるかで違ってくるのかと仮設を立てましたでござる。<br><br>→ <a href="https://t.co/ccaYPPkrHj">https://t.co/ccaYPPkrHj</a></p>&mdash; 悉生 游漩 (@StewEucen) <a href="https://twitter.com/StewEucen/status/1538013882102747136?ref_src=twsrc%5Etfw">June 18, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

このツイートはJSでのかなり攻めたコーディング規約について書かれたものです。

有識者ではないと、難解な内容のため解説はしませんが、
要約するとテストを容易にするために、１つの責任をif elseなども使わない平坦なものにしようという試みです。

先ほどおじさんの否定したコードとなりそうですが、成功しているので設計としては間違っていないと思います。

おじさんのコードは
**メソッドが明確な作業(責任)とすることで責任としてコードを見やすくすることを優先したい。**
※初心者にも扱いやすいよ！！！(必死)

悉生 游漩のコードは
**メソッドを平坦にすることでテストを完璧にすることを優先したい。**
※もちろんほかにも利点あり！！！でも難しい！！！！

じゃあ、答えなんかないんじゃないか？
----
現時点では、おそらくシステム設計において完璧な答えはないと思います。
だから、様々なプログラミング言語やプログラム工学が世の中に広がっているんです。

答えのないこの分野を武器とするには、コードの書き方ではなく**どんなことを考えるべきか**が大事と考えています。

そのためには、先入観の持ちやすいコードでの説明はやめてイメージだけを身に着け、己が立ち向かうべきプログラムでの最適な単一責任のコードを導き出してほしいと思っています。

----
こんな理由で設計の記事の時にはこれからもコードは書かないつもりです。
もちろん、技術系の記事を書くことがあったらちゃんとコード書きますよｗ