💣Webフロントエンドにおける関数型「風」プログラミングに関する個人的まとめ

# ここ数年の流れについて
## 技術的側面
- Webフロントエンド（ほぼTypeScript＆React界隈）において、オブジェクト指向（厳密に言うと**クラスの利用**）から脱却する流れがあります。原因は以下の2点。
    - **クラスの継承の問題点が（IT業界全体に）広く定着したこと**
    - JS/TSの進化、Reactの進化、関数型言語の考え方などの影響により、**クラスを用いてデータと関数群を紐づけるメリットが薄くなった**こと
- 現状、設計レベル（実務的にはどの関数を纏めてモジュール化するのか、モジュール同士をどう繋ぎ合わせるのか、フォルダ割りどうするのか等）のノウハウがまだ固まっておらず、既存の設計論はそれなりに有効です。

## コミュニティ的側面（政治）
- これらの流れは**Webフロントエンドの中でもTypeScript＆Reactの界隈が主導しており、そのノウハウは長年絶対視されてきたオブジェクト指向を解体するような内容であったため、それ以外の界隈、特にバリバリにオブジェクト指向やっている人々と度々諍いになってきました。** フロントエンド以外の人が多いですが、フロントエンドでもこの組み合わせでやってる人はまだまだ少なく、採用していても距離を置かれていたりします。
- また**本家の関数型言語界隈とも距離があり**、「本格的に関数型やるには機能は足りてないわ文法も違うわで、ウチらと一緒にしないでほしい。~~TSなんて半端なのは捨てて[Elm](https://guide.elm-lang.jp)や[PureScript](https://www.purescript.org)やろうぜ💪（勧誘）~~」というような声も聞きます。後に述べますが、心情として理解はできるので、この記事のタイトルが関数型「風」になっているのはそこへの配慮です。
- このような経緯があり、Qiita、Zennですら中々記事が出ず、非公式ながら有名な[TypeScriptのドキュメント](https://future-architect.github.io/typescript-guide/functional.html)や有識者の各種ブログ等でも「最近は関数型が流行ってるんですよ～」と仄めかされるに留まっています。初心者向け記事はおろか交流なども少なく、やってる人も権威や集合知による裏付けがないので曖昧な記述になりがちです。

# 記事を書いた動機
**いや、この風潮いかんでしょ。😫** 記事が出ない理由は

- （上で説明したような）諍いを見て配慮している
- そもそも発展途上あるいは現在進行形のムーブメントであり、ノウハウが確立してないし模索中

につきると思うんですが、だからこそ委縮して[象牙の塔](https://ja.wikipedia.org/wiki/%E8%B1%A1%E7%89%99%E3%81%AE%E5%A1%94)化するのは良くないと感じます。誰も説明しないけど知ってて当然なんてのは、新規参入者が空気を読むのに苦労しますしね……。
また自分は雑魚エンジニアなんですが、この辺りの流れと行く末にかなり関心があります。しかし2021年はあんまり上の人からの情報発信を見つけられず、情報収集に困っているので、自分なりにまとめることにしました。

# 全体像
このムーブメントを理解するにあたって重要なキーワードは

- 固定データ（=イミュータブルなデータ）/変化するデータ（=状態/State）
- 純粋な関数/副作用のある関数

です。これらを徹底的に**分割**し、管理しやすくするというのが大枠の考え方となります。つまり**MVCで言うところのModelの細分化**です。木構造にするとこんな感じですね。

- Model
    - データ
        - 固定データ（=イミュータブルなデータ）
        - 変化するデータ（=状態/State）
    - ロジック
        - 純粋な関数
        - 副作用のある関数

あくまでコーディングする意識の上の話であり、フォルダ構成とはまた別です。ただポートフォリオとか小さなプロダクトだとmodelとかserviceとか作って全部突っ込む所からスタートしてもいいかもしれませんが。
データとロジックの分離は、現在主流のクラスを使ったオブジェクト指向では禁忌とされています。**しかし無視してください。** 外部ライブラリがクラスベースじゃない限り、理論上、クラスを使う必要はありません。 代わりに**膨大な数の型(type)と、関数とデータでプログラムを制御します。** 

また状態管理（と単方向データフローを用いたコンポーネントへの反映）について、関数型云々というよりかは、Webフロントエンド含むGUIプログラム特有の関心事という感じですが、それゆえに今ホット🔥な開発分野の一つで色んなライブラリがあります。これに関しては[uhyoさんによるまとめ記事](https://blog.uhy.ooo/entry/2021-07-24/react-state-management/)が素晴らしいのでご覧ください。Reactを使ってなくても、大いに学び考えさせられる部分はあるかと。

Mについてばかり書きましたが、Vに関してはコンポーネント志向で安定してるんで、componentsフォルダの中にコンポーネントごとのtsx/jsxファイルを入れ子していく感じになります。どの粒度で1ファイルにするかはAtomic Designの考え方が参考になるかと思います。雑すぎる説明ですいません。

# 関数型風への近づき方
参考になるか分かりませんが自分の変遷を置いておきます。

## 1.コレクション（≒配列）操作において高階関数系メソッド（.map/.foreach系）に親しむ
ごめんなさい、これ系メソッドって何て呼べばいいのか未だに分からんので分かり辛い書き方になっています。
さて、理論的なことはさておき、JSerのみならず多くの人が純粋な関数の有用性を肌で理解したのってこれじゃないでしょうか。別にフロントエンドに限った話でもなく大半の言語で実装されているし、初歩すぎる感もあるのですが、世の中には[foreach系関数はあるけど、地道にfor-each構文でやった方がいい有名言語](https://qiita.com/rana_kualu/items/0abd2b6f69527b0b4b92#%E9%96%A2%E6%95%B0%E5%9E%8B%E9%96%A2%E6%95%B0)もあるので……。
特にプログラム初心者の人は感覚に慣れてもらいたいですね。mapやfilterなどを純粋な関数でチェーンして（必要があれば）トドメにforEachで副作用！美しい✨ 

## 2.クラスにおいても純粋なメソッドと副作用のあるメソッドに分けようとする
さて純粋な関数と副作用のある関数にきっちり分ける感覚が身に付いた頃、**これは普遍性あるなぁ、クラスのメソッド作る時も分けていくべきだなぁ**と考え、オブジェクト指向を守りながら純粋なメソッドと副作用のあるメソッドに切り分けようとしました。
しかし切り分けている最中にある疑問が湧いてきました。

**純粋なメソッドってプロパティを一切参照せず、全部引数でパラメータを注入してるからクラスに属してる意味がないじゃん。関数でよくない？**

値が外から入ってきて別の値が外に出て行くフローになるので純粋なメソッドが顕著ですが、副作用ありのメソッドにしてもプロパティを一切参照しなくなるので、クラスで括る意味合いが薄いですね。

## 3.関数にしようとするも、まとめるためユーティリティクラス化
さて関数にしようと思ったものの、現実には以下のような流れになるかと。

1. 純粋関数を抽出して並べだす
2. ただの関数だと数が多すぎて管理しきれない
3. それじゃオブジェクト指向じゃ悪手とされるけど、ユーティリティクラス化するか。インスタンス化する意味ないしstaticで。組み込みでもMathクラスとかあるし純粋関数の塊ならそこまで問題ならんやろ……
4. ずるずると副作用ありの関数もユーティリティクラス化

オブジェクト指向を齧ってると特にこうなりがちかなと。自分も最初の頃やってました。😅 TypeScriptで言うと ```public static readonly``` メソッドの山みたいなw 
2017～2018年頃だったか、staticおじさん絡みのコメントでJSer（死語）と思しき人の微妙な再評価とか微妙な擁護コメントを見かけたことがあるのですが、おそらくこの段階の人です。
他言語だと仕様の関係でここまでしか無理な場合もあるかもしれません……が、 **今のJavaScriptはもう一歩先に行けます。**
かつての自分含む、この段階の人向けに、[mizchiさんの記事](https://mizchi.hatenablog.com/entry/2018/07/31/124354)よりこの一文を引用します。

> また、名前空間がほしいだけのクラスも不要です。

😲

## 4.関数のモジュール化
そう、関数の大群を管理する上で本当に欲しいのは名前空間だったんです。```export class```ばっか使っててすっかり忘れてたんですが、JavaScriptでは

```ts
//関数のみのモジュール(module.js)
export const getHoge = () => "hoge"
```

```ts
//使う側
import { getHoge } from "./module"
const hoge = getHoge()
```

みたいな形でも使えるんですよ。今TypeScript&Reactをやりだしたら当たり前かもしれませんが、ずっとclass使ってたら変数や関数もexportできることを忘れますよw
ここらのモジュール化をどう行うか（＝大量の関数群をどう纏めるか）という部分においては現在の課題であり、旧来の設計論も多少は生きるのかなという感があります。

## 5.ノウハウ無き荒野で改善のために模索する
すいませんが、僕自身がここで止まってるので具体的に紹介できるのはここまでです。この先の段階まで行ってる記事となると一気に減るので、**おそらく関数型風のユーザーのボリュームゾーンもここ** だと考えていますが。
でもこの段階だと **「イミュータブルと関数の区別（純粋か否か）にとことん拘った手続き式プログラミング」** と呼べなくもないじゃないですか。😅 これでは関数型界隈から「一緒にするな」と言われても仕方がないなという気持ちはあります。なので「風」をつけています。

さて、ここから先は、上の人達の動向を見る限り、

- 状態管理ライブラリを試す
- 現状のTSだとイミュータブル化が不完全になりやすいので、部分的にクラス使う（？） or [immer.js](https://github.com/immerjs/immer)/[Immutable.js](https://immutable-js.com/)を導入する。（違いについては[uhyoさんの比較記事](https://zenn.dev/uhyo/articles/immutable-immer)を参照のこと）
- 関数合成（カリー化）を駆使しだす
- [fp-ts](https://gcanti.github.io/fp-ts/)を導入する

あたりが次のステップとなるっぽい印象を受けています。まぁ最初の2つは関数型云々ともちょっとズレる課題になりますが。

この中で言うと、関数合成（カリー化）も2015年あたり（？）にちょっと流行って記事はそこそこあるんですが、僕自身は使いどころが分からない＆現在の文法だと括弧のネストになりすぎて可読性が落ちるとかあって、普通にimportした関数をラップしてexportしてる感じです。最近では[JavaScriptにパイプラインがやってくる](https://www.kabuku.co.jp/developers/pipe-operator-debate)という話が出てきて、もし導入されたらこのあたりの風潮もかなり動きそうですね。

# 課題と疑問
## 1.クラスの使いどころについて（イミュータブル化の現状について）
いきなりJavaScript初心者向けの説明になりますが、constでもオブジェクトの値の変更は可能です。
```ts
const healthState = { isHealthy:true }
state.isHealthy = false
console.log(state.isHealthy) // false
```
全然イミュータブルじゃありません。これを防ぐためにTSにも[as const](https://typescriptbook.jp/reference/values-types-variables/const-assertion)とか[readonly](https://typescript-jp.gitbook.io/deep-dive/type-system/readonly)とか[Readonly\<T\>](https://www.typescriptlang.org/docs/handbook/utility-types.html#readonlytype)とか色々機能が搭載されているんですが、どうしても面倒だったり入れ忘れたりで不完全になりがちです。 **「eslintのルールで、constで割り当てたオブジェクトやクラスインスタンス、配列を自動的にディープReadonlyやらas const扱いするやつできないかなぁ」** とかボヤいてるぐらいには認識してます😅
つい最近、この記事で書かれているような思想を試したものと思われる、[クラスを使わないアプリを実際に作ってみた気付き](https://snamiki1212.com/no-class-application)という記事を見つけて、「言うてることは分かるし、やっぱimmer入れてるなぁ」と感じました。
これでも個人開発とか、空気の読めてるメンバーだけなら全然回せるんでしょうが、やはり限界があるんだろうなというのは感じてて、getterを駆使してイミュータブルなデータ型を作るためだったらクラスの利用もアリとは思います。

## 2.型と関数モジュールの命名
型名に関しては、理解しやすくするためにこまめに命名したい方なんですが、そういう理解のための便宜上の型って抽象的すぎて名前のつけようがないケースが多くて命名に困りますね。あと関数の引数のデータ型とかは「返り値を出すために必要なパラメータ群」以上の意味合いがないパターンがあるのでこれも困ってます。
関数モジュール名に関してはホント単純な話で、[既存のクラス命名規則](https://qiita.com/KeithYokoma/items/ee21fec6a3ebb5d1e9a8)から借用したりしてるんですけど、「クラスっぽい名前なのに中見たらただの関数の塊だったら嫌かな～」と気にしちゃってるというだけですw

## 3.膨大な数のtypeと関数をどうモジュール化するか（ファイルで纏めるか）、どうディレクトリ分けするか
これも悩みどころですね。特にtypeの管理が深刻で、

- まとめ方（置き場所）
    - 関連する関数モジュールに一緒に置く
    - typeだけ纏めたType.tsを作る
- exportの仕方
    - 型ごとexport
    - 型はexportせず、関数の入出力の型として```Parameters<type>,ReturnType<type>```で間接的に取得する

色々試したんですが、微妙に一長一短あります。
かなり意見割れるかもしれませんが、まずexportの仕方に関しては関数の公開インターフェースという考え方を重視して、堂々と型名つけて型ごとexportしちゃってもいいと思います。
置き場所については、主流は関連する関数モジュールに一緒に置く形かなと思うんですが、個人的には一つのデータ型に関連する関数が一つとは限らずモジュールを跨ぐことも頻繁にあるので、typeだけのファイルとして切り出すのが妥当かなと思っています。単に自分のデータや関数の設計が良くない可能性も十分ありますが……。
ただドメインとしてのデータ型と、関数のインターフェースとかのある種便宜上のデータ型があって、少なくとも前者は直接利用する関数がなかろうが単独で存在しうるので、どこかの関数モジュールに添え物として型定義を置くのはそぐわないだろうという気もしていて。とはいえ両者の境界は曖昧な気も……🤔

type周りについて長々と書きましたが、どう関数をモジュール分けするかとか、フォルダ分けどうするか等も自分の中で曖昧なんですよね。Zennの「○○使って△△作りました」系記事にディレクトリ構成図を載せてくれる方も多いので、そこらへん参考にして、何とかやりくりしてます。

## 4.（ロジックとデータの分離について）ドメインモデル貧血症ではないかという批判について
自分はバックエンドも多少触ってるんでDDDは気になりつつ勉強してないんですが（怠慢）、ドメインモデル貧血症に関しては記事が多くてよく目にします。それで「フロントとバックの違いはあれど、ここまで言い切ってるし、バックのコミュニティでは支持もされてるのにロジックとデータを分離しちゃっていいのかな……」と結構悩んでます。
ただドメインモデル貧血症という言葉を作ったMartin Fowler本人による[記事](https://bliki-ja.github.io/AnemicDomainModel/)を見て、オブジェクト指向が根本になってるので、その根本自体が解体されつつあるフロントに関してはとりあえず棚上げにしてていいのかなと。
またフロントとバックの違いということで片づけてもいいんですけど、個人的にはnode.jsバックエンド（というかTSバックエンド）がもうちょい普及すると思ってるので、あんまり無視したくないんですよね。この先、**フロントからキャリアを始めた人間がどんどんバックにも進出して、文化的衝突が起きると思いますし。**
node.jsおよび関数型言語でバックエンドやってる人達って、このあたりモロに直撃してると思うんですが、どう折り合いつけてるんだろ……。

あと若干話題が変わりますが、関数型言語+DDDについて書かれた「[Domain Modeling Made Functional](https://www.amazon.co.jp/Domain-Modeling-Made-Functional-Domain-Driven/dp/1680502549)」って英書があるらしくて、評判もいいので、ここへのアンサーが載ってるのか気になってます。まぁDDDを勉強してから……（やらないパターン）

# 参考
- [オブジェクト指向の呪いと、その避け方 - mizchi's blog](https://mizchi.hatenablog.com/entry/2018/07/31/124354)
- [現代のオブジェクト指向の class の割れ窓化と宣言的プログラミング](https://zenn.dev/mizchi/articles/oop-think-modern)
- [オブジェクト指向には、カメラがやっとついたころのガラケーのイメージがある - きしだのHatena](https://nowokay.hatenablog.com/entry/2021/01/21/004148)
- [不要なクラス宣言、やめちゃおっか？ - タオルケット体操](https://hachibeechan.hateblo.jp/entry/you-might-not-want-to-declare-classes)
- [Elixir試飲録 (4) – オブジェクト指向と関数型の違い](https://ubiteku.oinker.me/2016/01/14/elixir%E8%A9%A6%E9%A3%B2%E9%8C%B2-4-%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%81%A8%E9%96%A2%E6%95%B0%E5%9E%8B%E3%81%AE%E9%81%95%E3%81%84/)
- [クラスを使わないアプリを実際に作ってみた気付き](https://snamiki1212.com/no-class-application)
- [私家版 TypeScript 抽象データ型表現](https://blog.outer-inside.net/2020/03/typescript.html)
- [イミュータブルについて（副作用） - やってみる](https://ytyaru.hatenablog.com/entry/2020/08/04/000000)
- [関数型はプログラミングスタイル](https://zenn.dev/j5ik2o/articles/97b458eff8283c783d9b)