摘要:作为一门深受开发者喜爱的编程语言,JavaScript 的应用广泛,也不断有新的开发者在尝试使用它搭建新的程序。但同时,许多人发现,JavaScript 项目总是在时隔几个月后,就出现不少问题。
链接:
https://pouria.dev/programs-are-dead/
声明:本文为 CSDN 翻译,未经允许禁止转载。
曾几何时,你是否曾厌倦了自己所做的一切工作,烦透了屏幕上的每一个亮点,于是一个大胆的想法在你的脑海中闪现——“我可以创建一个程序!”只要一个简单的程序,就可以解决问题,让自己的生活更轻松。如果幸运的话,同事们可能也会喜欢这个程序,每个人都将露出笑容。
于是,你坐下来,开始编写你的 JavaScript 项目。只需敲入几个命令,就可以安装所需的一切。你的服务器架构和前端界面都在同一个地方。
接下来,你添加了一些库,并尝试了 TypeScript,所有代码都可以很好地协同工作。用了很短的一段时间,你就编写好了一个可以正常运转的程序。从酝酿最初的想法,到编写出最终的程序,整个过程快到令人难以置信。
几个月后打开程序,出现一连串的问题
这一天终于来了。你对自己构建的产品感到自豪,你决定与全世界分享你的程序。事实证明,确实有很多人喜欢你的程序。你的 GitHub 代码库获得了大量 Star,而且日常用户数量也很庞大。
六个月过去,虽然你几乎已经忘记了自己的小项目,但现在你有了一些更好的新想法。这个项目还有一些悬而未决的问题和功能请求,于是你又重新打开了项目。
你按捺着激动的心情,低声对自己说,来吧。你打开终端,运行 npm install,然后一边等待 npm 安装依赖项,一边浏览网页。片刻之后,你看了一眼终端,却发现屏幕上显示了一个……错误!再次运行 npm install,并仔细观察,红色的错误仍然在——可是,在过去的六个月里,你甚至没有碰过这些代码,究竟怎么回事?
仔细检查错误,你注意到构建二进制插件的某个 node-gyp 包出了问题,因为这个包与你的新操作系统不兼容。之前你也遇到过类似的问题,也已经修复了这个问题,但这一次的错误消息有点不同。你仔细研究了一番,但没有找到合适的解决方案。
两个小时过去,你放弃了。反正你也不需要压缩那么多图像,所以只需要删除这个依赖项就好了。当然,这只是临时的解决方案,你想着等完成其他工作以后再来添加。于是再次运行 npm install,谢天谢地,这次终于没有错误了(其实,还有 50 个严重的漏洞,只不过此刻你还不知道,至少你可以启动应用程序了)。
你的应用程序终于可以运行了,现在你可以添加自己想到的新功能了。为此,你需要最新版本的 Next.js,而它依赖于最新版本的 React。你注意到 Next.js 的主要版本已经升级了两次,所以现在必须立刻升级。你的应用程序目前使用的版本已经旧了、很慢、很低效,再过几年,就有可能落后 4~6 个主版本,还是赶快升级比较好。
于是,你更新了 Next.js 和 React,并再次尝试运行应用程序。这时,你又遇到了一个错误。你使用的 CSS-in-JS 解决方案与这两者都不兼容,而且状态管理器库也不能正常工作,因为该项目已被维护者放弃,另外现在还要解决 TypeScript 的问题,还有一堆不能修复的漏洞,因为修复这些漏洞会进一步破坏应用程序。我只能默默地祝你好运了!
经过漫长的努力,你终于设法解决了所有问题,并将新功能添加到了应用程序。你长长地舒出一口气,心想自己付出的这些努力是否值得。你问自己,如果再过几个月,你还会想再次打开这个项目吗?你相信一切都能正常工作吗?你信得过 JavaScript 及其生态系统吗?
根据我个人过去五六年使用 JavaScript 的经验,每次打开一个老项目——无论规模大小、也无论是服务器端还是前端,总会遇到各种问题。如果想开发新功能,甚至有时只是想运行程序,都首先需要克服重重障碍。
刚开始,我以为这只是我个人的问题,可能我缺乏经验,不知道如何使用这门编程语言及其工具。但即便如此,为什么一门编程语言会出现这样的问题?为什么这么容易出错呢?我认为,编程语言应该帮助我们,给我们信心和力量,减少错误,引导我们朝着正确的方向前进,而不是不断地让我们产生自我怀疑,以为自己做错了什么,找不到正确的方法。
我知道,上面提到的这些问题涉及整个 JavaScript 生态系统,而不仅仅是语言本身,也许有人会说把一切责任推到 JavaScript 头上是不公平的,但我认为语言本身也难辞其咎。这些问题涉及范围甚广,而且并不简单,不能归结成依赖系统等问题。语言有责任为程序提供上下文和环境。当我们谈论一种编程语言时,我们指的是一个整体以及用户的使用方式,而不仅仅是语言的规范。
JavaScript 一直在快速发展和进步,这与我接触过的任何其他技术都不一样。其中一个原因是,越来越多的应用程序和设备都采用了 JavaScript,因此使用的程序员和用户也越来越多。这意味着,所有这些领域每天都会遇到新问题,而这些问题统统需要通过这门语言及其背后的社区来解决,所以他们会不断发布新的功能和工具,这样才能跟上前进的步伐。
这些人每天都在朝着自己前进的方向努力,他们推出了 TypeScript、Vite 或 esbuild 之类的工具、Node.js、Deno 或 Bun 之类的运行时、Next.js 或 Electron 之类的框架和库、eslint 或 tslint 之类的 linters、Jest 之类的测试运行器,他们每天都在进步,凭借自己的努力突破极限,同时彼此依赖,并努力跟上最新版本的 JavaScript。
另一个原因可能是 JavaScript 本身存在缺陷。这门语言当初的设计初衷与如今的发展大相径庭。我们来比较一下如今的 JavaScript 与十年前的样子。
在 2009 年之前,JavaScript 甚至没有 .map() 之类基本的不可变数组方法。JavaScript 走了很长一段路才发展成今天的样子,尽管这一路上 JavaScript 推出了各种补丁、工具以及 TypeScript 之类的超集,但依然无法满足所有的需求。事实上,人们对 JavaScript 的要求太高了,甚至超出了它目前可以处理的范围。就目前的状态而言,JavaScript 还面临着一大堆漏洞需要填补,核心的问题需要解决,缺乏的功能需要实现。
JavaScript 的这些需求是否证明了我们创建的框架和工具的变化速度及频率很合理呢?也许是,也许不是。但考虑到 JavaScript 生态系统的结构及其互相依赖性,以及该语言在各个领域的使用,也许在做决定之前,我们应该先退后几步,反思整个语言的长期发展愿景,并认识到每一个变化,哪怕是一个微不足道的小变化,也有可能影响到所有用户。我们有责任确保我们的应用程序、库或框架能够与其他常用的库或框架协同工作。
我并不是设计编程语言或为其编写运行时的专家,而且我明白即便是解决一个很小的问题也有很多难处,尤其是在 JavaScript 如此规模之下。然而,作为一名用户,我依然有一个心愿,我希望在完美的世界里,我可以轻松地打开旧项目,一切都能正常工作。在这个完美的世界里,我的程序能够经得起时间的考验。
在这个完美的世界里,我有一个统一的模块系统,我不需要担心文件扩展名、构建工具和兼容性,我不需要几十个第三方 linter、类型检查器和配置来确保我的代码正确,我不会因为没有使用某项技术而觉得得我的应用程序不够完美。
在这个完美的世界里,我可以随意使用任何库,不必担心这些库依赖于数百个其他库,不必担心这些库已无人维护。
在这个完美的世界里,我正在使用的框架不会每隔几个月就从头开始重写。
我希望将来有一天我能微笑着重温这篇文章,JavaScript 能够证明我错了,他们已经将一切资源整合到一起了。