2024年Clojure状态调查!分享您的想法。

欢迎!有关详细信息,请参阅关于页面。

+2投票
Clojure

我是Clojure的忠实粉丝,因为它的简洁性、多线程模型、语言稳定性和出色的Java互操作。但我更痴迷于静态类型,这对于多人参与的项目非常有帮助。

TypeScript为JS添加了一层出色的类型检查,可以在编译时消除许多编程错误。它也打开了大量的编辑器和IDE工具的可能性。我会说,TypeScript是发生给JS的最好的事情。

我在想,Clojure的核心团队或者有足够能力和资源的任何一方是否正在考虑为Clojure开发类似于TypeScript的东西?

如果没有,为什么?

谢谢

1 个回答

+5投票

Clojure核心团队没有计划为Clojure开发静态类型,因为我们认为这不是必要的。我们的努力集中在spec(https://clojure.org/about/spec),它提供了描述Clojure数据和函数的报表规格支持。

Typed Clojure项目(https://typedclojure.org/)是Ambrose Bonnaire-Sergeant在攻读博士学位期间做的一项相当大的努力。您可能还感兴趣于Spectrum(《https://github.com/arohner/spectrum》)是一个基于规格的静态类型检查器。据我所知,这两个都还没有被广泛使用,也不是特别活跃的开发中。


编辑
感谢您的回答。

我们研究了规范,发现它主要关乎运行时。对于文档和测试来说非常有帮助,但在我看来,它无法做到类型系统的功能。

我们是一家小型初创公司,有几位程序员。当我们开始时,我们认真考虑了Clojure,但最终我们选择了Scala,因为它拥有强大的类型系统。在需要JavaScript的情况下,我们也使用TypeScript。

我确信许多Clojure爱好者都与我处于相同的情况。他们喜欢Clojure,想要用它进行实际工作,但必须因缺乏类型检查而选择其他语言。为了澄清,我的意思并不是Clojure不适合做严肃工作。我的意思是对于某些团队或公司来说,在为严肃项目选择语言或技术堆栈时,类型系统是一个重要的因素。

我理解无类型是Clojure的一个特性。但TypeScript证明了良好的类型系统可以为灵活且功能强大的无类型语言的生态系统带来巨大价值。

附言:那天在2017年的Clojure会议上,我遇到了一个由Zach Tellman发表的关于抽象的技术发言。我记得他分享了一个观点,即在通常的Lisp语言家族中,包括Clojure在内,过于灵活,这在某种程度上阻碍了它的成功。
我不认为TypeScript“证明”了类型系统可以“带来巨大价值”,但我认为您评论中的关键点是“对于某些团队……类型系统是一个重要的因素”。而对于关注灵活性的团队来说,Clojure这样的语言会比Scala更适合。

在我所在的公司,我们尝试引入Scala,但类型系统对每个人都非常不吸引人,所以我们转而使用Clojure。那是近九年前的事情了,现在我们运行着大约四十个在线交友网站,拥有数百万客户,后端完全使用Clojure。我们发现其提供的强大功能和灵活性使我们能够非常快速地改变和改进系统。我们在生产中大量使用Spec进行输入验证,以及在测试中用于所有各种事情,人们可能会依赖于类型系统,但它的功能更强大,因为它可以在类型系统无法描述的方式中描述形状和行为。
感谢分享您的见解。

我可以问问您正在使用哪个Clojure网络框架吗?

REST API服务是我们服务的关键部分。我们以前曾对Netty情有独钟,在建立自己的商店之前,我们就曾在Netty上运行了一个定制的REST API框架。因此,当我们开始时,我们希望选择一个基于Netty的Web/REST框架。我们对Clojure的网络框架进行了评估,发现大多数Clojure网络框架都没有积极维护,或缺乏生产案例。我们最感兴趣的一个aleph,似乎也被遗弃了。

这也是我们选择Scala的原因之一,因为Akka http。但我仍然热心想将Clojure用于其他项目,这正是你提到的理由。

了解您的技术栈对您有所帮助。谢谢。
我还会补充一下,clj-kondo最近添加了一种简单的类型检查形式,也是值得一看的:https://github.com/borkdude/clj-kondo/blob/master/doc/types.md
关于您的评论,很多人已经在生产中使用Aleph取得了成功。因此,我认为它是一个安全的选择。

话虽如此,我相信最活跃维护支持netty(和其他)的HTTP服务器可能是Pedestal: https://github.com/pedestal/pedestal

否则,Clojure中最受欢迎、积极维护的选择是ring https://github.com/ring-clojure/ring,它附带ring-jetty-adapter,可以直接与Jetty服务器一起使用。

关于进一步阅读,我建议您阅读以下指南:https://purelyfunctional.tv/mini-guide/clojure-web-servers/

此外,请注意,您可以直接使用Netty,Clojure的Java互操作相当不错,远远优于Scala的。因此,直接使用Java服务器接口也不是一个太差的选择。
谢谢。

正如您所说,如果我们决定用Clojure开始做一些事情,我们可能会直接使用Netty。我们已经在Netty上对Java互操作性进行了一些实验,一切都很顺利。裸机方法会给我们更多灵活性。
我们不会在Clojure中使用任何“框架”。我们使用一系列库的组合。Ring几乎是最核心的。我们使用Compojure作为几乎所有应用的路由(我们使用Bidi在其中一个应用中)。我们主要使用嵌入式的Jetty网络服务器(通过“标准”Ring适配器),但我们的应用也可以启动http-kit,这取决于命令行参数和环境变量。我们直接使用Netty用于一个严重依赖SocketIO的应用(通过Java互操作性)。

我们在大约十多项服务中按不同的组合使用了大量其他库。其中一些是服务器端渲染的HTML -- 我们几乎使用Selmer进行所有的HTML渲染,Hiccup用于从一个Clojure数据渲染HTML片段的地方。

我们最初在2015年考虑将ClojureScript作为可能的用户界面,但当时生态系统非常粗糙,工具感觉很脆(并且,当时Clojure和ClojureScript之间的差异比现在大得多)。因此,我们决定使用JS和React.js / Redux / Immutable.js等构建我们的客户应用程序。我们有一个前端团队专注于JS。

如果我们今天再次做同样的项目,我认为我们会再次将ClojureScript作为一个严肃的竞争者来评估,因为生态系统在过去4-5年中发生了巨大变化。我不知道那时我们会选择JS还是cljs。
谢谢。这非常有帮助。我们也许会考虑Clojurescript。

顺便问一下,我能建议这个论坛的版主将一个有关clojure开发者在生产中分享技术栈和见解的线程置顶吗?

我认为这对社区将非常有帮助。
非常有帮助。谢谢
我认为这里有一个误解
"静态类型,对于有多个开发者的项目来说非常有帮助"
“Clojure 核心团队没有计划为Clojure开发静态类型,因为我们认为这不是必需的。我们的努力集中在spec(《https://clojure.org/about/spec”)

根据我的理解,请纠正我如果我是错误的,发布者请求的是“设计时类型”,而答案涉及Java理解的静态类型。

我和,可能的问题作者都在寻找的是编写
 
(defn describe-dog [^:happy-puppy-co.api/dog dog]
      (println (str (:breed dog) (:age dog))))

并且让智能感知获取  :happy-puppy-co.api/dog 规范并提供基于其键及其各自子规范的建议。也就是说,帮助我按照其作者的意图使用 ::dog,而无需查看其文件。

TypeScript在编译之后不存在,其输出是JavaScript。TS最大的好处在于它可以帮助你更快地理解别人的代码(同时也提供一些避免误用的帮助,但这不是主要目的)。
对我来说,你的评论并不完全与原始问题相符,但如果你在询问与函数定义集成的规范,这是我们正在规范2.0中研究的。
那么,以下内容还能如何解读呢?

"我是静态类型的粉丝,这对于拥有多个开发者的项目非常有帮助。

TypeScript ... 也为编辑器和IDE工具集提供了很多可能性。我认为TypeScript是JS历史上的最佳发明。

按照我的理解,这意味着你将不断地与新代码打交道,这些代码你可能乃至你的团队都没有编写或审查过。企业应用通常会有十几个具有30+键的DTO,命名非常不一致。典型的思维过程是这样的:“好吧,我们的函数将需要一个 'sales-deal' DTO,我需要将其转换为 'financing-deal' 并发送给分析,'sales-deal' 上的利润率属性叫什么?是 'margin'、'markup' 还只是'rate'?并且它是十进制还是销售清单中仍然是明细价款的子DTO?” 然后,对 'financing-deal' 也要进行同样的提问...

我完全赞同“JS历史上的最佳发明”一语。遗憾的是,尝试ClojureScript感觉就像是回到了JS——并不好。我赞赏spec的强大功能,以及它在运行时和测试中的帮助。我现在想要做的是利用这部分的能力,并将其集成到我的IDE中,以帮助我编写代码。如果你还没有编写它们,就没有可以运行或测试的。
附属说明:为了更好地说明我寻找的内容,请查看这个库: https://github.com/vriad/zod
它可以让你在设计和编译时定义类似于spec的模式,这些模式同时也被TS编译器兼容和理解。

// spec定义 - 在TS编译之后仍存在,可用来验证模式
const dogSchema = z.object({
  name: z.string(),
  neutered: z.boolean(),
});

//在运行时验证schema
const cujo = dogSchema.parse({
  name: 'Cujo',
  neutered: true,
}); //通过,返回Dog

// TypeScript类型定义 - 在TS编译之后不存在
type Dog = z.infer<typeof dogSchema>;
/*
相当于
type Dog = {
  name: string;
  neutered: boolean;
}
*/

// 使用推断类型进行编译时类型检查和设计时智能感应
const fido: Dog = {
  name: 'Fido',
}; // TypeError: 缺少必需属性 `neutered`
...