Horo
Horo

目前是 LikeCoin Chain 验证人 Yoitsu 背后的家伙,以及 CDC/CFC 划水组成员(笑)。偶尔会变身成狐狸。( @foobarz )

编程生涯 ABC(C) - 程序之道,提问杀虫

上一篇文章(可以在关联文章里看到)里有人和咱讲说初学者真的有必要学习那么多工具的话以后……

嘛这也真是一个难办的问题,选择好的工具可以提高学习效率,工具学的太深又影响主要的学习进度。

于是自己看着办吧…… ,面向初学者的教程通常会推荐一部分合适的工具,应该不会有太大的问题。(汝看的教程太坑的话另当别论)

程序是什么?提问?杀虫?这些和编码和有什么关系?马上就会知道了(大概吧)。

所以程序是什么?

程序是一个描述一组运算的指令的序列。这种运算也许是数学上的,比如求解一组等式或者求多项式的根;当然也可以是符号运算,比如在文档中搜索和替换文字,或者一些图形化过程,比如处理图像或者播放一段视频。

尽管程序功能各有不同,编程语言也五彩斑斓(啥?)但几乎所有的编程语言都具备这几种基本操作:

  • 从各种地方获得输入,例如键盘、文件、网络还是别的地方。
  • 将数据发送到哪里,例如屏幕、文件和网络。
  • 进行基本的数学操作,最少要有个加法(?),看需要可以扩展到四则运算或者更复杂的计算什么的。
  • 检查特定条件是否满足来运行相应的代码。
  • 重复进行一些操作,重复的过程中通常都会有些变化。

可以大言不惭(?)的说,汝现在和未来会写出的程序的多复杂的部份,都能被分解成这几种基本操作的组合。

编译和解释 - 两大“教派”

就像人类按国家或地区不同,所掌握的语言也不尽相同的话,计算机也大抵如此。它可不懂咱们讲的汉语英语什么的,由于设计啥的一些原因,计算机能理解的就是一堆 0 和 1 啦。

然而人类并不愿意直接写一堆 0 和 1 啦,于是就发明了各种稍微贴近人类写法的程序设计语言们。以及帮忙把源代码转换成计算机可以执行的机器代码的程序,这就是编译器(或者解释器)啦。

举一个栗子的话,一个程序的源代码就像一个用汉语(程序设计语言)写下的红烧肉菜谱(程序源代码),用于指导懂汉语(编译器或解释器)同时也会烹饪手法(体系结构)的人来做这道(程序)。

  • 编译器是一组把源代码转换成适合目标体系结构的目标代码(有时也被称作“机器代码”)的程序,源代码编译成目标代码后,只需要目标代码即可运行。编译语言虽然编译需要一些时间,但是能够显著提高运行效率,因此很多基础领域和对运行效率有要求的领域都大量的采用编译语言,例如 C 和 C++ 。
  • 解释器是一组读取源代码,然后依次转换成目标代码并执行的程序。解释语言虽然因为解释器的缘故效率会有下降,但是解释语言通常可以很快的进行测试,修改源代码后可以迅速运行。现在采用解释的语言也逐渐多了起来,例如 Python 和 JavaScript。
  • 然而这两种语言并没有明显的界限,有的编译语言会采用一些解释手段提高编译速度,有的解释语言也会采用一些编译手段提高运行效率。典型的栗子就是 Java 和 Python,它们都有把源代码编译成体系结构无关的中间代码(通常被称作“字节码”)的过程。

调试和虫子的“不解之缘”

就算汝没有写过代码,可能也有听说过调试(Debug)这个词。里面是不是还看到了“昆虫”(bug)?比较流行的说法就是那个第一只(?)导致程序出错的昆虫咯……


“在被要求解释为何系统未按期望运转时,有一位技术人员答道,‘有一只虫子在系统里’,并且负责地把它——翅膀和其它所有部份,粘贴到了日志簿里。”

因为人无完人嘛,也没有谁能写出没有错误的代码。如果汝已经开始动手写些什么了的话,大概能够感同身受。要把程序错误像垃圾一样(?)清晰的分类的话,常见的有这么几种。

  • 因为程序的源代码需要通过一些方式(例如汝可能经常听说的编译或解释)来转换成电脑可以执行的指令,如果中间过程的程序(编译器或解释器)不能理解汝的源代码的话,就会产生一个语法错误。

造成语法错误的原因有很多种:

  • 例如不合规则的命名和运算符(很多的语言要求变量不能以数字或者某些符号开头,或者不能以某些名字命名变量什么的)。例如 1 = 0class = None 都会在 Python 里造成语法错误。(如果汝有意稍微深入一下的话,变量不能用数字开头,而 class 等一些词因为经常在源代码里出现而被 Python 用作保留字,以保留字命名变量会导致语法错误。)
  • 以及某些不可见元素(像是空格和制表符什么的)在某些语言里也会造成语法错误。(没错还是 Python,对源代码的缩进还是很有要求的,以及不能把空格和制表符放在一个源代码里。)
  • 还有没配对的括号和引号什么的。

要对付语法错误的话,一个支持语法高亮的文字编辑器或者集成开发环境都能解决个七七八八啦。支持这种功能的话,在看到源代码的文字没有标上合适的颜色的话,就能发现问题里呗。

  • 如果源代码能顺利的编译或解释,但是运行的过程中遇到什么问题的话,这就是一个运行时错误。在某些地方,运行时错误也被称作“异常”,因为一般表示一些意外的尤其是比较糟糕的情况发生了。

造成运行时错误的原因……还是有很多种。例如数学运算超出范围啦,要打开文件但是找不到啦,需要访问网络的时候连不上网啦等等。这种错误的话,老实讲没有啥通用的策略,只有遇上的时候具体问题具体分析啦。

  • 如果源代码能顺利的运行,但是运行的结果和汝期望的不一样的话,汝有可能遇到了一个语义错误。
  • 当然语义错误的另一种极端情况就是,它做的正是汝要它做的。(是不是有些不明所以?)

一个典型的语义错误就是计算,例如前一阵子讨论特别多的 10%+10% ,因为人和计算器计算方法不同导致的结果大相径庭。(中缀表示法中括号的重要性)

意识到自己遇上一个语义错误已经不容易了,发现一个就更难了,汝可能需要仔细回顾代码和程序输出,要搞清楚到底程序做了什么。

那么,如果汝真的遇上了一个错误,在汝感到愤怒、压抑,或者难受之前……

不负责调试策略(简)

人们大抵会像对人那样对待电脑,他正常工作时,咱们会觉得他们像是队友;一旦工作出错了,对咱们很粗暴的时候,咱们也会像对那些讨厌的人一样对待他。于是该怎么做?

  • 修正问题,而不是发出指责。虽然汝现在(应该)只是单打独斗,但是当汝开始和其他人合作的时候,希望汝还记得这一点。
  • 不要恐慌,在汝发现这个 Bug 过后,它就已经发生了,所以不要再说啥“这不可能”这类的话啦……
  • 小心“近视”,问题真正的位置不一定总是在报错产生的地方,汝可能要上下都小心的求索一下根源。
  • 试着展示汝的数据和踪迹,例如变量在某个时刻的值和程序目前运行的位置什么的。最简单的打印语句就是很好的开始。
  • 如果汝正在使用其他人的代码(例如示例或库),而汝翻来覆去看了自己的代码却没有发现问题的时候,再考虑是不是引入的代码的问题。(只在汝十分确定的时候再送出报告……)
  • 「当你剔除了所有那些不可能,剩下的无论多么荒谬,都必然是真相。 」

于是当汝使出浑身解数,还是没有什么进展的时候,可以考虑寻求一下他人的帮助。不过在此之前……

“正确”的报告 Bug - 当汝计划寻求他人(特别是汝正在使用的软件的开发者的)帮助时

汝前面多做一点,后面需要做的和可能的麻烦就会少一点……
  • 为了避免得到像是 RTFM 或者 STFW 这类的答案(不知道是什么意思的话请自行上网搜索,然后汝就自己践行了 ……),先花点时间阅读一下程序的文档(特别是常见问题和回答、已知问题和 Bug 报告提交指南,如果有的话)
  • 把问题产生的整个过程亲身演示给伙伴看,如果因为距离等原因做不到的话,就告诉他/她复现的详细的过程。以及汝自己电脑上的某些信息(例如系统和安装的软件,因为这有可能会影响运行的结果)
  • 如果汝有看到像是错误代码或者留下了日志或者转储文件之类什么的,最好也提供给对方。(如果害怕因为太多而被厌烦而且汝知道哪里是重要部份的话,可以自己先精简一下。)
  • 当第一次出现问题而汝又手足无措的时候,什么都不做比胡乱做些什么要好。
  • 尽管自己试图诊断是好的,但首先要传达的是症状而不是汝的猜测。

延伸义 - 为了顺利的获得答案,汝需要“正确”的提出问题

如果汝一时无法联系到亲近的人,或者大家都对付不了的时候,汝可能就需要向不特定的人群发问了。只是大家都很忙,因此不愿意把时间浪费在一堆没有不愿思考、或者在发问前不做他们该做的事的人身上。汝不会想成为这样的人吧?

  • 当汝准备提问的时候,先自己作出一些尝试。例如上网搜索、阅读手册、询问身边的朋友等等。并且如果没有解决的话,在提问时适当的表示一下自己做过的尝试。表明愿意在找答案的过程中做点什么是一个非常好的开端。
  • 尽管友好的态度并不能消除拙劣的提问的负面效应,但依然很重要,其中一点就是不要低声下气。
  • 在合适的地方发问,通常软件开发者会有所表示哪些是“合适”的地方。
  • 使用有意义且描述明确的标题,“目标 - 差异”这样的标题是个不错的栗子。以及别忘了用清晰、正确、精准并语法正确的语句,经验表明粗心的提问者通常也会粗心的写程序与思考。(如果汝在非母语的地方提问的话,记得用论坛的主要语言(或者英语),对拼写错误可以适当放宽,但决不能松懈思考。)
  • 用易于读取且标准的文件格式(例如普遍通用的纯文本,而不是某些“私有格式”)发送问题,以及使问题容易回复(除非出于隐私因素等原因,千万不要要求私下回复)。
  • 提供精确有内容的信息,简化问题消息的过程也是解决问题的过程,以及去掉无意义的提问句,除非汝想得到逻辑上正确,但毫无意义的回答。
  • 除非非常的有根据,不要动辄声称找到了 Bug。不同凡响的说法需要不同凡响的证据,当这样声称时,汝必须有清楚而详尽的缺陷说明文件作后盾,以及这样做的觉悟。
  • 为了避免在某个目标中的某个过程本身有问题而绕弯路(这通常被称作“X-Y 问题“),描述目标而不是过程。在一个根本错误的方向上就是浪费他人大量的时间和精力!
  • 清楚的表达汝的问题和需求,请把专业技能想像为充裕的资源,而回复的时间则是稀缺的资源。汝要求他们奉献的时间越少,就越有可能从真正专业而且很忙的专家那里得到解答。
  • 询问有关代码的问题时,用一个小的例子提示一下该从哪里入手。以及别把汝应该自己解决的那些问题(例如家庭作业)发上来。
  • 问题解决后,记得加个简短的补充说明,让每位参与协助的人因问题的解决而从中得到满足感。以及看看汝能够再做些什么,例如更新文档或者补丁。
  • 如果看不懂回应,别立刻要求对方解释。先像对待一个新的问题一样试着找到回应的解答。
  • 如果还是得不到回答,别灰心~ 有可能是现在看到汝的问题的家伙们不知道答案。试着再等等,或者回到开始继续寻求附近的帮助(例如本地用户组等等)。

多看一眼

  • Think Python ,《像计算机科学家一样思考 Python》

如果汝也有意学习 Python 的话,咱推荐这本书,因为咱看的第一本就是它……

CC BY-NC-ND 2.0 版权声明

喜欢我的文章吗?
别忘了给点支持与赞赏,让我知道创作的路上有你陪伴。

加载中…
加载中…

发布评论