Locked History Actions

sbt/whyDifficult

なぜsbtはわかりにくいのか?

以下は多分に私見。

sbtがわかりにくい原因は、sbt自体のデザインについてマニュアルに記述が無いのが最も大きな要因。 つまり、sbtがなぜこのような仕組みになっているのか、どうしてこのようなデザインにしたのか、その理由について何の説明も無い。 以下では想像が含まれるが、これについて説明してみる。

ビルドシステムの本質的要素

ビルドシステムの本質的要素(?)は次の三つと思われる。

  • 入力
  • タスク
  • 依存

多分こんなところだろう。何らかの成果物を作成するには、入力が必要で、それをどう処理するかというタスクがある。そして、あるタスクはその前段階の別のタスクに依存する。

例えばantでは(Mavenについてはほとんど知識がないので)、これをどのように処理すべきか。

  • 入力はおそらくpropertyなどとして定義する。
  • タスク(ユーザ定義のタスクのことをantではtargetという)。
  • それぞれのタスク(target)について、他への依存を定義する。

昔はこれでもよかったのだが、やるべき仕事を多くなるに連れ、これでは面倒になってきた。antでは基本的に「いちいち指定してやらなければならない」からだ。定型的なパターンを取り決め、それに従えば面倒が無いように考え出されたのが、Convensionなどと言われているものだ。

例えば、scalaソースはsrc/main/scalaというディレクトリ以下に置く。こうしておけば、compileを指示するだけで、コンパイルしてくれる。

めでたしめでたし、とはいかない。相変らず「パラメータ」を指定しなければならない状況がある。このような状況の場合には、「antのように」それらを指定すればよいのか?

つまりこういうこと

  • コンパイル対象のソースをコンパイルタスクのパラメータとして指定する。
  • ソースリリース対象のソースをパッケージタスクのパラメータとして指定する。
  • 他の何らかのソースコードに対する処理について、ソースのありかを指定する。

antでは、それぞれのタスク(target)について、いちいちこれらを指定しなければならない。つまり、各targetの属性、あるいは子要素として同じものを記述するのである。これが馬鹿げていることは明らかなのだが、antではこのようにするほかはない。

これをやめるためには、複数のタスクにおいて共有できるような「パラメータ」の存在が必要になる。「ソースファイル」を示すパラメータは、上記三つのタスクが共有して(あるいは、別のタスクも)使用できるようなものとする。

ここがそもそものモチベーションであるにも関わらず、主となるタスクと従となるパラメータがsbtではほとんど同列に扱われており、それらの間に「依存がある」といった説明しかされていない。これがわかりにくい原因かと思われる。

ビルドシステムの本来的な考え方というのは、最初に示したように、入力とタスクと依存であり、これを起点として説明されなければならないはずだが、sbtではそれらを分解した後の状態を示し、その状態から説明しようとしているために混乱がおきるのである。