我在苹果学到的编程技巧

当我还在苹果在线商店工作的时候,我们从来没有对在线网站做过负载测试。我们也不觉得需要这么做。然而,当每次史蒂夫·乔布斯在演示某个幻灯片过程中切换到在线商店时,会走下台来等待,这是非常有趣的经历。作为事后检查的一部分,每次在线商店重新上线时,我们都会问自己服务器的瓶颈在哪里:是 CPU、网络带宽、磁盘I/O还是内存?虽然准确预测整个系统在实际环境中的行为非常困难,幸运的是我们有一整套的测试策略来确保在重新启动之前有足够的测试。
 
 
作者:Joe Moreno
 
负载测试 / Load Testing
 
许多公司用负载测试来试验他们的web应用程序能够支持怎样的负载。一个最常用到的,但是错误的方式是把web站点上线然后启动负载测试。这种方式的问题在于,它不会告诉你web站点从在线状态到不能提供服务这个过程中是如何运行的。当一个web站点在使用状态时宕机然后重新启动,这时web站点表现出的行为,一定与负载测试状态下有很大的区别。例如,我们发现在iTunes商店(iTunesStore)第一次启动时,一个被信任的 WebObjects组件不是线程安全的,而这个问题只有在该对象处于重负荷情况下才会出现。
 
初生牛犊 / Cutting My Teeth
 
当我第一次加入苹果在线商店开发小组时,我和一位经验丰富的软件工程师搭档,他教会我如何快速地熟悉代码库,构建流程以及单元测试和组件测试。由于在线商店已经上线了,我们只有在对新代码进行测试以及搜集数据之后才能发布。
 
我的第一项任务是和搭档一起实现一个在网络上用特性表形式搜集产品信息的简单web服务。一般这样的简单web服务程序只需要一到两天,而我们俩在师傅的一步步指导下花了一整个礼拜,通过结对编程方式完成了整个流程。(虽然我们采用结对编程,但是我们使用的是Agile/Scrum,而不是极限编程。每个开发小组可以在保证进度的前提下使用任何他们达成共识的开发技术。我服务的团队碰巧有几个经过训练的scrum大师,他们得到了管理团队的支持。)
 
在实际开始编写产品代码之前,我们需要编写单元测试。所有的软件工程师都被要求先为他们的API编写单元测试,这个一个很值得学习的规范。(编注:测试在敏捷当中非常重要,参考这篇《敏捷方法中测试人员的价值》。)接下来,我们在Eclipse/WOLips上使用WebObjects/Java编写代码,与此同时我们为应用程序设下关键的断点,然后在调试模式下运行,这样我们就可以单步调试代码。我见到了有太多在别处工作的软件工程师,他们不断地编码,就像他们在不断地往墙上扔东西,然后看看到底会有什么会粘在墙上(像碰运气一样)。
 
在我们签入我们代码的同时,软件仓库会自动构建所有的应用程序,然后对它们运行单元测试。如果你的代码让这次构建失败,开发小组的每个人,包括一到两位项目经理会受到邮件通知——你就是构建失败的罪魁祸首。
 
令牌 / Token
 
我们有一段非常特殊的软件代码,一次只能由一个软件工程师签出(check out)、编写(work on)、然后签入(checkin)。你只有在得到一个物理令牌时才能够接触到这段代码。在我们这里,这个令牌就是一个DarthTater玩偶,它放在你的工作的格子间或者书架上最显眼的地方。
 
搜集度量数据/ Gathering Metrics
 
一旦我们的服务编码完成,没有错误,并且被签入到代码仓库后,我们开始组件测试并搜集新代码的度量数据。这是另外一个在新手团队里被忽略的步骤。我怀疑“搜集度量数据”这个步骤甚至都没有被包含在Joel测试中,因为Joel Spolsky的产品是一个桌面应用程序而不是一个需要重负载测试的web程序(或者,也许这个被隐含在“你有测试工程师吗?”这个步骤里)
 
甚至在我们考虑将代码放到实时代码分支之前,我们就已经对代码进行了数百万次的请求测试。在苹果公司,我们有一个非常复杂的缓存算法,根据我们设定的目标,它可以保存我们需要的任意数目的记录。我们是否需要五百个或是五万个产品的请求记录缓存呢?在一次冷启动开始之后,我们是否需要对指定的产品用缓存来“热身”呢?在没有任何的请求命中时,我们需要等多久才把一个产品从缓存中移除并释放内存呢?
 
附注一点,我们的缓存通常是一个哈希表。哈希表的优点在于它的大O表示法运行时间是常量O(1)。当你在一个面试中被问道“什么是最快的查找函数”时,千万不要说“一个B树二叉树”。完美的哈希表通常会轻松胜出。
 
调整并完成 / Tweaking and Done
 
我们会不断调整代码直到我们得到可接受的度量数据。我们的测量数据会对缓存内存消耗多少以及满足每个服务请求/响应的时间长短进行度量。根据我们的需求,我们会努力达到99.7%的服务请求在35毫秒之内返回,95%的请求在10毫秒之内返回,没有单个请求超过50毫秒的响应时间。
 
这些测试在一个非常接近产品环境的实时数据库的拷贝中运行。这不能完美地指出web应用程序一旦在实际环境中会如何执行。但是将它变成一个设定期望的很好的办法,这不会需要很久时间。
 
在我们“疾跑”(Sprint)结束的时候,所有这些度量数据都会作为敏捷定义“完成”时演示的一部分。这时代码已经准备就绪可以被检入质量保证的代码分支,在代码发布上线之前还会进行功能测试。
 
编注:
 
1. 大O表示法:用来描述算法的时间复杂度,O(1)的时间复杂度最低
 
2. 疾跑(Sprint):是scrum开发方法的一个最基本开发单元

php中常用的预定义常量简介

php中常用的预定义常量简介:

    这些常量在 PHP 的内核中已经定义好了,可以直接使用.

  1. __FUNCTION__: 函数名称(PHP 4.3.0 新加).自 PHP 5 起本常量返回该函数被定义时的名字(区分大小写).在 PHP 4 中该值总是小写字母的.
  2. __FILE__: 文件的完整路径和文件名.如果用在包含文件中,则返回包含文件名.自 PHP 4.0.2 起,__FILE__ 总是包含一个绝对路径,而在此之前的版本有时会包含一个相对路径.
  3. __LINE__: 文件中的当前行号
  4. __CLASS__: 类的名称(PHP 4.3.0 新加).自 PHP 5 起本常量返回该类被定义时的名字(区分大小写).在 PHP 4 中该值总是小写字母的.
  5. __METHOD__: 类的方法名(PHP 5.0.0 新加).返回该方法被定义时的名字(区分大小写).
  6. DIRECTORY_SEPARATOR: windows下的是\和/,而LINUX下的是/,以前觉得既然windows,LINUX 都支持/,那都用成 / 得了,这是没错的.可是从这个例子可以看出,当要对路径字符串进行处理的时候,就比较危险了,所以最好还是用DIRECTORY_SEPARATOR吧.

Grep学习笔记

Grep学习笔记

整理:Jims of 肥肥世家

第一次发布时间:2004年7月16日


1. grep简介

grep(global search regular expression(RE) and print out theline,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。Unix的grep家族包括grep、egrep和fgrep。egrep和fgrep的命令只跟grep有很小不同。egrep是grep的扩展,支持更多的re元字符,fgrep就是fixed grep或fastgrep,它们把所有的字母都看作单词,也就是说,正则表达式中的元字符表示回其自身的字面意义,不再特殊。linux使用GNU版本的grep。它功能更强,可以通过-G、-E、-F命令行选项来使用egrep和fgrep的功能。

grep的工作方式是这样的,它在一个或多个文件中搜索字符串模板。如果模板包括空格,则必须被引用,模板后的所有字符串被看作文件名。搜索的结果被送到屏幕,不影响原文件内容。

grep可用于shell脚本,因为grep通过返回一个状态值来说明搜索的状态,如果模板搜索成功,则返回0,如果搜索不成功,则返回1,如果搜索的文件不存在,则返回2。我们利用这些返回值就可进行一些自动化的文本处理工作。

2. grep正则表达式元字符集(基本集)

^

锚定行的开始 如:’^grep’匹配所有以grep开头的行。

$

锚定行的结束 如:’grep$’匹配所有以grep结尾的行。

.

匹配一个非换行符的字符 如:’gr.p’匹配gr后接一个任意字符,然后是p。

*

匹配零个或多个先前字符 如:’*grep’匹配所有一个或多个空格后紧跟grep的行。 .*一起用代表任意字符。

[]

匹配一个指定范围内的字符,如'[Gg]rep’匹配Grep和grep。

[^]

匹配一个不在指定范围内的字符,如:'[^A-FH-Z]rep’匹配不包含A-R和T-Z的一个字母开头,紧跟rep的行。

\(..\)

标记匹配字符,如’\(love\)’,love被标记为1。

\<

锚定单词的开始,如:’\<grep’匹配包含以grep开头的单词的行。

\>

锚定单词的结束,如’grep\>’匹配包含以grep结尾的单词的行。

x\{m\}

重复字符x,m次,如:’0\{5\}’匹配包含5个o的行。

x\{m,\}

重复字符x,至少m次,如:’o\{5,\}’匹配至少有5个o的行。

x\{m,n\}

重复字符x,至少m次,不多于n次,如:’o\{5,10\}’匹配5–10个o的行。

\w

匹配文字和数字字符,也就是[A-Za-z0-9],如:’G\w*p’匹配以G后跟零个或多个文字或数字字符,然后是p。

\W

\w的反置形式,匹配一个或多个非单词字符,如点号句号等。

\b

单词锁定符,如: ‘\bgrep\b’只匹配grep。

3. 用于egrep和 grep -E的元字符扩展集

+

匹配一个或多个先前的字符。如:'[a-z]+able’,匹配一个或多个小写字母后跟able的串,如loveable,enable,disable等。

?

匹配零个或多个先前的字符。如:’gr?p’匹配gr后跟一个或没有字符,然后是p的行。

a|b|c

匹配ab或c。如:grep|sed匹配grep或sed

()

分组符号,如:love(able|rs)ov+匹配loveable或lovers,匹配一个或多个ov。

x{m},x{m,},x{m,n}

作用同x\{m\},x\{m,\},x\{m,n\}

4. POSIX字符类

为了在不同国家的字符编码中保持一至,POSIX(The Portable Operating SystemInterface)增加了特殊的字符类,如[:alnum:]是A-Za-z0-9的另一个写法。要把它们放到[]号内才能成为正则表达式,如[A-Za-z0-9]或[[:alnum:]]。在linux下的grep除fgrep外,都支持POSIX的字符类。

[:alnum:]

文字数字字符

[:alpha:]

文字字符

[:digit:]

数字字符

[:graph:]

非空字符(非空格、控制字符)

[:lower:]

小写字符

[:cntrl:]

控制字符

[:print:]

非空字符(包括空格)

[:punct:]

标点符号

[:space:]

所有空白字符(新行,空格,制表符)

[:upper:]

大写字符

[:xdigit:]

十六进制数字(0-9,a-f,A-F)

5. Grep命令选项

-?

同时显示匹配行上下的?行,如:grep -2 pattern filename同时显示匹配行的上下2行。

-b,–byte-offset

打印匹配行前面打印该行所在的块号码。

-c,–count

只打印匹配的行数,不显示匹配的内容。

-f File,–file=File

从文件中提取模板。空文件中包含0个模板,所以什么都不匹配。

-h,–no-filename

当搜索多个文件时,不显示匹配文件名前缀。

-i,–ignore-case

忽略大小写差别。

-q,–quiet

取消显示,只返回退出状态。0则表示找到了匹配的行。

-l,–files-with-matches

打印匹配模板的文件清单。

-L,–files-without-match

打印不匹配模板的文件清单。

-n,–line-number

在匹配的行前面打印行号。

-s,–silent

不显示关于不存在或者无法读取文件的错误信息。

-v,–revert-match

反检索,只显示不匹配的行。

-w,–word-regexp

如果被\<和\>引用,就把表达式做为一个单词搜索。

-V,–version

显示软件版本信息。

6. 实例

要用好grep这个工具,其实就是要写好正则表达式,所以这里不对grep的所有功能进行实例讲解,只列几个例子,讲解一个正则表达式的写法。

$ ls -l | grep ‘^a’

通过管道过滤ls -l输出的内容,只显示以a开头的行。

$ grep ‘test’ d*

显示所有以d开头的文件中包含test的行。

$ grep ‘test’ aa bb cc

显示在aa,bb,cc文件中匹配test的行。

$ grep ‘[a-z]\{5\}’ aa

显示所有包含每个字符串至少有5个连续小写字符的字符串的行。

$ grep ‘w\(es\)t.*\1’ aa

如果west被匹配,则es就被存储到内存中,并标记为1,然后搜索任意个字符(.*),这些字符后面紧跟着另外一个es(\1),找到就显示该行。如果用egrep或grep -E,就不用”\”号进行转义,直接写成’w(es)t.*\1’就可以了。


2013年10月15日 10:23:07 星期二 yclimw转载

 

怎样利用.htaccess文件

  • 1禁止对无索引文件的目录进行文件列表展示
    默认情况下,当我们访问网站的某个无索引文件(如index.html,index.htm或index.php)目录时,服务器会显示该目录的文件和子目录列表,这是非常危险的,因为它可能暴露网站的内部结构,也许不小心就将含有敏感信息的文件公之于众了,为了禁止这种行为,我们可以在网站根目录创建一个.htaccess文件,内容如下:
  • 2创建重定向或改变丢失文件的响应状态
    当我们从服务器请求一个找不到的文件时,默认情况下服务器会返回404状态码,浏览器和访问者便知道URL指定的位置找不到该文件,但这是一个通用的消息,没有太大的实际意义,我们希望告诉浏览器和访问者更多有用的信息,如:
◆文件被永久移走
    状态码301告诉浏览器文件已经被永久移动到另一个位置,这样我们就可以通过.htaccess文件实现重定向了,例如,使用下面的代码可以将浏览器重定向到新的地址:
Redirect 301 /path/from/htaccess/file.html http://www.domain.tld/path/file.html
◆文件被暂时移走
    状态码307告诉浏览器文件已经被移走,但这是暂时的,浏览器接收到301状态码时就会访问新地址,但不用改变文件的链接,也不会为新地址创建缓存(除非它受Cache-Control或过期头信息字段控制),浏览器每次都会继续请求源地址。
Redirect 307 /path/from/htaccess/file.html http://www.domain.tld/path/file.html
◆文件不存在
    状态码410告诉浏览器,它请求的文件已经从服务器上永久删除,和404不一样,404仅仅表示文件不在这里的意思,而410表示文件不仅不在这里,在其它地方也没有。
  • 3创建自定义错误响应页面
    如果不向浏览器返回状态码,我们可以创建自己的错误页面,我们可以创建一个自定义错误页面,例如,对于401状态码我们可以创建一个未经授权的错误页面,对于404状态码,我们可以创建一个未找到错误页面,我们需要做的就是修改.htaccess文件,添加下面两行代码:
  • 4给不同类型的文件设置缓存过期时间
    这个设置告诉浏览器保持文件的缓存多长时间,在未过期前,访问该文件时就不用向服务器发起请求了,服务器向浏览器返回文件时,会附加上一个Expires头信息。
我们可以使用ExpiresDefault指令后面跟一个基础时间+时间长度设置文件的默认过期时间,使用ExpiresByType指令后面跟一个文件类型+基础时间+时间长度指定特定文件类型的过期时间。
基础时间可以是访问时间,它从浏览器请求该文件时开始计数,也可以是修改时间,它从文件最后一次修改时间开始计数,注意,如果你使用修改时间,返回给浏览器的动态内容不会加上Expires头,如动态生成的图像,因为非已存在的文件不存在修改时间。
过期时间要和基础时间结合使用,通过添加一个plus和一个时间,这个时间可以给出年、月、日,时、分、秒,如果我们只使用一个单位,可以使用单数表示,例如,我们可以指定它为“1分钟”或“10分钟”。
在下面的例子中,我使用ExpiresDefault指令将所有文件的默认过期时间设为1天,然后使用ExpiresByType指令为不同文件类型指定过期时间。
  • 5文件发送到浏览器之前先压缩
    任何现代浏览器都能处理服务器压缩过的文件,这样做也是为了减少页面的载入时间,如果服务器默认没有开启文件压缩功能,我们可以通过.htaccess文件来开启。
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css application/javascript application/x-javascript application/rss+xml application/atom_xml text/javascript
注意,我这里没有为图像文件开启压缩,因为我们的图像文件已经通过其它压缩技术处理好了。
  • 6给文件夹设置密码保护
    为了保护含有敏感数据的特殊文件夹,我们需要创建一个包含有效的用户名和密码的文件,然后在.htaccess文件中添加一些设置,但用户名和密码仍然是以明文形式发送到服务器的,因此很容易受到中间人攻击,除非我们使用SSL。
    首先,我们创建一个名为.htpasswd的文件,将权限修改为600(只有文件所有者有读写权),这样其他用户才不能访问。创建好文件后,我们需要向这个文件注入用户名和密码,如果你使用Linux或Unix类操作系统,使用htpasswd命令就可以办到,如果你能通过SSH登陆到你的服务器,那么你可以使用htpasswd管理.htpasswd文件中的用户名和密码,如果不行,还有很多在线工具可以帮助你生成.htpasswd文件中使用的密码。
    使用下面的命令可以向这个文件中注入用户名和密码:如:它会提示你输入密码,然后他会加密密码并保存到.htpasswd文件中。如果Apache是安装在除Windows,Netware和TPF(一种IBM大型机)外的任何系统上,默认情况下下,它会调用crypt()函数加密密码。使用这个命令我们可以创建多个用户,并可以修改已有用户的密码,你可以使用-n参数获得加密后的密码字符串值。它会返回类似下面这样的字符串:然后用文本编辑器打开.htpasswd文件,将上面返回的内容粘贴到文件中,每行代表一个用户。
还可以使用-m参数调用md5加密方法加密密码,在Windows,Netware和TPF下,默认就使用的是md5加密,也可以适应-s参数调用SHA加密,使用-d参数告诉命令调用crypt函数,在大多数系统上,这也是默认的行为。
    如果文件不存在,则添加-c参数,它会创建文件,如果文件已经存在,添加这个参数后就会重写整个文件,只留下新创建的用户,如果想删除.htpasswd文件中的某个用户,使用-D参数。
最后,我们可以和其它命令结合使用,如果加入参数-b,我们可以直接在命令中加上密码,但这样做是不安全的。
htpasswd .htpasswd juan randompassword
    创建好用户后,他们就可以访问这个目录及其子目录了,但我们还需要在要保护的文件夹下添加一个.htaccess文件,内容如下:
这里的AuthName指的是要求你输入用户名和密码时的提示信息,AuthType表示需要的认证类型,在这个例子中,我只想弹出一个对话框,要求输入用户名和密码,因此设置为Basic,AuthUserFile指的是保存用户名和密码的文件位置,在这个例子中指的是.htpasswd文件,位置和我们的.htaccess文件相同,Require valid-user指定只有.htpasswd文件包含的合法用户才能访问。
  • 7将HTML文件当PHP文件使
    为了将html扩展名文件当作php文件使用,需要在.htaccess文件中添加下面的内容:这样服务器就会把HTML文件作为PHP文件进行解析。
  • 8修改PHP设置
    如果我们不能访问php.ini文件,有些主机服务商允许我们修改.htaccess文件来改变一些PHP设置,例如,我想生成所上传图片的缩略图,有些主机服务商默认将PHP的内存限制为2MB,显然要生成缩略图是不够用的,因此我要将这个限制改大一点,如增加到16MB,如果要移除内存限制,可以将其设为-1。
为了在.htaccess文件中修改PHP设置,服务器必须启用了AllowOverride Options(或AllowOverride all)选项,如果那样,我们只需要在.htaccess文件中添加下面一行命令即可:

计算机专业学习浅谈

原文出处: 林建的博客


一、广泛了解,从科普书籍开始

选择计算机专业的同学,也许是因为原先有一定的基础,也许是因为一时的激情,但更多的人,可能对自己的选择没有深刻的认识,或多或少对计算机专 业有一些神秘的感觉。自己究竟是否喜欢这个学科?才华能够在哪个分支领域有所施展?抑或是真的不适合这个专业?诸多疑问,解决的方法首先便是了解和认识我 们的学科。浓厚的兴趣是学好任何学科的源泉;而广泛的了解则是获得兴趣的途径。当今我们对于信息的获取已非难事,其中“阅读”是一个简洁而有效的方法。

也许你认为阅读专业书籍对于刚刚步入大学的自己来说有点困难,也很枯燥,那么不妨先从科普书籍看起。科普书籍是了解理论、获得应用知识最好的途 径。相信不少理工科的同学被量子物理和相对论搞得头昏脑胀过。究其原因,是我们的现实生活与抽象的数学模型之间存在思想意识上的鸿沟。然而要是读读斯蒂 芬·霍金的《时间简史》,你就会被书中有趣的故事和例证所吸引,从而对抽象的理论有了感性的认识——即使仍然没有读懂,你也至少了解了这个学科研究的领域 和目标是什么,也必然有所收获。所有理工学科都有这样的性质,计算机专业也不例外。

我们知道,计算机理论是建立在数学基础之上的。大学计算机专业对数学的要求较高,其重要性不必多言。数学令不少同学头痛,除了其“繁”与“难” 外,很大程度上是因为他们没有理解这些抽象理论的实际应用方向。与本科数学专业的课程设置相比,计算机专业的数学课程大都偏重实用性。比如我们的离散数学课程中涉及到的逻辑代数奠定了计算机一切运算的基础,形式语言构成了计算机程序编译的模型,代数系统则是当前各类数据库系统的理论依据等等。因此,如果能够提前地了解到并简单地学习一下这些数学知识的具体应用,对理解理论是很有益处的。此外,电子学、信号与系统、控制理论等也是计算机专业学生必修的公共课,然而不少同学往往认为它们与计算机专业的关系不大,从而放松了学习。事实上这些学科是计算机硬件与网络通信的基础,学好这方面知识的前提是认识它们的现实应用及其与计算机的密切联系。

也许你将来学习图论的时候,对“欧拉路”的概念会很清晰,这是因为你在小时候的图画书上玩过“一笔画”的游戏;然而“二分图”、“生成树”这些概念又是怎么回事呢?你的理解可能就不是那么深刻了——因为你一时难以找到一些生活中的实例,并从中抽取出特性。在这种情况下,翻阅一些涉及这些知识的科普书籍就十分有必要了。我曾读过一套《数学游戏》(《科学美国人》杂志汇编,中文版:科学技术文献出版社),它将图论、逻辑代数、自动机理论等领域的抽象的概念具体化为一个个有趣的故事,引导读者了解这些知识的现实应用,启发读者将抽象思维与感性生活有机结合。我还读过一本《编码的奥秘》(《CODE》, 中文版:机械工业出版社),它则将逻辑代数、数字电路、汇编语言等知识以实物和简单电路的形式进行类比,揭示其中的原理,并引导读者动手实践。事实上这类与计算机专业相关的科普书籍还有很多,在学习课本的间隙阅读一下,绝对能起到催化剂的作用。

谈到科普书籍,相关的另一个问题便是计算机科学与计算机技术之间的关系。也许不少同学选择计算机专业,是源于对计算机令人眼花缭乱的应用的认识。所谓计算机技术,一般是指包括文字处理、信息管理、多媒体、网站建设等在内的计算机应用技术;而所谓计算机科学,一般指数据结构、组成原理、操作系统、编译原理等计算机内部实现机制。前者是计算机在各行各业提高生产力的体现,属于各类职业教育和专科教育的范畴;而后者是研究是计算机本身的理论,是本科计算机教学的重点。市面上大多数计算机书籍与杂志是计算机应用技术方面的,属“技术普及型”,从受众角度来看与科普书籍有着类似的性质。适当地涉猎一些自己感兴趣的应用技术,对培养学习兴趣、增强实践能力、了解业界行情是很有好处的。不过如果确实想在计算机行业长期做下去,仍然应当将主要精力放在对计算机科学的学习方面。毕竟用科学的理论指导实践是大学教育的意义所在。

总之,广泛了解计算机学科基础科普知识,在今后学习具体理论的时候才会少一些盲目,多一些顿悟。

 

二、把握全局,学习计算机导论

当你对计算机学科涉及的领域有所了解后,就应该着手展开专业学习了。初读本专业的教学计划与课程设置,你或许会被诸如离散数学、编译原理、接口技术等生疏的课程名称弄得一头雾水。这些课程都是研究什么的?它们各自与我们面前的计算机有哪方面的联系?要回答这类问题,首先需要把握全局,从整体上认 识计算机科学。

国内高等院校一般都为大一学生开设计算机基础课程。这类课程的受众面广,主要涉及计算机基础应用知识。各种版本的计算机基础教程几乎都以计算机科学导论作为开篇。对于把计算机作为应用工具的其他专业的学生而言,导论只算是“内容概要”,他们往往更注重后面的应用型知识;而对于把计算机作为研究对象的我们,则决不能忽略这类指导性的内容。专门地、有意识地学好计算机科学导论,能够使你对计算机科学有一个大局观,清楚地认识到每一个分支学科的研究领域与重要意义,从而在今后的具体学习中明确方向,加深理解。

依我个人的学习经验,建议初学者阅读一些国外优秀计算机基础与导论教材。与国内大多数讲解软硬件具体使用的同类教材相比,国外教材更偏重以应用为切入点,深入浅出地阐述计算机科学原理。诸如《计算机文化(第8版)》(《New Perspectives on Computer Concepts》,中文版,机械工业出版社)、《计算机科学导论》(《Foundations of Computer Science: From Data Manipulation to Theory of Computation》,中文版,机械工业出版社):前者适合于各种信息类专业的学生或计算机爱好者阅读。该书图文并茂,语言生动,从应用角度出发,广泛涉及计算机软件、硬件、网络的基本原理,同时概述了计算机学科的历史背景与行业现状。随书的光盘中给出了不少影音材料,在学习的同时还可以提高计算机专业英语听说能力。后者在风格上与前者类似,但内容更适合计算机专业学生阅读,被美国不少高校定为计算机专业学生的入门课。它以实例作为出发点,系统地讲解了计算机组成、计算机网络、操作系统、数据结构、算法设计等分支学科的研究领域、基本原理和应用方向,而几乎不涉及晦涩的数学模型与实现细节。阅读此类书 籍,可以在潜移默化中理清初学者对于计算机科学学习的思路。

计算机科学是一个有机联系的整体,每个分支都或多或少地与其它分支存在依赖关系。如果死板地依照教学计划线性地进行学习,往往会遇到知识理解上 的问题。例如算法分析课程与程序设计课程分属理论与实践;组成原理课程与体系结构课程是对计算机系统不同层面的剖析。我们不能简单地找出它们的先修、后修关系,这样难以建立完整的知识体系。因此在把握大局之后,我们仍有必要简单了解一下每个分支学科的基础知识。在这方面,推荐大家阅读《编程卓越之道(第一卷):深入理解计算机》(《WRITE GREAT CODE: Volume 1:Understanding the Machine》,中文版,电子工业出版社)这本书。分开来看每一章节,其内容编排结构与国内高校计算机课程体制相近,涵盖了逻辑代数、数字电路、机器指令、体系结构、存储器管理等方面的基础知识和实现方法,特别是阐明了各个分支学科之间的本质联系。有了这些基础之后,在遇到更高阶的问题时,你至少会明白这个问题应该在哪个分支学科中寻找答案了。

当你有了一定的计算机理论基础,尤其是程序设计基础后,想更加深入地把握计算机科学的脉络,不妨看看这本书:《深入理解计算机系统(修订版)》 (《Computer Systems A Programmer’s Perspective》,中文版,中国电力出版社)。它与《编程卓越之道》系列的共同特点是从程序员的视角观察计算机系统。而这本书作为国外数十所高校的计算机系统导论教材,其组织更加严密,风格更加严谨。它以“程序在计算机中如何执行”为主线,全面阐述计算机系统内部实现的诸多细节。当你在学习数据结构、组成原理和体系结构等课程和时候,翻阅一下此书的相应章节,同时编程实现其中的例子,一定会对课本上单纯的文字型理论有更加感性的认识——原来它们是 这样活生生地存在于我的计算机里的!

正所谓“会当凌绝顶,一览众山小”,从计算机科学全局的高度整体把握其分支学科,在头脑中率先构建计算机科学的整体框架并为其夯实最基层的结构,就能够为你在未来每一步的学习中扫清迷雾,指明方向。

 

三、运筹帷幄,掌握编程的思想

程序设计与开发是计算机学习的一个关键环节,编程能力是衡量一名计算机专业人员素质的重要考核点。这是因为程序是连接理论与实践的纽带,是计算机科学与计算机技术相交融的领域。作为一名计算机专业学生,我们一方面有别于其它专业将计算机作为工具的应用型人才,不能仅仅利用计算机,而要为他人利用计算机提供平台;另一方面我们暂时达不到计算机科学家的水平,不能做出理论研究成果,但能为理论学习铺垫实践基础。因此,只有具备足够的程序设计与开发能力,才能真正体现我们的智慧,同时充分发挥计算机的潜力。

学习编程,首先应掌握至少一门程序设计语言。C语言作为一种语法清晰、功能强大、应用广泛的高级语言,长期以来被国内大多数高校的定为程序设计必修课。全面理解和掌握C语言的脉络的重要意义这里毋庸多言。市面上C语言的教程多如牛毛,但最经典的当数C语言的设计者Kernighan与 Ritchie 合著的权威白皮书——《C程序设计语言(第2版)》(《The C Programming Language》,中文版,机械工业出版社)。书虽不厚,但绝对全面而准确。其语言简洁,例证通俗,实用性强。相比之下国内的一些C语言教材在学习曲线可能比前者平滑,但它们往往以考试为导向,过多地纠缠语法死角,同时大都未遵从ANSI标准。对于计算机专业学生来说,前者能够让我们看到更加严谨与实务的态度。当你的语言功底达到一定程度后,就需要从一个更高的视角来探察语言的本质,不妨看看这本:《计算机程序的构造和解释(第2版)》 (《Structure and Interpretation of Computer Programs》,中文版,机械工业出版社)。它阐述了编程语言本身的机制与实现,同时引入了一门对于大多数中国学生来说不甚了解的语言——LISP。 LISP是很多美国高校计算机专业的入门语言,也是一种结构上与C、Pascal、Java、Basic等完全不同的非冯·诺依曼语言。研读SICP,体味LISP,给你耳目一新的感觉之后更多地可以加深对编程思想本质的理解。

大学的各类程序设计与开发课程旨在培养我们两方面的能力——算法设计能力与应用开发能力。前者偏重计算机科学,后者偏重计算机技术。算法是用计算机思维解决现实问题的理论,具有较强的数学性。算法学的旷世巨著应数Knuth的《计算机程序设计艺术》(《The Art of Computer Programming》,中文版,清华、机工、国防等出版社皆有授权),不过要彻底读懂这个大部头需要相当的数学理论基础与编程实践经验积累。对于初学者,建议首先培养使用常规算法解决小规模问题的能力,并行地提高驾驭语言的水平与抽象问题的思维。针对这个目的,结合程序设计实践一类的课程,可以读读这几本书:《编程珠玑(第2版)》(《Programming Pearls》,中文版,中国电力出版社)、《程序设计实践》(《The Practice of Programming》,中文版,机械工业出版社)、《代码阅读方法与实践》(《Code Reading: The Open Source Perspective》,中文版,清华大学出版社)、《C专家编程》(《Expert C Programming》,中文版,人民邮电出版社)。它们的侧重点各有不同,但对于通过实践来学习算法与数据结构都是很有益处的。

应用开发方面,实践是第一要务,然而高效的实践是建立在科学的程序设计方法之上的。以C语言为代表的结构化程序设计方法是规范的程序逻辑的基础,目前主要使用在系统级开发中,前面所提到的诸多书籍都或多或少有所涉及。而以Java、C++为代表的面向对象程序设计方法广泛应用于实用项目开发, 这方面的经典之作中,推荐阅读Bruce Eckel的《Java编程思想(第3版)》(《Thinking in Java》,中文版,机械工业出版社)与《C++编程思想(第2版)》(《Thinking in C++》,中文版,机械工业出版社)。此外软件架构设计、编码规范与风格、代码除错与质量管理以及软件工程的各类原则在实际项目开发中都是及其重要的,在 具备了一定的编程经验、准备投入一些实际项目开发的时候务必要了解。建议阅读《代码大全(第2版)》(《Code Complete》,中文版,电子工业出版社)这本大而全的软件构建综合性宝典,它在从总体上指导软件开发的各个环节的同时也引入了一些细节问题(诸如 goto的使用)的讨论,引导我们对一些司空见惯的程序设计理念不但要知其然,而且要知所以然。

有一位热衷于游戏的同学告诉我,游戏给予他满足控制欲的空间。但是请放眼看看,游戏的控制范围不外乎一个特定进程中他人预先设定好的一系列数据,并以有限的图像与声音形式体现出来。然而如果你掌握了编程这一强大的武器,就能够面对眼前的计算机游刃有余,在硬件条件允许的情况下尽你所能将控制欲升华为创造力,方便自己的同时造福他人。运筹帷幄,掌握编程的思想,无论走向科学研究或是应用开发,这都将为你奠定坚实的基础!

 

四、理性思辨,体味计算机哲学

Bill Gates对计算机事业充满激情——“每天早晨醒来,一想到所从事的工作和所开发的技术将会给人类生活带来的巨大影响和变化,我就会无比兴奋和激动。”自由软件运动的精神领袖Richard Stallman几十年如一日,将打破知识垄断、共享人类智慧作为己任,带领着数以万计的软件志愿者推动着开源世界的发展。但并非每个计算机业者都能有Gates那样豪迈的气度和Stallman那种坚定的信仰,计算机及其相关技术对于大多数业者来说仅仅是兴趣爱好或者谋生的工具。计算机行业半个多世纪 以来形成了其独有的文化氛围,作为一名计算机专业学生,了解专业文化,体味专业哲学,对于学习和从业都是具有指导意义的。

首先必须承认,计算机世界中存在着形形色色的意识理念差异。诸如微软帝国与开源世界的明争暗斗,不仅仅是一场商战,更多的是两种哲学的搏击。当代大学生多数是在微软Windows光环照耀下认识计算机的。在这种环境下,多接触一些开源世界的事物,对于理解计算机的本质不无裨益。《共创未来:打造自由软件神话》(《Free for All: How Linux and the Free Software Movement Undercut the High-Tech Titans》,中文版,上海科技教育出版社)是一本讲述开源世界发展史的书,你可以从中了解自由软件运动及其领袖人物的传奇故事,从而对GNU、 Linux、OpenSource这些概念蕴生人性化的理解。清华大学王垠的《完全用GNU/Linux工作,摈弃Windows——你我共勉》、兰州大学黄平的《自由,你忘记了吗?》等长篇文章则是国人对开源运动的慷慨陈辞。尽管这些文章常常被指为“偏激”,但没有调查就没有发言权,无论支持还是反对, 客观的认识是第一位的。

其次,我们应该用平和的心态对待知识与技术,衡准专业学习在生活中的位置。一些同学出于种种原因,成为了“先进技术”的追随者:通晓各类流行的编程语言,一有新版本的工具推出立即安装学习,一有新的技术论战立即关注其走向。还有一些同学成为了某些技术的忠实信徒:看准了Java就对.NET的东西置之不理。这些追随者和信徒们往往为突飞猛进的技术所累,以至于有感于学习的空虚。过分追捧技术可谓舍本逐末,死扣某一知识也显得目光短浅。一方面百变的技术离不开计算机科学的本源,在实践过程中深入理解基础知识是关键;另一方面任何技术都有统领其实现细节的思想精髓,观其形不如知其神。我们不妨甩开冗繁的技术,换个角度静下心来读几部计算机文化与哲学作品:

程序人生方面:《编程之道》(《The Tao of Programming》,双语版,电子工业出版社)一书出自一位对东方道家与禅宗思想有着独特理解的美国软件工程师之手,全书由一则则短小而富有哲理故事组成,以类似寓言的形式生动地反映了程序员群体的生活以及计算机文明的演进。闲暇时随手翻阅,即使不能立刻体会到每个故事的真谛,但随着自身阅历的增长,相信你会领悟程序人生的“道法自然”。

设计理念方面:开源软件界的“斗士”级元老Eric Raymond所著的《Unix编程艺术》(《The Art of Unix Programming》,中文版,电子工业出版社)一书,以Unix系统的设计原则为主线,展示了Unix所开启的“KISS”(Keep It Simple, Stupid!)编程文化与思维方式。对于很多干啃千篇一律的课本、禁锢于Windows开发的计算机专业学生来说,这本书一定能够使你眼界大开——“结构化”并非真理,“面向对象”也不是王道;而对于有一定Unix/Linux使用或开发经验的同学,这本书也一定会使你豁然明朗——原来一个程序的设计竟可以如此精巧!

管理哲学方面:对于有志于软件工程,想涉足项目管理的同学,《人月神话》(《The Mythical Man-Month》,中文版,清华大学出版社)这本书就有必要读一读了。它拿真实案例说事,仿佛一部实例化的软件工程课本。如果你在团队开发的道路上陷入了困境,不如参考一下前辈们是如何处理“人”与“月”二者之矛盾的吧。事实上不仅是软件工程,任何事业的成功,往往技术不是关键,社会科学的因素才是埋 头技术的朋友们更应当关注的。

归根结底,计算机的哲学依旧是人的哲学。抛开理念之争议,超越技术的形式,以人为本地认识我们的行业与自身的地位,或许会使将来的发展道路走得更舒心一些。