Clojure アプリケーションの構築とデプロイのベスト プラクティス:良いチュートリアル?
-
25-09-2019 - |
質問
私は Clojure を初めて使用しており、アプリケーションの構築を実験し始めています。
これまでのところ、Clojure プログラムのコンパイルに関するチュートリアルについて私が見てきたものはすべて、対話性を伴うものでした。たとえば、「REPL をロードし、(load-file "this-or-that") と入力して実行します。これでもいいのですが、それだけでは十分ではありません。
私は C や Delphi などの言語の編集、コンパイル、実行のイディオムに慣れているため、本能的に編集を行ってから「M-x コンパイル」を押したくなります。
問題は、「lein uberjar」は「make」と同等であると私は理解していますが、hello world であっても実行が非常に遅いことです。したがって、この「インタラクティブな開発」機能がどのように機能するかを理解して、uberjar を簡単に作成するかのように使用するのをやめ、一日の終わりのためだけに保存しなければなりません。
(lein uberjar を使用して) ビルド中に私が気づいたもう 1 つのことは、私が取り組んでいる小さな GUI アプリがコンパイル プロセスでフレームをポップアップすることです。 実行中 コンパイル中。それは私にとって少し直観に反するように思えます。それは私が思っていたほど「作る」とは似ていません。
私は、Lisp の開発方法が REPL で対話的に動作していることを知っており、それを変更しようとはしていません。この生き方に適応していきたいと思います。残念ながら、その方法に関するドキュメントの形で私はほとんど見たことがありません。たとえば、マシンの現在の状態をリセットする方法などです。何らかのリセットを行うことなく、個々のスニペットをその場でコンパイルし続けるのは、ちょっと面倒に思えます。
私がこれまでに見た Clojure (および Lisp) に関するチュートリアルのほとんどは、REPL でのハッキングに焦点を当てているようです。アプリケーションの展開に関するベスト プラクティスは私にとって謎のままです。私のユーザーはただのユーザーになるだけです。彼らは REPL にファイルをロードする開発者になるつもりはありません。
そこで私の質問は次のとおりです。デプロイメントを含む Clojure アプリケーションの構築プロセス全体に関する有益な情報またはチュートリアルに関するリソースはありますか?
(注記:前提条件がすべてインストールされ、動作しています(例:Emacs、Slime、Leiningen など)、これはそれに関する質問ではありません)。
解決
いくつかの簡単なヒントといくつかのリンク:
使用しないでください lein uberjar
開発中。好む lein jar
. 。違いは、 lein uberjar
すべての依存関係を生成されたファイルに置きます jar
(Clojure 自体を含む)そのため、単一の jar はアプリを内部に含む完全に自己完結型のパッケージになります。 lein jar
独自のコードのみを jar に入れます。の uberjar
このアプローチにはデプロイメントには明らかな利点がありますが、開発に関しては、アプリの実行時に適切なクラスパスを使用するだけで、uberjar の準備に必要な時間を節約できます。テスト実行のクラスパスを手動で管理したくない場合は、 lein run
プラグイン.
また、ほとんどの場合、コードの大部分は実際には AOT コンパイルされるべきではありません。AOT は一部の Java 相互運用シナリオでは必要ですが、ほとんどの場合、起動速度がわずかに向上し、Clojure のさまざまなリリースとのバイナリ互換性に関する厄介な問題が発生します。後者の問題は関係ないと思います uberjar
-ed スタンドアロン アプリの種類のプロジェクトですが、可能であれば少なくともライブラリ コードは JIT 化されたままにしておく必要があります。Leiningen を使用すると、 :namespaces
の条項 defproject
フォームイン project.clj
どの名前空間をコンパイルするかを決定します。省略したものはすべてデフォルトで JIT 化されます。Leiningen の古いバージョンでは、デフォルトですべてがコンパイルされていましたが、これは実際にアップグレードする良い理由です。
コンパイル中にウィンドウが飛び出すことについては、マクロの展開中、または関数定義または同様の構成の外側でウィンドウを飛び出すコードを実行しているのではないかと思います。(のようなもの (println "Foo!")
) これは、コードをスクリプトとして実行するつもりがない限り、やるべきではないことだと思います。この問題を回避するには、副作用のあるコードを関数定義にラップし、 :main
の条項 project.clj
. 。(あなたが言うなら :main foo
, 、 そうして -main
からの関数 foo
名前空間はアプリへのエントリ ポイントとして使用されます。とにかく、それがデフォルトであり、少なくとも上記のとおりです lein run
名前はハードコードされているようです -- lein 自体についてはわかりません)。
REPL の状態のリセットに関しては、REPL を再起動するだけです。SLIME では、M-x Slime-restart-inferior-lisp が Emacs セッションの他のすべての状態を維持しながら、まさにそれを実行します。
Clojure Google グループに関する次のディスカッションも参照してください。
他のヒント
いいえ、REPL では関数を入力しません。
いつものようにソース ファイルを編集します。Lisp の利点は、システムを同時にバックグラウンドで実行できることです。そのため、ソース ファイルから個々の関数をコンパイルして実行中のシステムに入れたり、そこで置き換えたりすることもできます。
スライムを使用する場合は、 C-c C-c
ソースファイル内で関数をコンパイルしてその時点でロードします。その後、REPL に切り替えてテストと調査を行うことができますが、ソースとして保持したいものはすべてソース ファイルに入れます。
通常、チュートリアルは REPL に何かを入力することから始まります。そのために設定する必要があることはそれほど多くありませんが、本格的な開発では、実行中のシステムとソース ファイルの管理が統合されます。
説明のために、私の通常のワークフロー (私は Common Lisp を使用していますが、Clojure も同様です) は次のとおりです。
- Emacsを起動する
M-x slime
Slime、Lisp システムを起動し、Swank 経由で 2 つを接続します。,
(指示)load-system
foo
現在のプロジェクトをイメージにロードします (必要な場合のみコンパイルします)。C-x b
ソースバッファに切り替えるC-c ~
ソース ディレクトリを現在のディレクトリにし、ソース パッケージを REPL の現在のパッケージにします。
これで、システムがバックグラウンドで実行されるようにセットアップされました。その場合、作業は次のようになります。
- 関数またはクラス定義を変更または追加する
C-c C-c
コンパイルしてイメージにロードします- REPL に切り替えてテストします
- デバッグ
一度に全体をコンパイルすることはなく、個々の定義だけをコンパイルするため、大幅なコンパイルの一時停止はありません。