旧gaaamiiのブログ

間違ったことを書いている時があります。コメントやTwitter、ブコメなどでご指摘ください

「CODE COMPLETE」を読んだ感想を書きたい

会社の先輩から勧められて借りてきた。上巻から読んでる。

コンストラクション

この本ではソフトウェアづくりのことをコンストラクションと呼んでる。コンストラクションの範囲のことは語るけどその外のことはこの本の範疇外やでということらしい。コンストラクションの範囲は、ひどいソフトウェア開発だろうがうまいソフトウェア開発だろうが絶対通るような、作る工程のことを指してるっぽい。設計とかは入るけど、顧客折衝とかは入らない感じっぽい。

リーダブルコードだと基本的にコーディングのことばかりだけど、この本はもう少し広い範囲を対象にしてそうというのがわかる。

第5章

第5章は設計の話。設計っていうのはヒューリスティック(発見的)なものであり、決定論的なものじゃないということが書かれている。正解があって、一発で、はいこれねと正解が出せるものではなさそうなのがわかる。

第6章

具体的な話になってきた。ADT(Abstract Data Types)の話。 プログラムのデータ型というとまずstringとかintとかそういうプリミティブなものがあるけど、それをそのまま使うんじゃなくて、現実世界のものを抽象化して表現すると良いぞ、みたいな話。読み進めながら、なるほどオブジェクト指向のクラスの話かと思ったけど、それよりも土台の話らしい。

ADTはクラスの概念の土台となる。クラスをサポートするプログラミング言語では、ADTをそれぞれ専用のクラスとして実装することができる。通常、クラスには他にも継承やポリモーフィズムという概念がある。クラスは「ADT + 継承およびポリモーフィズム」として考えることもできる。

第7章

ルーチンの話。関数(値を返すルーチン)とプロシージャ(値を返さないルーチン)の使い分けなど。C++のマクロの話はあんま関係ないな〜と思って読み飛ばしてしまった。

自分は普段ここで書かれているルーチンの種類を特に区別せず全部関数って呼んでたのだけど、値を返すかどうかによってそうやって言い分けるものなんだ〜というのを学んだりした。

第8章

防御的プログラミングの話。garbage in garbage out (ゴミを入れてゴミを出す)ではだめで、エラーメッセージを出したり、そもそもゴミを入れさせないようにしたりと、ゴミに対処するべきという話。

8.3.1 では堅牢性と正当性という言葉が出てくる。

正当性とは、不正確な結果を決して返さないことを意味する。不正確な結果を返すくらいなら、何も返さない方がましである。堅牢性とは、ソフトウェアの実行を継続できるように手を尽くすことである。

どんなアプリケーションのどんな機能かによって、正当性を優先するか堅牢性を優先するかが変わってくる。正当性を優先すれば、誤ったものがきたときにエラーメッセージを出して処理を中断とかにするだろうし、堅牢性を重視するなら、そうはせずに近い値やデフォルト値みたいなものを変わりに入れて処理を続行したりする。

また、8.4では例外についても触れられている。安易に例外使わないようにしたほうがいいよというスタンスで、こんなことが書かれている。

例外は、予想外の状況に対処する強力な手段と、コードの複雑さの増大とのトレードオフを表す。たとえば、あるルーチンを呼び出すためには、呼び出し元のコードはどこでどの例外がスローされるのかを知らなければならない。したがって、例外はカプセル化を弱め、これによりコードの複雑さが増し、「ソフトウェアの鉄則:複雑さへの対応」にマイナスに働く。

第9章

擬似コードによるプログラミングの話。

第10章

変数の話。なるべく宣言した近くで使おうねという話など。

第11章

第11章は変数の名前の話。その変数が持つ意味を考えて、あとで読んだときに推理しないでもぱっとわかる変数名つけようねという話。

第12章

第12章は基本的なデータ型。浮動小数点数の話とか。


書き途中です。

TypeScriptのkeyofの使いどころ

読者登録したブログ記事をだらだらと巡回していて、こちらの記事を拝見しました。淡々と学んだことをブログに書いていてすごいなと思っていつも読ませてもらっています。

yurufuwa-tech.hatenablog.com

特定のオブジェクトのkeyの値しか許容しない、みたいなパターンの時に使えるって話なんだとは思うのだがこれがどこで使えるのか…というのはちょい謎。。。

TypeScriptは覚えることが多くて自分もあまり自信がないのですが、keyofについてはちょうど最近便利だな〜と感じたことがあったので、傲慢にも勝手にアンサー記事みたいなのを書こうと思いました(間違ってること言ってたらご指摘ください)。釈迦に説法だったら生温かい目で見てください。

Formikのフィールド名に使える

具体的すぎ感ありますが、keyofはFormikのフィールド名を表現するのに使えました。

FormikというのはReactでフォームを扱う際に便利コンポーネントを提供してくれるライブラリです。Formikを利用したフォームは、通常のHTMLフォームと同様、フォームがあって、そのなかにフィールドがあって、それぞれのフィールドにはname属性がついている、みたいな形になります。

const MyInnerForm = (props: Props) => {
  return (
    <Form>
      <Field name="hoge" />
    </Form>
  )
}

Formikを使うと、↑こんな感じでフォーム要素を記述して、 ↓withFormikというHOCで必要なコールバックなどを流し込んだコンポーネントを作れます。

const handleSubmit = (values: Values) => { /* ...省略 */ }
const validate = (values: Values, props: Props)  => { /*...省略 */ }
const MyForm = withFormik({ hanldeSubmit, validate, /* ほかにもいろいろ入れるけど省略 */,  })(MyInnerForm)

Formikは、ユーザーがそのフィールドを触ったかどうかとか、validateで判定したエラーの結果なんかをFormikのpropsとして持っています。

なので、エラーがあるときはこんな形で参照できます。

interface Values {
  hoge: string;
  fuga: string;
  foo: string;
}

const MyInnerForm = (props: Props & FormikProps<Values>) => {
  console.info(props.touched.hoge)
  console.info(props.errors.hoge)

  return (
    <Form>
      <Field name="hoge" />
    </Form>
  )
}

で、場合によってはここで以下のような hasError みたいな関数を定義したくなります(なりました)。 使いやすい、イケてるウェッブサービスをつくりたいので、hasErrorだったときはその場でフィールドを赤くしたりしたくなるのです。

const hasError = (props: Props & FormikProps<Values>): boolean => {
  return props.touched.hoge && props.errors.hoge
}

いいんじゃないでしょうか。しかしこれが複数のフィールドになると面倒です。

const hasErrorOnHoge = (props: Props & FormikProps<Values>): boolean => {
  return props.touched.hoge && props.errors.hoge
}
const hasErrorOnFuga = (props: Props & FormikProps<Values>): boolean => {
  return props.touched.fuga && props.errors.fuga
}
const hasErrorOnFoo = (props: Props & FormikProps<Values>): boolean => {
  return props.touched.foo && props.errors.foo
}

関数1つにしたいですね。フィールド名を渡すようにします。

const hasError = (props: Props & FormikProps<Values>, fieldName: string): boolean => {
  return props.touched[fieldName] && props.errors[fieldName]
}

できた〜。イケてる〜。

となるんですが、問題は、fieldNameの許容する値が広いことです。

hasError(props, 'hogeee')

こうしても、型のエラーにはなりません。stringなのだからそりゃそうです。

ここでようやく、keyof の出番です。これでどうでしょう。

const hasError = (props: Props & FormikProps<Values>, fieldName: keyof Values): boolean => {
  return props.touched[fieldName] && props.errors[fieldName]
}
hasError(props, 'hoge')
hasError(props, 'hogeee') // Argument of type '"hogeee"' is not assignable to parameter of type "hoge" | "fuga" | "foo"

打ち間違えてhogeeeにしたらちゃんと怒られるようになりました。めでたし。

まとめ

TypeScriptほんと難しくてあれやこれや覚えないとな〜という感じで、自分で型書いているときはあまり難しいことはできていないのですが、keyofはわりと出番がありそうだなと思ってます。

関連

「儲かる会社、つぶれる会社の法則」を読んだ感想

面白かった。

こんな会社はだめ、気をつけろ、みたいな例がたくさん書かれていた。 ああそらだめそうですなと思うのと同時に、 いま自分が勤めている会社は割といい会社なんじゃないかとも思えた。

「幸せな選択、不幸な選択――行動科学で最高の人生をデザインする」を読んだ感想

読んだ。面白かった。

まず、幸福度を測るの難しそうだなという感想を持った。とはいえ自分は研究者としてではなく読み物としてだらだら読んでるだけなので、調査方法の詳細はへえそうなのというレベルで読み流した。

第4章の内容はけっこう好きだ。目標とかやりがいといったものについて考える上で参考になる。このへんは気に入った。

もちろん 、目標達成や真正性といった他の考慮材料もたしかに重要だ 。ただし 、これらが重要なのはそれに 「道具的価値 (手段的価値 ) 」があるからで 、つまり 、幸福度を高める意味においてのみ重要なのだ 。目標達成や真正性は概して幸福度を高めるが 、私たちがその奴隷になってはならない 。

何を幸せかと考える上で、仕事なり競技なりでトップを目指すような、いわゆる意識高い系の考え方と、そんなことより幸せに過ごしたいみたいなゆるめの考え方があると思うんだけど、そのどちらにとっても、この考え方は役立つと思う。

日高屋実践入門

昨年度1年の支出なんかを振り返っていて、ずいぶん贅沢してしまったなと反省した。 今年度からは、一人で行く昼飯とかで無意識に贅沢しないようにしようと思い、日高屋によく行くようになった。

なぜ日高屋なのか

量を少なめにしても、味が濃いので満足できる。

なにを頼んでいるのか

  • 半チャーハン:¥260
  • 餃子(3個):¥130

昼飯が¥390におさまる。すごい。

すこし変化を入れたいときはイワシフライ(¥230)を頼んでいるが、それでも¥490である。すごい。

健康

健康にはあまり良いとは言えない。ただ、朝夕の飯さえちゃんとすれば絶望的に健康に悪いというわけでもないと思う。

まとめ

日高屋は好きだが、さらにコスパの良い外食があるような気もしている。 これがいいぞなどあれば教えてください。

Visual Studio CodeのWebTemplateStudioを触った感想

こちらに書いた。

scrapbox.io

なんか誰に役立つものかよくわからなかった。もっとXcodeのStoryboardみたいなやつを想像していたけど、yeomanみたいなやつだった。

HTML要素を加工したReactコンポーネントに属性値を渡して展開して入れ込む方法

具体的にはlabelみたいなものですね。Labelというコンポーネントを作って、htmlのlabelと同じように属性値を渡しつつ、独自のスタイルを当てたりするコンポーネントをつくりたいみたいな。

こうする

const Label = (props: React.Props<{}> & React.HTMLLabelAttributes<HTMLLabelElement>) => {
  const { children, ...attributes } = props
  return <label {...attributes}>{children}</label>
}

「いつも「時間がない」あなたに:欠乏の行動経済学」を読んだ感想

Kindleストアを眺めていて、あっこれおれ読まないとダメなやつじゃん、と思って読んだ。面白かった。

借金の話

時間の話を、借金の話とかぶせて説明されたりして、納得感あった。

処理能力の制約

このへんの文が個人的には熱かった。

教育が良いことであるのはまちがいない 。しかし貧困者が犠牲を払わずに受けられるものであるかのように扱われているが 、実際には処理能力への高い代償がともなう 。本人が集中できずに教育の努力が無駄になるか 、本人は集中するが処理能力に負荷がかかるか 、いずれかである 。本人が実際に訓練やインセンティブに集中するとき 、何に集中しないことになるのだろう ?新たに課された授業はほんとうに 、彼が本を読んだり子どもと過ごしたりするためにひねり出した貴重な時間をつぶすだけの価値があるのだろうか ?

貧困者が貧困に陥る原因は、お金の教育がされていないからだ -> じゃあお金の教育プログラムを受けさせればいいはず。みたいなことがされてるけど、そこには処理能力という見えてない制約があるんじゃぞ、そこも考慮しないとだめよ、というような話。

感想

この本から得られた個人的な教訓としては、借金よくないね、時間あるときに前もってやるべきことやろうね、余裕はある程度持とうね、というごく当然のことなんだけど、それがいかに難しいことか、ということを本書を読んで改めて知ることができた。

自分もこの本に書かれているような失敗を何度もしているので、興味深く読めた。自分は幸い借金はないけど、時間の使い方についてはこの本の言い方でいうとジャグリング状態だ。スラックがない。

何度も読み返しながら、実生活を改善していきたい。

アフロ田中という人生漫画について

一気に読んでしまうほど面白くはないけど、読みながら一緒に歳をとれて、漫画の中のエピソードが自分の友だちとの思い出みたいな感覚で残っていくので面白い。いまは結婚アフロ田中の3巻が最新だけど、そこから読み始めてもいい。

ウェブフロントエンドのビルド設定を単純に考える

ウェブフロントエンドは設定周りがひたすらつらくて、なにかプロジェクトを作ろうとするとそれだけで挫折してしまうことが珍しくない。その辺を簡単にするツールもあるけれど、その中身が何をしているものかわからないと、設定の追加や最適化ができなかったりして結局つらいことになったりもする。無駄に難しいことに向き合うのは誰だって嫌なので、ウェブフロントエンドのビルド周りの設定って何が必要なんだ...?というのを、なるべく難しい話を省いて書いておこうと思った。

何もなくてもいい

まず、簡単なウェブサイトにちょっとしたスクリプトを入れるのであれば何もなくてもいい。テキストエディタでindex.htmlとindex.jsを作って、index.htmlに<script src="index.js" />を書けばいい。ほんとにちょっとしたものであれば、index.htmlに<script>alert('hello world');</script>と書けばいいだけかもしれない。

モジュール

簡単なスクリプトでも、1000行近いindex.jsになってしまっていたら、そのプログラムは読むのが大変。なので、他のプログラミング言語と同様に、複数のファイルに分けて、わかりやすくしたい。index.htmlは以下のようになる。

<script src="a.js">
<script src="b.js">

b.jsで、a.jsの機能を使うという依存関係があるため、a.jsはb.jsより先に読み込まれている必要があり、そのため<script src="a.js">の記述が先に来る必要がある。

これでも困らなければこれで良い。しかしファイルが多くなってくると、管理はどんどん大変になってくる。 そこで、モジュールとして扱えるようにしたくなる。

b.jsで、このように記述して、a.jsからモジュールをimportできるようにする。

import A from 'a';

A.hello();

モジュールバンドラーの導入

上のような感じで、モジュール分けられた〜良かった〜。となるものの、ファイル数が多いと、サーバーからJSファイルをダウンロードするのをモジュールの数だけやることになる。HTTP 1.1だとこれがけっこうな時間になりかねない。

f:id:shgam:20190324230744p:plain

そこで、ファイルを束ねて返すために利用できるのがwebpackなどのモジュールバンドラー。 設定を書いて、コマンドを叩くと、複数のモジュールが一つのファイルに束ねられる。なので、それをサーバーから配信するときも1つのファイルを返すだけになって助かる。

モジュール束ねるだけじゃなくてもっといろいろやりたい

ウェブアプリ開発では、モジュールを束ねる以外にもいろいろやりたいことが出てくる。webpackでは、loaderという、バンドル対象のソースコードを変換していくための設定が書ける。

ES5にしたい

上で書いたimportなどは、そのままだと古いブラウザ(Internet Explorer 11とか)だと動かない。じゃあどうするのっていうことで、古いブラウザで動くJavaScriptにしたくて、それがES5(ECMAScript 5)という仕様。babelというツールがあり、これを使うとES5にできる。だから古いブラウザでも動く。古いブラウザを使っているお客さんにもアプリケーションを使ってもらえる。

JavaScriptではなくてTypeScriptで書きたい

JavaScriptは動的型付けの言語なので、静的型付けの言語でウェブアプリを書きたいとなると、だいたいTypeScriptを使うことになる。これも、設定を書けばできる。

SASS使いたい

これも設定を書けばできる。

Lintかけたい

これも同上。


...と、ほかもいろいろ羅列しようとすると疲れそうなのでもうやめる。

上に書いてきたものは情報としてあまり価値がないかもしれない。 時間が進んで、古いブラウザを切れるようになってくると前提が変わってくる。すると、必要な設定も変わってくる。コードも変わってくる。 だから、ウェブアプリ書いてる人間はいつまで設定と格闘しなきゃいけないんだつらいっていう気持ちにもなるけど、前提が変わる以上はずっとやらないといけないことだとは思う。

単純に考えると、どういう環境で動くものを作りたいか、どうコードを書きたいかという2点を考えて今後もやっていけばよさそう。

SPA時代について

SPAについてのブログ記事を読んだ。自分が考えていることを箇条書きにしておく。

  • ビューもRailsにのっかって書いたほうが、生産性とか安心感が得られるかもしれない。
  • それを捨ててまでSPAにしたからといって使いやすいアプリケーションになるとは限らない。
  • すごい頑張ってSPAにして、すごい気を使って作って、ほんのちょっと使い勝手が良くなるかもしれない。
  • ほんのちょっとの使い勝手の良さが競争に勝つためにすごい大事かもしれないし、そうではないかもしれない。
  • 既存のアプリケーションをSPAにしようとして、スケジュールが遅延して苦しいことになるかもしれない。

そんな末端を最適化しなくとも、ちゃんと使えるシステムを作っていれば十分なのかもしれないし、逆にそうやって言ってる間にみんな末端を最適化したサービスだらけになっていて競争で勝てなくなるかもしれない。仕事難しい。

基礎からわかるElmを読んだ感想

1年半くらい前に注文したものの、Elmのバージョンが0.18->0.19に上がる都合とかで出版予定日が延びていたElm本がついに昨日、自宅に届いていた。感動した。

勉強になったところとか、感想を書いていく。

基礎からわかる Elm

基礎からわかる Elm

Amazon

型の話

Elmといえば静的型付け言語であり、No Runtime Errorなウェブアプリを書けるという良さがある。 一方で、型が読めないと何が何だかわからない。型の話がわからないと、自分で型を書けないのはもちろん、なんといってもドキュメントが読めなくて困る。

この本では、50〜71ページのおよそ20ページでこのElmの型についての説明が書かれている。この辺の節を読むと、制約つきの型変数、type aliasがコンストラクタを生成すること、カスタム型とパターンマッチなどについて学べる。とても丁寧でわかりやすい。特にtype aliasとかカスタム型は自分で勉強したときよくわからなくてつらかった思い出があるので、もっと早くこの本が欲しかった。

MaybeとかResultとか

Elmにはnullとかnilってものはないという話で、その代わりMaybeって型がある。Maybeはモジュールにもなっていて、withDefaultとかmapとかandThenなどの関数が生えているのでだいたいやりたいことはできる。なんとなく自分の理解が怪しかったので復習がてら読んだ。

Resultも似たようなものだけど、Maybe以上に自分の理解が怪しかったのはおそらく、APIへリクエスト投げてレスポンス取得して云々みたいな処理を実装しようというときに初めてこのResultに出会ったからだと思う。ElmでHTTPリクエストを送る処理はHttpというモジュールでやる。そこでResultという型が出てくるのだけど、もちろんResult自体はそれ以外のところでも使えるし、Httpのためだけのものでもない。

本書では、

Resultは失敗するかもしれない結果を表すデータ構造です。

と簡潔に書かれていて、例示されているコードもHttpとかは関係のないものになっている。「ElmでAPIへリクエスト投げてデータ取得する実装をやろう」となって、「実装してみたもののResultってやつがなんだかよくわからない」となったときに本書のこの辺を読むとすっきりわかってよさそう。

描画の仕組みと高速化

Html.KeyedとHtml.lazyの話。

ReactでもkeyアトリビュートとReact.PureComponentがあり、これらと同じようなものだと思う。

ナビゲーション

onUrlRequestonUrlChangeの説明がありがたい。 ナビゲーション周りの知識はSPAつくるときに必須なので、これが簡潔にまとめられているのは助かる。

感想

Elmを使って、実行時エラーが発生しないアプリを作れるのは魅力的だけど、新たに言語覚えるのはしんどい。 日本語の書籍にまとまったことで、言語覚えるしんどさが軽減されて、Elm人気もじわじわ高まっていくんじゃないかと思った。

combineReducersってなんだ

最近、Structuring Reducersとかそこらへんのページを読んでる。

なんで読んでるのかというと、Reduxでウェブアプリケーション書いていて、reducerどう分けるのがきれいなんだっていうのがいまいちわかっていない気がしたから。Immutable.js入れときゃいいのか?とか考える前に、ここを読むべきっぽいので読もうみたいな気持ち。

その中で、combineReducersっていう関数が何をしているのか気になったので、調べた。

combineReducersは複数のreducerたちを、createStoreに渡せる一つの関数の形にしてくれるやつらしい。 実際何をしているのか見てみる。

てきとうにreduxをnode_modulesにインストールしてあるプロジェクトで、nodeのREPLを立ち上げる。

$ node
>

そんで、redux.combineReducersという関数を雑に確認

> const redux = require('redux')
undefined
> redux.combineReducers
[Function: combineReducers]
> redux.combineReducers.toString()
'function combineReducers(reducers) {\n  var reducerKeys = Object.keys(reducers);\n  var finalReducers = {};\n  for (var i = 0; i < reducerKeys.length; i++) {\n    var key = reducerKeys[i];\n\n    if (process.env.NODE_ENV !== \'production\') {\n      if (typeof reducers[key] === \'undefined\') {\n        warning(\'No reducer provided for key "\' + key + \'"\');\n      }\n    }\n\n    if (typeof reducers[key] === \'function\') {\n      finalReducers[key] = reducers[key];\n    }\n  }\n  var finalReducerKeys = Object.keys(finalReducers);\n\n  var unexpectedKeyCache = void 0;\n  if (process.env.NODE_ENV !== \'production\') {\n    unexpectedKeyCache = {};\n  }\n\n  var shapeAssertionError = void 0;\n  try {\n    assertReducerShape(finalReducers);\n  } catch (e) {\n    shapeAssertionError = e;\n  }\n\n  return function combination() {\n    var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n    var action = arguments[1];\n\n    if (shapeAssertionError) {\n      throw shapeAssertionError;\n    }\n\n    if (process.env.NODE_ENV !== \'production\') {\n      var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache);\n      if (warningMessage) {\n        warning(warningMessage);\n      }\n    }\n\n    var hasChanged = false;\n    var nextState = {};\n    for (var _i = 0; _i < finalReducerKeys.length; _i++) {\n      var _key = finalReducerKeys[_i];\n      var reducer = finalReducers[_key];\n      var previousStateForKey = state[_key];\n      var nextStateForKey = reducer(previousStateForKey, action);\n      if (typeof nextStateForKey === \'undefined\') {\n        var errorMessage = getUndefinedStateErrorMessage(_key, action);\n        throw new Error(errorMessage);\n      }\n      nextState[_key] = nextStateForKey;\n      hasChanged = hasChanged || nextStateForKey !== previousStateForKey;\n    }\n    return hasChanged ? nextState : state;\n  };\n}'

てきとうなreducerを渡して何がかえってくるかを見てみる

> redux.combineReducers({ hoge: (state, action) => { return state }})
[Function: combination]

関数が返ってきたので、これのなかみを雑に見る。

> redux.combineReducers({ hoge: (state, action) => { return state }}).toString()
'function combination() {\n    var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n    var action = arguments[1];\n\n    if (shapeAssertionError) {\n      throw shapeAssertionError;\n    }\n\n    if (process.env.NODE_ENV !== \'production\') {\n      var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache);\n      if (warningMessage) {\n        warning(warningMessage);\n      }\n    }\n\n    var hasChanged = false;\n    var nextState = {};\n    for (var _i = 0; _i < finalReducerKeys.length; _i++) {\n      var _key = finalReducerKeys[_i];\n      var reducer = finalReducers[_key];\n      var previousStateForKey = state[_key];\n      var nextStateForKey = reducer(previousStateForKey, action);\n      if (typeof nextStateForKey === \'undefined\') {\n        var errorMessage = getUndefinedStateErrorMessage(_key, action);\n        throw new Error(errorMessage);\n      }\n      nextState[_key] = nextStateForKey;\n      hasChanged = hasChanged || nextStateForKey !== previousStateForKey;\n    }\n    return hasChanged ? nextState : state;\n  }'

中身を見ると、なるほどたしかにstateのキーごとにreducer(state, action)を呼び出して、次の状態を作っている。

function combination()というのを見て、なんだ(state,action) => stateの形になってないじゃないかと一瞬思ったけど、よく見るとarguments[0]をstateに、arguments[1]をactionに代入しているので、combination()combination(state, action) と呼び出せることがわかる。関数定義で引数がなさそうでも、引数を渡して呼べて、それをargumentsでアクセスできるらしい1

呼び出してみる。

> const combination = redux.combineReducers({ hoge: (state, action) => { return state }})
undefined
> combination(1, {})
Error: Reducer "hoge" returned undefined during initialization. If the state passed to the reducer is undefined, you must explicitly return the initial state. The initial state may not be undefined. If you don't want to set a value for this reducer, you can use null instead of undefined.

エラーになった。さすがに雑すぎたようだ。このエラー文で言われている通り、初期状態をundefinedにしたらいけないので、そこらへんもちゃんとしたreducerを渡して再度試す。

> const myCombination = redux.combineReducers({ hoge: (state = 0, action) => { return state }})
undefined
> myCombination({ hoge: 1}, {type: 'HOGE_ACTION', payload: 'hogehoge'})
{ hoge: 1 }
>

できた。雰囲気としてactionぽいものを渡しているけど、reducerで利用していないので、空のオブジェクトでも呼び出せる。

> myCombination({ hoge: 1}, {})
{ hoge: 1 }

以上で、combineReducersがほんとにただ複数のreducerをまとめるだけの普通のヘルパー関数であることがわかった。よかった。