为什么 Java 开发者会对 Node.js 和 JavaScript 如此激动?

直到最后一口气,在Sun Microsystems的Java SE团队工作10年以上的人难道不应该流出Java字节码并实例化抽象接口么?对于这位前Java SE团队成员来说,2011年学习Node.js平台是一股清流。在2009年1月从Sun被解雇之后(就在Oracle收购之前),我学习了Node.js并且迷上了它.

怎么迷上了?自2010年以来,我撰写了大量关于Node.js编程文章。即,Node.js Web开发的四个版本,以及关于Node.js编程的其他书籍和众多教程博客文章。这些文章很多时间解释了Node.js和JavaScript语言的进步。

在Sun Microsystems工作期间,我相信一切皆java。我出席过JavaONE会议,共同开发了java.awt.Robot类,运行了Mustang回归竞赛(Java 1.6版本的漏洞发现竞赛),帮助推出了OpenJDK之前的“Distributions License for Java”回答Linux发行版分发JDK版本,后来在启动OpenJDK项目中扮演了一个小角色。在此过程中,我在java.net(一个现已解散的网站)上发布了一个博客,每周写1-2次,讨论Java生态系统中的事件约6年。一个重要的主题是保护Java免受那些预测Java死亡的人的影响。

为什么 Java 开发者会对 Node.js 和 JavaScript 如此激动?

Java元码发生了什么?我在这里的目的是解释这个纯粹的Java倡导者是如何成为一个纯粹的Node.js / JavaScript倡导者。

我并没有完全脱离Java。在过去的3年中,我编写了大量的Java/Spring/Hibernate代码。当我完全享受这项工作的时候——我在太阳能行业工作过,做过一些让人精神振奋的事情,比如编写关于千瓦小时的数据库查询——用Java编程已经失去了它的光彩。

基于 Spring 的两年编程经验带给我一个非常深刻的教训:掩盖复杂性并不能造就简单,那只会让事件变得更复杂。

TL;DR

  • Java 中充斥着样板代码,他们掩盖了程序员的真实意图
  • Spring & Spring Boot 带来的教训:掩盖复杂只会变得更复杂
  • Java EE 就是个”设计委员会“项目,它涵盖了企业应用开发的一切事务,复杂无比
  • Spring 的编程体验非常棒,直到有一天,一个莫名其妙的异常从一个你一点也不了解的深层子系统中冒出来,让你花了至少 3 天来搞明白遇到了什么问题
  • 零代码框架的会带来怎样的代价?
  • 像 Eclipse 这样的 IDE 非常强大,但它也揭示了 Java 的复杂性
  • Node.js 是从轻量事件驱动架构中提炼出来的产物
  • JavaScript 社区似乎很乐意抛开样板代码,让程序员们的思想自由闪耀
  • 用于解决回调地狱的 async/await 函数就是一个去除样板,拥抱创造的例子
  • 使用 Node.js 编程让人身心愉悦
  • JavaScript 缺乏像 Java 那样严格的类型检查,这有利有弊,因为写代码变得容易了,但却需要更多测试来保证其正确性
  • npm/yarn 包管理系统非常棒,非常好用,比可恶的 Maven 不知道好到哪儿去了
  • Java 和 Node.js 都有出色的性能。并不是不像有人说的那样,因为 JavaScript 慢,所以 Node.js 性能低下
  • Node.js 的性能利益于 Google 为了给 Chrome 提速而投入开发的 V8
  • 浏览器之间的激烈竞争使得 JavaScript 一年比一年强大,这是 Node.js 的福音

Java已经成为一个负担,使用Node.js是充满快乐的

有些工具或物件是设计师花了数年打磨和改进的结果。他们尝试了不同的想法,删除了不必要的属性,最终得到了一个对象,该对象的属性恰好合适。通常这些对象有一种强大的简单性,非常吸引人。Java不是那种系统。

Spring是开发基于java的web应用程序的流行框架。Spring(特别是Spring Boot)的核心目的是使用预先配置的Java EE堆栈。Spring程序员不需要连接所有servlet、数据持久化、应用服务器,谁知道还有什么,就可以获得完整的系统。相反,Spring负责处理所有这些细节,而您则专注于编码。例如,JPA Repository类用“findUserByFirstName”之类的名称来综合数据库查询方法——您不需要编写任何代码,只需将以这种方式命名的方法添加到存储库定义中,Spring就会处理剩下的问题。

这是一个很棒的故事,也是一次很好的经历,直到它没有了。

当您得到关于“传递给持久化的分离实体”的Hibernate PersistentObjectException时,这是什么意思?这花费了好几天的时间——冒着过于简化的风险——这意味着到达REST端点的JSON具有带值的ID字段。Hibernate,重载,想要控制ID值,并抛出这个令人困惑的异常。有成千上万同样令人困惑和迟钝的异常消息。在Spring堆栈中一个接一个的子系统中,就像一个复仇女神坐在那里等着你犯最小的错误,然后用一个应用程序崩溃异常来攻击你。

然后是巨大的堆栈跟踪。他们在几个屏幕上展示了很多抽象的方法这个和那个。Spring显然正在制定实现代码内容所需的配置。这个抽象级别显然需要相当多的逻辑来查找所有内容并执行请求。长堆栈跟踪并不一定是坏事。相反,它指出了一个症状:内存/性能开销成本到底是多少?

零编程的情况下,“findUserByFirstName” 会怎样执行?框架必须解析方法名,猜测程序员的意图,构造一些类似于抽象语法树一样的东西,生成 SQL 等等。这会带来什么样的开销?难道这样程序员就不需要写代码了吗?

有过数次这样的经历后,你需要花数周时间去学习原本不需要学习的深奥知识,然后得出和我一样的结论:掩盖复杂性并不会让事情变得简单,只会让事情变得更复杂。

重点关注下 Node.js

为什么 Java 开发者会对 Node.js 和 JavaScript 如此激动?

“兼容性问题”是个非常酷的口号,它表示 Java 平台的关键价值主张是完全向后兼容。我们对此非常认真,甚至把它像上图一样印在 T 恤上。保持这种程度的兼容性可能会是个非常沉重的负担,而有时候避免使用陈旧无用的方法,本身很有效。

Node.js 的另一面…

相比于 Spring 和 Java EE 的异常复杂,Node.js 是一股清流。首先是 Ryan Dahl 在开发 Node.js 核心平台所用的设计美学。Dahl 的经验是在重量级复杂系统中使用线程。他寻求不同的东西,并花了几年时间打磨和改进了一系列核心思想,并将之在 Node.js 上实现。最终完成一个轻量级系统,一个执行线程,巧妙地使用 JavaScript 匿名函数进行异步回调,以及一个巧妙地实现异步性的运行时库。最初的目标是高吞吐量的事件处理,并将事件传递到回调函数。

然后还是由于 JavaScript 语言本身。JavaScript 程序员似乎具有去除样板代码的审美,因此程序员的意图是可以清晰地发挥作用的。

对比Java和JavaScript的一个例子是侦听器函数的实现。在Java中。侦听器需要创建抽象接口类的具体实例。这需要大量的空话来掩盖正在发生的事情。在样板文件的面纱后面,程序员的意图是什么?

在JavaScript中,一个使用简单的匿名函数——闭包。您没有搜索正确的抽象接口。相反,您只需编写所需的代码,而不需要过多的冗余。

另一个学习:大多数编程语言都模糊了程序员的意图,使得理解代码变得更加困难。

这个点指向Node.js。但有一个警告,我们必须处理:回调地狱。

解决方案有时也会带来问题

在JavaScript中,异步编码长期存在两个问题。一个是Node.js中所谓的“回调地狱”。很容易陷入深度嵌套回调函数的陷阱,在这种情况下,每一层嵌套都会使代码复杂化,从而使错误和结果处理变得更加困难。另一个相关的问题是JavaScript语言没有帮助程序员正确地表达异步执行。

出现了几个库,它们有望简化异步执行。另一个掩盖复杂性的例子创建了更多的复杂性。

相关推荐