コードの書き方について最近感じていること（雑文）

## コードの書き方について最近感じていること雑文
3年半ほどWebエンジニアをやって、コードの書き方について勉強してきました。良いコードなるものについて世の中では様々な方が様々なことを書いていて、僕はよく混乱してきました。まだ混乱していますが、なるべく自分が理解できる等身大の言葉に置き換えて、かつての自分が読みたかったような文章を年末で時間もあるので残したいと思います。思いついた順に書いているので順番や粒度がおかしい点はご了承ください。rubyとTypeScriptに強く影響を受けています。また、できれば各項目について具体例を書ければと思っています。具体例を優先的に読みたい項目があればコメントお願いします。

## 目次
1. 純粋性が高いコードを増やす
2. 宣言的、手続き的というワード
3. 紛らわしい用語
4. MVCアーキテクチャはPDCAフレームワークのようなもの
5. アーキテクチャとは
6. APIサーバとSPAの関係で大体のアーキテクチャは理解できる
7. オブジェクト指向と関数型指向

## 感じたこと
### 1. 純粋性が高いコードを増やす
純粋性が高いコードを増やす。これはつまり、副作用がある関数は意図された副作用だけ、純粋な関数は純粋なことだけをする（両者を分離する）ということである（副作用のあるコードは、アプリの機能が同じなら同じ副作用を発生させなければならない以上、減らしようがない）。
例えばJSで何も考えないで作ると一般に副作用とデータの操作は渾然一体となりがちだが、なるべく純粋性が高い関数やオブジェクトで構成されたコード領域を分離して増やしていくのが良いとされていると思う。バリューオブジェクト、厳密な純粋関数、DIなどを利用すると実現しやすい。確かにこうすると特に単体テストによりテスト済みコード率を簡単に増やすことができる。
ここでいう純粋性とは、副作用が一切ないという厳密な意味の純粋ではなく、「データがなるべくイミュータブル」「副作用を実行する関数やオブジェクトはDIで渡される」など純粋要件を満たしていればいるほど純粋性が高いと考える。たとえばrepository(DBアクセス用オブジェクト）をDIされて、それを実行するとDBに接続する副作用がある関数が純粋かどうかを考えてみる。すると、副作用があるのでその意味では純粋ではないが、引数によって全ての動作が決定しているので純粋性はDIを経由しないものよりは高い、といったような考え方がちょうど良いように思う。
ちなみに、なぜ単体テストがされていると良いかというと、自動車のように、まず部品ごとに十分に性能をチェックして、あとはそれらテスト済みのパーツを組み合わせれば全体としてのテストは全体として動かしたとき固有のエラーのみ現れるので、テストの手間が全体として小さくなるからだという考え方があるからだと思う。ただ経験上のデメリットとして、純粋性が高い方がコードを書く量が多くなってしまうので、小さなアプリでテストも最小限にとりあえず動くことを目指している場合は意識的に純粋性の低いコードを書くのも良いと思う。

### 2. 宣言的、手続き的というワード
まず、手続き的と宣言的という対立要素があり、これは相対的に大きい、小さいといった意味であって絶対的に手続き的な言語やツールも絶対的に宣言的な言語やツールもない。そして宣言的であるとは「より指示の粒度が粗くて済む」「より最終的な結果の指示だけで済む」、手続き的とは「より指示の粒度を細かくしないといけない」「より結果に至る手順を説明しないといけない」と読み替えて概ね問題ない。それぞれメリットもデメリットもある。宣言的なツールや言語は楽で良いが、やり方を細かく指示したかったり結果に対して細かく指示をしたい場合、むしろ手続き的にやるより手間である。逆に手続き的なツールや言語は細かく指示をしないと大きな成果を出しづらいが、細かく指示するためのツールは宣言的なツールより揃っているので、細かい指示が必要な場合はより快適に操作できる。要はオートマ車vsマニュアル車、あるいはショベルカーvsスコップである。また、見てわかる通りオブジェクト指向vs関数指向と宣言的vs手続き的は直接的には関係ないと思う。

### 3. 紛らわしい用語
#### モジュール、コンポーネント、パッケージ、ライブラリ
ニュアンスの違いはあるが基本的に区別しなくて良い。1つの文脈で同じ概念に同じ名前を一貫して付けられていれば良い。

#### 関数、メソッド
オブジェクトやクラスに定義されていればメソッド、それだけで存在していれば関数。関数の挙動は引数だけによって決まるが、メソッドの挙動は引数とオブジェクトのステートによって決まる。ただ、たとえばブラウザJavaScriptにおいてwindowオブジェクトのメソッドを関数と呼んだりするので要注意だが、そもそもメソッドと関数は違いが大事なとき以外はあまり拘らなくて良いと思う。また、メソッドが生えているオブジェクトをオブジェクト指向業界用語でレシーバ(receiver)ともいう。メソッド呼び出し=そのオブジェクトに対するメッセージ送信であり、メッセージを受け取ったのがそのオブジェクトだからである。

#### （継承より委譲というフレーズにおける）継承、委譲
この違いを考えると実質的に、継承は親クラスをハードコードすることで、委譲は親クラスを変数にすること。親クラスとの差分が子クラスの定義にあるわけだけど、子クラスとして表現したい内容が必ずしも特定の親クラスを前提としない場合がある。親クラスを動的に選べた方が子クラスの汎用性が上がるので、親クラスを変更できるようにするべきときに継承より委譲というフレーズが使われる。その子クラスがその親クラス以外を親クラスとして選ぶ必要がない場合は、（簡潔にするために）継承を使えばいいし、動的に決めたければ委譲すれば良い。

### 4. MVCアーキテクチャはPDCAフレームワークのようなもの
ソースコードのアーキテクチャとは、どういった概念で分割してコードを書いていくかという程度の話。レイヤーとしては、ソースコードにおけるMVCアーキテクチャはビジネスにおけるPDCAフレームワークのようなもの。ビジネスにおいてPDCAとは、などといったことを深掘ってもある程度は意味があるがそこから先は意味がないのと同じように、あまり深堀りしても得るものはなく、その場その場で意思疎通のためのちょっとした補助具にすれば良いと思う。

### 5. アーキテクチャとは
プログラムを書いていくにあたり、そこに書かれるコードはいろいろな概念で分類することができるが、様々な概念の中のどの概念でソースコードを分割するか、あるいは分割しないか、という分割のしかたがアーキテクチャである。分割の目的はひとえに、巨大なコードを一度に理解できない人類が共同でコードベースを育てていくために、メンテナンス性と生産性を高めることである。
例えばWebアプリでのMVCにおける概念分割としては、まずは「M:DB接続やロジックを扱う部分, V:データの表示に関わる部分, C:MとVを繋ぐ部分」といったような概念分割から始まる。最初はそれで良いが、段々とこれらの概念に収まらないコードができてきたり、Mが肥大化したりしてもっと細かい概念で分割する必要が出てくる。あくまで各概念で分割したコードがメンテナンス性と生産性が維持できる適正サイズであれば良いので、小さなアプリなら最初から1つの概念で済ませてもいいし、逆に大きくなってきたら10個程度の概念で切り分けてより理解しやすくすれば良い。もちろん、3個の大概念と、各々の中に3つの小概念を入れても良い。結局、とあるコードがどこにあるかを探す時間・とあるコードをどこに書くべきかを考える時間が少なくなれば何でも良いと思う。

### 6. APIサーバとSPAの関係でアーキテクチャの基礎が理解できる
よくあるAPIサーバ(REST想定）とブラウザJS（クライアント）の関係を理解すると、他のアーキテクチャを理解しやすい。他のアーキテクチャも大体APIサーバとブラウザJS（クライアント）の関係と性質がとても似ているからである。APIサーバは抽象的なインターフェースと裏側のデータの取得や更新のAPIを提供し、内部的な計算ロジックやそのままのDBデータは隠蔽して表に出さない。この関係はなにも物理的に離れたブラウザとAPIサーバという関係のみならず、APIサーバの同じコードベースの中にも現れるし、この考え方で色々整理できる。
例えばDBアクセス層は、DBの詳細を隠蔽するAPIサーバと考えられる。DBの操作においては本来好きなSQLをアプリサーバの好きな場所からその場その場で文字列として組み上げてDBに対してリクエストすれば良い。が、文字列としてのSQLなどというあまりに細かな粒度で調整可能なAPIをアプリのあちこちから好きに投げられてしまうと自由度が高すぎて、利用者および提供者双方に不満が出る。そこで、DBの利用者（この場合、同じアプリのDB接続以外のコード部分）側に限られたAPIのみを関数として提供しようという試みがなされることがあり、そうして提供されるAPIを定義するファイルをDBアクセス層と表現することがある。
また、あるいは時刻層というものものも考えられる。たとえば、時刻に関するロジックやAPIは全てそこのレイヤーから提供される関数やクラスのみに定義するのである。この場合、例えば時刻に関するライブラリを利用するのはそのレイヤ内部のみということにすれば、例えばそのライブラリをJSの場合だとmoment.jsという古いライブラリからdate-fnsという新しいライブラリに置き換えることも容易（理論上、時刻層以外のファイルを開く必要すらない）だし、現在時刻をモックするのも時刻層から提供されている現在時刻を取得する関数だけモックすれば、アプリ全体において現在時刻を切り替えることができる（テストの時に有効。将来の時刻になったとき規定の動作をするかをあらかじめ確認したい場合がある）。これも、時刻に関する情報を提供するAPIサーバと、そのクライアントの関係と似ている。

### 7. オブジェクト指向と関数型指向
オブジェクト指向と関数型指向は、僕の理解では要はプログラムを作るにあたって「クラスやオブジェクトを基本パーツとして作っていく」か、「関数を基本パーツとして作っていくか」というプログラミングに対するメンタルモデルの違いであり、言語により規定されるものではない。それぞれの考え方にはそれぞれの専門用語や価値観が定まっており、それらについて既に了解があるので理解している人同士なら簡単に意思疎通ができる。
たとえば、オブジェクト指向なら「オブジェクトなるミニマシーンがあり、それらが責務をもち、その責務により定められるステートとメソッド（ステートにより振る舞いが異なる）を持ち、それらオブジェクト同士がメッセージをやりとりすることによりプログラムは動作する」、関数型指向なら「まず無数の小さく純粋な関数があり、これらを合成することにより大きくて複雑な関数を生成することができる。関数には引数を部分適用したり合成したりといった操作ができ、これらを駆使してデータを加工する大きな純粋な関数を作っていく」といったような全く異なるプログラム構築における考え方があり、これらの違いによりコーディングスタイルなどの価値観が定まっていく。
詳しく知りたければ（自分もまだまだかじり中だが）PureScriptやHaskellなどの純粋関数型言語の言語が実装している言語仕様について勉強するしかないと思う。それらの性質を学び、そういった性質1つ1つがあればあるほど関数型っぽいと感じるようになるのだと予想している。