标签 编程 下的文章

准备好你喜欢的饮料、编辑器和编译器,放一些音乐,然后开始构建一个由多个文件组成的 C 语言程序。

大家常说计算机编程的艺术部分是处理复杂性,部分是命名某些事物。此外,我认为“有时需要添加绘图”是在很大程度上是正确的。

在这篇文章里,我会编写一个小型 C 程序,命名一些东西,同时处理一些复杂性。该程序的结构大致基于我在 《如何写一个好的 C 语言 main 函数》 文中讨论的。但是,这次做一些不同的事。准备好你喜欢的饮料、编辑器和编译器,放一些音乐,让我们一起编写一个有趣的 C 语言程序。

优秀 Unix 程序哲学

首先,你要知道这个 C 程序是一个 Unix 命令行工具。这意味着它运行在(或者可被移植到)那些提供 Unix C 运行环境的操作系统中。当贝尔实验室发明 Unix 后,它从一开始便充满了设计哲学。用我自己的话来说就是:程序只做一件事,并做好它,并且对文件进行一些操作。虽然“只做一件事,并做好它”是有意义的,但是“对文件进行一些操作”的部分似乎有点儿不合适。

事实证明,Unix 中抽象的 “文件” 非常强大。一个 Unix 文件是以文件结束符(EOF)标志为结尾的字节流。仅此而已。文件中任何其它结构均由应用程序所施加而非操作系统。操作系统提供了系统调用,使得程序能够对文件执行一套标准的操作:打开、读取、写入、寻址和关闭(还有其他,但说起来那就复杂了)。对于文件的标准化访问使得不同的程序共用相同的抽象,而且可以一同工作,即使它们是不同的人用不同语言编写的程序。

具有共享的文件接口使得构建可组合的的程序成为可能。一个程序的输出可以作为另一个程序的输入。Unix 家族的操作系统默认在执行程序时提供了三个文件:标准输入(stdin)、标准输出(stdout)和标准错误(stderr)。其中两个文件是只写的:stdoutstderr。而 stdin 是只读的。当我们在常见的 Shell 比如 Bash 中使用文件重定向时,可以看到其效果。

$ ls | grep foo | sed -e 's/bar/baz/g' > ack

这条指令可以被简要地描述为:ls 的结果被写入标准输出,它重定向到 grep 的标准输入,grep 的标准输出重定向到 sed 的标准输入,sed 的标准输出重定向到当前目录下文件名为 ack 的文件中。

我们希望我们的程序在这个灵活又出色的生态系统中运作良好,因此让我们编写一个可以读写文件的程序。

喵呜喵呜:流编码器/解码器概念

当我还是一个露着豁牙的孩子懵懵懂懂地学习计算机科学时,学过很多编码方案。它们中的有些用于压缩文件,有些用于打包文件,另一些毫无用处因此显得十分愚蠢。列举最后这种情况的一个例子:哞哞编码方案

为了让我们的程序有个用途,我为它更新了一个 21 世纪 的概念,并且实现了一个名为“喵呜喵呜” 的编码方案的概念(毕竟网上大家都喜欢猫)。这里的基本的思路是获取文件并且使用文本 “meow” 对每个半字节(半个字节)进行编码。小写字母代表 0,大写字母代表 1。因为它会将 4 个比特替换为 32 个比特,因此会扩大文件的大小。没错,这毫无意义。但是想象一下人们看到经过这样编码后的惊讶表情。

$ cat /home/your_sibling/.super_secret_journal_of_my_innermost_thoughts
MeOWmeOWmeowMEoW...

这非常棒。

最终的实现

完整的源代码可以在 GitHub 上面找到,但是我会写下我在编写程序时的思考。目的是说明如何组织构建多文件 C 语言程序。

既然已经确定了要编写一个编码和解码“喵呜喵呜”格式的文件的程序时,我在 Shell 中执行了以下的命令 :

$ mkdir meowmeow
$ cd meowmeow
$ git init
$ touch Makefile     # 编译程序的方法
$ touch main.c       # 处理命令行选项
$ touch main.h       # “全局”常量和定义
$ touch mmencode.c   # 实现对喵呜喵呜文件的编码
$ touch mmencode.h   # 描述编码 API
$ touch mmdecode.c   # 实现对喵呜喵呜文件的解码
$ touch mmdecode.h   # 描述解码 API
$ touch table.h      # 定义编码查找表
$ touch .gitignore   # 这个文件中的文件名会被 git 忽略
$ git add .
$ git commit -m "initial commit of empty files"

简单的说,我创建了一个目录,里面全是空文件,并且提交到 git。

即使这些文件中没有内容,你依旧可以从它的文件名推断每个文件的用途。为了避免万一你无法理解,我在每条 touch 命令后面进行了简单描述。

通常,程序从一个简单 main.c 文件开始,只有两三个解决问题的函数。然后程序员轻率地向自己的朋友或者老板展示了该程序,然后为了支持所有新的“功能”和“需求”,文件中的函数数量就迅速爆开了。“程序俱乐部”的第一条规则便是不要谈论“程序俱乐部”,第二条规则是尽量减少单个文件中的函数。

老实说,C 编译器并不关心程序中的所有函数是否都在一个文件中。但是我们并不是为计算机或编译器写程序,我们是为其他人(有时也包括我们)去写程序的。我知道这可能有些奇怪,但这就是事实。程序体现了计算机解决问题所采用的一组算法,当问题的参数发生了意料之外的变化时,保证人们可以理解它们是非常重要的。当在人们修改程序时,发现一个文件中有 2049 函数时他们会诅咒你的。

因此,优秀的程序员会将函数分隔开,将相似的函数分组到不同的文件中。这里我用了三个文件 main.cmmencode.cmmdecode.c。对于这样小的程序,也许看起来有些过头了。但是小的程序很难保证一直小下去,因此哥忒拓展做好计划是一个“好主意”。

但是那些 .h 文件呢?我会在后面解释一般的术语,简单地说,它们被称为头文件,同时它们可以包含 C 语言类型定义和 C 预处理指令。头文件中不应该包含任何函数。你可以认为头文件是提供了应用程序接口(API)的定义的一种 .c 文件,可以供其它 .c 文件使用。

但是 Makefile 是什么呢?

我知道下一个轰动一时的应用都是你们这些好孩子们用 “终极代码粉碎者 3000” 集成开发环境来编写的,而构建项目是用 Ctrl-Meta-Shift-Alt-Super-B 等一系列复杂的按键混搭出来的。但是如今(也就是今天),使用 Makefile 文件可以在构建 C 程序时帮助做很多有用的工作。Makefile 是一个包含如何处理文件的方式的文本文件,程序员可以使用其自动地从源代码构建二进制程序(以及其它东西!)

以下面这个小东西为例:

00 # Makefile
01 TARGET= my_sweet_program
02 $(TARGET): main.c
03    cc -o my_sweet_program main.c

# 符号后面的文本是注释,例如 00 行。

01 行是一个变量赋值,将 TARGET 变量赋值为字符串 my_sweet_program。按照惯例,也是我的习惯,所有 Makefile 变量均使用大写字母并用下划线分隔单词。

02 行包含该 步骤 recipe 要创建的文件名和其依赖的文件。在本例中,构建 目标 target my_sweet_program,其依赖是 main.c

最后的 03 行使用了一个制表符号(tab)而不是四个空格。这是将要执行创建目标的命令。在本例中,我们使用 C 编译器 C compiler 前端 cc 以编译链接为 my_sweet_program

使用 Makefile 是非常简单的。

$ make
cc -o my_sweet_program main.c
$ ls
Makefile  main.c  my_sweet_program

构建我们喵呜喵呜编码器/解码器的 Makefile 比上面的例子要复杂,但其基本结构是相同的。我将在另一篇文章中将其分解为 Barney 风格。

形式伴随着功能

我的想法是程序从一个文件中读取、转换它,并将转换后的结果存储到另一个文件中。以下是我想象使用程序命令行交互时的情况:

$ meow < clear.txt > clear.meow
$ unmeow < clear.meow > meow.tx
$ diff clear.txt meow.tx
$

我们需要编写代码以进行命令行解析和处理输入/输出流。我们需要一个函数对流进行编码并将结果写到另一个流中。最后,我们需要一个函数对流进行解码并将结果写到另一个流中。等一下,我们在讨论如何写一个程序,但是在上面的例子中,我调用了两个指令:meowunmeow?我知道你可能会认为这会导致越变越复杂。

次要内容:argv[0] 和 ln 指令

回想一下,C 语言 main 函数的结构如下:

int main(int argc, char *argv[])

其中 argc 是命令行参数的数量,argv 是字符指针(字符串)的列表。argv[0] 是包含正在执行的程序的文件路径。在 Unix 系统中许多互补功能的程序(比如:压缩和解压缩)看起来像两个命令,但事实上,它们是在文件系统中拥有两个名称的一个程序。这个技巧是通过使用 ln 命令创建文件系统链接来实现两个名称的。

在我笔记本电脑中 /usr/bin 的一个例子如下:

$ ls -li /usr/bin/git*
3376 -rwxr-xr-x. 113 root root     1.5M Aug 30  2018 /usr/bin/git
3376 -rwxr-xr-x. 113 root root     1.5M Aug 30  2018 /usr/bin/git-receive-pack
...

这里 gitgit-receive-pack 是同一个文件但是拥有不同的名字。我们说它们是相同的文件因为它们具有相同的 inode 值(第一列)。inode 是 Unix 文件系统的一个特点,对它的介绍超越了本文的内容范畴。

优秀或懒惰的程序可以通过 Unix 文件系统的这个特点达到写更少的代码但是交付双倍的程序。首先,我们编写一个基于其 argv[0] 的值而作出相应改变的程序,然后我们确保为导致该行为的名称创建链接。

在我们的 Makefile 中,unmeow 链接通过以下的方式来创建:

# Makefile
...
$(DECODER): $(ENCODER)
        $(LN) -f $< $@
       ...

我倾向于在 Makefile 中将所有内容参数化,很少使用 “裸” 字符串。我将所有的定义都放置在 Makefile 文件顶部,以便可以简单地找到并改变它们。当你尝试将程序移植到新的平台上时,需要将 cc 改变为某个 cc 时,这会很方便。

除了两个内置变量 $@$< 之外,该 步骤 recipe 看起来相对简单。第一个便是该步骤的目标的快捷方式,在本例中是 $(DECODER)(我能记得这个是因为 @ 符号看起来像是一个目标)。第二个,$< 是规则依赖项,在本例中,它解析为 $(ENCODER)

事情肯定会变得复杂,但它还在管理之中。


via: https://opensource.com/article/19/7/structure-multi-file-c-part-1

作者:Erik O'Shaughnessy 选题:lujun9972 译者:萌新阿岩 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

学习一门新的编程语言是在你的职业生涯中继续前进的好方法,但是应该学习哪一门呢?

如果你想要开始你的编程生涯或继续前进,那么学习一门新语言是一个聪明的主意。但是,大量活跃使用的语言引发了一个问题:哪种编程语言是最好的?要回答这个问题,让我们从一个简单的问题开始:你想做什么样的程序?

如果你想在客户端进行网络编程,那么特定语言 HTML、CSS 和 JavaScript(看似无穷无尽的方言之一)是必须要学习的。

如果你想在服务器端进行 Web 编程,那么选择包括常见的通用语言:C++、Golang、Java、C#、 Node.js、Perl、Python、Ruby 等等。当然,服务器程序与数据存储(例如关系数据库和其他数据库)打交道,这意味着 SQL 等查询语言可能会发挥作用。

如果你正在为移动设备编写原生应用程序,那么了解目标平台非常重要。对于 Apple 设备,Swift 已经取代 Objective C 成为首选语言。对于 Android 设备,Java(带有专用库和工具集)仍然是主要语言。有一些特殊语言,如与 C# 一起使用的 Xamarin,可以为 Apple、Android 和 Windows 设备生成特定于平台的代码。

那么通用语言呢?通常有各种各样的选择。在动态脚本语言(如 Perl、Python 和 Ruby)中,有一些新东西,如 Node.js。而 Java 和 C# 的相似之处比它们的粉丝愿意承认的还要多,仍然是针对虚拟机(分别是 JVM 和 CLR)的主要静态编译语言。在可以编译为原生可执行文件的语言中,C++ 仍在使用,还有后来出现的 Golang 和 Rust 等。通用的函数式语言比比皆是(如 Clojure、Haskell、Erlang、F#、Lisp 和 Scala),它们通常都有热情投入的社区。值得注意的是,面向对象语言(如 Java 和 C#)已经添加了函数式构造(特别是 lambdas),而动态语言从一开始就有函数式构造。

让我以 C 语言结尾,它是一种小巧、优雅、可扩展的语言,不要与 C++ 混淆。现代操作系统主要用 C 语言编写,其余部分用汇编语言编写。任何平台上的标准库大多数都是用 C 语言编写的。例如,任何打印 Hello, world! 这种问候都是通过调用名为 write 的 C 库函数来实现的。

C 作为一种可移植的汇编语言,公开了其他高级语言有意隐藏的底层系统的详细信息。因此,理解 C 可以更好地掌握程序如何竞争执行所需的共享系统资源(如处理器、内存和 I/O 设备)。C 语言既高级又接近硬件,因此在性能方面无与伦比,当然,汇编语言除外。最后,C 是编程语言中的通用语言,几乎所有通用语言都支持某种形式的 C 调用。

有关现代 C 语言的介绍,参考我的书籍《C 语言编程:可移植的汇编器介绍》。无论你怎么做,学习 C 语言,你会学到比另一种编程语言多得多的东西。

你认为学习哪些编程语言很重要?你是否同意这些建议?在评论告知我们!


via: https://opensource.com/article/19/2/which-programming-languages-should-you-learn

作者:Marty Kalin 选题:lujun9972 译者:MjSeven 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

编程字体有些在普通字体中没有的特点,这五种字体你可以看看。

什么是最好的编程字体呢?首先,你需要考虑到字体被设计出来的初衷可能并不相同。当选择一款用于休闲阅读的字体时,读者希望该字体的字母能够顺滑地衔接,提供一种轻松愉悦的体验。一款标准字体的每个字符,类似于拼图的一块,它需要被仔细的设计,从而与整个字体的其他部分融合在一起。

然而,在编写代码时,通常来说对字体的要求更具功能性。这也是为什么大多数程序员在选择时更偏爱使用固定宽度的等宽字体。选择一款带有容易分辨的数字和标点的字体在美学上令人愉悦;但它是否拥有满足你需求的版权许可也是非常重要的。

某些功能使得字体更适合编程。首先要清楚是什么使得等宽字体看上去井然有序。这里,让我们对比一下字母 w 和字母 i。当选择一款字体时,重要的是要考虑字母本身及周围的空白。在纸质的书籍和报纸中,有效地利用空间是极为重要的,为瘦小的 i 分配较小的空间,为宽大的字母 w 分配较大的空间是有意义的。

然而在终端中,你没有这些限制。每个字符享有相等的空间将非常有用。这么做的首要好处是你可以随意扫过一段代码来“估测”代码的长度。第二个好处是能够轻松地对齐字符和标点,高亮在视觉上更加明显。另外打印纸张上的等宽字体比均衡字体更加容易通过 OCR 识别。

在本篇文章中,我们将探索 5 款卓越的开源字体,使用它们来编程和写代码都非常理想。

1、Firacode:最佳整套编程字体

 title=

FiraCode, Andrew Lekashman

在我们列表上的首款字体是 FiraCode,一款真正符合甚至超越了其职责的编程字体。FiraCode 是 Fira 的扩展,而后者是由 Mozilla 委托设计的开源字体族。使得 FiraCode 与众不同的原因是它修改了在代码中常使用的一些符号的组合或连字,使得它看上去更具可读性。这款字体有几种不同的风格,特别是还包含 Retina 选项。你可以在它的 GitHub 主页中找到它被使用到多种编程语言中的例子。

 title=

FiraCode 与 Fira Mono 的对比,Nikita Prokopov,源自 GitHub

2、Inconsolata:优雅且由卓越设计者创造

 title=

Inconsolata, Andrew Lekashman

Inconsolata 是最为漂亮的等宽字体之一。从 2006 年开始它便一直是一款开源和可免费获取的字体。它的创造者 Raph Levien 在设计 Inconsolata 时秉承的一个基本原则是:等宽字体并不应该那么糟糕。使得 Inconsolata 如此优秀的两个原因是:对于 0o 这两个字符它们有很大的不同,另外它还特别地设计了标点符号。

3、DejaVu Sans Mono:许多 Linux 发行版的标准配置,庞大的字形覆盖率

 title=

DejaVu Sans Mono, Andrew Lekashman

受在 GNOME 中使用的带有版权和闭源的 Vera 字体的启发,DejaVu Sans Mono 是一个非常受欢迎的编程字体,几乎在每个现代的 Linux 发行版中都带有它。在 Book Variant 风格下 DejaVu 拥有惊人的 3310 个字形,相比于一般的字体,它们含有 100 个左右的字形。在工作中你将不会出现缺少某些字符的情况,它覆盖了 Unicode 的绝大部分,并且一直在活跃地增长着。

4、Source Code Pro:优雅、可读性强,由 Adobe 中一个小巧但天才的团队打造

 title=

Source Code Pro, Andrew Lekashman

由 Paul Hunt 和 Teo Tuominen 设计,Source Code Pro由 Adobe 创造的,成为了它的首款开源字体。Source Code Pro 值得注意的地方在于它极具可读性,且对于容易混淆的字符和标点,它有着非常好的区分度。Source Code Pro 也是一个字体族,有 7 中不同的风格:Extralight、Light、Regular、Medium、Semibold、Bold 和 Black,每种风格都还有斜体变体。

 title=

潜在易混淆的字符之间的区别,Paul D. Hunt 源自 Adobe Typekit 博客。

 title=

在计算机领域中有特别含义的特殊元字符, Paul D. Hunt 源自 Adobe Typekit 博客。

5、Noto Mono:巨量的语言覆盖率,由 Google 中的一个大团队打造

 title=

Noto Mono, Andrew Lekashman

在我们列表上的最后一款字体是 Noto Mono,这是 Google 打造的庞大 Note 字体族中的等宽版本。尽管它并不是专为编程所设计,但它在 209 种语言(包括 emoji 颜文字!)中都可以使用,并且一直在维护和更新。该项目非常庞大,是 Google 宣称 “组织全世界信息” 的使命的延续。假如你想更多地了解它,可以查看这个绝妙的关于这些字体的视频

选择合适的字体

无论你选择那个字体,你都有可能在每天中花费数小时面对它,所以请确保它在审美和哲学层面上与你产生共鸣。选择正确的开源字体是确保你拥有最佳生产环境的一个重要部分。这些字体都是很棒的选择,每个都具有让它脱颖而出的功能强大的特性。


via: https://opensource.com/article/17/11/how-select-open-source-programming-font

作者:Andrew Lekashman 译者:FSSlc 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

通过树莓派学习编程,让你在就业市场上更值钱。

在本系列的上一篇文章中,我分享了 教孩子们使用树莓派编程 的一些方式。理论上,这些资源并不局限于只适用于孩子们,成人也是可以使用的。但是学习就业市场上急需的编程语言,可以让你得到更好的机会。

这里是你可以使用树莓派学习的三种编程语言。

Python

Python 已经成为开源世界里 最流行的编程语言。它的解释器已经打包进每个流行的 Linux 发行版中。如果你在树莓派中安装的是 Raspbian,你就会看到一个名为 Thonny 的应用,它是为新手准备的 Python 集成开发环境。简单来说,一个集成开发环境就是能够提供让你的代码运行起来所需要的任何东西的一个应用程序,一般来说,包括调试器、文档、自动编译,和仿真程序。这是一个在树莓派上使用 Thonny 和 Python 入门的非常好的小教程

Java

虽然 Java 已经不像以前那样引人注目了,但它仍然在世界各地的大学和企业中占据着重要的地位。因此,即便是一些人对我建议新手学习 Java 持反对意见,但我仍然强烈推荐大家去学习 Java;之所以这么做,原因之一是,它仍然很流行,原因之二是,它有大量的便于你学习的图书、课程和其它的可用信息。在树莓派上学习它,你可以从使用 Java 集成开发环境 BlueJ 开始。

JavaScript

“我的黄金时代…" JavaScript 的本质是一个允许用户去组织和自动化浏览器中的用户事件以及修改 HTML 元素的客户端语言。目前,JavaScript 已经不仅限于浏览器中,它在其它类型的客户端(移动应用)中也是可以使用的,甚至也用在服务器端编程。Node.js 是一个流行的运行时环境,它允许开发者在客户端-浏览器范式之外写程序。想学习在树莓派上运行 Node.js 的更多知识,请查看 W3Schools 教程

其它编程语言

如果这里没有列出你想学习的编程语言,别失望。你可以使用你的树莓派去编译或解释任何你选择的语言,包括 C、C++、PHP 和 Ruby,这种可能性还是很大的。

微软的 Visual Studio Code 也可以运行在 树莓派 上。它是来自微软的开源代码编辑器,它支持多种标记和编程语言。


via: https://opensource.com/article/19/3/programming-languages-raspberry-pi

作者:Anderson Silva 选题:lujun9972 译者:qhwdw 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

资深软件开发人员都知道 Hello World 程序,这是一个能在设备显示器上输出某种变体的 “Hello, World!” 的程序,是学习编程的第一步。在这个编程中只涉及到一些最基本语法的程序,可以用大多数编程语言了来编写。事实上,路易斯安纳理工学院计算机协会(ACM)在最近统计发现这个程序至少有 204 个版本。

传统意义上,Hello World 程序是用于说明编码过程是如何工作的,以及确保编程语言或系统能正常运行。它们经常是新手程序员学习的第一个程序,因为即使是经验很少或者没有经验的人也能轻松正确的执行 Hello World。

首先,Hello World 简单,这就是为什么它经常被用做程序执行成功的晴雨表。如果 Hello World 在该框架中无法有效执行,那么其它更复杂的程序中也可能会失败。正如 Win-Vector 的一位专家所说,Hello World 实际上是一个对抗性程序。“该作者还说道,‘你的计算机系统能不能工作并不是一目了然,除非我能看到它至少能打印一行文字,否则我不会在上面浪费太多时间。’” Win-Vector 博主 John Mount 说。

但是这个两词短语在计算机科学领域有着重大的影响。以 Hello World 为基础,新手程序员可以轻松的理解计算机科学原理或元素,而拥有多年编码经验的程序员可以用它来学习编程语言的工作原理,特别是在结构与语法方面。这样的一个小程序,在任何难度的应用程序和几乎所有语言中都有着悠久的历史。

用途

以上概括了 Hello World 程序的主要用途:这是新手程序员熟悉新语言的一种方式。然而,这些程序不仅仅是对编码世界的介绍。例如,Hello World 可以作为测试,以确保语言的组件(编译器、开发和运行环境)安装正确。因为配置完整的编程工具链的过程复杂而漫长,所以像 Hello World 这样简单的程序通常用作新工具链的首次运行测试。

根据 Cunningham & Cunningham(C2)的编程顾问所说,在系统设计人员并不预期可以执行代码的地方,黑客经常使用 Hello World 程序作为一个可以通过漏洞执行任意代码的概念验证(POC)。事实上,它是在设备上使用自制内容或者“自酿”的第一步,当有经验的编码人员正在配置环境或在学习新事物时,他们会通过 Hello World 来验证其行为是否正确。

它也作为调试过程的一部分,允许程序员检查他们是否正确地编辑了可在运行时修改的程序并重新加载。

Hello World 的一个更常用的用途是作为基础比较。根据 C2 的 wiki 所讲,程序员可以“比较语言生成的可执行文件的大小,以及程序背后必须存在多少支持的基础设施才能执行。”

开端

虽然 Hello World 的起源还有些不太明了,不过人们普遍认为它作为测试用语,最早出现在 Brian Kernigham 在 1972 年发布的《 B 语言简介教程 A Tutorial Introduction to the Language B 》中。在此文中,该程序的第一个已知版本用于说明外部变量。因为该教程中的前一个例子在终端上打印了 “hi!”,而需要更多的字符常量来表达相对复杂的 “hello,world!”,这是学习过程的下一步。

在那以后,它还被用于 1974 年的贝尔实验室备忘录,以及 1987 年的《 C 语言程序设计 The C Programming Language 》。这两篇著名的文字是让 Hello World 闻名于世的主要原因。在书中的一个例子(第一个,也是最著名的例子)打印了没有大写字母和感叹号的 “hello,world”。此时的 Hello World 几乎只是用于说明语言的一些功能,而不是测试系统是否正常运行。

在 Kernigham 的关于 B 语言和 C 语言的开创性文章之前,没有真正意义上的第一个程序,甚至直到 1974 年,它也没被广泛使用。著名的 BASIC 教程 “ 我的电脑喜欢我用 BASIC 跟它讲话 My Computer Likes Me,When I Speak BASIC ”,从一个写一行文本的简单程序开始,不过那句话是 “MY HUMAN UNDERSTANDS ME”,跟如今程序员侃侃而谈的这个双词问候语差的有点远。不过,当 Hello World 被发明后,它就迅速传播,并在 20 世纪 70 年代后变成了众所周知。直到今天它也依然受欢迎。

一个声明,多种语言

以下是目前正在被使用的一些流行的编程语言中的 Hello World 代码。

Java

class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}

C

using System;
class Program
{
    public static void Main(string[] args)
    {
        Console.WriteLine("Hello, world!");
    }
}

Python

print("Hello, world!")

Ruby

puts "Hello, world!"

Scala

object HelloWorld extends App {
    println("Hello, world!")
}

ASP.NET

Response.Write("Hello World!");

Lisp

(princ "Hello, world!")

Haskell

main = putStrLn "Hello, world!"

Malbolge

('&%:9]!~}|z2Vxwv-,POqponl$Hjig%eB@@>}=<M:9wv6WsU2T|nm-,jcL(I&%$#"
`CB]V?Tx<uVtT`Rpo3NlF.Jh++FdbCBA@?]!~|4XzyTT43Qsqq(Lnmkj"Fhg${z@>

Go

package main
import "fmt"
func main() {
    fmt.Println("Hello, world!")
}

如今的 Hello world:各种形式下的标准实践

在现在的编程语言中,Hello World 有着不同的复杂程度。例如,Go 语言中引入一个多语言版的 Hello World 程序,XL 则会提供一个具有图形、可旋转的 3D 版本。一些编程语言,像 Ruby、Python,仅仅需要一个语句去打印“Hello World”,但是低级汇编语言则需要几个命令才能做到这样。现在的编程语言还引入对标点符号和大小写的变化,包括是否有逗号或者感叹号,以及两个词的大写形式。举个例子,当系统只支持大写字母,会呈现像“HELLO WORLD”的短语。值得纪念的第一个 Malbolge 程序打印出了“HEllO WORld”(LCTT 译注:Malbolge 是最难的编程语言之一。事实上,在它诞生后,花了 2 年时间才完成第一个 Malbolge 程序)。它的变体跨越了原本的字面意思。像 Lisp、Haskell 这样函数语言,用阶乘程序替代了 Hello World,从而注重递归技术。这与原来的示例不同,后者更强调 I/O 以及产生的副作用。

随着现在的编程语言越来越复杂,Hello World 比以往显得更加重要。作为测试和教学工具,它已经成为程序员测试配置的编程环境的标准方法。没有人能确切说出为什么 Hello World 能在快速创新著称的行业中经受住时间的考验,但是它又确实留下来了。


via: https://www.thesoftwareguild.com/blog/the-history-of-hello-world/

作者:thussong 选题:lujun9972 译者:zzzzzzmj 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

为开源项目作贡献最好的方式是为它减少代码,我们应致力于写出让新手程序员无需注释就容易理解的代码,让维护者也无需花费太多精力就能着手维护。

在学生时代,我们会更多地用复杂巧妙的技术去挑战新的难题。首先我们会学习循环,然后是函数啊,类啊,等等。当我们到达一定高的程度,能用更高级的技术写更长的程序,我们会因此受到称赞。此刻我们发现老司机们用 monads 而新手们用 loop 作循环。

之后我们毕业找了工作,或者和他人合作开源项目。我们用在学校里学到的各种炫技寻求并骄傲地给出解决方案的代码实现。

哈哈,我能扩展这个项目,并实现某牛 X 功能啦,我这里能用继承啦,我太聪明啦!

我们实现了某个小的功能,并以充分的理由觉得自己做到了。现实项目中的编程却不是针对某某部分的功能而言。以我个人的经验而言,以前我很开心的去写代码,并骄傲地向世界展示我所知道的事情。有例为证,作为对某种编程技术的偏爱,这是用另一种元编程语言构建的一个 线性代数语言,注意,这么多年以来一直没人愿意碰它。

在维护了更多的代码后,我的观点发生了变化。

  1. 我们不应去刻意探求如何构建软件。软件是我们为解决问题所付出的代价,那才是我们真实的目的。我们应努力为了解决问题而构建较小的软件。
  2. 我们应使用尽可能简单的技术,那么更多的人就越可能会使用,并且无需理解我们所知的高级技术就能扩展软件的功能。当然,在我们不知道如何使用简单技术去实现时,我们也可以使用高级技术。

所有的这些例子都不是听来的故事。我遇到的大部分人会认同某些部分,但不知为什么,当我们向一个新项目贡献代码时又会忘掉这个初衷。直觉里用复杂技术去构建的念头往往会占据上风。

软件是种投入

你写的每行代码都要花费人力。写代码当然是需要时间的,也许你会认为只是你个人在奉献,然而这些代码在被审阅的时候也需要花时间理解,对于未来维护和开发人员来说,他们在维护和修改代码时同样要花费时间。否则他们完全可以用这时间出去晒晒太阳,或者陪伴家人。

所以,当你向某个项目贡献代码时,请心怀谦恭。就像是,你正和你的家人进餐时,餐桌上却没有足够的食物,你只索取你所需的部分,别人对你的自我约束将肃然起敬。以更少的代码去解决问题是很难的,你肩负重任的同时自然减轻了别人的重负。

技术越复杂越难维护

作为学生,逐渐使用高端技术证明了自己的价值。这体现在,首先我们有能力在开源项目中使用函数,接着是类,然后是高阶函数,monads 等等。我们向同行显示自己的解决方案时,常因自己所用技术高低而感到自豪或卑微。

而在现实中,和团队去解决问题时,情况发生了逆转。现在,我们致力于尽可能使用简单的代码去解决问题。简单方式解决问题使新手程序员能够以此扩展并解决其他问题。简单的代码让别人容易上手,效果立竿见影。我们藉以只用简单的技术去解决难题,从而展示自己的价值。

看,我用循环替代了递归函数并且一样达到了我们的需求。当然我明白这是不够聪明的做法,不过我注意到新手同事在这里会遇上麻烦,我觉得这种改变将有所帮助吧。

如果你是个好的程序员,你不需要证明你知道很多炫技。相应的,你可以通过用一个简单的方法解决一个问题来显示你的价值,并激发你的团队在未来的时间里去完善它。

当然,也请保持节制

话虽如此,过于遵循 “用简单的工具去构建” 的教条也会降低生产力。通常用递归会比用循环解决问题更简单,用类或 monad 才是正确的途径。还有两种情况另当别论,一是只是只为满足自我而创建的系统,或者是别人毫无构建经验的系统。


via: http://matthewrocklin.com/blog/work/2018/01/27/write-dumb-code

作者:Matthew Rocklin 译者:plutoid 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出