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

欢迎!请参阅关于页面以获取更多关于如何操作的信息。

+2
Clojure

我是 Clojure 的忠实粉丝,因为它的简洁性、多线程模型、语言稳定性以及优秀的 Java 互操作性。但我是更大一级的静态类型粉丝,这对超过几个开发者的项目非常有帮助。

TypeScript 为 JS 添加了一个出色的类型检查层,这有助于在编译时消除许多编程错误。它还开辟了许多编辑器/ide工具的可能性。我可以说是 JavaScript 有史以来最好的事情。

我在想,Clojure 核心团队或任何有能力并拥有丰富资源的组织是否在考虑为 Clojure 开发类似 TypeScript 的东西?

如果没有,为什么?

谢谢

1 回答

+5

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

Typed Clojure项目(https://typedclojure.org/)是Ambrose Bonnaire-Sergeant在攻读博士期间等时期进行的一项相当大的努力。您可能还对Spectrum(https://github.com/arohner/spectrum)感兴趣,它是基于规格的静态类型检查工具。据我所知,这两者都没有得到广泛应用,也没有特别活跃的开发活动。


编辑
谢谢您的回答。

我们研究了spec,并发现它主要是一个运行时的事情。它在文档和测试方面非常有帮助,但我认为它不能做什么一个类型系统能做到的事情。

我们是一家小型初创公司,有几位程序员。当我们的初创公司刚起步时,我们认真考虑了Clojure,但最后我们还是决定使用Scala,因为它的强大类型系统。我们也使用TypeScript来进行需要的JavaScript。

我相信许多Clojure迷都和我有同样的情况。他们都喜欢Clojure,并希望用它来开展严肃的工作,但由于缺少类型检查,不得不选择其他语言。为了澄清,我的意思并不是Clojure不是一个用于严肃工作的语言。我的意思是,对于一些团队或公司来说,类型系统在选择语言或在项目中选择技术栈时是一个重要因素。

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

附注:几天前,我在2017年的一场Clojure会议上听到了扎克·泰勒曼(Zach Tellman)关于抽象的一次技术演讲。我记得他分享了一个观点,即Lisp语言家族,包括Clojure,在某种程度上太过灵活,这可能成为其成功的一个障碍。
TypeScript并不能“证明”类型系统能“增加巨大价值”,但我认为您评论中的关键点是“对于_某些_团队……类型系统是一个重要的因素”。而对于那些重视灵活性的团队来说,与Scala相比,Clojure这样的语言将更适合。

我在的公司曾尝试引入Scala,但类型系统对每个人都非常令人却步,所以我们转而使用Clojure。这几乎是在九年前,现在我们运营着四十多个在线约会网站,拥有数百万用户,完全采用Clojure后端。我们发现它所提供的强大功能和灵活性使我们能够非常快速地改变和增强系统。我们在生产中大量使用Spec进行输入验证,并在测试中进行各种事情,一些可能依赖类型系统的用户,但Spec更强大,因为它可以以类型系统无法描述的方式描述形式_和_行为。
by
感谢分享你的见解。

我可以问问你使用的是哪个Clojure网络框架吗?

REST API服务是我们服务的关键部分。我们之前是Netty的大粉丝,使用Netty运行了一个自定义构建的REST API框架,然后我们开始了自己的商店。所以当我们开始的时候,我们希望能够使用以Netty为基础的网络/REST框架。我们评估了Clojure的,发现大多数Clojure网络框架都没有活跃维护或缺乏生产案例。我们最感兴趣的aleph似乎也被遗弃了。

这也是我们为什么在Akka http之后选择Scala的原因之一。但我仍然非常想将Clojure应用于其他项目,正是出于你提到的那些原因。

关于你的技术栈的一些见解将会非常有帮助。谢谢。
by
我还要补充一点,clj-kondo最近增加了一种简化的类型检查,这也值得一看:[https://github.com/borkdude/clj-kondo/blob/master/doc/types.md](https://github.com/borkdude/clj-kondo/blob/master/doc/types.md)
by
至于你的评论,很多人已经在生产中成功使用了Aleph。所以我会认为这是一个安全的赌注。

话虽如此,我认为最有活力维护并支持netty(及其他)的HTTP服务器可能是Pedestal:[https://github.com/pedestal/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 服务器接口也是一个不错的选择。
by
谢谢。

正如你所说,如果我们要用 Clojure 启动一个新的项目,我们可能直接使用 Netty。我们已经在 Netty 上进行了一些 Java 互操作实验,并且一切顺利。裸机方法将给我们更多灵活性。
by
我们不使用 Clojure 的任何“框架”。我们使用一系列库。Ring 几乎是所有东西的核心。我们在几乎所有应用程序中使用 Compojure 进行路由(在一个中使用 Bidi)。我们主要使用嵌入式的 Jetty 服务器(通过“标准”的 Ring 适配器),但根据命令行参数和/或环境变量,我们也可以启动所有应用程序的 http-kit。我们直接使用 Netty 用于一个高度依赖 SocketIO 的应用程序(通过 Java 互操作性)。

我们在大约 dozen 个服务中使用了大量不同的库组合。其中一些是服务器端渲染的 HTML -- 我们使用 Selmer 几乎完成了所有的 HTML 渲染,Hiccup 在一个地方用于根据 Clojure 数据渲染 HTML 片段。

早在 2015 年,我们就考虑过将 ClojureScript 作为可能的桌面前端,但那时的生态系统非常粗陋,工具似乎也很脆弱(并且,那时,Clojure 和 ClojureScript 之间的差异比现在大得多)。因此,我们决定使用 JS 和 React.js / Redux / Immutable.js 等技术构建我们的客户应用。我们有一个专门的 JavaScript 团队。

如果我们今天再次进行相同的项目,我认为我们会再次认真评估 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))))

并且让智能感知检索到 狗的规范,根据其键及其子规范提供提示。例如,帮助我以作者期望的方式使用 ::dog,而无需查看其文件。

在编译 TypeScript 之后,其并不存在,其输出是 JavaScript。TypeScript 的最大优点是它可以帮助你更快地理解别人的代码(并在避免误用方面提供一些帮助,但这并非主要优点)。
对我来说,你的评论与原始问题是否一致并不十分清楚,但如果你是在询问与函数定义集成的规范,那么这正是我们在规范第 2 版中考虑的事情。
那么,这些话又该如何解读呢?

“我是一个静态类型学的粉丝,这在有多个开发人员的项目中极为有用。

TypeScript 也带来了大量的编辑器 / IDE 工具可能性。我会说,TypeScript 是 JavaScript 最好的事情之一。”

 按我的理解,这意味着你将不断与大量的代码打交道,这些代码既没有被你编写,也没有被你或你的团队预先审查过。在企业应用程序中,有数十个带有 30+ 键的 DTO,并且命名非常不统一。典型的思考过程是:“好的,我们的函数将获得一个‘sales-deal’ DTO,我需要将其转换为‘financing-deal’并发送给分析,‘sales-deal’中的利润率属性叫什么?是‘margin’、‘markup’还是单纯的‘rate’?它已经是十进制数了吗?还是销售-deal 仍然将其作为详细的项目化率组件子 DTO?”然后对‘financing-deal’重复同样的问题...

我完全赞同“最好的事情发生在 JavaScript 部分”。遗憾的是,尝试 ClojureScript 感觉就像回到了 JavaScript - 并不好。我赞赏规范的力量,它如何帮助我在运行时和测试中。我现在想做的是,将所有这些力量都整合到我的 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类型定义 - 编译后不存在
type Dog = z.infer<typeof dogSchema>;
/*
相当于
type Dog = {
  name:string;
  neutered: boolean;
}
*/

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