長生きしたいなら、パンは自分で焼くのがいいかも

久々に、全くエンジニアリング関係ないネタです。

最近、パンを焼くのにハマっている。食パンを買ってきて焼くんじゃなくて、小麦粉にいろいろ混ぜてコネコネして焼くほうのパン焼き。

パンを焼いてて考えたことをなんとなく書いてみた。

まずは、オレオレパンの焼き方を紹介するぞ

はじめは面倒と思ってたパン焼きが、意外とお手軽カンタンだったので紹介しておきたい。

を適当な小皿にいれて放置。 →材料①

  • 小麦粉(全粒粉) 240g
  • 水160g
  • 豆乳40g
  • 食塩3g
  • メイプルシロップ少し(目分量で大さじ1くらい)

3合炊きの炊飯釜 にいれてまぜまぜ。(はかりに釜を載せて材料を量りながら入れていくと、洗い物が出なくて超ラク) →材料②

材料①と材料②を混ぜれば、もうパンの香りがほのかにしてくる。

f:id:YusukeIwaki:20180616200400p:plain

炊飯器をセットして、発酵のために保温1時間。

1時間たったら、さらに少しまぜまぜして、炊飯。

すると・・・

f:id:YusukeIwaki:20180616200521p:plain

多少不格好だけど、まぁまぁそこそこ、というかかなり美味しいパンが出来上がる。

 

ちなみに、↑の手順をみて「まぁまぁめんどくさいじゃん?」と思った人がいるかも知れないけど、多分実際やってみたらそんなことはないとわかるはずだ。

そもそも私はものすごく面倒くさがりで飽き性だ。ちまたの料理番組とか見てると、次々にボウルに分けられた材料を投入していくシーンを見て「その大量のボウル、洗うの大変だよね!」とか思ってしまって、たいていの料理は参考にはできない。そのくらい面倒くさがりなのだ私は。

それでも、↑のパンづくりは続けられてる。だって、パンつくったあとに 洗い物がほとんどなくて 、美味しいパンが食べられるんだぜ?最高だぜ?

 

(これは完全に余談なんだけど、ホームベーカリーはダメだ。ホームベーカリーは洗うの大変だし、パン焼く以外には用途なくて場所取るから、おいしいパンを食べるのに見合った工数ではパンは焼けない。↑のオレオレパンは炊飯器で焼くというのが大きなポイントだ。)  

しかしこのパン、材料費がかかるぞ?

オレオレパン、おいしさとお手軽さは素晴らしいのだけど、実はなかなかに材料費が高い。

  • ドライイースト・・・28円(10袋で280円前後)
  • 小麦粉・・・約288円(500gで600円前後)
  • 水・・・10円(2リットルで100円の、サントリーのなんちゃら天然水)
  • 豆乳・・・8円(1リットルで200円前後)
  • 食塩・・・1円未満
  • メイプルシロップ・・・20円(300gで800円前後)

→355円!! 食パン1斤でだよ??

高い原因は間違いなく

こいつだ。有機の全粒粉 を使ってるからだ。

実のところ、安い小麦粉 を使えば、1kgで350円くらいなので、計150円くらいのパンになる。

ただ、安い小麦粉だと全然美味しくないパンが出来上がってしまったため、モチベーション維持のために有機全粒粉を使うことにしたのだ。

 

ところで、市販のパン・・・安すぎないか?

オレオレパンは、小麦粉で少し贅沢してるのは間違いない。小麦粉以外でも、メイプルシロップとかで少し贅沢してるのかもしれない。

でもちょっとまて、本当に贅沢なのか、これ??

逆に、スーパーとかコンビニで1斤100円とかの食パンって、一体どーやって作ってるの????大量仕入れだけで、本当にそんな安く作れるか?!

ということで、とりあえずファミマで100円で売ってるパンの裏をみてみよう。

f:id:YusukeIwaki:20180616211417p:plain

小麦粉、パン酵母、食塩、はわかる。

 

ショートニング ??((((;゚Д゚))))ガクブル

 

乳などを主要原料とする食品 ???((((;゚Д゚))))ガクガクブルブル

 

 

なにこれ・・・!?

 

 

てきとうに予想するに、

  • バターは高いからコストカットのためにショートニング使って、
  • それだと美味しくないから果糖ブドウ糖液糖で甘みでごまかして、
  • あとは味をととのえるために色々いれて、

みたいな、健康への配慮は二の次にした企業努力のようなものはあるのかもしれない。

それにしても、100円で売れるパンは安すぎる。これ、小麦粉は一体どんな粗悪品を使っているのだ・・・?!

 

食の安全を考えると、安いものは実はそんなに安くない?

100円のマクドと400円のモスはどっちが安いか

(※ これは完全に空想話なので全く根拠がある内容ではない)

たとえばハンバーガーで、マクドは100円。モスは400円。

週1くらいの頻度で食べて、仮に

  • マクド食べてた人は10年後に病気を発症して、その治療に40万くらいかかる
  • モス食べてた人は20年後に病気を発症して、   〃

としたら・・・?

1年は約52週間なので、1回あたりの治療コストの積立は

マクド→766円 モス→383円

くらいになる。

ハンバーガーの値段と足し合わせると、マクドが866円、モスは783円。 モスのほうが1割ほど安くなる。

あらためて、オレオレパンは高いのか?

パン好きな人であれば、食パンはハンバーガーよりも高頻度で食べるはず。 毎日2枚食べるとして3日でなくなる計算。

ちまたの100円食パンをX年食べ続けて、仮にその治療費に40万かかるとすると、そのときの治療コストの積立は

X 治療コスト積立
5 657
10 328
15 219

ということで、約13年以上長く病気にならずに食べ続けることができれば、オレオレパンよりも100円食パンのほうが真に安いということになる。

 

私の場合は、体質的にダメなのか、ショートニングを摂取した途端に皮膚が荒れ始める。なので、13年摂取しつづけて病気にならないとか無理だww

ということで、健康維持のコストも考えて、これはやっぱりパンは自分で焼いて食べるぞ! ってなった。

 

まとめ

  • 健康維持のためのコストは意外と高い
  • オレオレパンはとても美味しい

"else if"を書くよりも先に...

まえおき

最近、仕事をしていて「つまらない、もうやめたい」って思ったときってどんなときだったっけ?と振り返ってみた。

モチベーションが下がりまくりな仕事の一因として、「パターンが多い」ってのがあると思った。

function handleWebHook(event) {
  if (event.type == "Liked") {
    if (event.source == "Article") {
      handleArticleLiked(event.data);
    }
  } else if (event.type == "Comment") {
    if (typeof event.data["bot_id"] != "undefined") {
      handleBotMessage(event.data);
    }
  } else if ( ... ) {
    ...

重厚長大なif文は、テスト書くときにも死ぬほどパターンを用意しないといけなくて、とにかくストレスがたまる。

こんな感じのコードが300行くらい続いたら、確実に集中力が切れる。てかキレる。

"else if" よりも、クラス分割?

であれば、分割すればいいやん?というのは自然な発想。

ここでいきなりPythonっぽいサンプルコードになるけど、

class LikeHandler(BaseHandler):
  def shouldHandle(event):
    return event.type == "Liked"

  def handleEvent(event):
    if event.source == "Article":
      handleArticle(event.data)


class CommentHandler(BaseHandler):
  def shouldHandle(event):
    return event.type == "Comment"

  def handleEvent(event):
    if "bot_id" in event.data:
      handleBotMessage(event.data)

...

eventHandlers = [
  LikeHandler,
  CommentHandler,
   ...
];

def handleWebHook(event):
  for handler in eventHandlers:
    if handler.shouldHandle(event):
      handler.handleEvent(event)

Pythonに限った話ではなくて、JavaでもRubyでもだいたいこんな感じで分割するのはぱっと思いつく。分割することで、テストもクラスに応じて1つずつ書いていけるし、ストレス値は一気に減る。

でも・・・

  • 毎度 def shouldHandle とか event.type== とか def handleEvent とか書かないといけないのってだるいよね
  • def handleEvent って結局どういう処理するのかって、ソースのコメント書かないと、メソッド名ではぱっと読めないよね
  • 多くのhandlerは event.typeで判定するんだろうけど、ほんとにそうなの?ってのが全部のhandlerみないとわからない

というところが今度は地味なモチベーション低下要因になってくる。

より "else if" の「判断ポイント」を明確にする書き方

Pythonbottle とかFlask っていうAPIサーバを書くライブラリをみて、ふと思った。

かりに

router = Router()

@router.on('Liked')
def handleLike(event):
  likeRouter.route(event.source, event)

@router.on("Comment"):
def handleComment(event):
  if "bot_id" in event.data:
    ...

 (中略)

def handleWebHook(event):
  router.route(event.type, event)

みたいに書くことができたらどうなるだろう?と。

毎回 event.type== xxx とか should_handle(event): return xxx とかを書く手間もなければ、判断基準(event.typeで判定しているという事実)がブレることもない。

直感的に「これだ!」とおもったので、Pythonで適当にライブラリを作ってみた。

github.com

Pythonじゃなかったらどう書く?

JSならこんな感じ?

class Route {
  constructor() {
    this.routes = {}
  }

  on(key, target) {
    this[key] = target;
  }

  route(key, ...args) {
    if (typeof this[key] == 'function') {
      this[key](...args);
    }
  }
}

r = new Route()

r.on("Liked", (event) => {
  ...
})

r.on("Comment", (event) => {
  ...
})


///////////

r.route(e.type, e);

結論?

else if を30個くらい書いてて吐き気がするところは、積極的に分割しよう。

Routerっぽいものを実装すると見通しが良くなるかもしれない。

cobra/viperでコマンドラインツールを作っていて良かった所、詰まった所

まえおき

最近、Androidアプリを開発するのが全然おもしろくなくなってきたので、Dartを触り始めた。(※ Flutterではない)

で、Dartコマンドラインツール作ろうと思ったけど、コマンドラインツールといえば、とりあえずGoの cobra/viper 知っとかないと・・・

ということでGoを5年ぶりくらいに触り始めた。

何を作った?

github.com

appetize.io っていうWebベースのエミュレータAPIを便利に使うコマンドラインツールを作ってみた。 brew tapでインストールできるようにリポジトリを適当に作った ので、たぶん

brew tap YusukeIwaki/appetize
brew install appetize

で使えると思われる。

※ 完全に余談だけど、今回はとくに「自分自身が "使いたい!" と思う形でリリースする」ということにこだわった。

「必須だけどユーザによって使う値はだいたい決まっている、けどコマンドラインパラメータでオーバーライドもできる」が瞬殺だった

会社の同僚がQiitaに書いていて、そのまんまなんだけども。

APIトークンとかって、毎回毎回 --token=tok_79ad08a09dca80dc9a みたいなのを打つのはあまりに面倒。

  1. ~/.appetize.ymlapi_token: tok_9ads8ad9a7dsa みたいな設定値があればそれを使う
  2. 環境変数APPETIZE_API_TOKEN=tok_7987adaca9d7ca8c7 みたいな変数があれば、それを使う
  3. コマンドラインパラメータで --token=toka9sd7sa9d87a みたいなパラメータが指定されていれば、それを使う

で、同時指定の場合は、3 > 2 >1 の優先順位で動いてくれるのが望ましい。

これ、viperとcobraの典型的なユースケースで、わりと瞬殺で実装できてしまう。

// initConfig reads in config file and ENV variables if set.
func initConfig() {
    // Find home directory.
    home, err := homedir.Dir()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    // Search config in home directory with name ".appetize" (without extension).
    viper.AddConfigPath(home)
    viper.SetConfigName(".appetize")
    viper.BindEnv("api_token", "APPETIZE_API_TOKEN")

    // If a config file is found, read it in.
    if err := viper.ReadInConfig(); err == nil {
        //fmt.Println("Using config file:", viper.ConfigFileUsed())
    }
}

func init() {
    cobra.OnInitialize(initConfig)

    rootCmd.PersistentFlags().String("token", "", "Appetize api token")
    viper.BindPFlag("api_token", rootCmd.PersistentFlags().Lookup("token"))
}

これだけだ。なんて便利。

「上書き保存用のフォームオブジェクト」ってどうやってつくるの?

App
  |- PublicKey
  |- Timeout
  |- Disabled

みたいなのがサーバー側でモデルとしてあって、JSON APIで書き換えるときに詰まった。

1つの属性だけ書き換えたい時にどうするか?

たとえば、 ./appdemo update --timeout 100 って打った時に、勝手にdisabled=falseを上書きするような実装だと困る。

コマンドラインパラメータの処理

cmd.Flags().GetBool("Disabled") だと、

  • ユーザが指定せずデフォルトパラメータとして falseが返っている
  • ユーザが意図して --disabled false を指定している

がわからない。

調べてみると、cobraリポジトリにissueが既に上がっていて、

Question: See if a flag was set by the user · Issue #23 · spf13/cobra · GitHub

Changed を使えばわかるよ!って書いてあった。

if cmd.Flags().Changed("Disabled") {
  attributes.Disabled = cmd.Flags().GetBool("Disabled")
}

ってすればいいらしい。

パラメータの構造体の定義

if cmd.Flags().Changed("Disabled") { のなかでいきなりJSONを組み立てるのとかはさすがに筋が良くないので、多くの場合は一旦それ専用の構造体をつくることになる。

ここでも、「ユーザが意図してfalseを設定したのか、デフォルト値としてのfalseなのか・・・」というのを迷うことになった。

type AttributesForUpdate struct {
  PublicKey  string
  Timeout     int
  Disabled    bool
}

愚直に↑みたいなフォームを作ると、Disabled = false のときの処理に困ることになる。(ちなみに、これは正直Goに限った問題ではなくて、だいたいどの言語でも同じようなことは言える)

var attributes AttributesForUpdate
attributes.Timeout = 100

fmt.Println(attributes.Disabled) // => false

これは、調べてみるといくつかのパターンはあって、みんなそれなりに苦しんでいるっぽい?

nilもいけるように、ポインタ型にしちゃう?

proposal: spec: option types · Issue #7054 · golang/go · GitHub

type AttributesForUpdate struct {
  PublicKey  *string
  Timeout     *int
  Disabled    *bool
}

*int がなかなかに鬼畜、ってissueでコメントしてる人がいる。

Optional型を作っちゃう

GoogleのCloud PlatformのSDKがこの方式を使っている

nilでToBoolするとpanicする、ってなかなか激しいぞ・・・

type AttributesForUpdate struct {
  PublicKey  optional.String
  Timeout     optional.Int
  Disabled    optional.Bool
}

JSONのMarshalとかをやらないなら、アリかもしれない。

ぜんぶstring型にしちゃおう

さすがにこれをやってる例は見なかった。

type AttributesForUpdate struct {
  PublicKey  string
  Timeout     string
  Disabled    string
}
if attributes.Disabled == "true" {
  params.Add("disabled", true)
} else if attributes.Disabled == "false" {
  params.Add("disabled", false")
}

ヤバイw

いっそのことstructじゃなくて、 map[string]interface{} にする

var attributes map[string]interface{}

if cmd.Flags().Changed("Disabled") {
  attributes["Disbaled"] = cmd.Flags().GetBool("Disabled")
}

うん、タイポしててもわからないね・・・。

これはさすがに却下。


ということで、とりあえずGoogleがやってるように、Optional型つくる、かなぁー・・・

まとめ

cobra/viperは素晴らしい