请在2024 Clojure 状态调查中分享您的想法!

欢迎!请访问关于页面获取更多关于如何使用本站的信息。

+2
Clojure

我是Clojure的忠实粉丝,因为它的简洁性、多线程模型、语言稳定性以及卓越的Java互操作性。但对我而言,静态类型更是不可或缺,这对于拥有多个开发者的项目来说非常有帮助。

TypeScript为JavaScript添加了出色的类型检查层,可以在编译时消除许多编程错误。它同时也开启了大量的编辑器和IDE工具的可能性。我可以说TypeScript是JavaScript历史上最好的事情之一。

我在想,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)感兴趣,它是一种基于specs的静态类型检查。据我所知,这些都没有得到广泛应用,也并非特别活跃的开发项目。


编辑了
感谢您的回答。

我们确实研究过规范,发现它主要是运行时的事情。这对文档和测试非常有帮助,但在我看来,它无法做类型系统所能做的事情。

我们是一家小型的初创公司,有几个程序员。当我们开始的时候,我们认真考虑了Clojure,但最终还是决定使用Scala,因为它有强大的类型系统。当需要JavaScript时,我们也使用TypeScript。

我相信许多人都有过我这样的情况。他们喜欢Clojure,希望用它来处理重要的工作,但由于缺乏类型检查,不得不选择其他语言。为了澄清,我的意思不是Clojure不是一个适合做重要工作的语言。我的意思是对于一些团队或公司,在为重要的项目选择语言或技术栈时,类型系统是一个重要的因素。

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

顺便提一下,前几天我在2017年一次Clojure大会上遇到了一个关于抽象的技术演讲,演讲者是Zach Tellman。我记得他分享了一个观点,即就一般Lisp语系而言,包括Clojure在内,在某种程度上过于灵活,这可能会阻碍它的进一步成功。
TypeScript并不“证明”类型系统“增加了巨大的价值”,但我想您评论中的关键点是“对于某些团队……类型系统是一个重要的因素”。对于重视灵活性的团队来说,像Clojure这样的语言将比Scala更适合。

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

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

REST api服务是我们服务的关键部分。我们曾是Netty的忠实粉丝,在开始自己的商店之前,我们在Netty上运行了一个定制的REST api框架。因此,当我们开始时,我们想要选择基于Netty的Web/REST框架。我们评估了Clojure的框架,发现大多数Clojure Web框架都没有积极维护或者缺乏生产案例。我们最感兴趣的aleph似乎也被遗弃了。

这也是我们由于Akka http选择了Scala的原因之一。但我仍然非常希望能将Clojure引入到其他项目,正好如您所述的原因。

了解您的技术栈的一些信息将非常有帮助。谢谢。
by
我还会补充,clj-kondo 最近加入了一种简单的类型检查形式,这也值得一看: https://github.com/borkdude/clj-kondo/blob/master/doc/types.md
by
至于您的评论,许多人已经在生产环境中成功使用了Aleph。所以我认为这是一个安全的赌注。

尽管如此,我相信目前最活跃维护并支持Netty的HTTP服务器可能是Pedestal: https://github.com/pedestal/pedestal

另外,Clojure中一个被积极维护且最受欢迎的选择是ring https://github.com/ring-clojure/ring,与Jetty服务器一起使用的ring-jetty-adapter。

为了进一步阅读,我建议你阅读本指南: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 程序员生产经验、分享技术架构和见解的帖子固定在顶部吗?

我认为这将对社区非常有帮助。
我不会固定这个问题,但有一个技术栈问题在 https://ask.clojure.org/index.php/8280/what-is-your-clojure-and-clojurescript-stack
非常有帮助。谢谢

编辑了
我认为这里有一个误解
"静态类型,这对于拥有多个开发者的项目非常有用"
“Clojure 核心团队没有计划为 Clojure 开发静态类型,因为我们认为它不是必要的。我们的努力集中在 spec (https://clojure.org/about/spec)”

AFAIU(根据我的理解),如果我有误请纠正,提问者是在询问“设计时类型”,而答案讨论的是Java所理解的静态类型。

我和,可能还有问题作者,想要做的是编写
 
(defn describe-dog [^:happy-puppy-co.api/dog dog]
      (println (str (:breed dog) (:age dog))))

并且让智能提示接收到  :happy-puppy-co.api/dog 规范并提供基于其键和相应子规范的提示。也就是帮助我按照作者的意思使用 ::dog,而无需去查看其文件。

TypeScript 在编译后不存在,其输出是 JavaScript。TypeScript 最大的好处是它能帮助你更快地理解其他人的代码(还提供了一些避免误用的帮助,但这只是次要的)。
by
你的评论与原始问题并没有完全一致,但如果你在问是否可以将规格与函数定义集成,这是我们正在 spec 2 中考虑的内容。
by
那么以下内容又如何解读呢?

"我是...静态类型的粉丝,这在有超过几个开发人员的项目中非常有用。"

TypeScript ... 也为编辑器 / IDE 工具打开了无数的可能性。我觉得,TypeScript 是 JS 有史以来最好的东西了。"

在我看来,这意味着你将不得不不断与大量代码一起工作,这些代码 neither 你,也可能不是你的团队之前编写或审查过的。在企业级应用程序中,通常会有成打的对象(DTO),包含 30 个以上的键,并且命名很不一致。典型的思维过程是这样的:"好吧,我们的函数将使用 'sales-deal' DTO,我需要将其转换为 'financing-deal' 并发送到分析,'sales-deal' 上的利润率属性叫什么?是 'margin'、'markup' 还是 plain 'rate'?而且它已经是一个十进制值了吗,还是说销售 DTO 仍然具有作为明细率组件的子 DTO?" 然后,对于 'financing-deal' 也要提出相同的问题...

我完全赞同 "JS 有史以来最好的东西" 这部分。遗憾的是,使用 ClojureScript 感觉像是回到了 JS - 这不是好事。我欣赏 spec 的强大功能,以及它如何在运行时和测试中帮助我。我现在想做的就是将所有的这些功能都集成到我的 IDE 中,以便帮助我写代码。如果我还没有写出代码,那么就没有什么可以运行或测试的。
by
附言:为了更好地说明我在寻找什么,请查看这个库:https://github.com/vriad/zod
它允许你在设计和编译时定义类似于 spec 的模式,这些模式也可以被 TS 编译器理解和使用。

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

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

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

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