Kengo's blog

Technical articles about original projects, JVM, Static Analysis and TypeScript.

Gradleのbaseプラグインに書くべきでないconventionとは何か

ひとつ前の記事では「Gradleの設定やコードをどこに書くべきか」のうち、答えが明確な「build.gradleファイルとbuildSrcディレクトリの使い分け」について書きました。この記事ではまだ自分の中でもよくわかっていない「Gradleでbaseプラグインに書くべきでないconventionとは何か」について書きます。

baseプラグインとは

ここで言うbaseプラグインは、plugins { id "base" } で使えるThe base pluginのことではありません。Gradleプラグインの設計手法のひとつとして推奨されている「設定より規約」の文脈で登場するものです。「設定より規約」を実現しつつ、(大部分のケースをカバーするであろう)規約が適用できないケースでもプラグインの機能を使えるようにするため、プラグインの規約(conventions)と基本的な機能(capabilities)とを別のプラグインに定義する設計手法です。

例えば java プラグインjava-base プラグインの場合、 java プラグインが規約を提供し、 java-base プラグインが基本的な機能を提供します。 java プラグインjava-base プラグインに依存することで、java-base プラグインが提供するtaskやextensionを利用します。

なお公式にはbaseプラグイン「ではない」方のプラグインには固有名詞がないのですが、ここでは記載を簡略化するために「規約プラグイン」と呼ぶことにします。

GradleはConventionという用語を多義的に使っている

ではbaseプラグインに書くべきconventionとは何か。この話題に触れるにあたり、GradleがConventionという用語をいつどのように使っているか確認する必要があります。私の知る限り、大きく分けて以下の3つが存在します:

  1. ”設定より規約”の文脈でのconventionのこと。一般的な用法。
  2. プロパティを指定しなかった場合に暗黙的に採用される値。default valueのこと。
  3. プラグイン設定用のconvention
    • 例えばJavaPluginConventionなど。
    • 現時点では非推奨なため、Extensionを利用する必要がある。

こうなるとよくわからないのが「baseプラグインに書くべきでないconventionはどれ?」です。

1のconventionはプラグインが提供する規約そのものでありbaseプラグインに書くべきでないのは明らかですが、JavaBasePluginCargoBasePluginは2と3のconventionを含んでいます。

規約プラグインであるJavaPluginCargoPluginはconventionを持っていることを期待され、実際1や2のconventionを含んでいます。

非推奨となった3のconventionは脇に置くとしても、2の置き場所やそれを決定する判断基準は明瞭に持ちたいところです。

メソッド名に惑わされないのが吉か?

私も2021年7月現在では明瞭な判断基準は持っていないのですが、ポイントはProperty#convention(Provider)というメソッド名に惑わされないことだと思われます。言い換えれば、2のconventionはどこにでも出てくるものだと割り切り、1のconventionを規約プラグインに限定して書くことのみに注力します。そして機能を書く上で必要なプロパティがある場合、baseプラグインでも気にせずにデフォルト値をProperty#convention(Provider)メソッドで設定してしまいましょう。

公式フォーラムに問い合わせてみた

自分的にはわかった気になれましたが、なんかしっくりこないので公式フォーラムに問い合わせてみました。

discuss.gradle.org

返信もらえたらこちらのブログ記事も更新します。

2021年9月29日更新: 公式Slackの方で「JavaBasePluginが異色なだけ、普通は1と2と3は全く同じものでbaseプラグインには出てこないべき」というコメントを貰いました。確かに一番シンプルなまとめ方かもしれません。