阿里、蚂蚁、晟腾、中科加禾精彩分享 AI 基础设施洞见,现购票可享受 9 折优惠 |AICon 了解详情
写点什么

一张主流编程语言的变迁图,讲清程序员迁移模式

  • 2019-05-08
  • 本文字数:6454 字

    阅读完需:约 21 分钟

一张主流编程语言的变迁图,讲清程序员迁移模式

我绘制了一个主流编程语言的变迁图,用以表示程序员在不同语言之间的切换路径。


关于编程语言,还有很多类似的图可以表示它们相互之间的演进。不过我并不想从语言设计者角度来说明这个问题,而是想从程序员本身来看待语言演变。虽然两者间有些接近,但并不完全相同。


从该图可以看出,如果开始使用的是编程语言 A,下一个最有可能切换过去的是哪种语言。这种推测不是非常科学。不过如果你需要精确的科学,就不会在这里阅读这篇文章了,对吗?也许这张流程图对我来说,能揭示更多的内容。


声明:在此处,不考虑程序员最喜欢的是什么语言。人们可以在任意两个语言之间切换,也可以学习很多种语言、然后选择最适合工作的一种语言。本文中的观点有一定的倾向性。


在接下来的篇幅里,我所阐述的均为个人观点。为了不影响读者阅读,就不再一一做出声明了。



程序员迁移模式


我想强调下最普遍的“终极节点”。在这些节点上,人们在他们所处的维度找不到更好的可替代编程语言。这些终极节点包括:Rust、 Java、 Go、 Python 3、Javascript 和 node.js(node.js 作为一种特殊的 Javascript,在这里特别指出)。


几年前,我认为 C 也是一个终极节点。可能现在也还可以这样认为,因为有大量的重要项目(如 OS 内核)仍使用了 C,而且可以认为它无可替代。不过有迹象表明 C 其实是可以替代的。我最喜欢的例子就是有趣的空指针。Linux 内核有个编译器带来的致命弱点,即 NULL 值“不可能”出现,因此没有对函数进行空指针检查。C 也是一团糟,其规格里有几个新编程语言所没有的致命错误。也许某天这些错误能被修复。


让我们回退几步。如果从顶部开始,根据人们进入编程的不同规格,可以看到四个主干:


  1. “低级”编程,包括 asm 和 C。

  2. “商业型”或“学习型”编程,从 BASIC 开始。

  3. 计算类/科技类编程,如 Fortran,MATLAB 和 R。

  4. 脚本/胶水编程,如 shell 和 perl。


(我们也会谈到“数据库查询语言”,比如 SQL。它是一枝独秀,所有替代它的尝试都以失败告终。数据库语言从上世纪六十年代开始就停滞不前了。甚至到现在,其关键字仍使用大写,因为(他们认为)这样能更好的理解代码。)


(我还忽略了 HTML 和 CSS。他们是真正的语言,不过现在大家都开始学习这两种语言,图上无法用相应的箭头来标识。Lisp 也没有考虑在内,因为它一直没有流行过,虽然有一小部分人一直希望它能流行起来。我还建议添加第五个分类,“配置编辑”)


(该图也忽略了 Haskell。它可以在旁边用一个独立的框来表示,和其他语言之间没有出入的箭头,不过这没关系。Haskell 是个自嘲式的大笑话,除非涉及到 Monads,它不再使用 I/O 概念。)


不管怎么样,让我们回到上世纪九十年代。假设那时编程世界很简单,(1)初级程序员使用 C,asm 或者 Turbo Pascal,(2)商业程序员使用 VB,(3)数值计算人员使用 Fortran,R 或 MATLAB,(4)胶水编程者使用 sh 或 perl。


那时,编程语言就是这么严格划分的。画该图时,我才意识到这一点。显然,我们不会用 perl 来写操作系统内核,不会用 MATLAB 来写胶水程序,不会用 VB 来写大型矩阵相乘算法。


现在则变化很大。选择什么样的语言已经不再像过去那样明确了。

语言的变化主要是风格的变化

我们先来看树起点 asm(汇编语言)。用 Asm 来写程序是相当困难的。不过即使到现在,它仍是写某些程序最好的方式(如电脑启动后的最初几个指令,或是中断处理的入口代码)。不管是在 App Store 里还是手机上的 JIT 里,每个编译语言最终都会将代码编译成汇编或机器语言。


基于 asm,出现了两个分支:C 类型分支和 Pacal 类型分支。(Algol 出现的更早,不过此处忽略掉。宣称自己是 Algol 程序员的人并不多。Algol 对其他语言影响很大。)


Pascal 风格分支语言的特点是有"begin…end"。C 风格语言的特点则是有括号。当然,C 影响了很多的编程语言设计,这点在图中没有体现。因为我们现在讨论的是程序员,而不是语言设计人员。


首先来看看 C。很奇怪,一旦人们开始使用 C,就习惯用它来处理各种情况。不管实现优劣与否,它是为数不多的能合理实现所有四类编程问题的语言之一。这四类都有些难度(除了低级编程,它正是 C 擅长的领域),不过 C 都能搞定,速度也还可以。


如果你是个 C 程序员,接下来会使用那种语言呢?这取决于用它来做什么。


显然,C++是一个选择。虽然其名字与语法和 C 很像,但它其实和 C 风格迥异。除了 BeOS,其他操作系统内核不会使用 C++。在极具潜力的 Rust 使用前,操作系统基本都使用 C 编写。


但是商业(“大型程序”)和数值计算(“快速程序”)领域的人员喜欢 C++。说喜欢不一定准确,但他们别无选择,只能使用 C++。


对于胶水程序,很多人会直接从 C(或 C++)转到 python 2。我最近也这样做过。和怪异的 perl 不同,Python 2 类似 C 语言风格,其语法更简单。C 程序员很容易理解 python C 模块(并可以编写新的 python 模块)。从 python 里调用 C 函数比其他语言更简单。如果在 Java 里调用,就需要处理非引用计数的垃圾回收问题。python 的“os”模块提供了 C 系统调用及该调用能工作的环境。程序员可以访问 C 语言中的错误码并设置相应信号处理程序。唯一的问题就是 python 有些慢。不过只把它作为胶水语言,则可以不考虑python的慢速。速度慢时,可以写 C 模块或调用 C 的库或子程序。


另外,Java 面世后,很多 C 和 C++商业软件的程序员非常快地切换到 Java。C++编译时间长,头文件繁多,可移植性差,有释放后重用的错误问题。因此,虽然 Java 运行的很慢(和 python 不同的是,Java 宣称“理论上运行很快”),人们还是更愿意使用 Java。


我记得有篇文章讲过,Go 的设计者最开始认为 Go 可以和 Java 或 C++媲美,但实际没有做到。Java 就像知名酒店,或是门洛帕克(Menlo Park),一旦入住就不想离店。同时,程序员没有从 C++切换到 Java 主要是因为:a)Java 速度比 C++慢,b)Java 仍有垃圾回收的经典问题。


Go 在之前已经切换到 python 2 的胶水程序人员中流行起来。事实证明 python 的慢速是其痛点所在。计算机复杂度急剧增加,python 胶水程序规模也越来越大。相较其优势,动态类型带来的麻烦更多,因此人们开始使用预编译二进制。python 2 占用很多内存,因此 Go 做了 RAM 改进,避免了从 C++迁移到 Go 带来的问题。Go 的难度和 python 差不多,但它运行更快,占用 RAM 更少。


我们现在称 Go 是一种“系统”语言,因为提起胶水程序,我们更多的是想到 perl 和 ruby,不过它们的作用是一样的。(试试告诉一个 C 语言内核开发者,Go 是“系统”语言,看看他们的反应)Go 是粘合剂,可以把各个组件组合到一起成为一个系统。

Hejlsberg 因素

我们接下来看 Visual Basic 和 Pascal 分支。人们有不同的想法:明显正确的(“我为什么会使用与 C 或 Java 一样让人痛苦的语言呢?”),或明显错误的(“可视化的…Basic?开玩笑吧?”)。二十世纪八十年代和九十年代,一些人仍认为编程应该让新手可以方便使用,因此在个人电脑上预装了免费的编程语言,大部分都是 BASIC。


另一方面,大学教授编程时,则避开了 BASIC(“如果学生前期使用过BASIC,就不能对学生很好的进行编程授课”),也没有选择 C。他们更倾向于 Pascal,认为 Pascal 易于学习。就像 Algol 的学术论文里提到的一样,而且它的语法适合教学,能让每个学生都能听懂。因此就有了学术分支和个人电脑分支,不过它们有个共同点,那就是都和 C 不像。


基于 PC(DOS)的 BASIC 演变为基于 Windows 的 Visual Basic,这可能是 javascript 出现前使用最多、最受欢迎的编程语言。(现在,它仍是在 Excel 中使用的“宏”语言。目前有很多 Excel 的程序员,虽然他们并不认为自己是程序员。)


同时,Pascal 也在努力往 PC 转。因为 Turbo Pascal 的出现,它变得流行起来,并一度成为最快的编译器。在速度上,Pascal 的确没有夸张。甚至有一些 C 程序员也喜欢用 Pascal,不是因为喜欢其类 C 的语法,而是因为它的速度很快。(Turbo C 也可以,但速度还不够。它比其他 C 编译器都快。)(大学里,Pascal 学术性越来越强,后来演变成 Modula 和 Ada。如果不是美国军方在其高可靠系统中采用了 Ada 语言,这个分支早该终结了。现在我们可以忽略 Ada。)


那时还有两个“商业”开发分支:BASIC 和 Pascal 分支。Windows 问世后,出现了 Visual Basic。基于 DOS 的 Turbo Pascal 有点过时,基于 WIndows 的 Turbo Pascal 也并不出众。为了竞争,Turbo Pascal 的设计者Anders Hejlsberg创建了 Delphi。Delphi 和 Visual Basic 一样,有可视化的编程环境,但它基于 Turbo Pascal 语言,也极少出现找不到或不匹配实时动态链接库的烦人问题。


Delphi 很好,但它不属于 Microsoft。掺杂商业因素后,局面变得有些困难。在一系列出人意料的事件之后,Hejlsberg 离开了 Microsoft,但仍继续 C#的开发,发布了 Microsoft .NET 平台,并包含 Visual Basic.Net(这是个很可怕的产品)。据称 C#统一了两个分支。


不幸的是如前所述,VB.NET 很可怕。它和 Visual Basic 几乎没有共同点,更像是 C++的一个慢速版本,披了件有点非典型 Basic 的语法外衣,还带着一个更糟的 UI 设计工具。C#也不是 Delphi。不过这几种语言都销声匿迹了,Microsoft 尽力推动了这一点。(除了 Microsoft Office,它到现在仍在使用最开始的 Visual Basic 语法,称为"Visual Basic for Applications", 即 VBA。比起.NET,它使用的更广泛,更受用户喜欢。)


我不清楚怎样才能叫做一名 Visual Basic 程序员。微软致力于让他们改用 VB.NET,但大多数人并不愿意。我想在图中画一条“他们实际的选择”的箭头,不过老实说我也不知道应该指向哪里。也许他们成为了 web 开发者,或者编写了 Excel 的宏。


从现在看,如果写基于微软主推的基于.NET 平台的 Windows 软件,是件很有趣的事。可能使用的语言都会深受 Hejlsberg 的影响。Hejlsberg 的语言在反击之前被微软和 Visual Basic 所遏制,于是 Hejlsberg 转向写 Typescript,这个留待以后讨论。

胶水语言的简要介绍

最初的胶水语言是 Unix shell,它因引入“管道”概念也很著名。“管道”连接简便的工具来完成复杂的工作。


啊,就是那些日子


那些日子一去不复返,perl就是献给它们的悼词


– Rob Pike


事实证明,设计小而简单的工具是困难的,通常我们没有足够的时间来做这个。能够让我们跳过这些轻便工具,致力于编写奇特的、能够粘着很多乱七八糟的小程序的语言变得越来越流行。(它对 shell 语言的缺陷,尤其是与引用和通配符扩展规则相关的缺陷并没有帮助。)


第一个是 awk,它是语法和 C 类似的解析语言,可以用在 shell 的管道上。那时,在一种语言(sh)的一行中里使用另一种微语言(awk)有点奇怪,庆幸的是我们适应了,因为现在的 web 程序都是这样的。(我们略过 csh,它是另一种与 C 语法不兼容的语言,存在不同的致命缺陷,可以被 sh 替代。)


接下来是 Perl。awk 没有足够多的标点符号,从而促成了 Perl 的产生。(好吧,这只是个玩笑。)


Perl 开始到 perl 5,越来越受欢迎。现在,Perl 停止改进语法,在 perl 6 上倾尽全力,从零开始打造。(在图中并没有标出 perl 6,因为还没有人切换过去。)


这样的配置给在几个方向断层进行“粘合”留下了空间。如果程序员觉得 perl 的语法差劲,可能会切换到 python。如果他们认为 perl 的语法很神奇有效力,只需要一些调整,则可能会切换到 ruby。如果使用 perl 来运行 web 的 CGI 脚本,则可能会保持原样,也可能会转而切换到 PHP。


ruby 很快成为 web 服务器支持的语言(进而是 Ruby on Rails)。Python 也同样在演进。


现在有趣的是:整整一代程序员摒弃了命令行方式(这也是胶水语言运行的方式),希望在 web 端可以做任何事情。从某方面来说,这样更好,比如在一个胶水程序中可以超链接到另一个胶水程序。从另一方面来说,则更糟糕,因为现在所有的 web 程序都很慢,不能使用脚本,而且安装 Electron 的另一个副本需要 500MB 的 RAM 空间等等。这就引入了 web 语言这个话题。

Web 语言

图中,集中在 javascript 的“胶水”分支有很多的箭头指向,这并不奇怪。Javascript 最初只使用于前端。当 node.js 出现后,这种情况完全改变了。现在,只需要学习一种语言来写前后端和命令行工具。Javascript 最初的设计是将其作为最终的胶水语言,试图融合 HTML、CSS、面向对象编程、面向函数编程、动态语言、JITs 以及其它一切能通过 HTTP 请求得到的东西。


但是这样不太好,因为后向兼容对于 web 的成功至关重要。要保证这一点,就无法修复一些严重错误。1995 年,经过 10 天的设计,Javascript 发布了。对于 10 天的成果而言,它相当优秀,但同时它也存在一些问题,无法对其进行修复。


这就是图中唯一一个有双向箭头的地方:javascript 和 python 3 之间。我们把它叫做脚本语言的阴阳两面。


大部分出现过的胶水+web 语言正在消失,python 不在其列,至少目前还不会消失。我猜是因为 python 本身是合理的。使用 javascript 编程时间足够长的话,过段段时间后就会变得不大正常。这时为了缓解压力,程序员有可能会切换到 python。


同时,如果长时间使用 python,最后准备编写 web 应用程序时,前端代码和后端使用完全不同的语言是很烦人的。一个的语法是[‘a’,‘b’,‘c’].join(’,’),而另一个则变成了’,’.join([‘a’,‘b’,‘c’]),这让人完全记不清谁是谁了。


一种语言有 JIT,可以让其一旦运行起来就会速度很快。而另一种则是启动快,运行慢。


一种有合理的命名空间系统,而另一种则没有。


我不清楚从长期看,python 3 是否能打败 javascript。但至少目前看,它不会被击败。


同时,对于编程事实分支从不满意的 Hejlsberg,看到了 javascript 的很多问题,引入了 TypeScript。与此同时,微软突然停止了对 Windows 应用程序的大力推进,开始大面积推广 web 和开源。这意味着 Microsoft 第一次将其开发者推向 web 语言即 javascript。在此基础上,他们有自己的 TypeScript,我觉得这是一种很好的语言。这个分支存在有数十年,开始和其分支融合,可能不久后会消失。


TypeScript 和 javascript 比,能胜出吗?这是个有趣的问题,我也不知道。我以前赌 Hejlsberg 能赢,不过我一般容易赌输。

Python 2 和 Python 3 的对比

综上所述,我对 python 2 和 3 有了结论。它们很相似,但不尽相同。我认为,这是因为他们在整个程序员语言迁移图中所处的位置不同。Python 2 开发者来自 C 和 perl 开发人员,希望编写胶水代码。Web 服务器是后续添加的一个应用场景。我的意思是,python 2 出现后,web 程序变得流行起来,这并不出人意料。很多 python 2 的开发者转到 Go 的开发,因为他们想写的某些“系统胶水”代码使用 Go 正合适。


Python 3 的开发者是从不同的语言切换而来的。事实证明,python 3 问世后,python 的使用得到很大的发展,不过新加入的人群和以前的人群有所不同。由于带有模块 SciPy 和 Tensorflow,从科学类和数值类处理转过来的新程序员占了其中很大的比例。老实说,在高吞吐量的数值处理中,Python 是一个相当怪异的选择。但不论如何,这些库的存在是我们选择它的一个原因。我猜 python 的另一个优势则是易于和 C 模块集成。当然,python 3 本身就是网络编程。


想要理解 python 2 和 3 的区别,只需看看其不同的字符串类型。Python 2 中,字符串是一组字节,因为操作系统、Unix 管道处理、网络 socket 的处理均以字节为单位。对于系统程序而言,python 2 是胶水语言,其处理以字节为单位。


在 python 3 中,字符串是一组 unicode 码。因为人们不擅长 unicode 码的转换,而和网络交互时,都是以 unicode 为基础。做科学数值计算的人不关心字符串,做网络编程的人更关心 unicode,所以 python 3 使用 unicode。如果要用 python 3 来编写系统程序,就会一直疲于 unicode 的转换,即使最简单的文件名也需要进行转换。这也正是有其因,必有其果。


相关文档


Misunderstanding Exceptions (2007)


You can’t make C++ not ugly, but you can’t not try (2010)


原文链接


https://apenwarr.ca/log/20190318


2019-05-08 15:03120240

评论 1 条评论

发布
用户头像
Rust其实蛮受函数编程影响的,特别是trait的概念基本直接照搬了Haskell,所以应该多一个从Haskell到Rust的箭头。ES6的destructering assign其实也有点pattern matching的意思,Erlang程序员会觉得很熟悉。现在小众函数式语言程序员成为主流程序员也越来越容易了。
2020-07-13 10:46
回复
没有更多了
发现更多内容

Spring 源码阅读 29:基于 XML 配置初始化 Spring 上下文过程总结(10+详细流程图)

Java快了!

xml

时代变了,企业网站应该这么策划内容

石头IT视角

SAP系统和微信集成的系列教程之二:如何通过微信公众号消费API

Jerry Wang

API 系统集成 SAP 微信开发 9月月更

库调多了 都忘了最基础的概念-进程/线程篇

知识浅谈

9月月更 线程与进程

Linux系统安装MySQL

MySQL Centos 7 navicat 9月月更

自适应熔断原理分析与源码解读

万俊峰Kevin

Go golang 熔断 go-zero 限流熔断

【FAQ】接入华为应用内支付服务常见问题解答

HMS Core

Spring5源码14-SpringMVC-HandlerMapping

Java快了!

springmvc

围绕“开源+深耕”策略和数字化监控手段,动态管理场景生态价值

易观分析

银行 易观 场景金融

数据治理(九):Atlas界面操作

Lansonli

数据治理 Atlas 9月月更

数据库的视图怎么用?

阿柠xn

MySQL 运维 视图 数据库· 9月月更

美团前端一面常见面试题

beifeng1996

JavaScript 前端

看得懂又好看的数学书,万人亲测的硬核教程!

博文视点Broadview

2022-09-06:以下go语言代码输出什么?A:Hi All;B:Hi go All;C:Hi;D:go All。 package main import “fmt“ func app() f

福大大架构师每日一题

golang 福大大 选择题

数据中台改名DaaS平台?究竟什么是数据即服务(DaaS)?

雨果

DaaS数据即服务

深入学习SAP UI5框架代码系列之四:HTML原生事件 VS UI5 Semantic事件

Jerry Wang

JavaScript SAP SAP UI5 ui5 9月月更

SAP系统和微信集成的系列教程之一:微信开发环境的搭建

Jerry Wang

系统集成 SAP 微信开发 微信平台 9月月更

分布式中灰度方案实践

Java 架构

边缘服务网格 osm-edge 数据平面基准测试

Flomesh

Service Mesh 服务网格

SPL工业智能:发现时序数据的异常

石臻臻的杂货铺

SPL 9月月更

我用WireShark结合一款神器成功绘画出入侵者的地图!

wljslmz

Wireshark 9月月更

深入学习SAP UI5框架代码系列之三:UI5 控件的渲染器

Jerry Wang

JavaScript 前端框架 SAP UI5 ui5 9月月更

《小米创业思考》之三:互联网七字诀

郭明

读书笔记

Hugging Face:成为机器学习界的“GitHub”

OneFlow

神经网络 机器学习

[极致用户体验] 在微信大字号模式下,网页样式乱了怎么办?

HullQin

CSS JavaScript html 前端 9月月更

京东前端面试题

loveX001

JavaScript 前端

Java进阶(八)Java加密技术之对称加密、非对称加密、不可逆加密算法

No Silver Bullet

对称加密 非对称加密 9月月更 不可逆加密

消除 JavaScript 的一些“异味”

掘金安东尼

JavaScript 前端 9月月更

如何重新评估未完成的工作

ShineScrum捷行

Scrum 敏捷 DoD 未完成的工作

你真的理解C语言的灵魂 “ 指针 ” 吗?(初阶篇)

Albert Edison

指针 C语言 野指针 9月月更

NFT商城开发——NFT数字收藏平台开发解决方案

开源直播系统源码

NFT 元宇宙 数字藏品 数字藏品开发

一张主流编程语言的变迁图,讲清程序员迁移模式_编程语言_apenwarr_InfoQ精选文章