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

kes*_*kes 47 lisp deployment clojure leiningen

我是Clojure的新手,我开始尝试构建应用程序.

到目前为止,我所看到的有关编译Clojure程序的教程的所有内容都涉及交互性.例如,"加载REPL并键入(加载文件"this-or-that")以运行.这很好,但这还不够.

我已经习惯了C语言或Delphi等语言的编辑 - 编译 - 运行习惯,我本能地驱动编辑,然后点击"Mx编译".

问题是"lein uberjar",我理解相当于"make",即使对于一个你好的世界也很难执行.因此,我将不得不弄清楚这种"交互式开发"的东西是如何工作的,停止使用像它快速制作的超级发布,并且只在一天结束时保存它.

我在构建时注意到的另一件事(使用lein uberjar)是我正在处理的小GUI应用程序在编译过程中弹出帧,就像它们在编译时执行一样.这对我来说似乎有点违反直觉; 它并不像我想象的那样类似于"制造".

我知道Lisp的开发方式是在REPL中交互式工作,我并不想改变它:我想适应这种生活方式.不幸的是,我没有看到关于如何这样做的文档形式.例如,如何重置机器的当前状态.只是继续编译各个片段而不能进行某种重置似乎有点麻烦.

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

所以这是我的问题:任何有关构建Clojure应用程序的整个过程(包括部署)的良好信息或教程的资源?

(注意:我已经安装并运行了所有先决条件(例如Emacs,Slime,Leiningen等),所以这不是一个问题).

Mic*_*zyk 26

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

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

此外,很可能大多数代码实际上不应该是AOT编译.AOT在某些Java互操作方案中是必需的,但大多数情况下它会使启动速度略有提升,并且与不同版本的Clojure的二进制兼容性会产生烦人的问题.我认为后一个问题与uberjar-ed独立应用程序类型的项目无关,但是如果可能的话,至少应该留下任何库代码进行JIT编辑.使用Leiningen,您可以:namespacesdefproject表单中放入一个子句project.clj来确定要编译的命名空间; 你遗漏的任何内容都将默认为JIT编辑.较旧版本的Leiningen默认用于编译所有内容,这实际上是升级的一个很好的理由!

至于在编译期间弹出的窗口,我猜你在宏扩展时或者在任何函数定义或类似构造之外运行窗口弹出代码.((println "Foo!")最顶层的东西.)我认为这是你不应该做的事情 - 除非你打算将你的代码作为脚本运行,无论如何.要避免此问题,请在函数定义中包含副作用代码,并使用中的:main子句为应用程序提供入口点project.clj.(如果你说:main foo,那么命名空间中的-main函数foo将被用作你的应用程序的入口点.这是默认的,无论如何,至少上面提到的lein run似乎有硬编码的名字 - 不确定lein本身.)

至于重置REPL的状态 - 您可以重新启动它.使用SLIME,Mx slime-restart-inferior-lisp将在保持Emacs会话的所有其他状态的同时执行此操作.

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

  1. Clojure用于系统管理
  2. 为包装准备clojure(是:Re:用于系统管理的Clojure)
  3. Leiningen,Clojure和图书馆:我错过了什么?


Sva*_*nte 13

不,您不在REPL上输入功能.

您可以像往常一样编辑源文件.Lisp的优势在于您可以同时在后台运行系统,因此您可以从源文件中编译单个函数并将它们放入正在运行的系统中,甚至可以在那里替换它们.

如果您使用Slime,则按下C-c C-c源文件以编译并加载该函数.然后,您可以切换到REPL进行测试和探索,但是您希望将任何内容保留为源,并将其放入源文件中.

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


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

  • 启动Emacs
  • M-x slime 启动Slime,Lisp系统,并通过Swank连接两者
  • ,(命令)load-system foo将当前项目(仅在必要时编译)加载到图像中
  • C-x b 切换到源缓冲区
  • C-c ~ 使源目录成为当前目录,将源包作为REPL的当前包

现在,我设置了我的系统在后台运行.然后工作:

  • 更改或添加函数或类定义
  • C-c C-c 编译并将其加载到图像中
  • 切换到REPL,测试
  • 调试

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

  • 还有`Cc Cz`用于从任何Lisp源缓冲区切换到REPL缓冲区.一般来说,学习正确利用SLIME和Paredit是最重要的 - 然后有许多不那么重要但仍然非常有用的东西,例如偶像模式(或者达到类似目的的东西 - - 可能是冰柱或任何东西.el).(感谢编辑,BTW!) (2认同)