ScalaのFunction22問題(またはTuple22問題)について思うこと

Scalaで実際にシステム開発を行う上でかなりの高確率で遭遇するのがFunction22問題(またはTuple22問題)です。Scala Conference in Japan 2013のセッションではScalaの問題点として挙げたのですが、実際はいろいろと思うところもあるので書いておきます。

Function22問題(またはTuple22問題)とは?

Scalaフレームワークではケースクラスへの値のマッピングにタプルを使ったり、値のバインドやアンバインドにapplyメソッドやunapplyメソッドを使うものが多いのですが、Scalaには以下のような制約があるため、22個以上のプロパティを定義することができない、というものです。

  • 22個以上の引数を持つ関数を作ることができない(メソッドとしては定義できますが、変数に代入したり関数渡しをしようとするとコンパイルエラーになります)
  • 要素が22個以上のタプルを生成することができない

実際にはフレームワーク側で使う引数もあったりして、たとえばPlay2のフォームでは18個までのプロパティしか定義することができません。
これはScalaにおいて関数やタプルを引数や要素の数に対応したクラスとして扱っているためで、Javaとの相互運用性を考慮したJVM言語では致し方のないところかと思います。

回避策はあります

多くのフレームワークではプロパティをネストさせることでこの問題を回避することができます。
で、実際問題ちゃんとデータをモデリングしていればフラットに22個以上のプロパティが必要になることってまずないと思うんですよね。むしろ、22個以上のプロパティをフラットに定義することができないという制約によって適切なモデリングが促進される側面もあるのではないかと思います。
Scala Conference in Japan 2013のセッションでは、「はじめから22個(Play2の場合は18個)を超えることが予想できない場合にあとから修正するのが非常に面倒」と言いましたが、そういう状況が発生すること自体、設計ミスでしょうということです。

それでも困るケース

たとえばPlay2のフォーム定義のように手でマッピングを記述する部分はそれでよいのですが、やはり困るのはDB周りなんですよね。
テーブルにマッピングするクラスとかさすがにひとつずつ手で書くのはしんどいので自動生成することを考えるわけです。ORマッパによってはモデルからDDLを生成できるからDB設計の代わりにモデルを書けばよいみたいなものもありますが、個人的にはDBはER図や専用のツールで設計したほうが効率がよいと思います。新規開発でなければ最初からDBが存在するケースも多いでしょうし。
で、DBは効率を考えるとドメインが異なっても1対1(もしくは1対0)の関係なら1つのテーブルに格納するという選択をすることは普通にあると思います。そんなのいちいちバラバラにしてジョインしてたらやってられないです。そうするとカラム数が22個を超えるテーブルって普通に出てきちゃうんですよね。
そんなわけで、自動生成ツールを使うとしてもそういう部分だけはモデルやマッピングを手で書く必要がでてきます。むしろカラム数が多いテーブルこそ自動生成したいのに、1つ2つならいいですが、数が多いと非常につらいです。スキーマを修正した場合も手動でメンテナンスすることになりますし。

結局どうすればいいのか?

なかなかいけてない感じですが、いまのところいい解決策が思いつきません。個人的にはこういう部分はもう関数に拘らず、(Javaの)リフレクションを使ってしまってもいいんじゃないかなぁと思うのですが、どんなもんでしょうか。