关于学程序需不需要学习英语的忠告

转载自百度百科,很受触发,以下是正文。

俗话说,没有金刚钻,就别揽瓷器活儿。套用到IT业,英语不行,就别做程序员。网上关于程序员学英语的文章不少,但我想谈谈我自己的看法。首先详细讨论一下为什么程序员离了英语不行,然后针对程序员应该怎么学英语说说我的体会。   

英语是计算机的母语,是程序的母语,所以必然是程序员的母语。程序中的变量名、函数名起得好不好是决定代码质量和可维护性的最关键因素。高质量的代码应该是这样的:代码基本上是自解释的(self-explanatory),不需要太多注释,不管代码的规模有多大,具有相关知识背景的读过文档的人都可以立刻上手、立刻参与维护和开发。要想使代码能够自解释,给变量和函数起个好名字很关键,很显然,只能用英文起名字,一是用汉语拼音起名字可读性很差,二是英文单词通常比汉语更expressive(看吧,如果用汉语来说,就得说“表达能力更强”、“更有表现力”这么罗嗦),由于程序的复杂性,变量和函数往往表示一些很抽象的概念,起个既准确又简洁的名字并不容易,可是很多时候,用汉语需要很多字才能说清楚的一件事,用英文一个单词再加点词形变化就能说清楚了。例如APUE上讲sleep函数的实现,其中有个变量表示“本来应该睡到某个时刻,但是提前被信号唤醒了,唤醒时与本来应该睡到的时刻相差的时间”,如果为了简洁而不求准确,这个变量名至少也得叫“未睡到”,而书中只用了一个单词unslept,非常准确、简洁地表达了这个意思。为了写程序而学英语需要学到什么水平?我认为能起出这种变量名就够水平了。很多在IT外企工作的中国人,说话写文章经常夹杂着英文单词(比我严重多了因为我不在外企),非常可以理解,确实是为了表达得更准确简洁的需要,而不是纯为了play zhuangbility。总之,要写程序必须学好英语,否则连变量名都起不好,这虽然是一个非技术问题,但却是个根本问题,比任何技术问题都重要。当然,现在很多编程语言也支持用Unicode字符给变量和函数起名,但是你见过有人用汉字写程序吗?根本不实用。有人会辩驳说一页英文翻译成中文往往只占半页,中文不是更简洁吗?但是你算算打一页英文和打半页中文哪个敲键盘次数多。另外,要读别人的代码也必须学好英语,如果你不知道unslept是由 sleep变形而来的,就体会不到其中的精妙,只有大量阅读高质量的代码,才能写出高质量的代码,创作都是从模仿开始的。   

说说英语对于看书学习的重要性。中文技术书和英文技术书的水平根本不在一个量级上,这是有很多原因的,不能全归结于中文书的作者水平差。最重要的是,出中文书的低回报率决定了作者不可能花太多心血在上面,你去amazon看看一本书卖多少美刀,再去chinapub看看一本书卖几块钱。老外写一本书,可以做到全书没有一个拼写错误(当然英文的拼写检查工具更完善也是部分原因),中文能找出一本没有错别字的书吗?Knuth可以悬赏让全世界读者来找磋,中文书作者有哪个敢这么做?不是因为老外态度有多认真治学有多严谨,而是因为他们赚到了,就应该拿出高质量的作品来,不然会被读者骂的。   

英文技术书的翻译质量通常很差。也不能归结于译者的水平差,我也翻译过书,也努力想译好,但真的很难译好。IT业的新名词层出不穷,像“内核”、“网络”这种常见术语还好,稍微专一点的术语都没有统一的译名。我们在教学中发现,很多学员看书时搞不清这本书的名词A和那本书的名词B是什么区别,来问老师,才发现原来A和B就是一回事儿。这是一个单词对应多个译名的情况,还有一个译名对应多个单词的情况,比如field、domain、realm都译成“域”,block、 bulk都译成“块”,argument、parameter都译成“参数”,attribute、property都译成“属性”,虽然这些词的意思本来就差不多,但是在一篇文章里,作者可以换着用,不同的单词表示不同的概念,翻译完了一看,都成一个概念了。英文书背后都有index,看到一半忘了某个名词是怎么定义的就可以翻index,而译文通常没有index,名词都已经乱七八糟了,没法做index。还有更发指的是,老外喜欢造词,现有的单词上加一点变化和组合(例如有人喜欢说automagically),看着心领神会,想译出来就很费劲。老外即使在技术书中也经常用一些生动的表达方式和俏皮话,而中文的书面语言非常死板,生动的表达方式只存在于口语中,如果写在书上就很不像话,这也是很难翻译的一个重要原因。看中文译本,不仅质量差,而且跟不上时代,通常一本英文书出来,至少要等一到两年才能看到中文译本。两年啊!等你看到这本书的中文译本时,这个版本都快淘汰了。   

然后说说英语在开发工作中的重要性。看书学习通常只起一个引导入门的作用,在工作中更有用的是手册、文档。学完了C语言开始写程序了,谁还会去查K&R附录中的库函数?查man page才是最有效率的。然而手册比入门书更少有中文译版,因为手册是随时变的,会随着软件版本更新,而且需要看这些开发手册的人通常不会有英文障碍,有英文障碍的人即使看了翻译的手册也写不出好程序来,所以当然没必要翻译了。不管什么技术,官方的手册和技术标准才是最原始的第一手资料,看别的书都是以讹传讹,由于自然语言不可避免是有歧义的,文档中表达得不准确的地方就会被文档的读者也就是技术书的作者误解,技术书中再有表达不准确的地方又被译者误解。我们小时候都玩过传话的游戏,几个人站一排,通过悄悄话传一句话,传到最后变成什么了?所以,学网络协议,就得看RFC,学ARM,就得看ARM公司的 Architecture Reference Manual,要学习C语言就得看C99,有歧义不要紧,自己去揣测原作者的意思,总比道听途说的可靠。   

我们的学员出去面试经常被问到的一个问题就是:在开发工作中遇到问题,书和文档上都没有答案,网上搜一下也没有答案,怎么办?要我说,能看懂源代码的就去源代码中找答案,这称为hacking,不管是内核、libc还是各种framework,你调用的东西有问题都能从它的代码中找到原因。如果没有能力 hacking,或者时间紧不想去hacking,最好的办法就是去官方邮件列表和IRC问。如果英文不行就没办法了,只能去一些中文论坛:“各位大虾帮忙,小弟有一个问题求救!跪求!!在线等!!!”在线等了好几天也无人问津,或者答非所问。岂不知逛这些论坛的没有大虾,都是菜鸟,大虾们都在IRC上聊得正欢呢。我在做Qt开发时曾经有一个问题,当时在教育网,上国外网不方便,去各大中文论坛问了好几天也没人给出满意的回答,后来花钱连了国外网,去 trolltech官方新闻组提问,只等了几分钟就得到了满意的解决办法。这次经历给我留下了深刻印象,从此以后再也没有去中文论坛。   

那么,如果现在英文水平很差,又想做程序员,应该怎么学英语呢?我下面说的方法有两个前提,一是你的英文至少达到高中毕业水平,也就是语法基本都学完了,即使用得不熟练也知道有那么回事儿,二是你希望尽快在工作中用上英语,写程序够用就行,而不是有考T考G这样的更高要求。   

学习英语有听说读写四个方面的要求,做程序员至少需要读和写非常流畅,如果在外企工作还需要听和说的能力。技术英语和考T考G是不一样的,一是听和说不像读和写那么重要,不必担心自己是“聋哑英语”,没关系,丝毫不影响你成为编程高手,二是要求的词汇量要小得多。考T考G都要拿一本单词书背,很少有人会觉得背单词很有意思,至少我是觉得很痛苦,幸运的是看技术书不需要多少词汇量。技术书的描述对象都是局限于一个很窄的领域的,就那么几个单词翻来覆去地用,而且技术书是为了让人看懂的(不像诗是为了让人看不懂的),比较复杂的词在书中都有定义或解释。有些作者喜欢卖弄词汇量,用一些很生僻的单词,也有些作者卖弄一些典故,由于文化背景不同很难理解,不过这些通常都可以无视,不会影响阅读,还是因为技术书是为了让人看懂的。对于学习者来说,阅读能力是最重要的,等你完成了学习,成为一个合格的开发者时,需要写代码注释,需要写文档,需要通过邮件交流,写作的能力才开始重要了。所以应该首先从阅读开始练习英语。   

现在就拿起一本英文原版书开始看吧。和学游泳一样,阅读的能力只能通过阅读本身来练习。我的经验是,不必先系统学习了单词和语法再看书,可以在看书时用到什么就补什么。我建议初学者看电子版,因为现在的词典软件都可以鼠标取词,边看边查很方便,很多勤快人喜欢把查过的单词都抄下来,我觉得没有必要,反正查字典很方便,下次再看到了就再查,多查几次总会记住的,抄下来就打断了看书的思路,而且不见得抄下来就能记住。也许是因为我这人比较懒,我用的都是懒办法。很多人不喜欢看电子书,理由是盯着屏幕看书太累,那么盯着屏幕写程序累不累?这种人显然不适合做程序员。语法不熟练怎么办?大多数情况下单词的意思都明白了就不影响阅读。技术书有时候喜欢用长句,其中可能包含各种从句,如果实在读不懂就去查语法书,同样也不需要把这种从句彻底弄明白,只要这一句能看过去就行了,以后多查几遍书,自然就掌握了。另外,技术书是说明文,通常不应该有过去时,看到过去时就需要注意了,很可能是虚拟语气,如果不注意这一点,看到的意思可能和真实的意思正好相反。   

应该从哪本书开始看起呢?从你当前最需要学的技术书看起。看书是相当花时间的,如果能一边学英语一边学技术,这时间利用得就很有效率。比如,如果你的C语言已经学得相当好了,不要专门为了学英语去重看一遍原版的K&R。市面上有一些专门的计算机英语教材,我的建议是不要看,浪费时间,nonsense。初学时最好选一本有中文译本的书,有看不懂的地方可以翻中文版来对照,但是不要相信中文的翻译,原因在前面讨论过了。如果你是初学编程,没有任何基础,我可以推荐一本英文很浅显技术也很浅显的书:How To Think Like a Computer Scientist,有Python、Java和C++版本,可自由下载。   

要逐渐养成良好的阅读习惯。一是不要每个生单词都去查,有些单词很生僻,查了也记不住,记住了也不会再见到它了,但是前面讲过,都是作者在卖弄词汇量,无视它丝毫不影响阅读,因此要学会猜测单词的意思,能不查就不查,继续贯彻“懒”的原则。二是看书不要动口,不念出声也不行,就是不要动口,要努力在大脑中建立从词形到语义的直接映射,如果只能从词形到读音再到语义就太慢了,严重影响阅读速度。三是努力做到每句话都从头到尾只看一遍,不许回头反复看,这一点比较难,必须注意力高度集中,经常在记忆中暂存前面半句的内容和句式才能做到,但是一旦神功练成就会成倍地提高阅读速度。最后一层境界,学会skim,就是略读,很多优秀的作者在组织材料时会给读者一些建议,比如这一段是扩展的高级话题,和主线的相关度较低,可以先skim到后面,注意不是让你skip到后面,这一段还是要读的,但是不必逐字句地读,而是抓主旨,大概讲了个什么概念(有一些下定义的句式),有哪些要点(有数字编号或bullet列表项),适用于哪些场合有哪些注意事项(有 caveat、gotcha、noteworthy这种字眼),后面可能还会碰到这个概念,虽然你没有仔细看这是个什么东西,但大体上也知道了,这样就能不影响后面的阅读,这不仅需要高度集中的注意力、熟练的语言能力,而且要有足够的背景知识去猜测性地理解。但是语言能力还是最重要的因素,我和几个同学交流过,他们也能熟练地看英文书,但是需要skim查一个东西时就觉得还是不如中文书查得快。skim的技能在查阅手册时尤其重要,没有人会像看入门书一样把上千页的手册从头到尾看一遍,都是用到哪儿就查哪儿。总之,锻炼各种阅读习惯就为了一个目的:如何在最短的时间内,在保证正确性的前提下,获取尽可能多的知识。程序员的学习时间都是非常宝贵的。   

以上本着“够用就好”的原则,多次提到用懒办法,但是学技术学英语这两件事不能懒,贵在坚持。要养成良好的阅读习惯也有很多东西需要坚持,其中最根本的是持续高度集中注意力,充分调动记忆能力、推理能力、猜测能力,就像考试做阅读题一样看每一段话。最根本也是最重要的,“有英文原版就不看中文版”这个原则一定要坚持。一开始看英文书可能会很慢,但只要一直坚持就会慢慢达到原来看中文书的速度,再坚持下去就会比中文书看得更有效率,因为避免了很多歧义和术语翻译的问题。有人会说,项目紧任务急,看英文资料太慢,这次就先用中文尽快解决工作中的问题吧,等以后有时间了再看英文书学习。可是什么时候才会有时间呢?工作总是一个接一个的,老板怎么会付了工资让你闲着呢?如果你有这样的困难,我的建议是干脆辞职,学好了英文再去工作。你只要想想,你的同行们在外企全英文的环境下工作,英文和技术每天都在突飞猛进,而你还在用效率极其低下的方式学习和工作,你和别人的差距不是越来越大了吗?另一方面,现在的在校学生从小学就开始抓英语,基础都很好,很多高校也逐渐重视引进原版教材,开设很多英文授课的专业课。你再不奋起直追,就不觉得以后的职业道路充满危机吗?   

最后说说写作。刚开始练习时不要怕写错,能表达清楚自己的意思即可。我看过很多源代码和文档中的英文,一看就是中国人写的,谓语动词不分单复数,名词复数不加s,处处可见中国式英语,但是丝毫不影响我对这些编程大牛的景仰,因为其中的思想我看懂了,并且我认为很强大。我有一个朋友,中学毕业就出来混的,由于工作的性质总要跟老外打交道,他从来不惧和老外交流,虽然连一个囫囵的句子都说不出来,但总是能用中学学的那点单词让老外明白他的意思,这一点我就非常佩服。总之就是说,不要因为不知道怎么写是对的就不敢动笔写,只要敢交流,并且别人能懂你的意思,就是很有效的交流。而且随着阅读量的增加,自然能写出一手好英文,前面讲过了,创作总是从模仿开始的。不怕出错才能有一个好的开始,才能逐步练习提高,而练习的最终目的当然还是希望写好,不仅字句通顺无语法错误,还能适当修辞。

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
目录 历史 前言 I. C语言入门 1. 程序的基本概念 1. 程序和编程语言 2. 自然语言和形式语言 3. 程序的调试 4. 第一个程序 2. 常量、变量和表达式 1. 继续Hello World 2. 常量 3. 变量 4. 赋值 5. 表达式 6. 字符类型与字符编码 3. 简单函数 1. 数函数 2. 自定义函数 3. 形参和实参 4. 全局变量、局部变量和作用域 4. 分支语句 1. if语句 2. if/else语句 3. 布尔代数 4. switch语句 5. 深入理解函数 1. return语句 2. 增量式开发 3. 递归 6. 循环语句 1. while语句 2. do/while语句 3. for语句 4. break和continue语句 5. 嵌套循环 6. goto语句和标号 7. 结构体 1. 复合类型与结构体 2. 数据抽象 3. 数据类型标志 4. 嵌套结构体 8. 数组 1. 数组的基本概念 2. 数组应用实例:统计随机数 3. 数组应用实例:直方图 4. 字符串 5. 多维数组 9. 编码风格 1. 缩进和空白 2. 注释 3. 标识符命名 4. 函数 5. indent工具 10. gdb 1. 单步执行和跟踪函数调用 2. 断点 3. 观察点 4. 段错误 11. 排序与查找 1. 算法的概念 2. 插入排序 3. 算法的时间复杂度分析 4. 归并排序 5. 线性查找 6. 折半查找 12. 栈与队列 1. 数据结构的概念 2. 堆栈 3. 深度优先搜索 4. 队列与广度优先搜索 5. 环形队列 13. 本阶段总结 II. C语言本质 14. 计算机中数的表示 1. 为什么计算机用二进制计数 2. 不同进制之间的换算 3. 整数的加减运算 3.1. Sign and Magnitude表示法 3.2. 1's Complement表示法 3.3. 2's Complement表示法 3.4. 有符号数和无符号数 4. 浮点数 15. 数据类型详解 1. 整型 2. 浮点型 3. 类型转换 3.1. Integer Promotion 3.2. Usual Arithmetic Conversion 3.3. 由赋值产生的类型转换 3.4. 强制类型转换 3.5. 编译器如何处理类型转换 16. 运算符详解 1. 位运算 1.1. 按位与、或、异或、取反运算 1.2. 移位运算 1.3. 掩码 1.4. 异或运算的一些特性 2. 其它运算符 2.1. 复合赋值运算符 2.2. 条件运算符 2.3. 逗号运算符 2.4. sizeof运算符与typedef类型声明 3. Side Effect与Sequence Point 4. 运算符总结 17. 计算机体系结构基础 1. 内存与地址 2. CPU 3. 设备 4. MMU 5. Memory Hierarchy 18. x86汇编程序基础 1. 最简单的汇编程序 2. x86的寄存器 3. 第二个汇编程序 4. 寻址方式 5. ELF文件 5.1. 目标文件 5.2. 可执行文件 19. 汇编与C之间的关系 1. 函数调用 2. main函数和启动例程 3. 变量的存储布局 4. 结构体和联合体 5. C内联汇编 6. volatile限定符 20. 链接详解 1. 多目标文件的链接 2. 定义和声明 2.1. extern和static关键字 2.2. 头文件 2.3. 定义和声明的详细规则 3. 静态库 4. 共享库 4.1. 编译、链接、运行 4.2. 动态链接的过程 4.3. 共享库的命名惯例 5. 虚拟内存管理 21. 预处理 1. 预处理的步骤 2. 宏定义 2.1. 函数式宏定义 2.2. 内联函数 2.3. #、##运算符和可变参数 2.4. 宏展开的步骤 3. 条件预处理指示 4. 其它预处理特性 22. Makefile基础 1. 基本规则 2. 隐含规则和模式规则 3. 变量 4. 自动处理头文件的依赖关系 5. 常用的make命令行选项 23. 指针 1. 指针的基本概念 2. 指针类型的参数和返回值 3. 指针与数组 4. 指针与const限定符 5. 指针与结构体 6. 指向指针的指针与指针数组 7. 指向数组的指针与多维数组 8. 函数类型和函数指针类型 9. 不完全类型和复杂声明 24. 函数接口 1. 本章的预备知识 1.1. strcpy与strncpy 1.2. malloc与free 2. 传入参数与传出参数 3. 两层指针的参数 4. 返回值是指针的情况 5. 回调函数 6. 可变参数 25. C标准库 1. 字符串操作函数 1.1. 初始化字符串 1.2. 取字符串的长度 1.3. 拷贝字符串 1.4. 连接字符串 1.5. 比较字符串 1.6. 搜索字符串 1.7. 分割字符串 2. 标准I/O库函数 2.1. 文件的基本概念 2.2. fopen/fclose 2.3. stdin/stdout/stderr 2.4. errno与perror函数 2.5. 以字节为单位的I/O函数 2.6. 操作读写位置的函数 2.7. 以字符串为单位的I/O函数 2.8. 以记录为单位的I/O函数 2.9. 格式化I/O函数 2.10. C标准库的I/O缓冲区 2.11. 本节综合练习 3. 数值字符串转换函数 4. 分配内存的函数 26. 链表、二叉树和哈希表 1. 链表 1.1. 单链表 1.2. 双向链表 1.3. 静态链表 1.4. 本节综合练习 2. 二叉树 2.1. 二叉树的基本概念 2.2. 排序二叉树 3. 哈希表 27. 本阶段总结 III. Linux系统编程 28. 文件与I/O 1. 汇编程序的Hello world 2. C标准I/O库函数与Unbuffered I/O函数 3. open/close 4. read/write 5. lseek 6. fcntl 7. ioctl 8. mmap 29. 文件系统 1. 引言 2. ext2文件系统 2.1. 总体存储布局 2.2. 实例剖析 2.3. 数据块寻址 2.4. 文件和目录操作的系统函数 3. VFS 3.1. 内核数据结构 3.2. dup和dup2函数 30. 进程 1. 引言 2. 环境变量 3. 进程控制 3.1. fork函数 3.2. exec函数 3.3. wait和waitpid函数 4. 进程间通信 4.1. 管道 4.2. 其它IPC机制 5. 练习:实现简单的Shell 31. Shell脚本 1. Shell的历史 2. Shell如何执行命令 2.1. 执行交互式命令 2.2. 执行脚本 3. Shell的基本语法 3.1. 变量 3.2. 文件名代换(Globbing):* ? [] 3.3. 命令代换:`或 $() 3.4. 算术代换:$(()) 3.5. 转义字符\ 3.6. 单引号 3.7. 双引号 4. bash启动脚本 4.1. 作为交互登录Shell启动,或者使用--login参数启动 4.2. 以交互非登录Shell启动 4.3. 非交互启动 4.4. 以sh命令启动 5. Shell脚本语法 5.1. 条件测试:test [ 5.2. if/then/elif/else/fi 5.3. case/esac 5.4. for/do/done 5.5. while/do/done 5.6. 位置参数和特殊变量 5.7. 函数 6. Shell脚本的调试方法 32. 正则表达式 1. 引言 2. 基本语法 3. sed 4. awk 5. 练习:在C语言中使用正则表达式 33. 信号 1. 信号的基本概念 2. 产生信号 2.1. 通过终端按键产生信号 2.2. 调用系统函数向进程发信号 2.3. 由软件条件产生信号 3. 阻塞信号 3.1. 信号在内核中的表示 3.2. 信号集操作函数 3.3. sigprocmask 3.4. sigpending 4. 捕捉信号 4.1. 内核如何实现信号的捕捉 4.2. sigaction 4.3. pause 4.4. 可重入函数 4.5. sig_atomic_t类型与volatile限定符 4.6. 竞态条件与sigsuspend函数 4.7. 关于SIGCHLD信号 34. 终端、作业控制与守护进程 1. 终端 1.1. 终端的基本概念 1.2. 终端登录过程 1.3. 网络登录过程 2. 作业控制 2.1. Session与进程组 2.2. 与作业控制有关的信号 3. 守护进程 35. 线程 1. 线程的概念 2. 线程控制 2.1. 创建线程 2.2. 终止线程 3. 线程间同步 3.1. mutex 3.2. Condition Variable 3.3. Semaphore 3.4. 其它线程间同步机制 4. 编程练习 36. TCP/IP协议基础 1. TCP/IP协议栈与数据包封装 2. 以太网(RFC 894)帧格式 3. ARP数据报格式 4. IP数据报格式 5. IP地址与路由 6. UDP段格式 7. TCP协议 7.1. 段格式 7.2. 通讯时序 7.3. 流量控制 37. socket编程 1. 预备知识 1.1. 网络字节序 1.2. socket地址的数据类型及相关函数 2. 基于TCP协议的网络程序 2.1. 最简单的TCP网络程序 2.2. 错误处理与读写控制 2.3. 把client改为交互式输入 2.4. 使用fork并发处理多个client的请求 2.5. setsockopt 2.6. 使用select 3. 基于UDP协议的网络程序 4. UNIX Domain Socket IPC 5. 练习:实现简单的Web服务器 5.1. 基本HTTP协议 5.2. 执行CGI程序 A. 字符编码 1. ASCII码 2. Unicode和UTF-8 3. 在Linux C编程中使用Unicode和UTF-8 B. GNU Free Documentation License Version 1.3, 3 November 2008 参考书目 索引
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值