GitHub 北极冰川火种计划中文指南

导言

GitHub Code Vault(GitHub 代码保险库)是由 GitHub Archive Program(GitHub 代码永久保存计划)设立的代码档案库,旨在保存开源软件以供未来使用。 一年后或一千年后,您可能会读到这份指南,但无论如何,我们希望其内容甚至每个开源的概念都会对您大有裨益。

首先,这是一个软件档案库。 软件即一系列命令,用于控制计算机操作。 计算机则是可自动执行数学函数的设备,拥有让人脑望尘莫及的迅疾速度及强大能力。 计算机可用于协助探索宇宙奥秘;凭借无所不在的信息网络将全人类紧密相连;快速操控信号以传输声音并将详细的移动图像投射至电气屏幕;同时,以人类劳动力难以逾越的能力和精度操控强大机械。

然而,计算机一旦脱离软件,上述一切功能均无从谈起。 计算机精妙绝伦,但若无软件,则毫无用处。 我们建立本档案库的目的在于,将所知晓的软件知识和盘托出。

软件是由复杂但人类可读的命令序列编写而成,各种不同风格的命令序列即称为“编程语言”,因此一个完整的软件通常可称为一个“程序”。 然后,程序会转换为可供计算机使用的二进制语言(由 0 和 1 构成), 这一过程即称为“编译”。

编译后的软件很难重新破解回原始程序形式,即源代码,因此人们可对该原始形式进行保密,并获得所有权。 开源软件并非不同类别的软件,但却遵循另一种理念。 开源的理念在于拒绝保密和所有权, 开源软件程序面向任何有需求的人士免费开放,反之这些人士可协助改进相关程序,或用其创建更棒的新事物。

数以千计的人员可能自发形成群体,并集全体智慧方可开发出一个开源项目。 正因如此,我们在此累积保存的所有开源软件项目便是由不计其数的人们集思广益而成。 尽管在某些特定项目里,有些个人拥有特殊权利(如对源代码的最新官方版本拥有批准或拒绝更改建议的权利),但是,没有人对其拥有所有权。 每个人都有权随时获取和使用任何开源项目的完整副本,而且无需承担任何代价或遭受任何惩罚。 这个过程即称为“复刻”项目。

当很多人同时对源代码进行编辑时,要对其所有更改进行记录并整合,可谓极具困难。 为了解决这一问题,名为“Git”的开源项目应运而生—— 即针对某个项目,将其所有添加和更改的完整历史记录完美整合至名为 Git 仓库的实体中。 本档案库所存档的正是此等仓库。

本档案库由一家名为“GitHub”的公司创建,该公司面向全球用户提供服务:协助用户存储其所编写的软件程序,持续追踪这些程序的相关更改,以及与他人协作改进和扩展这些程序。 GitHub 面向公共开源软件的开发者提供免费服务, 而该等用户基数高达数千万。

为了充分利用本软件档案库,我们将于以下篇章为您介绍所需知识和必备工具。 如果您无法了解或理解其中的部分或任何内容,请勿惊慌, 我们同时提供一份指南,教您如何消化吸收个中内容。 如基于某些原因,您无法成功掌握这些内容,那么您的子孙后代也可效劳。

使用本档案库所需的必备工具

基本上,仅需一个“光源”和某种“放大镜”,即可访问本档案库。 然而,档案库中的大部分(非全部)数据均通过编码和压缩格式,得以严实封装于胶卷中。 因此,将需大量计算方可读取、解码和解压这些数据。 理论上,无需计算机也能完成此操作,但过程会是非常繁琐且困难重重。

我们推测,您将无需我们就软件、计算机和其它术语提供相应定义。 我们也猜想,你们有自己的计算机。相较我们的机器,你们的计算机可能先进得多,且基础架构截然不同。 一旦了解下方概述和指南,您将可轻易访问所有数据。

当然,你们的计算机可能更为落后,或者说你们根本并未配备计算机。 倘若如此,我们早已备好一个未压缩、未编码但人类可读的数据胶卷,即所谓的“Tech Tree”(技术树)。 Tech Tree 中包含涉及基础科技、计算机和软件的相关信息,希望假以时日,你们将能够使用这些知识重建计算机,以便能够妥善利用本档案库中的开源软件。

库中内容

本档案库非常庞大,拥有高达约 24 万亿字节(详见下方内容),可谓海纳百川,真正实现民主决策。 数百万人苦心编写实用软件并公开发布,人人均可获取。 档案库中包含一张“快照”,记录了某一瞬间,由 GitHub 用户积极开发的所有公共软件组合而成的一张“全家福”。 这代表着,其中强势融合有数以百万计的各个仓库。 我们希望,这样浩瀚博大、科学民主的做法可吸引未来的历史学家前来研究。

本档案库中所包含的仓库纯粹根据其最后一次提交时间(即最后更新时间)及其星数确定。 (GitHub 用户均有权对公共仓库添加星标,以表示其喜爱或重视该仓库。)“快照”的启动时间为 2020/02/02,按我们的计时方式来算,即公历 2020 年 2 月 2 日。 本档案库中包含的仓库包括:前 80 天内有提交更改的所有仓库;前 365 天内有提交更改的所有仓库(至少有一颗星);以及 250 颗星及以上的所有仓库,无需理会其最后更新日期为何时。

当然,就影响力和依赖性而言,并非所有仓库都同等重要。 Tech Tree 中含有一份索引及简介,其中涵盖本档案库中最重要的仓库,并列出其所在的各个胶卷,以便确定那些最为实用的仓库,而无需逐一浏览全部几百万个仓库。

档案库概述

本档案库共含有 201 个胶卷,其中包括一个含有人类可读信息和指引的“指南胶卷”和 200 个软件存档胶卷。 每个胶卷包含 65,000 个单独的帧。 每个胶卷开头的帧及“指南胶卷”内的帧均包含人类可读文本和图像。 胶卷的所有其它帧则含有以二维码可视形式存储的数字数据。

数字数据意味着以二进制作为最终存储格式的数据,即 0 和 1。原因在于,计算机本身就是二进制,即通过分别对应 1 或 0 的“开”或“关”电信号进行控制。因此,相比其他方式,二进制数据更易于计算机识别。

人类可读元数据存储于每个胶卷的开头,包含该胶卷本身的信息、所用二维码编码指南、用于解码的软件程序及一份索引。 其中,该索引针对存储在该胶卷上的每个文件,均列出其相应标题、起始帧号和检验和。

文件是连贯一致的数据实体。 校验和是计算中的唯一值(称为哈希函数),运行于文件的整体内容上,以确保其内容未受到损坏或破坏;本档案库中使用的哈希函数称为"SHA-1"。

每个二维码由一个个白色或黑色小方块组成,该等小方块几乎占据胶片的整个帧。 使用二维码的原因在于,其比人类可读的文本更紧凑而可靠。 二维码可解码为二进制数据,即一系列 1 和 0。

就将二进制数据转换为有意义的信息而言,解码仅是第一步。 二进制数据是压缩数据,即通过压缩的方式来节省空间。其中的原理就如我们会写“128xA”,而不会将字母 A 重复写 128 遍一样。 解码后,其还须进行解压。

解压后的结果称为一个“存档文件”,即包含一个软件项目仓库全部内容的单个文件。 大部分仓库会包括许多文件,因此该存档文件就像是一本书,其内包含众多不同章节;或像是一个盒子,其内同样包含许多其它盒子。 通常建议在访问存档文件之前,将其解包到组件文件中,但该做法并非绝对必要。

最后,每个组件文件均为其各自的二进制数据集,即 1 和 0。 若您知道数据格式,即可理解该数据。 例如,在本档案库最常见的“UTF-8”格式中,1 和 0 被分成八位一组,称为“字节”,字节 01000001 代表字母 A;三个字节 01101001 01101110 01110100 即代表单词 int;两个字节 11000011 10000011 则代表字母 Ã(上面带有波浪号的 A)。

此数据存档过程——将二进制文件先压缩,再编制二维码,最后打包成存档文件——显然会比简单书写人类可读的文本要复杂得多。 提取档案的过程,即从二维码到压缩的二进制数据;从压缩到解压;从存档文件到多个文件;从文本文件到人类可读文本,也同样复杂。 然而,此复杂过程相比其它方式,可以计算机可读的相对简单方式存储更多数据。

若因为如此复杂而给您造成困难和导致高成本,我们深表歉意。但我们猜测,若真如此,本指南及人类可读的 Tech Tree 将会降低复杂性,而且可能比存档内容更实用,至少当计算机足够先进时,本档案库的数据复杂性会显得易于操作。

文件、目录、仓库和数据格式

我们将讨论本档案库在逻辑上的划分方式,这可能极具指导意义。 我们会特别讨论文件、目录和数据格式,这些可能十分实用。

一组数据组合一起,形成符合逻辑的实体并带有单一名称,即成为一个文件。您可以将数据想象成沙子,文件就是仅可用来装沙子的袋子。 目录是文件的集合。您可以将其看作是一种仅可装进其他袋子的袋子。 以此类推,每个仓库包含一个外层目录,称为“根目录”,其中含有一系列文件和/或一系列目录。 每个目录本身又包含文件和目录。

我们选择此结构的原因在于,将文件分成不同群组比单一的文件集合更易于管理。 外层目录下的某个文件之识别符包含其所有从属目录的名称:从根目录开始,紧接着是其本身的名称,各个名称中间用字符 / 隔开。 例如,在根目录下有一个名为 README.md 的文件,其识别符为 /README.md,而识别符为 /public/www/index.html 的文件即 index.html 文件,位于根目录内“public”目录下的“www”目录中。

每个仓库又含有两个名字,由一个分隔符分开,这个分隔符在本档案库中为“_ ”或称为“下划线字符”。 (此前,曾使用“/”或斜杠,但也用于指示目录,因此为了稍作区别,我们使用“_”。)第一个名字是拥有该仓库的 GitHub 帐户名称;第二个名字则是该单个仓库的名称。 将仓库和文件标识符两相组合,即可用于单独标识本档案库中的单个文件。 例如,在本档案库内的 GitHub 帐户"rezendi"中,有个仓库"ykarma"。其内,目录"web"下的文件"package.json"可单独标识为 rezendi_ykarma 中的 /web/package.json。

各种类型的文件具有不同用途。 GitHub 档案库包含大量文本文件,这意味着,这些文件中的数据代表书面语言。 大多数软件均采用文本文件进行编写,其中包含高度结构化的文本,称为“源代码”。 一种称为“编译器”的特殊程序能将人类可读的源代码转换为计算机可读的指令,即编译代码或机器代码。

文本文件以外的文件,如用于显示可视图像或包含编译代码的文件,则通常指代二进制文件。 遗憾的是,此术语具有误导性,毕竟文本文件最终也是由 1 和 0 构成。 为此,我们将文本文件以外的文件称为“非文本文件”。

使用 1 和 0 代表人类书面语言的方法为数众多。 由于历史原因,大多数源代码最初是由拉丁语脚本编写而成。 拉丁语脚本具有 26 个基本字符,用于表示可口头表达的单词,每个单词设有两种形式,即大写和小写。 此外,该脚本还有 10 位数可用来表示数字。 拉丁语脚本连同用于指示结构和其他概念的各种其他关联符号,均以 1 和 0 的格式(称为"ASCII")进行编码。该格式可表示 128 个不同字符,并且由于历史原因,多年以来曾在大多数软件中占主导地位。

然而,在人类以书面语言表达自我的众多方式中,拉丁语脚本仅为一个小分支。 为了支持其他脚本,同时允许所有编写目的为使用 ASCII 的软件,在无需更改的情况下继续运行,(此概念称为“向后兼容”),"UTF-8"数据格式得以随之引入。

ASCII 仍然是源代码中最常见的格式, 本档案库的每个胶卷均包含一份 ASCII 字符指南。 ASCII 是 UTF-8 的子集,换言之,所有 ASCII 编码同时也是 UTF-8 编码。 此外,本“指南胶卷”还包含一份涉及所有 UTF-8 字符的规范。 本档案库中几乎所有文本文件均应使用 UTF-8 进行编码。

非文本文件包括用于表示图像和格式化文档的文件。 按照通用习惯,文件名会以字符“.”及后缀结尾,以指示其文件类型。 例如,以 .jpg 结尾的文件可能是 JPEG 图像文件;以 .PNG 结尾的文件则可能是“可移植网络图形”图像文件;而以 .pdf 结尾的文件可能是“可移植文档格式”文件。

对于文本文件,尚无单一后缀可用于指示。 然而,源代码的后缀更多用于指示该代码编写所使用的编程语言或标记语言。 涉及编程语言和标记语言的相关内容,将会在下方篇章进行更详尽描述。

如何提取档案库的内容

下面,我们将简要介绍如何将某个存档的仓库解包成各个构成文件。 如前所述,这一过程包括:

  1. 找到仓库数据所在存档的具体胶卷和帧。

  2. 将那些帧上由黑、白、灰像素区域构成的二维码解码为二进制文件,即一个由(少则数千个、常常高达数百万个)1 和 0 构成的序列。

  3. 将二进制文件解压为一个更长但已解压的存档文件。

  4. 将存档文件解包为其所包含的不同子文件。 但注意,存档数据可能凌乱,但即便无此步操作,通常也能让人理解。

  5. 最后,若为文本文件,将每个子文件均转换为书面字符(子文件本身的 1 和 0 序列可长可短)。

找出仓库数据存档所在的具体胶卷和帧

每个胶卷最先以一段空胶片为引导,然后是“零点参考帧”,即一个空帧,其中的一角带有纯黑色矩形。 下一个人类可读的帧是“控制帧”,其含有此胶卷的相关信息。 接着是一个“内容目录”,其又包含一个“用户数据文件”的列表。

在这个胶卷上的每个仓库即为“用户数据文件”的其中之一。 此列表包含每个文件的一个唯一 ID、一个文件 ID 和一个名称。 例如,Python 帐户的 CPython 仓库文件 ID 可能为 12345,而名称为 python_cpython.tar。

“用户数据文件”列表后紧随着是“数字数据位置”列表。 此列表包含文件 ID、一个起始帧、一个起始字节、一个结束帧和一个结束字节。 因此,仍然假设有 CPython 仓库,此列表中 ID 为 12345 的文件项起始帧可能为 054321,起始字节为 03210321,结束帧为 054545,结束字节为 12321232。

这意味着,要获取 CPython 仓库中的数据,需前往此胶卷的帧 54321。 然后,将起始帧 54321 到结束帧 54545 的所有帧解码为二进制值,具体方法如下所述。 这样一来,您会得到编号从 54321 到 54545 的 225 个数据,其中前面的一些数据为空。 丢弃前面非空数据中的前 3210320 字节, 按顺序添加所有“中间”的数据, 最终添加从最后一个 54545 号数据开始的前 12321232 字节。 现在,您已组合完成完整的 CPython 仓库,得到一个压缩的存档文件。

将二维码解码为二进制文件

有关如何将胶片里的帧解码成为二进制数据的详细信息,请见人类可读的“说明信息”。该信息可在“内容目录”中找到,具体位置见本档案库每个胶卷的开头处。 每个胶卷中都有该信息,因此即使从本档案库中单独提取一个胶卷,也可对其内容进行破解。 “说明信息”依次包括如下内容:

  1. GitHub 代码永久保存计划指南(即本文档)

  2. GitHub 描述性索引,即该胶卷上所有仓库的一份列表和简介

  3. “说明信息”描述

  4. 数字保存及如何检索数字,即对数字检索细节的概览

  5. 存储介质介绍

  6. 数据检索技术

  7. 通用保存胶卷结构(胶卷格式)

  8. 通用 4K 帧格式说明

  9. 开箱资料库说明(针对二维码)

  10. 开箱资料库源代码

  11. ASCII 数据格式规范

  12. C 编程语言规范

  13. TAR 存档文件源代码

  14. PDF 源代码

  15. XZ 文件格式规范(用于压缩/解压缩,如下所述)

其中,第六项“数据检索技术”文档,针对使用扫描仪捕捉胶片中单个数字编码帧上的数据并将其转换为适合计算机分析的形式,介绍了相关要求和流程。 第八项“通用 4K 帧格式说明”提供有计算机获取扫描图像并转换为二进制数据的技术信息,包括源代码。

基本而言,在无计算机的情况下,理论上可将一个仓库从二维码编码数据转换为二进制数据。 但是,这会非常困难,而且可能需要一个组织良好的群体付出大量努力并耗上数周,甚至数月、数年时间方可实现。 由于这些仓库的内容均为设计用于在计算机中运行的软件,所以在没有计算机的情况下,其用途微乎其微。

如果本档案库的继承者没有计算机,则应该确保档案库完好、安全,直至成功配备计算机为止。 建立人类可读 Tech Tree 的其中一个目的在于,当此情况确实出现时,可协助加快技术及计算机发展。 (其他目的还包括将技术和发展汇编起来,以供未来的历史学家研究。)

将存档文件解包为其所包含的不同子文件

每一个仓库的二进制文件均采用一种称为 TAR 的格式,TAR 即“胶带存档”。 一个 TAR 文件主要由一系列文件组成,这些文件首尾相接,就像利用胶带将不同纸片粘贴一起,形成卷轴。 TAR 文件可能包括一系列大小不一的文件,并各自划分在不同数量的目录和子目录中。

TAR 文件中每个子文件的开头均为 512 字节的文件头记录,充当上述卷轴比喻中的胶带作用。 这些文件头记录包含有关该文件的信息,如文件名和文件大小。 存档文件的结尾会用至少两个连续的 512 字节块来指示。

基本而言,TAR 文件是文件集合,而这些文件之间会以文本记录作为连接。因此,若 TAR 文件包含的全为文本文件,那么该 TAR 文件本身也可认为是一个文本文件。 若其包含混合类型文件,则可认为这是一个文本文件,但该文本文件同时包含结构化、有意义的文本(构成文本文件)和无法理解的无用数据(构成非文本文件)。

我们可将 TAR 文件嵌套进 TAR 文件,就像在容器中装入另一容器,而这正是大部分存档数据的存储方式。 无论哪个仓库,其外层 TAR 文件都将至少包含如下内容:

  • 一个名为 META 的未压缩元数据文件,其包含仓库名称、帐户名、说明、语言、星数、复刻数
  • 一个名为 COMMITS 的压缩文件(如下所述),包含该仓库有史以来的更改记录
  • 一个名为 repo.tar.xz 的文件,是包含实际仓库内容的压缩 TAR 文件

其它诸如 wiki、gh-page、issue 和 pull request 等元数据也可能包含在不同压缩文件中。

如要查看 TAR 文件以及用于对其进行编码和解码的相关软件之详细信息,请见本档案库各个胶卷中的“说明信息”。

将压缩文件解压为已解压的可读文件

为了将尽可能多的仓库和数据包括入内,大部分数据均经过压缩。 压缩即意味着,在大量数据中应用某种模式和重复性方法,以少量数据代表大量数据。 例如,如果您确信读取器能理解 9a 表示未压缩文本 aaaaaaaaa,则只需编写压缩文本 9a,而无需将该字符连续书写九次。

高效压缩算法比这要复杂得多,但道理完全一样。 本档案库使用一种名为“XZ”的压缩程序,其所使用的算法称为“LZMA”。 每个胶卷中的第二个数据文件包含用于 XZ 的源代码和文档,并位于一个未压缩 TAR 存档文件中,如下所述。 (第一个数据文件包含以各种人类书面语言书写的《世界人权宣言》。)

LZMA 将“LZ77”算法和“区间编码”算法亮相结合。 按 LZ77 算法,重复的数据会替换为一个引用,指向先前出现的该数据。 例如,为了达到极致简化的目的,如果一个 80 字节的短语出现两次,中间间隔 400 字节,那么其第二次出现时,为了压缩数据,该算法基本上会表达为"重复 400 字节之前出现的 80 字节"。 基本上,区间编码是将一整条消息转换为一个极长的数字,而此数字也可进行编码。

用于解压数据的算法具体步骤详见每个胶卷中第二个数据文件内包含的 XZ 源代码。 如上所述,理论上,可进行手工加压,但那将是异常费时费力的过程。 实际上,我们通常需要一台计算机。

将各个单独文件转换为书面字符

过去一千年间,人类已使用多种书面字符。 本档案库中,用于代表这些字符的 1 和 0 编码方式称为“UTF-8”。 一个 UTF-8 字符(即一个书面符号)在任何时候都会占用 1-4 字节的二进制数据。

鉴于历史原因,一种叫“ASCII”的字符(和概念)集合是最高效的编码方式(每个字符 1 个字节),毕竟在软件开发的初始时段以及最初开发地内,这是应用最广的一种字符集合。 非 ASCII 字符均使用 2 个或以上的字节对每个字符进行编码。 本档案库中的大多数文本文件均为 ASCII 格式,但也存在大量其他格式的文件。 更多文件则是采用大部分 ASCII 字符加上偶尔几个非 ASCII 字符的方式组合而成。

有关 ASCII 的详细介绍,请见本档案库每个胶卷中的“说明信息”。 UTF-8 的详细规范请见“指南胶卷”。 本档案库每个胶卷中的第一个数据文件均包含以各种人类书面语言书写的《世界人权宣言》, 作为一种翻译工具以及 ASCII 和 UTF-8 的示例。

文件种类

出于不同目的,我们创建出众多不同种类的文本文件。 出于本档案库之目的,这里的首要文件种类为源代码。 源代码是非常密集且极致结构化的文本,其中的“{”和“;”等符号均具有重要意义。

编写源代码是为了让编译器读取,这点至关重要。 编译器也是一种软件,换言之,源代码的编写目的在于,让计算机加以读取。 同理,编写优秀代码也为了让其他人类加以理解。当然,这些人员需拥有软件方面的技能或接受过软件领域的教育;但是,只有当编译器能理解代码时,这一切才有意义。

编译器通过复杂的序列(参见 Tech Tree)将源代码转换为由 1 和 0 组成的序列,计算机据此执行代码所描述的功能和活动。 举一个非常简单的例子:

(int i=0; i<5; i++) { }

以上这行代码将经由编译器转换为一系列二进制指令并提供给计算机,令计算机中名为“寄存器”的小部件将其值设为 0,随后再将该值递增为 1、2、3 和 4。 (以上示例并非意指一行有用代码;这仅为了说明利用源代码运行软件是一个多层次过程。)

其它文本文件类型,如 JSON、XML 和 HTML,则用于存储计算机的所用数据(而非命令)。 人类一般也能将其读懂,但相较于像本文件这样的低结构化叙事性文本,其结构化格式令其更青涩难懂。

其它大部分文本文件类型最终均为了形成人类可读的文件。 有些文件较为简单,主要是非结构化的文本,比如您正在阅读的这一文件。 在本档案库中,您将常常碰到 Markdown 这一文件类型。此类文件以 .md 为文件扩展名,这是一种中间形式,意味着在其原始形式下,具有人类可读性。同时,其也得到结构化处理,以便计算机将其格式化为视觉上更美观、更有用的布局。 本档案库中的大部分仓库都含有 README.md 的 Markdown 文件,一般作为仓库的初始介绍,描述该仓库是什么、为何存在及如何使用等问题。

下文将简要介绍非文本文件的最常见形式,这对您可能同样重要。 编译代码为非文本类型, JPG 和 PNG 文件是以数字格式编码的图像文件,而 MP3 和 WAV 文件则是编码的音频文件。 PDF 文件为编码文档,具有简洁完美的格式。 上述 ZIP 和 TAR 文件属于容器文件,可能包含一个或多个其它文件。

人类语言和编程语言

人类语言

在今天,人类使用的书面语言多达数千种,而口头语言则更多。 其中大部分语言的使用人群均相对较少,但至少有二十种语言构成至少 6 千万人的母语或第二语言。

英语和汉语构成全球使用范围最广的语言。 出于历史原因,多年以来,大部分软件开发仅出现在英语的母语国家内。因此,英语曾一度是软件的默认语言。 大部分编程语言在其语句中均使用英语单词。 编写本档案库指南所使用的第一语言也是英语。

我们无法保证本档案库的传承人懂英语,但英语似乎极有可能会世代相传。 倘若以其他语言编写的指南比较实用,我们将会在每个胶卷的开头提供一个未压缩的 UTF-8 文件,其中包含超过 500 种语言版本的《世界人权宣言》,而且这在 Tech Tree 中也能找到。 该《宣言》是我们这一时代每个人所拥有的权利和自由。无论如何,绝不可剥夺这些权利和自由。

编程语言

编程语言是人类用来向计算机传达指令的语言, 软件正是使用这种语言来加以表达。 其他(受过训练)的人也应能读懂由编程语言编写的软件,但这是次要目标。

编程语言包含一系列预定义的元素,其中大多数为单词,通过结构化的排列,指示计算机以指定方式执行指定操作。 这种指令的集合称为“程序”,也叫“源代码”。 源代码基本上是以“冻结”的书面形式存在之软件。

程序通常可分成离散的步骤,称为语句。这些步骤又分组到称为“函数”的集合中。 一个完整的程序可能仅包含在一个文件中,也可能分布在数千个文件中。

世界上有数百种不同的编程语言,采用各不相同的形式、方法和原理。 有些编译为各个单独的二进制文件,然后由计算机执行;有些称为“直译”语言,经过有效编译即可直接运行,无需中间阶段。 大多数现代语言包括预先编写的函数库,而且此类函数库的内容极为丰富且详细。 当今最流行的编程语言包括:

  • C 语言——最古老、最快速、最通用、最强大的语言之一,在某些方面十分简单,但在其他方面却极为受限,而且并不那么直观,也不太易于阅读或学习。

  • C++ 语言——在 C 语言的基础上,进化而来的一种语言,具有更复杂、抽象和强大的特点。

  • C# 语言——进一步进化的语言,并非编译成二进制机器代码,而是直译式的"运行时"。

  • Java 语言——与 C# 语言类似(但早于 C# 语言),可能是当今使用最广泛的语言。

  • JavaScript 语言——与 Java 语言大不相同,尽管名称相似,也称为"ECMAScript",最初完全用于 Web 浏览器,即从一台远程计算机(称为“互联网服务器”)获取数据,经过解译后将数据显示出来的一种程序;然而,今天,JavaScript 语言同时广泛用于那些服务器。

  • TypeScript 语言——JavaScript 语言的一种形式,具有更严格的规则,因此错误(也称为漏洞)不太可能进入程序。

  • Python 语言——在科学家中流行的一种优雅语言,既强大又好用的第一语言。

  • Ruby 语言——一种直观的语言,通常,其语句读起来几乎像书面英语。

  • Go 语言——一种简单而强大的语言,在并行化程序方面尤为突出。并行化程序即通过程序编写,使多个函数可在同一时间独立运行。

  • Swift 语言——用于针对十亿人均使用的手机和其它设备,而特意编写的一种新语言。

  • Rust 语言——旨在替换 C 语言的语言,将危险漏洞大幅减少。

  • PHP 语言——一种直截了当的语言,可用于互联网服务器。

  • Lisp 语言——一种非常古老的语言,采用根本不同且功能优先的方法进行编程。

  • SQL 语言——一种非常不一样的语言,用于从结构化和高效数据存储库(称为“数据库”)中获取数据。

  • Assembler(或叫 Assembly)——一个非常晦涩、受限但快速、强大的语言系列,其语言构造和计算机的机器代码之间具有直接关联;可视为一种半编译代码。

软件开发、依赖项和开源

软件开发

获取一个简单的源代码文件并将其转换为计算机中的电脉冲信号,这个过程极其复杂。 为了解决这种复杂性,我们使用抽象层。 一个抽象层称为一个“指令集”,可使由编译器输出的机器代码用于各种各样的计算机。 源代码的作者一般无需知道或在意将使用何种类型的计算机(甚至何种指令集)运行代码;我们利用编译器进行抽象处理。

相较于一位作者编写单个程序并用于一台计算机的简单模式而言,现代软件更显复杂。 在一个项目中,现在软件包含多名作者,他们同时编写多个文件,并常常使用多种编程语言。 此外,每个项目均依赖其它独立的各个项目作为其工具和/或组件,而这些其它项目本身则需要其他项目使其运行,因而又依赖于别的项目。 因此,现代软件开发的难点在于,让所有这些活动的零部件巧妙高效地共同运转。

当多名源代码作者(也称为“软件开发人员”)共同参与同一项目开发时,每位作者均有自己的计算机,而且在其计算机里都有整个项目一份副本。 如果他们每个人都对项目进行更改,则同一个项目会存在多个不同版本。 对同一项目的多个版本进行协调,这个过程称为“版本控制”, 可由版本控制软件管理;在本档案库中,是由名为 Git 的软件进行管理,而 GitHub 的名字正源于此。 本档案库中的每个仓库称为一个 Git 仓库。

Git 会自动将不同版本的软件合并成连贯一致的形式,仅需极少人工干预即可。 Git 还会保存完整历史记录,如此一来,即可让您在需要时找回原先版本。 但是,为了节约空间,本档案库中的仓库一般不包含 Git 历史记录。

当多名开发人员同时在多个不同通道上开发一个项目时,这称为对项目进行“分支”,而这些通道均称为“分支”。 一个项目中公认的主分支称为“主干”或“默认分支”。 Git 提供一个设施,开发人员可用其汇总两个分支之间的不同之处,并建议将其合并为其它分支, 这即称为“拉取请求”。 现代软件开发主要包括:对项目进行分支、编写或编辑分支上的软件,以及在完成后提交拉取请求,以便重新归并回默认分支。

依赖项

基本而言,每种编程语言均支持在他人编写的代码基础上建立新的代码。 如果无法使用他人的代码,每个项目将会变得更为困难,且速度要缓慢得多,极少项目会真正在现实世界中得以应用。

如果项目 A 需要包含项目 B 才能运行,我们就称之:项目 A 依赖于项目 B,项目 B 是项目 A 的一个依赖项。项目 A 可以有许多依赖项,每个依赖项也可以有自己的依赖项,以此类推。 此外,每个依赖项都是针对一个指定项目的一个特定版本或版本范围。 一个项目会有多层依赖项,将其全部细目列出即为“依赖项树”。

一般来说,在源代码文件内,通常在最开头位置,会列出依赖项。每当编译器或直译器找到一个依赖项时,会从一系列预定义的目录中查找。 由于一个项目的依赖项树可能非常复杂,有时在一个项目中,其完整的依赖项树需要一个单独文件,称为一个“包列表”。 例如,Ruby 语言项目为此可能有一个 Gemfile 文件,而 JavaScript 语言项目可能有一个 package.json 文件。 这样一来,一种叫“包管理软件”的工具可从一个或多个互联网服务器中一次性获取一个项目的所有依赖项。

就本档案库而言,任何指定项目的依赖项均可能存在本档案库中的某个地方。 要在档案库中找到一个依赖项,您需先在源代码或包列表中找到该依赖项名称,其具体详情可能会因语言和框架而不同。然后,使用“指南胶卷”中的主索引(如无主索引,则使用每个胶卷前面的索引)确定应去哪个胶卷和哪个帧中找到该仓库。

开源

由于在计算机上运行程序仅需要经编译的机器代码,因此在传播机器代码时仍可对源代码进行保密。 这种做法称为“闭源”模型。 在计算技术发展的早期,源代码一般随着其机器代码一同传播,然而后来软件可为行业带来盈利,闭源模型也随之越发常见。

再后来,人们意识到将源代码公开,允许任何人复制、分支和改进,是一种更有效得多的软件开发方式。 让更多人读取某个项目的源代码意味着,更多人发现可能的需求和有用的新功能,更多人可充分了解该项目并为其锦上添花,更多人可能找到漏洞并提交解决方案,更多人可以测试和验证新代码的有效性。

总之,闭源会导致群体变得微小、狭隘、破碎,人们从中难以发现和应用更新的更佳理念。 相反,开源有助营造广大的互联社会。在其中,人人均可帮助他人发展、壮大项目,以获取成功;也可使用他人代码作为依赖项及/或重新利用其代码,实现互相学习。 开源软件是供所有人类集体使用的工具包,我们拥有越多、越好的工具,人类种群的发展进程才会越快、越好。

3赞