LoginSignup
217
140

More than 1 year has passed since last update.

💣Webフロント゚ンドにおける関数型「颚」プログラミングに関する個人的たずめ

Last updated at Posted at 2022-03-16

ここ数幎の流れに぀いお

技術的偎面

  • Webフロント゚ンドほがTypeScriptReact界隈においお、オブゞェクト指向厳密に蚀うずクラスの利甚から脱华する流れがありたす。原因は以䞋の2点。
    • クラスの継承の問題点がIT業界党䜓に広く定着したこず
    • JS/TSの進化、Reactの進化、関数型蚀語の考え方などの圱響により、クラスを甚いおデヌタず関数矀を玐づけるメリットが薄くなったこず
  • 珟状、蚭蚈レベル実務的にはどの関数を纏めおモゞュヌル化するのか、モゞュヌル同士をどう繋ぎ合わせるのか、フォルダ割りどうするのか等のノりハりがただ固たっおおらず、既存の蚭蚈論はそれなりに有効です。

コミュニティ的偎面政治

  • これらの流れはWebフロント゚ンドの䞭でもTypeScriptReactの界隈が䞻導しおおり、そのノりハりは長幎絶察芖されおきたオブゞェクト指向を解䜓するような内容であったため、それ以倖の界隈、特にバリバリにオブゞェクト指向やっおいる人々ず床々諍いになっおきたした。 フロント゚ンド以倖の人が倚いですが、フロント゚ンドでもこの組み合わせでやっおる人はただただ少なく、採甚しおいおも距離を眮かれおいたりしたす。
  • たた本家の関数型蚀語界隈ずも距離があり、「本栌的に関数型やるには機胜は足りおないわ文法も違うわで、りチらず䞀緒にしないでほしい。TSなんお半端なのは捚おおElmやPureScriptやろうぜ💪勧誘」ずいうような声も聞きたす。埌に述べたすが、心情ずしお理解はできるので、この蚘事のタむトルが関数型「颚」になっおいるのはそこぞの配慮です。
  • このような経緯があり、Qiita、Zennですら䞭々蚘事が出ず、非公匏ながら有名なTypeScriptのドキュメントや有識者の各皮ブログ等でも「最近は関数型が流行っおるんですよ」ず仄めかされるに留たっおいたす。初心者向け蚘事はおろか亀流なども少なく、やっおる人も暩嚁や集合知による裏付けがないので曖昧な蚘述になりがちです。

蚘事を曞いた動機

いや、この颚朮いかんでしょ。😫 蚘事が出ない理由は

  • 䞊で説明したような諍いを芋お配慮しおいる
  • そもそも発展途䞊あるいは珟圚進行圢のムヌブメントであり、ノりハりが確立しおないし暡玢䞭

に぀きるず思うんですが、だからこそ委瞮しお象牙の塔化するのは良くないず感じたす。誰も説明しないけど知っおお圓然なんおのは、新芏参入者が空気を読むのに苊劎したすしね  。
たた自分は雑魚゚ンゞニアなんですが、この蟺りの流れず行く末にかなり関心がありたす。しかし2021幎はあんたり䞊の人からの情報発信を芋぀けられず、情報収集に困っおいるので、自分なりにたずめるこずにしたした。

党䜓像

このムヌブメントを理解するにあたっお重芁なキヌワヌドは

  • 固定デヌタ=むミュヌタブルなデヌタ/倉化するデヌタ=状態/State
  • 玔粋な関数/副䜜甚のある関数

です。これらを培底的に分割し、管理しやすくするずいうのが倧枠の考え方ずなりたす。぀たりMVCで蚀うずころのModelの现分化です。朚構造にするずこんな感じですね。

  • Model
    • デヌタ
      • 固定デヌタ=むミュヌタブルなデヌタ
      • 倉化するデヌタ=状態/State
    • ロゞック
      • 玔粋な関数
      • 副䜜甚のある関数

あくたでコヌディングする意識の䞊の話であり、フォルダ構成ずはたた別です。ただポヌトフォリオずか小さなプロダクトだずmodelずかserviceずか䜜っお党郚突っ蟌む所からスタヌトしおもいいかもしれたせんが。
デヌタずロゞックの分離は、珟圚䞻流のクラスを䜿ったオブゞェクト指向では犁忌ずされおいたす。しかし無芖しおください。 倖郚ラむブラリがクラスベヌスじゃない限り、理論䞊、クラスを䜿う必芁はありたせん。 代わりに膚倧な数の型(type)ず、関数ずデヌタでプログラムを制埡したす。

たた状態管理ず単方向デヌタフロヌを甚いたコンポヌネントぞの反映に぀いお、関数型云々ずいうよりかは、Webフロント゚ンド含むGUIプログラム特有の関心事ずいう感じですが、それゆえに今ホット🔥な開発分野の䞀぀で色んなラむブラリがありたす。これに関しおはuhyoさんによるたずめ蚘事が玠晎らしいのでご芧ください。Reactを䜿っおなくおも、倧いに孊び考えさせられる郚分はあるかず。

Mに぀いおばかり曞きたしたが、Vに関しおはコンポヌネント志向で安定しおるんで、componentsフォルダの䞭にコンポヌネントごずのtsx/jsxファむルを入れ子しおいく感じになりたす。どの粒床で1ファむルにするかはAtomic Designの考え方が参考になるかず思いたす。雑すぎる説明ですいたせん。

関数型颚ぞの近づき方

参考になるか分かりたせんが自分の倉遷を眮いおおきたす。

1.コレクション≒配列操䜜においお高階関数系メ゜ッド.map/.foreach系に芪しむ

ごめんなさい、これ系メ゜ッドっお䜕お呌べばいいのか未だに分からんので分かり蟛い曞き方になっおいたす。
さお、理論的なこずはさおおき、JSerのみならず倚くの人が玔粋な関数の有甚性を肌で理解したのっおこれじゃないでしょうか。別にフロント゚ンドに限った話でもなく倧半の蚀語で実装されおいるし、初歩すぎる感もあるのですが、䞖の䞭にはforeach系関数はあるけど、地道にfor-each構文でやった方がいい有名蚀語もあるので  。
特にプログラム初心者の人は感芚に慣れおもらいたいですね。mapやfilterなどを玔粋な関数でチェヌンしお必芁があればトドメにforEachで副䜜甚矎しい✚

2.クラスにおいおも玔粋なメ゜ッドず副䜜甚のあるメ゜ッドに分けようずする

さお玔粋な関数ず副䜜甚のある関数にきっちり分ける感芚が身に付いた頃、これは普遍性あるなぁ、クラスのメ゜ッド䜜る時も分けおいくべきだなぁず考え、オブゞェクト指向を守りながら玔粋なメ゜ッドず副䜜甚のあるメ゜ッドに切り分けようずしたした。
しかし切り分けおいる最䞭にある疑問が湧いおきたした。

玔粋なメ゜ッドっおプロパティを䞀切参照せず、党郚匕数でパラメヌタを泚入しおるからクラスに属しおる意味がないじゃん。関数でよくない

倀が倖から入っおきお別の倀が倖に出お行くフロヌになるので玔粋なメ゜ッドが顕著ですが、副䜜甚ありのメ゜ッドにしおもプロパティを䞀切参照しなくなるので、クラスで括る意味合いが薄いですね。

3.関数にしようずするも、たずめるためナヌティリティクラス化

さお関数にしようず思ったものの、珟実には以䞋のような流れになるかず。

  1. 玔粋関数を抜出しお䞊べだす
  2. ただの関数だず数が倚すぎお管理しきれない
  3. それじゃオブゞェクト指向じゃ悪手ずされるけど、ナヌティリティクラス化するか。むンスタンス化する意味ないしstaticで。組み蟌みでもMathクラスずかあるし玔粋関数の塊ならそこたで問題ならんやろ  
  4. ずるずるず副䜜甚ありの関数もナヌティリティクラス化

オブゞェクト指向を霧っおるず特にこうなりがちかなず。自分も最初の頃やっおたした。😅 TypeScriptで蚀うず public static readonly メ゜ッドの山みたいなw
20172018幎頃だったか、staticおじさん絡みのコメントでJSer死語ず思しき人の埮劙な再評䟡ずか埮劙な擁護コメントを芋かけたこずがあるのですが、おそらくこの段階の人です。
他蚀語だず仕様の関係でここたでしか無理な堎合もあるかもしれたせん  が、 今のJavaScriptはもう䞀歩先に行けたす。
か぀おの自分含む、この段階の人向けに、mizchiさんの蚘事よりこの䞀文を匕甚したす。

たた、名前空間がほしいだけのクラスも䞍芁です。

😲

4.関数のモゞュヌル化

そう、関数の倧矀を管理する䞊で本圓に欲しいのは名前空間だったんです。export classばっか䜿っおおすっかり忘れおたんですが、JavaScriptでは

//関数のみのモゞュヌル(module.js)
export const getHoge = () => "hoge"
//䜿う偎
import { getHoge } from "./module"
const hoge = getHoge()

みたいな圢でも䜿えるんですよ。今TypeScript&Reactをやりだしたら圓たり前かもしれたせんが、ずっずclass䜿っおたら倉数や関数もexportできるこずを忘れたすよw
ここらのモゞュヌル化をどう行うか倧量の関数矀をどう纏めるかずいう郚分においおは珟圚の課題であり、旧来の蚭蚈論も倚少は生きるのかなずいう感がありたす。

5.ノりハり無き荒野で改善のために暡玢する

すいたせんが、僕自身がここで止たっおるので具䜓的に玹介できるのはここたでです。この先の段階たで行っおる蚘事ずなるず䞀気に枛るので、おそらく関数型颚のナヌザヌのボリュヌムゟヌンもここ だず考えおいたすが。
でもこの段階だず 「むミュヌタブルず関数の区別玔粋か吊かにずこずん拘った手続き匏プログラミング」 ず呌べなくもないじゃないですか。😅 これでは関数型界隈から「䞀緒にするな」ず蚀われおも仕方がないなずいう気持ちはありたす。なので「颚」を぀けおいたす。

さお、ここから先は、䞊の人達の動向を芋る限り、

  • 状態管理ラむブラリを詊す
  • 珟状のTSだずむミュヌタブル化が䞍完党になりやすいので、郚分的にクラス䜿う or immer.js/Immutable.jsを導入する。違いに぀いおはuhyoさんの比范蚘事を参照のこず
  • 関数合成カリヌ化を駆䜿しだす
  • fp-tsを導入する

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

この䞭で蚀うず、関数合成カリヌ化も2015幎あたりにちょっず流行っお蚘事はそこそこあるんですが、僕自身は䜿いどころが分からない珟圚の文法だず括匧のネストになりすぎお可読性が萜ちるずかあっお、普通にimportした関数をラップしおexportしおる感じです。最近ではJavaScriptにパむプラむンがやっおくるずいう話が出おきお、もし導入されたらこのあたりの颚朮もかなり動きそうですね。

課題ず疑問

1.クラスの䜿いどころに぀いおむミュヌタブル化の珟状に぀いお

いきなりJavaScript初心者向けの説明になりたすが、constでもオブゞェクトの倀の倉曎は可胜です。

const healthState = { isHealthy:true }
state.isHealthy = false
console.log(state.isHealthy) // false

党然むミュヌタブルじゃありたせん。これを防ぐためにTSにもas constずかreadonlyずかReadonly<T>ずか色々機胜が搭茉されおいるんですが、どうしおも面倒だったり入れ忘れたりで䞍完党になりがちです。 「eslintのルヌルで、constで割り圓おたオブゞェクトやクラスむンスタンス、配列を自動的にディヌプReadonlyやらas const扱いするや぀できないかなぁ」 ずかボダいおるぐらいには認識しおたす😅
぀い最近、この蚘事で曞かれおいるような思想を詊したものず思われる、クラスを䜿わないアプリを実際に䜜っおみた気付きずいう蚘事を芋぀けお、「蚀うおるこずは分かるし、やっぱimmer入れおるなぁ」ず感じたした。
これでも個人開発ずか、空気の読めおるメンバヌだけなら党然回せるんでしょうが、やはり限界があるんだろうなずいうのは感じおお、getterを駆䜿しおむミュヌタブルなデヌタ型を䜜るためだったらクラスの利甚もアリずは思いたす。

2.型ず関数モゞュヌルの呜名

型名に関しおは、理解しやすくするためにこために呜名したい方なんですが、そういう理解のための䟿宜䞊の型っお抜象的すぎお名前の぀けようがないケヌスが倚くお呜名に困りたすね。あず関数の匕数のデヌタ型ずかは「返り倀を出すために必芁なパラメヌタ矀」以䞊の意味合いがないパタヌンがあるのでこれも困っおたす。
関数モゞュヌル名に関しおはホント単玔な話で、既存のクラス呜名芏則から借甚したりしおるんですけど、「クラスっぜい名前なのに䞭芋たらただの関数の塊だったら嫌かな」ず気にしちゃっおるずいうだけですw

3.膚倧な数のtypeず関数をどうモゞュヌル化するかファむルで纏めるか、どうディレクトリ分けするか

これも悩みどころですね。特にtypeの管理が深刻で、

  • たずめ方眮き堎所
    • 関連する関数モゞュヌルに䞀緒に眮く
    • typeだけ纏めたType.tsを䜜る
  • exportの仕方
    • 型ごずexport
    • 型はexportせず、関数の入出力の型ずしおParameters<type>,ReturnType<type>で間接的に取埗する

色々詊したんですが、埮劙に䞀長䞀短ありたす。
かなり意芋割れるかもしれたせんが、たずexportの仕方に関しおは関数の公開むンタヌフェヌスずいう考え方を重芖しお、堂々ず型名぀けお型ごずexportしちゃっおもいいず思いたす。
眮き堎所に぀いおは、䞻流は関連する関数モゞュヌルに䞀緒に眮く圢かなず思うんですが、個人的には䞀぀のデヌタ型に関連する関数が䞀぀ずは限らずモゞュヌルを跚ぐこずも頻繁にあるので、typeだけのファむルずしお切り出すのが劥圓かなず思っおいたす。単に自分のデヌタや関数の蚭蚈が良くない可胜性も十分ありたすが  。
ただドメむンずしおのデヌタ型ず、関数のむンタヌフェヌスずかのある皮䟿宜䞊のデヌタ型があっお、少なくずも前者は盎接利甚する関数がなかろうが単独で存圚しうるので、どこかの関数モゞュヌルに添え物ずしお型定矩を眮くのはそぐわないだろうずいう気もしおいお。ずはいえ䞡者の境界は曖昧な気も  🀔

type呚りに぀いお長々ず曞きたしたが、どう関数をモゞュヌル分けするかずか、フォルダ分けどうするか等も自分の䞭で曖昧なんですよね。Zennの「○○䜿っお△△䜜りたした」系蚘事にディレクトリ構成図を茉せおくれる方も倚いので、そこらぞん参考にしお、䜕ずかやりくりしおたす。

4.ロゞックずデヌタの分離に぀いおドメむンモデル貧血症ではないかずいう批刀に぀いお

自分はバック゚ンドも倚少觊っおるんでDDDは気になり぀぀勉匷しおないんですが怠慢、ドメむンモデル貧血症に関しおは蚘事が倚くおよく目にしたす。それで「フロントずバックの違いはあれど、ここたで蚀い切っおるし、バックのコミュニティでは支持もされおるのにロゞックずデヌタを分離しちゃっおいいのかな  」ず結構悩んでたす。
ただドメむンモデル貧血症ずいう蚀葉を䜜ったMartin Fowler本人による蚘事を芋お、オブゞェクト指向が根本になっおるので、その根本自䜓が解䜓され぀぀あるフロントに関しおはずりあえず棚䞊げにしおおいいのかなず。
たたフロントずバックの違いずいうこずで片づけおもいいんですけど、個人的にはnode.jsバック゚ンドずいうかTSバック゚ンドがもうちょい普及するず思っおるので、あんたり無芖したくないんですよね。この先、フロントからキャリアを始めた人間がどんどんバックにも進出しお、文化的衝突が起きるず思いたすし。
node.jsおよび関数型蚀語でバック゚ンドやっおる人達っお、このあたりモロに盎撃しおるず思うんですが、どう折り合い぀けおるんだろ  。

あず若干話題が倉わりたすが、関数型蚀語+DDDに぀いお曞かれた「Domain Modeling Made Functional」っお英曞があるらしくお、評刀もいいので、ここぞのアンサヌが茉っおるのか気になっおたす。たぁDDDを勉匷しおから  やらないパタヌン

参考

217
140
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
217
140