現実的なオブジェクト指向でツラいところ

cassetteの延澤です。
最近、Elixirにハマっている。モダンな言語らしく痒いところに手が届く良い言語だなと感じる。個人としては今まで色々な言語で書いてきて得意な言語はあるけど、好きな言語というのはなかったので良かった。関数型だがモナドを用いないやり方で副作用に対してアプローチしていくというのはすごく面白かった。で、興奮冷めないうちにオブジェクト指向と関数型について比較した内容を書く。Elixirについては書かないw

オブジェクト指向で書くということ

オブジェクト指向で書くことの問題の一つとして状態を持つことが挙げられる。例えば、Aというオブジェクトのaメソッドの中でB, Cのオブジェクトのメソッドが呼ばれていた。A, B, Cというオブジェクトはそれぞれ3つの状態があったとする。すると、aメソッドをUnitテストする場合、3 × 3 × 3の状態の組み合わせになり27パターンのテストをしなければいけなくなる。実際には27パターンの中でもあり得ない組み合わせなどがありもっと少ないが、その見極めをしなければいけない。いや、mockやstubを使えばもっと効率的に出来るという指摘もあるがそれを使うかどうかはまた別の話だ。

状態を上手く管理したいのであれば疎結合に作りカプセル化することである。その上でテストしやすくすることが求められるだろう。その実現としてDIコンテナ・デザインパターンも使用して高いレベルのクラス設計することが重要になっている。事実、オブジェクト指向を前提とした設計を扱う書籍はかなり多い。

オブジェクト指向で書く現実問題

私が考える問題は以下である。

  1. 状態の準備
  2. クラス設計の高いレベル
  3. Web業界の事情

状態の準備

Unitテストを実行する前に多大な準備が必要なケースが多い。上記で書いたようにオブジェクトの状態が特定の状態でないと正しく動かないケース。小さいアプリケーションではそこまで問題ではないが複雑で規模の大きいアプリケーションになると大きな負担となってくる。また、膨大に準備することはテスト実行時間にも影響が出て来る。

クラス設計の高いレベル

状態の準備が大きく必要だが疎結合で作られていないことが多い。そのため、適切な設計をすることが重要になってくる。私も過去に概念分析・UML作成・クラス設計をしてきちんとやった経験もある。そこで感じたのはやっぱり辛いなということだ。そもそも概念分析の必要性やクラス設計の意図を伝えることが大変だった。前提知識が違うため何でそういう意図の設計なのかを伝えるのに時間がかかる。メンバーからすればそこまで複雑な設計にしないといけないのという疑問もあったと思う。また関連する資料も作成したりするのでコストが高かった。正直、設計についてはそこまで辛くないが人に正しく伝えるというところが何だかんだ一番大変。

Web業界の事情

Webのサービスのシステムに本当に高いレベルの設計が必要かどうかが分からない。 それによってどういう影響があるかというと、Webでは設計期間をあまり取らずプログラミング主体なことが多い。設計が弱いため時間が立つと技術負債に陥りやすい。何が言いたいかと言うとオブジェクト指向で複雑な要件をシステムに落とし込むには高度な設計が必要なのに現実は出来ていない。
そのため、3〜4年経ったスタートアップでは技術負債により開発スピードが途端に落ちるケースが多い(この技術負債をどう返したかという記事はよく見かける)。現実問題としてはシステムを一からリライトは難しいのでマイクロサービス化に取り組むことが多い。。

関数型のメリット

上記のことを全て解決してくれる銀の弾丸ではないが関数型を用いることによって参照透過性は得ることが出来る。まあ検索すれば沢山オブジェクト指向と比較した記事があるのでわざわざ言及はしない。主張したいことは設計のテクニックで複雑性を解決するのではなく、言語の機能で解決する方がスマートではないのかということ。

で?関数型言語は普及するの?

しないと思う。明らかに現金よりキャッシュレスでのお会計の方がメリットあるのに中々普及しないのと同じ理由である。ライブラリが少ないなどの問題もあるかもしれないが、人々の意識の方がより根深い問題だと思う。それに、関数型を使える経済的メリットが少ない。関数型言語を使えることで大幅に年収がアップするなら勉強する人も多くなるがそういうわけでもないし全ての問題を解決してくれるわけでもない。

それでも普及させるには

社会全体に普及させるのは困難である。しかし、技術選定として関数型言語オンリーにするアプローチがある。よくサービスによってオブジェクト指向の言語と関数型言語のアプリケーションが混在していることがある。しかしこれだとリソースの効率性から人員をオブジェクト指向と関数型で分業してしまうことがある。大企業であれば別だがスタートアップでは分業はデメリットが大きい。しかも、採用面でも募集がやりにくい。
だから、システム要件に合わせるのではなく本当にやりたいのであれば関数型言語に統一した方が良い。私はサービスが成功するかどうかは技術アーキテクチャと関係ないと感じる。成功するサービスはPHPだろうがJavaだろうが成功する。つまり、Scalaを使おうがElixirを使おうが成功するサービスは成功する。 RubyPHPなどは扱える人が多く募集しやすいが、反面転職されやすい言語とも言える。そう考えると関数型にオンリーとするのはそこまで悪い選択肢ではない。