V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
LeanCloudRRY
V2EX  ›  Clojure

五年 Clojure 使用者浅谈 Clojure 语言的设计

  •  1
     
  •   LeanCloudRRY · 2015-08-04 11:40:25 +08:00 · 7651 次点击
    这是一个创建于 3425 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近不知道为什么,大家好像对函数式编程的兴趣又起来了,前阵子同事在知乎有一个比较精彩的回答,转到这里。说硬不硬,了解一下也好,和 Clojure 爱好者分享一下也好。

    基于 JVM 的决定

    Clojure 能够吸引人的很重要一点是它是 JVM 之上的语言,这个决定非常关键。

    • 首先,因为根植于 JVM 之上,并且做到了跟 Java 语言的相互调用,它能吸引很多成熟的 Java 开发者。

    • 其次,它可以使用 Java 社区丰富的开源软件,不需要从头去构建一个社区,你可以看到很多 Clojure 开源代码都是简单地包装 Java 的开源包,但是通过 Clojure 高度抽象简单的语法提供更便利的使用的方式;


    • 第三,由于 JVM 平台本身的高度成熟和优化,clojure 的编译器生成的 byte code 跟 Java 编译器生成的 byte code 并无二致(不完全是),它的性能和稳定性也能马上得到保证,这比从头构建一个新平台成本低得多。

    构建于 JVM 之上,Clojure 就是一门严肃的语言,而非很多人眼中的 LISP家族中的 玩具语言,你学习后可以马上使用并且实践。但是 Clojure 又是 LISP 方言,LISP 的神奇能力它还都保留,这样兼具美学和实用的语言如何让人不爱?我相信很多熟悉 Scheme 之类方言的童鞋,并且有 Java 背景的,都会对 Clojure 有相见恨晚的感觉。

    设计原则

    Clojure 的设计原则可以概括成 5 个词汇:简单、专注、实用、一致和清晰。这不是我概括的,而是《The joy of clojure》概括的。

    • 简单: 鼓励纯函数,极简的语法(少数 special form),个人也认为 clojure 不能算是多范式的语言(有部分 OO 特性),为了支持多范式引入的复杂度,我们在 C++ 和 Scala 身上都看到了。

    • 专注:前缀运算符不需要去考虑优先级,也没有什么菱形继承的问题,动态类型系统(有利有弊),REPL 提供的探索式编程方法(告别修改 / 编译 / 运行的死循环,所见即所得)。

    • 实用:前面提到,构建在 JVM 之上,跟 Java 语言的互操作非常容易。直接调用 Java 方法,不去发明一套新的调用语法,努力规避 Java 语言中繁琐的地方 (doto, 箭头宏等等)。

    • 清晰:纯函数(前面提到),immutable var,immutable 数据结构,STM 避免锁问题。不可变减少了心智的负担,降低了多线程编程的难度,纯函数也更利于测试和调试。

    • 一致:语法的一致性:例如 doseq 和 for 宏类似,都支持 destructring, 支持相同的 guard 语句(when,while)。数据结构的一致性:sequence 抽象之上的各种高阶函数。

    • 具体到 STM,我个人认为这个特性在日常编程中,其实你用到的机会不多。在 web 编程里,你的并发模型 Web Container 已经帮你处理(tomcat,jetty),事务也是数据库帮你处理,几乎找不到场合去使用 STM。这个特性在做一些中间件或者底层 framework 的时候才可能用到。这个特性的设计上面已经提到,跟 clojure 的设计目标是紧密相关的,跟 immutable 数据结构也是密不可分,同时它也不是没有代价,事务历史记录和慢事务频繁回滚的代价,有时候你还是需要退回去使用 Java 那套锁机制,庆幸的是 Clojure 不阻止你去使用,并且提供了类似 locking 这样的宏来方便你使用。

    缺陷

    Clojure 的设计缺陷不能说是缺陷,这是由于它设计的目标决定的,有得必有失。

    • 首先还是 JVM,基于 JVM 有种种好处,但是 JVM 的启动速度实在悲剧,因此用 Clojure 写一些小的 script 处理日常事务,显得还是不够得心应手,这样的工作我还是用 Ruby,Python 的脚本语言来搞定更便捷。不过目前 Clojure 有一些其他语言之上的实现,比如 clojure-pyjoxaclojureclr 这些实现应该会比 JVM 的启动快很多(抱歉,我没测试过)。

    • 不仅如此,因为 Clojure 跟 JVM 平台的绑定如此之深,并且为了真正发挥 Clojure 的威力,你还需要去熟悉 Java 平台的东西,熟悉 Java 语言、类库、内存模型、GC 优化、多线程和网络编程、开源类库等等。可以这样认为:想成为一个好的 Clojure 程序员,首先需要是一名好的 Java 程序员。这也一定程度上阻碍了 Clojure 的推广,提高了学习成本。

    • 其次,Clojure 的 API 设计上,有时候不符合你的直觉,而是符合 Clojure 的哲学,比如 contains?函数对 vector 等数组型集合的调用上。关于这一点,Rich 的回答是Elegance and familiarity are orthogonal.,也就是优雅和熟悉是正交关系的。保持 API 内在的一致性,比直觉的熟悉更重要,这是更深入思考、理性的直觉。

    • 第三,弱类型的好处足够多,灵活,减少声明代码,适合探索式编程;同样,坏处也不是没有,没有类型保障,错误可能要等到运行时才能发现,静态代码检查工具也没有办法帮你发现,这就需要你一定程度的测试代码来保证运行时行为。

    • 第四,性能上,虽然 clojure 生成的字节码已经很高效,也有 type hint 这样的技术来帮助提升性能,但是会有不少的转型 (checkcast)、装箱和拆箱(boxing and unboxing)以及类型判断分支跳转的多余指令,这在一些性能敏感的应用里可能会暴露出来。尽管我认为大多数网站型的应用瓶颈都会落在 IO 上。

    总之, Clojure 是一门精心设计的、完全融入作者对编程的思考的、富有生产力的现代编程语言,值得每个对生产效率、函数式编程、并发编程有兴趣的朋友深入了解下。

    作者:Dennis Zhuang LeanCloud Tech Leader

    备注:LeanCloud 采用了多种语言混合来构建整个后端系统,包括 Clojure、Java、Node.js、Scala 等。其中 Clojure 构建了整个网站门户、存储开放 API、推送、聊天等核心服务,Node.js构建了云端代码服务(类似应用代码托管),我们还使用 Scala 编写的 Spark 任务来处理离线数据分析,此外,还有大量的统计类 MapReduce 任务使用 Java 编写并运行在 Hadoop 集群上。不同服务之间使用 RESTful 协议、RPC 框架或者队列进行通信。

    4 条回复    2021-01-04 09:52:49 +08:00
    faywong8888
        1
    faywong8888  
       2018-04-15 22:30:13 +08:00
    +1
    ZoomQuiet
        2
    ZoomQuiet  
       2018-07-22 20:30:24 +08:00
    是也乎,( ̄▽ ̄)

    简单的说, 只有 资深的 JAVA 工程师, 才能真正用起来 Clojure
    Subfire
        3
    Subfire  
       2019-12-23 20:21:14 +08:00
    boss 直聘一搜 Clojure, 缪缪不到 1 页, 搜 Golang 等, 几千页...
    AndyAO
        4
    AndyAO  
       2021-01-04 09:52:49 +08:00
    @Subfire #3

    想到两本书上对类似现象有意思的描述

    ...

    举例来说,假设你需要写一个软件。你的经理根本不懂这个软件的运作机制,也不知道各种编程语言有什么区别。但是,他竟然明确要求你一定要使用某一种语言进行开发。没错,他就是要求你一定要用 Java 语言。

    为什么他会提出这种要求?让我们看看他脑袋里是怎么想的。他的想法无非就是,Java 是业界的标准。我知道肯定如此,因为媒体对此有铺天盖地的报道。既然它是标准,那么使用它就不会错。另外,这也意味着人才市场上肯定有无数 Java 程序员,即使现在为我打工的这批人都辞职了(真奇怪,这种事情总是不断发生),我也能够轻易地找到替代者。
    嗯,这听起来也不无道理。但是,它的前提是一个没有说出口的假设,而这个假设实际上是错的。你的经理相信所有编程语言的功能都差不多,可以互相替代。如果这种想法是对的,那么他要求你用 Java 编程就很合理了。反正编程语言之间没有区别,那么就用大家都在用的那种语言吧。

    但是,编程语言是不一样的。就算不探讨各种语言之间的具体区别,我也能向你证明这一点。回到 1992 年,如果你问经理使用什么语言开发软件。他会像今天一样毫不迟疑地回答说 C++。如果所有编程语言都一样,为什么答案变了?进一步说,为什么 Java 语言的设计者要如此麻烦地去创造一种新语言呢?

    一般来说,如果你动手创造一种新语言,那是因为你觉得它在某些方面会优于现有的语言。

    ...

    From:Hackers & Painters


    ...

    首当其冲的是,亚马逊的主流语言里有两门非常啰嗦的语言 C++和 Java,外加门精练的语言 Perl 。但是 Perl 正受到排挤,渐渐退出主流。我觉得这是因为 Perl 程序员能用更少的人力完成和 Java/C++程序员同样的工作量,所以要是比人多的话,他们注定是赢不了的。根据我们的估算,亚马逊的代码量比它的功能数量膨胀得更快。

    ...

    From:A Programmer's Rantings
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1468 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 17:10 · PVG 01:10 · LAX 09:10 · JFK 12:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.