本文要点
Ecastasy 是为云构建的通用、类型安全的模块化编程语言
构建 Ecastasy 的团队计划将其用作高度可扩展的平台即服务(PaaS)的基础
Ecastasy 仍在开发中,尚未准备好用于生产
Ecastasy 团队正在寻找贡献者,共同定义我们行业的未来
Ecastasy 由前 Tangosol 创始人Cameron Purdy和 Gene Gleyzer 共同创建,最近他们在CloudNative 2019伦敦大会上展示了这一语言。在创办xqiz.it,也就是 Ecstasy 项目的赞助商之前,Purdy 是 Oracle 的高级副总裁,负责企业级 Java、WebLogic、Coherence、Traffic Director、HTTP、JDBC 和 Exalogic 等产品。InfoQ 采访了 Purdy,探讨了这门语言本身及其旨在解决的问题等话题。
InfoQ:什么是 Ecastasy 语言(XTC)?
Cameron Purdy:Ecastasy是一种为云构建的通用、类型安全的模块化编程语言。我们总结了过去 30 年的经验,去芜存菁,将其提炼成了一种易于理解的语言。
某种程度上来说,我真希望当初能用这种语言来构建 Tangosol Coherence;我希望当初能用这种语言来构建 Web 和后端服务的应用程序;我希望在开始构建 Oracle Cloud 的一部分基础架构时也能用上这种语言。
它是一种专注于安全性、可组合性和可读性的语言,而其设计意图非常明确,可用于存储库、持续集成(CI)、Devops、持续部署(CD)、云和客户端可移植性、边缘计算/CDN/5G 集成以及地理分布式系统。
它也不只是一种新语言而已。Ecastasy 语言基于新的托管运行时,使用一种新的指令集编译为全新的可移植二进制格式,这种运行时的设计支持即时(JIT)、预先(AOT)和自适应编译。
InfoQ:参考文档上的内容(如果我理解正确的话)似乎暗示它绝对不是一种系统编程语言?
Purdy:它不是系统编程语言。我的意思是,我们没有将这种语言设计为用于编写操作系统或操作系统驱动程序的用途,它也不是用于管理内存或编写文字处理器的语言。当然,作为一种通用语言,理论上你能用它做任何事情;但语言是为特定目的而构建的,而这种语言是为帮助开发人员在云中编写和发展应用程序而诞生的。
这些应用会在各种云提供商的数据中心内执行,在云提供商的 CDN 内运行,在电信公司的 5G 基础架构内执行,抑或上至各种 ISP 的边缘,下至客户端的设备,甚至在这些客户端上运行的浏览器中执行。
我们的目标是,程序员只要了解 Java 或 C#(我曾大量使用这两种语言编程)或 Swift,就能无需学习过程,直接读懂 Ecastasy 代码;并且只需花费几小时或几天时间学习 Ecastasy 后,就能编写它的代码。尽管这种语言的许多功能对于 C 和 C++开发人员也是非常眼熟的,并且它在技术上属于 C 语言家族,但这些语言的用户并不是我们的主要目标群体。使用 Kotlin、Python、Erlang、Elixir、Smalltalk 或 Ruby 的程序员也应该能快速上手 Ecastasy;Ecastasy 中的许多语言思想和功能已经出现在了这些语言中,或正在被它们采纳。
像 Java 和 C#一样,Ecastasy 也是为托管运行时环境而设计的;但凭借后发优势,我们的设计能够充分利用托管运行时环境的理念好处。一个明显的例子是关于线程的:Ecastasy 没有将线程的概念暴露给开发者,因为这会让运行时无法动态管理并发。(在语言中隐藏线程还有其他很多好处,例如避开了在开发人员尝试编写正确的并发代码时遇到的所有陷阱。)在 Ecastasy 中,如何在可并发和可异步的任务之间分配线程,是运行时来决定的事情;某种程度上来说,我们是将 Java 语言中“Hotspot”自适应编译器的理念应用到了并发和线程问题上,从而允许运行时使用运行代码时收集到的经验数据,来优化相同代码之后的执行工作。此外,Ecastasy 是为预先(AOT)编译而设计的,这意味着可以在执行代码之前完成繁重的编译和优化工作;至于自适应编译则意味着,长时间收集到的信息和作出的优化可供未来使用——甚至在应用程序停止时也能发挥作用。
我们还认识到,自 1990 年代 JVM 和 CLR 发明以来,硬件已经发生了翻天覆地的变化。在过去,价值 10 万美元的高端服务器也只有 2 到 4 个并发的硬件线程,也许还有几 GB 的 RAM——如今一款现代智能手机也能轻松超越这些参数。当我们坐下来开始设计 Ecastasy 时,我们的目标是让它在强大的服务器上也能充分发挥硬件优势,这种服务器可能会在单个进程中拥有数十 TB 的 RAM,并且在单个进程中拥有数千个并发硬件线程。很快,我们消除了诸如“线程”和“同步”之类的语言概念,并增加了诸如不变性之类的概念;我们也有意消除了诸如“堆”之类的潜在限制。通过采用内置的参与者模式(就像 Smalltalk 的 messages 和 Erlang 的 processes),我们使架构师或开发人员可以轻松地将其应用程序细分为可并发的单元,Ecastasy 称之为服务。内存、线程和安全性的规则都是用服务来描述的,回过头来看这是非常明显的。
这种语言的美感在它的类型系统上也体现得很明显。Ecastasy 是静态类型的,具有出色的类型推断和泛型化等优点,但远不止于此:其类型系统的设计与运行时是一致的。换句话说,我们用一致的方式设计了这两套组件,这样类型系统就能在运行时的定义内起作用,而运行时从类型系统的角度来看也是有意义的。甚至属性、变量和对象引用都是对象,因此运行时反射就变得很自然,并且运行时和类型系统成为了共生体。在这方面的一些决定非常重要,包括设计了类型系统上可证明的闭包,支持分层次(可嵌套)运行时容器,以及安全、动态的代码加载设计。
InfoQ:对于 crates/npm/dep 之类的东西有什么计划(这些地方有很多关于不做某事的教程)?
Purdy:在设计语言和运行时时,这是一个我们非常关注的领域。我们的部分思想受到我们构建库、框架和应用程序的经验影响,这些成果被用在了各种不同的环境中,与其他各种库、框架和服务器共同使用。
例如,很久以前的某个时候,我工作的公司正在使用 SAX 或 DOM 库进行 XML 解析。有一天,有人引入了一个完全不兼容的 API 更改,这迫使我们必须选择针对旧版或新版进行编写和构建,不管选哪个都要完全切断到另一个版本的关系。更糟糕的是,这个库包含在许多不同的应用服务器中,因此这些应用服务器的较旧版本也会有这个库的较旧版本,而应用服务器的较新版本也会有这个库的较新版本。那时,我们的用户分布在许多应用服务器的众多不同版本上,并且一夜之间,我们更新时就不能再附带这个 Apache XML 解析器的依赖项了!所以——我没在开玩笑——我们不得不编写自己的 XML 解析器(以避免依赖项),然后一年又一年不断地支持它!
另一个例子是,我们希望自己的产品与 Spring 兼容,因此我们与 Spring 开发人员进行了一些联合开发;但是为了避免对 Spring 的强依赖(当时我们的许多客户没用过它),同时也为避免 Spring 对我们的任何强依赖,我们必须通过反射来做所有集成!因此,本来应该只用一行代码就解决的东西却要占用 20 行代码,而这种复杂性必须四处散布。类似地,我们添加了对 Hibernate 和 Solarmetric KODO 的插件支持,但是现在,这些“可选”库的各种组合却带来了组合而成的复杂性。通过反射可以在 Java 中实现模块化,但这会带来巨大的痛苦。有一次,我们甚至尝试使用 OSGi 来看看它能不能简化一些东西,但结果却变得更加复杂。
在与其他公司合作构建应用程序的过程中,许多类似的问题不断涌现,因此我们从所有这些经验中汲取了教训,并着手从头开始设计 Ecastasy 以解决这些问题。首先,我们将编译单元设计为一个模块——或者可以选择用一组模块,当模块之间存在循环依赖关系时这很有必要。接下来,我们允许模块(并且只有模块)以统一资源标识符(URI)的形式声明其自己的通用身份,从而将存储库支持嵌入了进来。当模块上存在依赖项时,该模块依赖项会表示为 URI,我们就会说这个依赖的模块已导入。
稍有点偏题了,但是导入模块如此简单,其机制如此优雅,这真的很棒:导入的模块在导入它的模块内部表示为一个包(也就是命名空间);就好像导入模块的所有内容都已复制到了这个包中,因此它们都可以通过本地名称访问,就像它们会出现在这个包中一样。例如,每个模块都会自动将(URI)"Ecstasy.xtclang.org"模块作为"Ecstasy"包导入,因此,来自 Ecstasy 模块的"collections.HashMap"类将作为"Ecstasy.collections.HashMap"类出现在所有模块中。
构建模块时会在其上标记一个版本。一般来说这个版本会是开发版本或 CI 版本。这个版本还包含一个符合Semantic Versioning 2.0.0规范的版本号,并且这个版本标记是可更新的,因此通过所有测试的 CI 版本可以被标记为 QC 或预发布版本。当构建准备好发布时,可以删除预发布标记。这些都是为了自动化而设计的,其灵活性足以匹配组织的现有流程。
模块的设计在另一个层面来看也是很独特的:单个模块可以包含同一模块的许多不同版本。当一个模块的两个不同版本组合在一起时,增加的模块体积只是两个版本之间存在差异的部分。这样一来,单个模块文件即可包含其支持的所有版本,再加上未来版本的预发行版,以及较早版本的可选补丁,等等。这一功能背后的理念是让模块可以轻松地向前和向后滚动,轻松进行 A/B 测试,并安全地提供可选补丁,所有这些都可以在单个交付中完成。
模块依赖不一定是硬依赖。例如,应用程序可以指定需要模块"A",期望模块"B"(也就是说,如果可以找到这个模块就链接到它),并且支持模块"C"(也就是说,如果依赖图中的其他模块导致这个模块被链接,则只链接到这个模块)。另外,模块可以被嵌入,这意味着它实际上被包含在嵌入它的模块中;这种能力主要是用来支持从多个模块构造而来的单个模块(出于组织或其他原因)的交付。
但最强大的方面则是这些功能的组合方式。具体来说,一个模块在运行时不一定存在(present)另一个模块,并且如果这个模块存在,也不一定是某个特定版本,不一定包含特定的类或功能。这就是我们以前所说的 DLL 地狱。Ecastasy 为类和代码的存在(presence)提供了一种方法,可选以版本或其他类的存在为条件,并且编译器将把这些条件编译到生成的模块中,具体做法和将多个版本放入同一模块的做法相同。换句话说,这个模块可以同时支持另一个模块或特定版本的存在与否,并且这个解析过程是动态链接过程的一部分。这允许模块避免对某个模块,或模块特定版本的硬依赖,同时仍与这些模块或版本(如果它们存在)完全集成并充分利用它们。
并且由于所有这些信息都被编码到了模块中,因此所有这些组合的测试都能完全自动化。说到测试:单元测试、功能测试和集成测试也可以内置到模块中,并且——就像不需要的版本一样——在生产环境中使用模块时就不会存在测试了。
到现在为止应该已经很明显了,我们考虑了很多事情,并且在设计上付出了很多努力。但为什么要这样做?其中一个原因是考虑到 CVE 和零 day,以及生产中引入的重大更改。想象一下,你需要的时候手头已经有了一个“已使用哪些版本测试了哪些版本”的矩阵。想象一下,模块中任何给定版本的回归和验收测试已经内置进了这个模块的对应版本中。想象一下,能够在 A/B 部署中推出新补丁,并以可以实时将隔离环境中补丁的效果与要替换的版本进行对比,提前确定最终用户将看到哪些实际更改。
支持这些功能的设计已经到位,但是工具和自动化(依赖于这些基础功能)尚未构建,并且仍然有一段路要走。
InfoQ:针对 DevOps 的设计目标是否会扩展到支持渐进式交付?
Purdy:是这样的,但这并不是一件容易的事。我们首先要明白的一件事是应用程序几乎总是存在版本偏移,而渐进式交付只是版本偏移的一个例子。每当你同时运行一个应用程序的两个不同版本时都会发生版本偏移。偏移可能出现在应用程序的旧版客户端和新版服务后端之间,也可以出现在后端的各种服务器实例之间。不管怎样,它对协议互操作性和状态兼容性提出了强制要求,而这种要求本身就很重要。关于状态,旧版本的代码必须能够与新版本的数据非破坏性兼容,并且新版本的代码必须能够接受(并可以自动升级)旧版本的数据。
我们首先认识到,版本偏移并不是反常现象,而是普遍存在的情况,几乎在任何有分量的应用程序中都会出现这种情况。从几年前设计可移植对象格式(POF)规范的工作中,我们就对该主题积累了一些经验,这一规范支持向前和向后的 schema 兼容性。事实证明,接受并支持安全版本偏移是许多强大功能的基础,包括渐进式交付、增量发布、传统的 A/B 测试(及其自动化)等等。在横向扩展环境中,为避免服务中断,服务器将使用新版本的应用程序启动,而装载旧版应用程序的服务器将继续运行一段时间。(当新版本的发布出现问题时,情况甚至可能会更加复杂,并且必须将应用程序回滚到以前的版本,因此新版本不能以某种方式更改应用程序的持久状态,使得旧的应用程序无法继续运行。)因此,我们在对象序列化和数据库接口设计方面所做的所有设计工作,从一开始就有这个要求。
结合强大的模块版本控制功能和资源注入(这是应用程序与外界通信的唯一方式),这允许自动化基础架构同时运行新版本(启用所有测试模式功能)和旧版本,同时将新版本保留在"盒中",以使其状态更改不可见,并且它对客户端的响应实际上并未传递;这样一来,就可以在生产负载和数据上试用新版本,而不会冒着损坏生产数据库的风险,也不会影响最终用户。同样,自动化基础架构可以用相同的方式发布升级,方法是逐步启动和预热运行新版本的服务器,然后逐渐减少从旧版到新版的流量;如果发生故障,可以逆转这一过程。理想情况下,应用程序的新版本将在生产中运行一段时间,然后再将实际的生产负载从旧版转移到新版——这段时间的长度要足够证明新版没有明显的退化。类似地,可以从一个小子集开始转移流量,同时继续将大多数流量路由到旧版本,这样在最终用户与应用程序交互后才发现问题的情况下,对最终用户的影响往往就能控制在最低限度。
数据库 API 的设计的一个目标是最终允许有状态系统在分层组织的基础架构中运行。我们的目标是允许应用程序的某些部分在内容交付网络(CDN)和边缘层,直到 5G 基站中都能运行。为了实现这一目标,Ecastasy 被设计为一种安全的可嵌入语言,并且数据库 API 的设计使用了基于参与者的模型,也考虑到了工作单元和最终的一致性。最终目标是支持这些 API 一路直达客户端级别,从而允许应用程序在间歇连接和脱机模式下也能正常运行。这些功能仍然处于蓝图之上,但我们打算提供概念证明,展示我们在完成这些 API 的初始版本时会怎样支持这些能力。
InfoQ:WASM已经在一些领域展现了生机,那么是什么让你们选择了 XTC?
Purdy:首先明确一点,我们尚不支持 WASM,但这是我们设计的编译目标之一,作为原生 x86/x64 和 ARM 的补充。Ecastasy 的一个目标是支持从前端的最前级到后端的最后级的所有共享组件。这意味着编程模型必须能一路可移植到浏览器中,因为浏览器占到客户端的很大一块比例。(在此之前还要能在 iOS、Android、macOS 和 Windows 客户端上原生运行)。
如果你以浏览器为目标,就必须转换为 JavaScript 或编译为 WASM。由于我宁愿砍掉自己的胳膊也不愿生成大量的 JavaScript 来调试,因此这个选择很简单。还要记住LLVM已经支持了 WASM:WASM 是 LLVM 项目中的一等公民(代码生成目标),而我们计划的编译后端一直都是 LLVM。
InfoQ:谁会使用这门语言,他们将如何使用它?
Purdy:我们已经在自己的产品开发工作中开始用它,然后发现用了 Ecastasy 后就很难换回一种较旧的语言了。这种语言令人上瘾。另一方面,这种语言仍处于积极开发阶段,因此尚未迎来自己的黄金时段;也就是说,它尚未准备好用来构建现代应用程序。除非你真的很喜欢语言、编译器和工具链开发,否则现在还不是采用 Ecastasy 的时候。
它在接下来的 24 个月内就可用于生产环境,我们也知道哪些人会用它。有些开发人员在为云构建应用程序,这些应用程序必须运行在多种客户端上,还要使用有状态的无服务器后端部署。还有些开发人员重视自动化、可维护性、可管理性,希望语言能减少软件生命周期的巨大成本。
在过去的 25 年中,我合作的大多数公司都花费了 95%的 IT 预算(通常甚至更高!)来维持旧事物的运行。想要投入新的开发工作,甚至为现有的应用程序带来巨大的发展,往往都是非常困难甚至无法做到的。这么久以来,我们第一次有机会颠覆这种成本模型。Ecastasy 是思想上的巨大变革。
这种语言是免费和开源的。所有的内容都是如此。运行时、工具链、库,所有的一切,完全开放。我们使用标准的 Apache 开源许可证。你可以 fork Ecastasy,你可以嵌入 Ecastasy。Ecstasy 商标归 Ecstasy 项目(该语言的维护组织)所有,但是除品牌之外,所有公司和开发人员可以使用这种语言做任何事情。
InfoQ:它会不会陷入无服务器和 Kubernetes 之间的夹缝中呢?
Purdy:这是第一种专为无服务器设计的语言。这听起来像是在吹嘘,但其实不然。之前的所有语言(除了 JavaScript 等几种例外)都是作为分层蛋糕构建的,构建在在原生类库和实现之上,在操作系统之上(能在系统中暴露的表面都暴露出来了),在物理机器之上。问题在于每一层都没有将自己下面的层隐藏起来,而这个错误是有意为之的!
看看现在的亚马逊是如何实现无服务器的:它们实际上为你提供了你自己的服务器。(是的,所有操作都在幕后完成,但这就是它的工作机制。)为什么? 因为你的无服务器负载可以对环境、操作系统和“机器”(显然是虚拟机)做任何事情,所以他们不会冒风险让多个帐户共享这台机器。
Ecastasy 不会暴露机器,或操作系统,或在操作系统中可以找到的任何库。相反,它使用的是控制反转(IOC):Ecastasy 将资源注入到应用程序中,而不是允许该应用程序遍历计算机以查找其所需的资源。需要数据库吗?注入它。需要文件系统吗?注入它。块存储?注入它。HTTP 访问?注入它。网络服务?注入它。历史上第一次,一种语言的设计明确隐藏了运行应用程序代码的整个宇宙,并且这是第一次一种语言允许所有不同的资源,按照托管应用程序的(Ecstasy)容器的意愿来完全管理。这是一种从根本上为安全设计的语言,而不是事后通过某些安全事物层来确保安全性。
因此,从设计之初 Ecastasy 就是无服务器的。对于 Kubernetes 而言,这是一个令人惊叹的工程解决方案,可以解决最初就不应该存在的极其复杂的问题。我希望 Kubernetes 会做得很好,因为有许多项目都与过去的事物紧密相联,而 Kubernetes 是让那些复杂的草皮球继续滚动的阻力最小的途径。
看,是时候改变了。如今,构建一个应用程序太昂贵了——通常需要开发人员将数十个甚至数百个库和组件整合在一起。只要看看 Node 或其他类似的语言即可; 这些事物几乎不可能维护,也难以保证安全性
我希望 Ecastasy 就是变革。
受访者介绍
Cameron Purdy 是 11x 开发人员,是 Ecstasy 编程语言的共同创建者,并且是 Oracle Coherence 的合著者。Cameron 是 xqiz.it 的联合创始人兼首席执行官。之前,他是 Tangosol 的联合创始人兼首席执行官,该公司被 Oracle 收购;并曾担任 Oracle 的高级副总裁,负责企业级 Java、WebLogic、Coherence,Traffic Director 和 Exalogic 等产品。Cameron 是 Java 语言和虚拟机规范的贡献者,便携式对象格式(POF)规范的作者,并且在分布式计算和数据管理方面拥有大量专利。
原文链接:
Newly Announced Ecstasy Programming Language Targets Cloud-Native Computing
评论