古いブックマークを漁っていたら、オブジェクト指向と関数型の違いに関する面白い記事を見つけた。
- Object oriented vs. functional programming
記事は Michael Feathers 氏の興味深いツイートから始まる。
- 試訳
- オブジェクト指向は、可変部分をカプセル化(隠蔽)することによって、コードを分かりやすくする
- 関数型は、可変部分を最小化することによって、コードを分かりやすくする
筆者なりに解釈すれば、オブジェクト指向はインターフェースにフォーカスし、可変部分を捨象することによって複雑なシステムを単純化し、関数型は副作用のない関数を組み合わせることによってシステムの可変部分を最小限に保ち、システムの動的な性質を掴みやすくしようとする。
オブジェクト指向の「可変部分を捨象する」という考え方がシステムを単純化する一方、インターフェースの裏側で起こることは予測し辛くなる。インターフェースの「契約」に現れない状態変化、極端な例を挙げれば「重要なデータを削除しないこと」など、それら全てについて自動テストを用意するのは現実的ではないため、オブジェクト指向のシステムが提供出来る信頼性には自ずと限界があることになる。
そして興味深いのは、オブジェクト指向の上に関数型の仕組みを乗っけるのは止めた方が良いという主張だ。この記事を書いた John D. Cook 氏は、関数型のメリットを享受したいのなら、まずは関数型だけに集中し、プログラムの大きなパーツ(モジュールなど)を管理する時にオブジェクト指向的な枠組みを利用すれば良いのではないかと書く(「functional in the small, OO in the large」)。
コードの中に、関数型の部分とそうでない部分が混在してしまうと、全体としては関数型の恩恵を受け辛くなるのだろう。この話題はこれからもちょくちょく出てくると思うが、Scala と Elixir の比較という観点からも興味深い指摘である。Scalaは基本的にオブジェクトから出発して関数型の流儀を徐々に入れて行くの対し、Elixirはまず関数型から出発する。そして、そこから関数をグルーピングするための Module や、Moduleにインターフェースの仕組みを導入するための Behaviour、そしてポリモルフィズム(多態)のような仕組みを実現する Protocol などが出てくる。
James Hague 氏は、100%純粋な関数型を実現するのは非現実的であり、大体85%ぐらいを目指せばいいのではないかと主張する。そして、残りの15%は注意深く分離してコードの中に分散しないようにすべきであると。
副作用がある部分を切り離すデザインは、Phoenix Frameworkで採用されているデータアクセスのフレームワーク、Ectoの中にも見られた。Ectoでは副作用のない Model と、副作用を担当する Repository を分けるという、いわゆる Repositoryパターンが採用されている。Railsの Active Record が Model 自身に副作用を内包するのとは対照的である。