构build和部署Clojure应用程序的最佳实践:好的教程?

我是Clojure的新手,正在开始尝试构build一个应用程序。

到目前为止,我所看到的关于编译Clojure程序的教程都涉及到交互性。 例如,“加载REPL并input(load-file”this-or-that“)来运行。这很好,但还不够。

我习惯于像C或Delphi这样的语言的编辑 – 编译 – 运行的习惯用法,我本能地驱动编辑,然后打“Mx编译”。

问题在于,“lein uberjar”,据我所知,与“make”相当,即使对于一个hello世界来说,执行起来也是很痛苦的。 所以我必须弄清楚这个“互动开发”的东西是如何工作的,停止使用uberjar就像快速制作一样,并且只能在一天结束的时候保存。

另一件我在构build(使用lein uberjar)时注意到的事情是,我正在处理的小型GUI应用程序在编译过程中popup框架,就好像它们在编译时正在执行一样 。 这对我来说似乎有些不合常理。 它不像我想象的那样与“制造”相似。

我知道Lisp开发事物的方式是在REPL中交互式工作的,我不想改变这个:我想适应这种生活方式。 不幸的是,我没有看到如何做文件的forms。 例如,如何重置机器的当前状态。 只是不停地编译单个代码片段,而不能做某种重置就显得有些杂乱。

我在Clojure(和Lisp)上看到的大多数教程似乎都把重点放在了对REPL的黑客攻击上。 部署应用程序的最佳实践对我来说仍然是一个谜。 我的用户只是成为用户; 他们不会成为将文件加载到REPL的开发人员。

所以,这里是我的问题:任何资源的良好信息或教程build立一个Clojure应用程序的整个过程,包括部署?

(注意:我已经安装了所有的必备软件(例如Emacs,Slime,Leiningen等等),所以这不是一个问题)。

几个快速提示,然后一些链接:

在开发过程中不要使用lein uberjar ; 更喜欢lein jar 。 不同的是, lein uberjar将所有的依赖关系放在生成的jar (包括Clojure本身)中,这样你的单个jar文件就是一个完全独立的包,里面包含了你的应用程序。 lein jar只能打你自己的代码。 uberjar方法对于部署有明显的好处,但是对于开发,在运行应用程序时应该能够使用适当的类path,从而节省准备uberjar所需的时间。 如果您不想手动pipe理testing运行的类path,请查看lein run插件 。

另外,很可能大部分代码实际上不应该被AOT编译。 AOT在一些Java互操作场景中是必需的,但是大多数情况下,它会使启动速度略微提高,并且与Clojure的不同版本的二进制兼容性令人烦恼。 我认为后一个问题与uberjar -ed独立应用types的项目uberjar ,但是任何可能的情况下,至less应该对任何库代码进行JIT编辑。 使用Leiningen,您可以在project.clj中的defproject表单中放置:namespaces子句,以确定要编译哪些名称空间; 不pipe你现在离开了什么,都将默认为JIT-ed。 老版本的Leiningen默认情况下用来编译所有的东西,这实际上是升级的一个很好的理由!

至于在编译期间popup的窗口,我猜测你是在macros扩展时或在任何函数定义或类似的构造之外运行窗口跳出代码。 (就像(println "Foo!")在顶层。)这是你不应该做的,我想 – 除非你打算把你的代码作为脚本来运行。 为了避免这个问题,在函数定义中包含副作用代码,并使用project.clj :main子句为应用程序提供入口点。 (如果你说:main foo ,那么来自foo命名空间的-main函数将被用作你的应用程序的入口点,这是默认的,至less上面提到的lein run似乎有硬编码的名字 -不知道关于lein本身。)

至于重置REPL的状态 – 你可以重新启动它。 使用SLIME,Mx slime-restart-inferior-lisp将会保持Emacs会话的所有其他状态。

另请参阅关于Clojure Google小组的讨论:

  1. Clojure进行系统pipe理
  2. 准备包装clojure(是:回复:Clojure系统pipe理)
  3. Leiningen,Clojure和图书馆:我错过了什么?

不,你不要在REPL上input函数。

像往常一样编辑源文件。 Lisp的好处是你可以同时在后台运行系统,所以你可以从源文件中编译单独的函数,并把它们放到正在运行的系统中,甚至在那里replace它们。

如果你使用Slime,你可以在源文件中按Cc Cc来编译和加载函数。 然后,您可以切换到REPL进行testing和探索,但是任何您想要作为源代码保存的内容都会放到源文件中。

教程通常首先在REPL上input内容,因为没有太多需要为此设置,但严重的开发集成了正在运行的系统和源文件pipe理。


为了说明,我平时的工作stream程(我使用的是Common Lisp,但是Clojure类似)是这样的:

  • 启动Emacs
  • Mx slime开始Slime,Lisp系统,并通过Swank连接两个
  • , (命令) load-system foo加载当前项目(仅在必要时编译)到映像中
  • Cx b切换到源缓冲区
  • Cc ~将源目录设置为当前目录,并将源代码打包为当前的REPL包

现在,我设置了我的系统在后台运行。 那么工作就是:

  • 更改或添加一个函数或类定义
  • Cc Cc编译并加载到映像中
  • 切换到REPL,testing
  • debugging

没有重要的编译暂停,因为我从不编译整个事情,只是个别的定义。