Leiningen のテンプレート機能とは一体なんなのか

たまにはノウハウ的なことを書いておいたほうが良いと思ったので書きます。

Leiningen のテンプレートが何かを知っていて、バージョンを指定出来るという話を知っている場合 [テンプレートを使う意義について](#should-i-use-template-or-not) に進んでください。

Leiningen テンプレートとは
==========================

[Leiningen](http://leiningen.org/) というツールについて改めて説明する必要はないと思いますが、もし分らなければ以下を参照してください。

-   [Leiningenの導入(1): 概要とインストール / clojournal](http://clojournal.com/entry/54e42e79e4b07686596991c1)

さて、この Leiningen というツールには **テンプレート** という機能が備っています。 どういう機能かというと **公開されているプロジェクトの雛形を展開できる** または **良く使うプロジェクトの雛形を公開できる** というものです。

これらは次のように利用することが出来ます。

``` shell
$ lein new $TEMPLATE_NAME $PROJECT_NAME
```

`$TEMPLATE_NAME` は省略可能でその場合は default テンプレート(後述)が利用されます。こうすることによって `$PROJECT_NAME` のディレクトリが作成( `--to-dir` オプションで展開先を変更することは可能)されます。

テンプレートは何処から来るのか
------------------------------

デフォルトで Leiningen 自体が抱えているプロジェクトテンプレートがあり、それは次の 4 つです。

-   default: ライブラリのための一般的なテンプレート
-   plugin: Leiningen のプラグインを作るためのテンプレート
-   app: アプリケーションプロジェクトのテンプレート
-   template: `lein new` 用のメタテンプレート

これらは Leiningen をインストールしているだけで自動的に使うことが出来るようになっているものでオフライン時でも利用が可能です。

これら以外のテンプレート名を `$TEMPLATE_NAME` に指定した場合、 [Clojars](https://clojars.org/) から自動的に `$TEMPLATE_NAME` を `group-id` [1] として `artifact-id` が `lein-template` のもの(つまり、 `$TEMPLATE_NAME/lein-template` )を探してきて取得しようとします[2]。

使用可能になっているテンプレートは以下のリンクから参照可能です。

-   [Search for 'lein-template' / Clojars](https://clojars.org/search?q=lein-template)

テンプレートのバージョンの話
----------------------------

以前もこの話は少し[書いた](http://qiita.com/ayato_p/items/5358cff8897783bba6d2)のですが改めて触れたいと思います。 Leiningen はテンプレートを取得する際、特に指定がなければ **最新の安定版** テンプレートを取得しようと試みます。このときオフラインだったり、既にローカルの Maven リポジトリに最新版が存在する場合、ダウンロードを実行せずにローカルに存在する最新のテンプレートを使用することになります。

ほとんどの場合は最新版のテンプレートで困ることはないのですが、最新版が壊れていたり、ドキュメント(書籍等)でテンプレートのバージョンが指定されている場合は **特定のバージョン** を使いたいときがあります。そのような場合、次のように解決できます[3]。

``` shell
$ lein new $TEMPLATE_NAME $PROJECT_NAME --template-version $TEMPLATE_VERSION
```

例えば [Luminus](http://www.luminusweb.net/) の最新バージョンは `2.9.10.3` [4]ですが、それより前のバージョンが使いたい場合は次のように書けます。

``` shell
$ lein new luminus luminus-app --template-version 2.9.10.2
```

また、開発版の snapshot を使いたい場合は次のように指定できます。

``` shell
$ lein new $TEMPLATE_NAME $PROJECT_NAME --snapshot
```

とはいえ Clojars に公開されているバージョンなので本当に最新の開発版が欲しいならリポジトリを clone して `lein install` などを実行する必要があります。

バージョン( or snapshot )の指定とテンプレートのオプションを同時に指定する場合 `--` を使って引数を区切ります( `lein new` それ自身の引数として解釈されるのを防ぐため)。

``` shell
$ lein new $TEMPLATE_NAME $PROJECT_NAME --snapshot -- template-arg-1 template-arg-2
```

``` shell
$ lein new luminus luminus-app --template-version 2.9.10.2 -- +postgres +cljs
```

また良く作られているテンプレートの場合 `lein new :show $TEMPLATE_NAME` とすることで、そのテンプレートに関する情報を見ることができます。

``` shell
$ lein new :show duct
Create a new Duct web application.

Accepts the following profile hints:
+cljs     - adds in ClojureScript compilation and hot-loading
+example  - adds an example endpoint
+heroku   - adds configuration for deploying to Heroku
+postgres - adds a PostgreSQL dependency and database component
+ragtime  - adds a Ragtime component to handle database migrations
+site     - adds site middleware, a favicon, webjars and more
+sqlite   - adds a SQLite dependency and database component

Argument list: ([name & hints])
```

テンプレートが出来ること
------------------------

最初に簡単に書きましたが、雛形を共有するというのが目的だと思ってもらえると分かりやすいでしょう。

なので、一般的な Clojure プロジェクトのテンプレートが出来ることというのは具体的に表現すると次のようになります。

-   `project.clj` を共有できるためライブラリやプラグインの特定バージョンが固定されたプロジェクト雛形を簡単に共有できる
-   一般的なグルーコードやボイラープレート、ノウハウなどを共有できる
-   ライブラリ/プラグイン作者がライブラリを素早く試すための土台を公開できる

おおよそ、テンプレート機能が出来ることというのはこのようなことです。

<span id="should-i-use-template-or-not"></span>テンプレートを使う意義について
=============================================================================

本題です。テンプレートについてはここまでで説明した通りですが、ある程度 Clojure に慣れてくるとこれらを使ってプロジェクトを開始する必要があるのかどうかという疑問が出てきます(例えば Web アプリを作りたいとして何かしたらのテンプレートを使ったほうがよいのか、など)。

ここではテンプレートを使用することのメリットとデメリットについて触れ、その上でどうするのが良いのかという話をします。

メリット
--------

-   とりあえず始めることが出来る
    -   どういうものを使ったらいいのか分からない場合などは、テンプレートを使うのは有用でしょう
-   退屈なボイラープレートを書く必要がない
    -   例えば Web アプリケーションを作るのであればサーバーの起動部分はほとんど共通だったりします(拘りがある場合は違いますが)
    -   準備が面倒なところを肩代わりしてくれるのも嬉しい(e.g. [descjop](http://descjop.org/))
-   特定のライブラリの使い方を知ることができる
    -   初めて見るライブラリやプラグインの README を読んでも具体的に嬉しさみたいなものが理解し難いときがあるのでそういう場合は有用です

デメリット
----------

-   テンプレート自体の品質維持が難しく壊れていることがある (e.g. [Luminus](http://www.luminusweb.net/))
    -   テンプレートはオプションを受け取って生成するプロジェクトを変化させることが出来ますが、大抵の場合その全ての組み合せをテストされているということは期待できません
    -   幾つかのテンプレート (e.g. [juxt/modular](https://github.com/juxt/modular)) ではプロジェクトが生成されることのテストを行っていたりするが、実際に実行できるかまでは保証されてないことが多い
-   テンプレートが更新されてもそれを追従することが出来るわけではない
-   展開されたテンプレートのライブラリを最新にしても簡単には動かなかったりする
    -   ライブラリもメジャーバージョンが違うと簡単には更新できない
    -   展開されたプロジェクトの何処に deprecated な関数があったりするのか容易には分からない

どうすべきか
------------

ここまででテンプレートというのものが一体どういう性質を持ったものなのか理解できたと思います。この機能は万能ではありません。なので、当然メリットを享受しやすいシーンもありますし、不便さしか感じることができないときもあります。

このテンプレート機能が活躍するのは具体的にはメリットにもあげたように学習のときだと僕は感じています。

例えば ClojureScript の Live Reloading に興味があって [Figwheel](https://github.com/bhauman/lein-figwheel) をどのように設定すれば良いのか具体的に知りたいときには [chestnut](https://github.com/plexus/chestnut) は良い例になるでしょうし、 [Component](https://github.com/stuartsierra/component) を使った Web アプリケーションを作りたい場合 [duct](https://github.com/weavejester/duct) は良い先生役になってくれると思います。 Luminus を見れば最近の流行っているライブラリを知ることが比較的容易にできるでしょう。

逆に真面目なプロジェクトの土台として使うには少々難があることが多いかなという感じがしています[5]。

どうすべきかというのを強く言うつもりはないですが、ひとつ間違いなく言えるのは「テンプレートは使わなくても大丈夫」ということです。なのでテンプレートを使ったほうがいいのだろうかと悩んだときはココまでで説明したことを改めて読んでもらって決めてもらえたらいいかなと思います。

まとめ
======

テンプレートは便利なだけではなく、不便なこともあるので使うかどうかは自分の裁量で決めましょう。

特別枠: Luminus について
========================

おそらく一番有名な Leiningen テンプレートだと思いますが、少しだけ本題とはそれますがこれに言及しておきたいと思います。

Luminus は **Web フレームワーク** として名前が知られていますが、これもひとつの **テンプレート** です。なので今迄で説明したようなメリット/デメリットを包含しています。

このテンプレートの特徴としては Web アプリケーション開発で必要となるであろうライブラリや設定、グルーコード/ボイラープレートを提供しているところです。これによって簡単に Web アプリケーションが作成できるようになっています。

ただメリットばかりがあるというものでもなく、デメリットも幾つかあります。 1. 最新の安定板が壊れていることが往々にしてある 2. 使っているライブラリがそれなりの頻度で変わる 3. 結構な頻度で本体もドキュメントも更新される。

これらのデメリットは恐らく最新の Luminus 公式ドキュメントを読んでチュートリアルを進めている間は気になることも少いと思いますが、困るのは恐らく和訳されたドキュメントを読みながら進めようとしたり、自分で何か作ってみようと思ったときでしょう。 一応テンプレートのバージョンについて頭に入れておけばハマることもないとは思いますが注意が必要です。

[1] 突然 `group-id` や `artifact-id` というものが出てきましたが Maven などで指定するものと同じですので、詳細はそちらを参照してください

[2] Leiningen のヘルプでは Clojars としか書いてませんが Leiningen のコア機能を使っているので恐らく [Maven Central](http://search.maven.org/) やサードパーティのリポジトリからも解決できるはずですが、一般的には Clojars に公開していると思うのでテンプレートに関してはあまり他のリポジトリを意識する必要はないと思います

[3] 書籍 [Clojure Web Development Essentials](https://www.packtpub.com/application-development/clojure-web-development-essentials) では `$HOME/.lein/profiles.clj` にてバージョンを固定する方法が示されていますが、 Leiningen のバージョンが最新であればそのような指定の仕方をする必要はありません

[4] 2016-2-25(Thu) 現在

[5] 例えば前述の chestnut では Reagent を使いたくても Om にべったりなので引き剥がすのに苦労しますし、かといって他のテンプレートだと少し微妙なところがあったりして使い辛かったりするという具合です