前言
这是在 ARGO 的 programming 版用 debian 这个 ID 发的系列短文, 整理后重发在这里.
阅读是人生的一个很重要的经历, 我外公的话记得最清楚的就是这句: 任何时候书都是最便宜的, 因为书是有价的, 而你能在书中学到的东西是无限的. 如果把外公的话从另一个角度分析的话, 就是著书者的劳动是无价或及其高价的(按照马克思的理论的话), 由于书的可分发特性, 所以我们买书的价格只是在分摊很小部分的版税以及书的印刷成本而已, 用这个价格去换作者宝贵的知识永远是赚的.
这是在文革其间读书无用论泛滥时外公对我妈妈他们说的, 外公没有见到图书市场的繁荣, 没有见到烂书的泛滥, 没有见到精装书的价格, 没有见到没有内容的书壳可以当装修材料卖个好价钱. 但是无论怎么样, 书仍然是最有价值的.
写这些文章的时候, 我也把写到的书一本一本地翻出来, 又重新回味一遍, 桌面也因此变得凌乱不堪. 好了, 要去收拾了, 也要擦擦书架了, 181 的灰尘真恐怖. 关于书, 我可以一直写下去, 不过很多都不是 programming 的内容了, 这个系列就此完结, 如果以后再看到好书, 仍会继续向大家推荐.
语言学习类
SICP (Structure and Interpretation of Computer Programs)
首先最喜欢的当然是 SICP (Structure and Interpretation of Computer Programs) 啦, 这本 MIT 计算机的入门教材当然不仅仅是 scheme 语言学习的最好教材那么简单啦, 它的编排跟普通的语言教学书是完全不同的, 第一章: 过程抽象, 第二章: 数据抽象, 第三章: 模块化, 对象与状态, 直到第四章: 元语言抽象, 它是在讲一种程序设计方法学乃至一种思维模式, 而不仅仅是一种语言 .
对语言的使用介绍穿插在这样的方法学介绍中, 它的基本思路是: 提出一个问题或一个程序的需求, 介绍一种方法, 介绍在 scheme 中用什么特性来实现这种方法, 接着不断地对这个程序进行优化. 用这样的方法带动读者一起思考, 并且鼓励读者尝试, 效果非常好.
而且这本入门书提出的问题一点都不简单, 例如第三章, 直到这里它才介绍了赋值语句, 赋值语句我们看来很简单, 但是笔锋一转: 赋值语句本质是把一个对象与一个名称绑定, 这个过程是怎么实现的呢, 或者说是一个在各种语言中都会涉及到的问题: 命名空间的确定, 接下来它就介绍了 scheme 的名字绑定使用的环境模型(Environment Model) --- 千万不要以为因为这是语言实现细节而可以忽略它, 理解不了这个模型的话后面巧妙地使用 scheme 的环境模型实现模块化和面向对象编程的内容是无法理解的, 而且 scheme 的环境模型与 Java 和其他类似的语言是完全一样的 (内存管理方面很容易看出 java 的语言对 LISP 类语言的借鉴), 我花了好大工夫把这个搞懂之后, java 类语言的内存管理模型我从来没有糊涂过, 而且对自己的软件设计也是很大的启发. 第三章的内容也令我们认真地反思这个 "简单" 的赋值语句, 为什么赋值语句或状态会造成副作用, 是否需要避免这个副作用等等问题, 这是在使用其他书学习语言的过程中无法触及到的.
提出以上的这些问题, 可能对一些计算机入门书来说是无法想象的, 但是 SICP 做到了, 它由浅入深, 从最基本的过程抽象 (即基本的定义函数), 到第四章的元语言抽象学习到如何使用 scheme 写一个 scheme 解释器, 完全地理解这门语言及其计算模型; 到第五章非常复杂的设计和实现一个寄存器计算机的模拟器, 并学习高级语言特性如何在其上实现. 计算机就真真正正地入了门了. 即使不是初学者(其实有多少真正的初学者会从这本书开始呢?) 认真地看一次这本书, 也会激起对各种问题的重新思考和重新认识, 会有很多的收获.
这本书作为教材, 当然有习题. 它的习题一点都不简单, 做起来很头痛的. 但是你一定会对这些习题很有兴趣, 我保证, 呵呵.
而且这本书的遣词造句非常生动形象, 而且妙句多多, 我想 Forward 中的以下这段话应该被引用过无数遍了:
Pascal is for building pyramids -- imposing, breathtaking, static structures built by armies pushing heavy blocks into place. Lisp is for building organisms -- imposing, breathtaking, dynamic structures built by squads fitting fluctuating myriads of simpler organisms into place.
还有例如 forward 的第一句话: "Educators, generals, dieticians, psychologists, and parents program. Armies, students, and some societies are programmed."
这本书的中译本已出版, 是北京大学的裘宗燕教授译的, 译得还是很准确到位的 . 总之这是一本有趣的, 有深度, 决不会让人厌倦的入门教材.
ps. 关于函数式编程, 一篇写得很好的文章叫 LISP 根源, 大家可以去看看, 连接在这里 http://daiyuwen.freeshell.org/gb/rol/roots_of_lisp.html.
C 语言学习书籍
这个我不想说太多的, 其他大牛应该有比我更好的经验. 我学 C 语言用的书一开始是谭浩强老师的书, 非常经典啦. 这本书似乎适合没有任何基础的人阅读, 由于年代久远忘得差不多, 不做评论.
学 C 语言的经典书当然是 K&P (The C Programming Language) 啦, 这本书完全是一本语法定义和指南, 有过 C/C++ 基础的人应该再翻一遍这本书, 巩固掌握. 而且里面的例程采用的代码风格也是一种 C 语言编程的标准, 就叫 K&P, 可惜 GNU 似乎不准备遵循这个标准, 嗯.
C++ 我不熟悉, 我认真看完的 C++ 入门书是 Thinking in C++, 没看过其他经典的 C++ 书, 所以也不作评论. 另外我看的 C++ 的第一本书是类似 "24 小时学会 C++" 那种, 写得糟糕外加憋脚的翻译, 让我小小年纪就明白烂书对这个世界的伤害有多深.
python 学习书籍
python 是我除了 C 之外最熟悉的语言之一, 入门学习的话, 我还是建议这样: 先搞清楚基本的语法和语言特性, 标准库不用看太多, 因为 python 的标准库实在大得恐怖, 我都是现用现查的.
我推荐一本似乎没有发行过的书: ann77 的python 学习笔记. 首先它是用一种正常人能看懂的中文写的 (相比于国内某些人写的言语晦涩故作高深令我宁愿回去读英文的中文书), 而且遵循的恰恰是一个 python 学习者的思路, 它第一章介绍语言特性, 后面两章介绍开发环境和常用的标准库, 认真读完第一章, 第二第三章跳着了解一点 (第三章第一第二节不能跳, 因为那是内置常用函数和文件操作介绍) 应该就能初步具备 python 开发的能力了. 我觉得它写得最好的是
1.13 类一节, 它不是去介绍一大堆语法规则, 而是很轻松地解释了 python 是怎样用一个简单的方法去实现复杂的面向对象特性的, 之后该怎么做就很自然了 . 结合 1.12 名称空间一节, 你会了解到 python 实现类的方法是多么的高明, 怎么是用 "self" 使得名称空间在加入面向对象特性后不会变得混乱, 使得语言定义变得简洁优美. 所以在学习这些章节的时候, 你不会觉得是在学习一些麻烦的与其他语言差不多却偏偏有点区别的语法规则, 而是学习一种解决问题的方法.
另外的入门书还可以推荐 "How to Think Like a Computer Scientist - Learning with Python", 看题目它想做成像 SICP 一样的书, 可惜失败了. 它还是更偏重于语法特性的介绍, 不过确实介绍得简单易懂, 似乎适合完全没有语言基础的读者查看. 绝对不推荐那本叫 python bible 的书, 为什么一个这么简单的语言都可以被它讲得这么啰嗦......
除此之外, python 的官方文档特别是标准库文档是要随身携带的, 随用随查, 常用的那几个包用多了就熟了.
操作系统设计与实现
我对这方面非常感兴趣, 认真看过的书也最多, 所以分列出来哈
UNIX 操作系统设计 vs. 莱昂氏 UNIX 源代码分析
两本都是经典到不应该再拿来做介绍的书. UNIX 操作系统设计讲的是较为近代的 SystemV, 莱昂氏讲的是更为原始的 UNIX V7. 两本我看的都是中译本而且无缘得见原版, 其中莱昂氏的翻译是尤晋元, 应该说是很有口碑的. 第一本虽然没有原版对照, 但我觉得翻得还是很好的, 各种用语翻得很准确清晰.
我觉得 UNIX 操作系统设计这本书的写作目的并不是进行操作系统原理和实现的教学, 而是试图从系统设计角度解释 UNIX 系统, 帮助用户更好地掌握它, 这与关于 UNIX 的第一篇论文是相似的. 而至少对我来说, 这样的方法非常成功, 我是通过看这本书才认识到 UNIX 系统的优秀的.
这本书不厚, 里面没有列系统源代码 (而且有版权问题), 但是对一些关键的调用有非常清晰易懂的类 C 伪码进行说明, 我非常喜欢这种形式. 我觉得它写得最好的是文件系统相关的内容, 即第三到第五章, 分别介绍高速缓冲的实现, 文件内部表示和文件系统接口, 这些部分本来就是 UNIX 实现得最精妙的地方, 而它的阐述也非常到位; 至于后面进程管理的章节, 可能是觉得已经 toooold 了吧, 没有太大的感觉. 另外它的 SysV IPC 描述可能是最权威的. 这也是一本我觉得习题比较难却很有价值的书, 值得一做.
这本书非常适合没有很多 UNIX 使用经验的读者观看, 因为它不会乱入 UNIX 专门词汇让人莫名其妙, 一点一点都介绍得清清楚楚, 认真地读读第二章, 就能对 UNIX 操作系统的精妙设计而不是它的看起来不近人情的界面有一个大概的认识.
至于莱昂氏 UNIX 源代码注释, 我手上并没有书, 是在珠海图书馆借来看的. 应该说这种列源代码然后写恰到好处的注释的方法很有意思, 也值得采用, 然而在猛戳带下划线的内容也不会给我跳转到相应页面的纸版书上, 用这样的学习方法其实是很辛苦的.
老实说我没有在这本书上学到很多关于操作系统实现的东西, 可能是因为用的源代码太老了吧, 它是很简单很清楚, 但是很多必须考虑的问题它都没有涉及. 所以它可能更适合作为一本操作系统原理的教学书而不适合作为实际操作系统实现分析的教学. 但是话说回来, 除了系统原理学习的意义外, 它是一个极好的 C 语言编程范本, 以至于人们可能产生 "今不如夕" 的感叹, 例如它的 namei() 函数, 真是叫做无懈可击, 多一句废话, 少一句跑不起来. 所以去认真看看源代码还是很有价值的.
4.4BSD 操作系统设计与实现 vs. 操作系统: 设计与实现.
这两本书的名字都很像吧呵呵. 第一本是 4.4BSD 的开发者写的, 第二本是 Tanenbaum 教授为了操作系统教学做出 MINIX 之后以此为基础写的 (顺带一提, 我用的是第二版, 似乎 MINIX3 的改动非常大), 这两本书我看的都是译本, 原本都读过一点, 翻译得都很不错. 两本书中我更喜欢前者.
4.4BSD 操作系统设计与实现 这本书与其他的书不同, 他是面向一个真实的, 广泛使用的系统. 现代的所有 BSD 系统 FreeBSD, NetBSD, OpenBSD 等都是基于
4.4BSD 并且没有很大的改动, 因此这本书有很大的实际使用价值, 我做 NetBSD 源代码分析 (http://student.zsu.edu.cn/~is03kyh/publish/BsdSource.html) 时的主要参考书就是它.
由于介绍的是一个真实的系统, 它涵盖了很多操作系统实现的细节, 更为重要的是, 这样做是为了解决什么的问题, 为什么要这样做, 为什么不这样做, 是在什么环境什么应用中得到这个结论的都写得清清楚楚, 我们可以很清楚地看到它的设计取舍, 对我们很有启发. 我觉得它写得最好的是第二部分进程, 它包括了以下关键性的论题: 被所有 BSD 系统沿用至今的调度算法, 为什么这种调度算法是可用且适用的 (光看理论书上的 "先来先服务" 之类的东西是什么都学不到的); 内存管理系统描述, 它是用什么办法支持共享内存, COW (Copy On Write) 等现代操作系统功能的, 这也是在其他书上没法看到的.
跟上面的 UNIX 操作系统一书一样, 这本书当然也 "理论上" 是 socket 和 TCP/IP 系统实现的最权威描述. 这本书对 socket 的实现以及对下层协议的接口是描述得很好的, 但是 TCP/IP 的实现就描述的一般般了, 因为篇幅根本就不够用, 但是它还是用了相当地篇幅介绍 TCP/IP 实现中一个很重要的问题: TCP Stream 的重组算法, 重发策略等, 并且写得很好. 不过这一部分的内容我还是比较建议看 "TCP/IP 详解, 卷二, 实现".
该书没有带任何的实现源代码 (其实我很鄙视拿源代码占篇幅的行为), 阅读的时候可以单独阅读, 也可以结合 4.4BSD 或 FreeBSD 等核心源代码进行阅读分析.
再说说 "操作系统: 设计与实现" 一书, 它的基本目的与上面的一本不同, 它是为了进行操作系统原理的教学, 它的有名也有很大程度上是因为 linux, 当然有 linux 之前它也是经典教材了. 这本书的每一章的大概结构都是这样的: 介绍操作系统中的某个子系统的原理和基本理论, 然后介绍 MINIX 中的实现. 它的优点是能让读者很容易看到它学的东西在 "实际" 中是怎么实现的, 而不会对这门知识有空中楼阁之感; 问题是这个 "实际" 其实并不实际, 看过 MINIX 代码就知道, 为了尽量简化实现方便理解, 它在很多地方都是使用了能用但效率很低的简化方法, 这对初步了解操作系统设计与实现是有好处的, 但如果想真的了解 "真实" 操作系统中会遇到的问题以及解决方法, 这本书并不合适; 但是如果对操作系统原理一无所知, 看 4.4BSD 那本大概是不会有什么收获的, 看这本倒比较好.
Linux 源代码分析书
我对各种 Linux 源代码的分析书都不大喜欢, 原因是: Linux 并不是一个适合进行系统分析学习的系统, 它太过庞杂, 用的方法太过 "先进" 而没有足够的文档说明, 而且它变化得太快. 而且大多数 Linux 源代码分析书鼓励懒惰, 因为它常常会列出打断代码然后详细解释, 所以不用怎么思考都可以看着书跟着" 分析" 完源代码, 却没有真正在机器上看过这段代码, 思考它在实现上的取舍得失, 没有在上下文中理解代码, 看谁调用它, 它调用的是谁, 又是怎样实现的 . 这样的收获不会多.
我认为如果为理解一个优秀的开源操作系统的设计与实现计, 应该看的是 4.4 BSD 操作系统设计与实现, 但如果是要做 Linux 内核的开发, 还是必须翻一翻相关的分析书籍的. 不过话说回来, 源代码分析这东西, 做过一个, 另一个也是很好做的, 分析过 BSD 源代码, 虽然 Linux 的函数命名和代码结构几乎完全不同, 但也能很顺利地找到地方, 再 google 一点资料对关键算法如调度算法来点点拨就已经可以了.
向大师致敬
W.Richard Stevens(1951-1999),国际知名的UNIX和网络专家,受人尊敬的作家。他的著作有《UNIX网络编程》(两卷本),《UNIX环境高级编程》《TCP/IP详解》(三卷本)等,同时他还是广受欢迎的教师和顾问。
Stevens先生1951年生于赞比亚,早年,他就读于美国弗吉尼亚州的费什本军事学校,后获得密歇根大学学士、亚利桑那大学系统工程硕士和博士学位。他曾就职于基特峰国家天文台,从事计算机编程。
Stevens先生不幸病逝于1999年9月1日,他的离去是计算机界的巨大损失。
他的三部巨著我都有幸读过, 虽然有的只是一小部分. Stevens 先生在书中总是用最平淡的语气说着那么重要的事. 似乎每本书每一部分都写得平淡无奇, 也没有提出什么新观点新算法, 但就是有这样的摄人的魅力, 每一本都被奉为圣经 . 看他不厌其烦地写出来的厚厚的书, 事无巨细都一一写出, 可能会觉得他嘴碎 , 可是只要再向前一步, 就会知道这只是他看问题比我深, 比我广, 在我遇到这些问题前已经给了我这许多金玉良言. 我想, 等我再往前走, 也会回来把他的书没读完的部分读完, 读过的部分再反复回味吧.
我也常常想, 写很多书, 著作等身不难, 但能写出三部被人奉为圣经的书有几个? 要写厚书不难, 但做到这么厚的书中的每一句话都可以给人细细斟酌吸收营养的又有几个? 凡大师者, 并不是因为他的专业水平有多高, 而更多的在于多少人能从他的工作中受益. 所以, Stevens 先生只凭着这三部书, 就足以称大师.
关于这三部书的评论已经有很多了, 这里的只是我自己的读后感. 其中我有纸板的只有 TCP/IP 详解的第一卷, 其他都是电子版. 除了 UNP 外, 我看的首先都是中译本.
APUE (Advanced Programming in UNIX Environment)
这本书又是经典的不用再介绍的. 这本可以说是 UNIX 编程的圣经了. 其实内容上我并不觉得有多大的出彩之处, 最简洁的形容就是: 准确, 透彻. 它力求对每一个接口都作最精确标准的描述, 大家常用的第二版是基于 POSIX 标准的. 它对每个接口都不是泛泛而谈, 甚至往往为了说明接口的用法而深入到内部的核心实现, 他还对各种接口的一些细微的却可能害死人的细节作了描述和讨论, 我想这就是对 UNIX 编程再熟悉的人也会经常读这本书的原因吧.
这本书虽然是介绍编程接口, 但它不是手册 (虽然也可以这么用), 它是一本真正的UNIX 编程入门书. 因为它不但说明了每个接口怎么用, 还说明了这些接口该在什么时候用, 用来干什么. UNIX 的系统调用很少很精炼, 有些功能如果没有一本书来提点是很难想到怎么做出来的, 比如用 manual 里只说了 dup 用来复制文件描述符, 并且返回的文件描述符是当前可用的最小的, 光知道这个, 要知道怎么用它构造输入输出重定向功能确实挺难. 这本书可以告诉你很多 UNIX 编程的惯例, 这是些 manual 不能告诉你但却被试为常识的东西.
不过话说回来, 有基本的 UNIX 编程知识后, 开发时最好用的还是系统自带的 manual, 首先这是最准确的, 其次每种 UNIX 系统都会有一些 "微妙" 的差别导致一些可能很严重的问题, 这时候只有 manual 能帮到你了.
UNP (Unix Network Programming)
这本书也是圣经级别的, 也是一本大~~~~ 书, 我手上没有纸版不知道有多厚, 但是没什么格式信息的 HTML 电子书全文是 8.8MB, 相当恐怖. 这本书几乎把能够用到的 socket 和 TCP/IP 内容都搬上来了. 不过我根本就没有从头到尾把它看过, 都是看着目录要用什么就查的.
这本书有一个特色, 就是有很多的例程. 几乎每个有独立接口的功能都有, 一些重要的应用 (比如 TCP 的 client/server) 会给出一个大一点的程序. --- 列一大堆程序的事国内很多书都会干, 可惜往往列的程序我都怀疑作者自己有没有看懂过, 我也见过把一个长长的自动生成的 Makefile 贴上去作为思考题书. 但这本书不同, 每一个程序都是小而必要的. TCP/IP 和 socket 的接口都非常复杂, 再加上选项没什么人能受得了的, 再加上它往往需要与系统的其他接口一起使用才能发挥作用, 所以必须在程序中展示这些接口和参数的实际应用, 才能令读者理解.
当然了, 我用到这本书的时候都是来抄代码的, 因为它的代码写的简洁精干, 通用性又强, 把它的代码东抄抄西抄抄改动一下就是一个很好的框架, 然后往里面填自己的东西就行了. 我总是觉得这么做的绝不止我一个, 因为看很多程序的相关代码都会有似曾相识的感觉, 特别是变量命名 --- 反正大家都是这么写的谁抄谁就不知道了咔咔.
TCP/IP 详解
这本书其实也不用介绍的, 经典的洪篇巨著. 大家可能看得最多的是卷一: 协议 . 这一章主要是在分析协议, 注意我用的是 "分析" 而不是 "介绍", 因为它的思路就是简要的介绍协议的基本思想和定义之后, 就开始用工具在实际网络中分析数据, 来展示协议是怎么使用和怎么工作的. 比如 TCP 三次握手, 我想学过相关知识的人都知道, 可是有没有真的用 tcpdump 去跟踪分析过三次握手呢? 另外它在这里也很注意例外情况的分析: 连接超时怎么办? 故意不完成三次握手会怎么样? 它都有提到并作分析.
TCP/IP 详解的第一卷并不是网络原理介绍书, 也不怎么会涉及 IP 层以下的东西. 我觉得它更适合给程序员, 给网络程序开发者使用, 让他们对这些底层原理有个概念, 知道自己层层包裹的应用层数据是怎么被发送出去的, 其中经历了多少艰难险阻, 也让他们在设计和实现上能够考虑到底层的情况而使用适当的方案 .
卷二: 实现, 我在做 NetBSD 源代码分析的 socket 一节时翻了一点, 它是一本源代码分析书, 分析的事 4.4BSD-lite 的 socket 和 TCP/IP 实现部分, 这当然时最经典的 socket 和 TCP/IP 协议栈实现. 这里用的办法是先讲大体的设计和结构, 然后小段小段地列举相应的代码, 再在后面对关键的行作注释, 看起来比莱昂氏的注释方法舒服很多, 但看的时候还是必须同步在计算机上打开同步源代码查看, 这样才能建立比较好的整体感觉, 而且查交叉引用比较方便, 看来后面忘了前面的事就比较好解决.
卷三没看过, 不作评论.
开发实践
程序开发是一项需要经验的活, 没有经验的时候就需要借鉴经验. 这是我喜欢的几本介绍开发实践的书, 而一些很经典我却没啥特别感觉的书, 比如设计模式的那本就没有列出来了, 并不代表我认为它们不好. 还有软件工程理论不包含在其中, 所以 "人月" 等几本经典书也没有列出.
Code Reading, The Open Source Perspective
这是一本很有意义的书, 其本意是展现一些开源工程中程序代码的通用模式, 帮助我们学习怎样分析一个大型系统的代码. 但是我觉得它的更大的意义是反过来的意义: 通过展现这些通用模式, 告诉我们什么是一个 "好的" 代码. 它首先基于 C 来描述了程序语言的基本元素, 基本数据类型的通用实现以及一些常用的 C 高级用法. 接下来讲述了怎么处理大型工程: 如何把握脉络, 把握架构, 编码规范, 文档标准等等 --- 这些都是从实际的开源软件工程中总结而来的, 而且都有广泛运用的实际运行代码作实例.
就像知道 UNIX 系统的每个系统接口也不一定能写出好的程序而要 APUE 帮助一样, 精通一门语言的语法规则, 对数据结构和算法也很熟悉, 也有可能写出很烂的程序, 这时候我们要知道一些编程的常用模式, 这些模式应该养成习惯, 直接套用, 比如遍历一个链表要怎么写, 就固定一个写法; 编码风格, 甚至包括注释的排版风格应该选定一个, 坚持使用下去, 而不是搞一套自己的编码风格, 这样写出来的代码才是高质量, 可理解, 可维护的. 这本书能帮助我们完成这些学习 , 与自己读一大堆源代码, 自己摸索总结相比, 这本书无疑是一个捷径, 但是不断地读代码还是很必要的咔咔.
Hacker's Delight
中译 "高效程序的奥秘", 不然又会被那些自以为黑客的小白买走奉为至宝了 . 不过原书的封面真的很黑咔咔. 这本书是介绍怎么通过位操作等原始手段实现常用的复杂功能, 以达到优化程序最常运行的部分, 提高程效率目的, 比方怎样将一个字作位翻转, 这本书把计算机的性能抠到了指令条数的量级上. 很多人可能认为这只是微不足道的小节, 现代编程也不会用到这样的方法, 或者认为编译器优化能解决一切问题, 但如果能让程序的一个核心函数性能提高一半, 可能就能令整个程序的性能提高 25% 以上, 这已经够要命了, 而书中提到的很多技巧, 在我看来都很难用自动编译器优化实现 (2 的幂的常数乘除外). 在分析操作系统代码的过程中, 可能会见到一些让人莫名其妙的位操作过程, 黑客们把这些当作常识, 我们却一面惘然, 其实很多都出自于本书了.
如果跟第一本相比, 这本书完成的就是细节处的第一本书的作用. 我不知道有谁能真的把这些技巧都记住 --- 都是要在实际使用中用多了才记住的, 但这本书即使记不住, 也是一本很有趣的读物, 时常拿着它看, 能看到几十来黑客们智慧和数学才能的光芒.
程序设计实践 (The Practice of Programming)
这本书的作者是 Brian W. Kernighan 和 Rob Pike, 好了不用说了, 绝对的票房保证.
这本书的意义与第一本是一样的, 不过它是从一个 "正" 的方向, 系统介绍了编码规范, 常用数据结构实现与选择, 开发与维护技巧等内容. 真的, 这本书不用其他介绍了, 意义我在说第一本书的时候已经说了, 它不是一本很特别的书, 但它是好书.
程序调试思想与实践 (The Science of Debugging)
这本书的作者之一是一个 M$ 的一个开发老手, 据说该书出版时的现在他的兴趣在玩 DEC 10. 这本书给 bug 归类, 编档, 说明发现, 诊断和解决的方法. 事实证明, 人是不可靠的, 人的一个错误犯了一次必然会犯第二次, 这个人犯的错误另一个人会接着犯, 所以看看这些常见 bug 列表很有好处.
这本书首先简述了一些著名的 bug 以及它的成因, 比如 AT&T 的电话网中断事件成因的详细说明, 接着介绍了颇为困难的 "什么是 bug" 的问题, 以及 bug 的产生, 发现, 修改等生命周期, 接下来才是详细的 bug 分类介绍, 然后告诉我们发现和定位 bug 的技巧以及详细的解决方法, 还有如何在 bug 发生前避免它. 直到这些内容后, 才介绍我们知道的传统测试技术和维护技术. 其实, 前面的内容对我们来说才是重要的, 知道怎么写测试报告书 (好吧, 我就是在做这个该死的作业), 知道黑盒白盒测试, 背熟路径覆盖标准是没办法把一个 bug 揪出来的, 发现 bug 的办法是经验以及借鉴他人的经验, 这就是这本书的价值.
这本书的习题很有意思, 而且给了解答. 它往往给出一些匪夷所思的系统出错情况, 要你定位可能的错误原因 --- 条件都是给足的, 虽然可能很隐蔽. 这是非常有趣的专业迷题, 看完后你会对抓虫子很感兴趣的~~
TAOUP (The Art of UNIX Programming)
NOTE: 这本书 linux 版精华区有全文, 大家支持一下吧, 咔咔~ 某著名发行版报告我吧嘿嘿.
这本书是 Eric S. Raymond 呕心沥血的巨著. 基本上是几十年来 UNIX 和开源软件开发的传奇和经验的合集, 也是一部真真正正的黑客传奇 (他自己有一篇 "Hacker 文化简史").
本书分为四个部分, 第一部分基本上是传奇介绍了, 但是在传奇中说明了一些重要的 UNIX 设计思想; 第二部分是 UNIX 设计模式介绍, 以一些著名的格言展开 , 第一条当然是 UNIX 的 KISS 原则, 其他的基本上是面面俱到了, 从界面到软件架构, 并且以一些著名的开源工程为例进行 case study, 因为他们都是著名的常用的软件, 所以你能马上体会到一项设计要点的功用. 第三部分讲的是实现 , 包括了语言选择, 编译器选择, 使用自动代码生成器的技巧等 (不要以为 lex 和 yacc 只是编译原理学习工具, 在实际项目中它往往用来自动生成很复杂的命令解析等代码的) 等等杂七杂八的内容. 最后一个部分就是移植性, 文档, 开源等等方面的内容了. 另外决不可忽视 Appendix D, 那是些对话体的很有趣的短文, 值得一看.
UNIX 编程是一个充满隐喻, 特殊文化和传奇的领域, 把这本书作为故事书也好, 作为设计的参考也好, 都是很有价值的. APUE 能让你学会 UNIX 编程, 而这本书可能是从 "UNIX 编程" 到 "UNIX 开发" 乃至 "UNIX 风格的开发" 的一个途径.
拾遗
很怀疑这些书跟 programming 版有多大关系, 不过作为系列, 就还是放在这里吧.
UNIX Haters Handbook
这是一本痛陈 UNIX 缺点的书, 从设计到界面指出 UNIX 的种种不足和严重失误 , 应该说, 这是非常中肯的.
比方说, 它引用了一个著名的笑话: Ken Thompson 有一辆他参与设计的新车, 它没有速度表等任何仪表, 如果驾驶员犯错了, 一个硕大的问号就会出现在仪表盘的中央, Thompson 说: 一个有经验的用户应该知道发生了什么. UNIX 是一个给程序员设计的并希望用户像程序一样工作的系统, 所以情况确实如此. 书中还有很多 UNIX 用户真实的血泪控诉...
书的内容还覆盖了可能是因为 UNIX 程序作者的键盘太过难敲而令人无法理解的缩写命令名 (如 ls, mv), 理论上很先进但实际应用中一般般的 XWindow 等等. 这不是一本笑话书, 而是一本严肃的设计检讨书. 我推荐它并不是说明我完全同意里面的观点, 而是有如精华区里 "C之诡谲" 那篇文章一样, 描述 UNIX 的一些似是而非的细节和一些 "奇妙" 的缺陷, 帮助我们更好地认识和使用 UNIX, 也能在其中受到启发, 为自己的设计开发所用.
The Jargon File aka. The New Hacker's Dictionary
作者同样是 Eric S. Raymond. 这是一本黑客用语辞典, 在黑客的用语中, 能看到黑客的传奇历史.
用样的, 这本辞典能够提供给我们一些猎奇用的细碎的小知识和小典故, 所以使它变得相当有趣. 总之, 这是一本可以闲时翻一翻好玩的书.
这本书似乎有纸质出版, 但我相当怀疑它的销量. 这本书的官方网站是 http://www.catb.org/jargon/, 除了提供原文之外, 还提供了一个搜索引擎能够搜索其中的词汇, 相当好玩.
Just for Fun
Linus 的自传, 还是推荐一下哈.
Linus 和 RMS 虽然是最著名的自由软件/开源软件的代表人物, 但他们的观点还是有一定分歧的. Linus 称 RMS 为伟大的哲学家, 而自己则是一个工程师. 而我认为形容 RMS 的最好的用语就是: "喋喋不休的传教士", 到处宣传自由软件. 而 Linus 是一个实干家, 这本书透露出了一个与 RMS 在自由软件思想上的不同的观点: Just for fun.
Linus 认为随着人类文明与科技的不断进步, 很多事情会由原始的生存需要, 转化成多少带有礼仪性的道德需要, 直到只是为了娱乐. 所以软件开发迟早也是一件用于娱乐的事情, 这种观点与 RMS 从道德, 经济和版权合理性的角度思考自由软件是不一样的.
这是一本故事书, 读着不累. Linus 把它的黑客生涯和 linux 开发说得很轻松, 我们也看得很轻松. 我想读着一定会为这句 "Just for fun" 感动. 这本来就是很简单的是, 不是去考虑市场, 也不是去考虑各种深奥高尚的哲学, 只是为了做一个会比 MINIX 好的系统, 就有了 Linux, 只是纯粹的为了让它变得更好, 就让 linux 发展到现在这个样子 (当然其他 linux 代码的贡献者可能不会那么纯粹, 比如贡献大量代码的 IBM 等公司). 为了自己的兴趣去开发软件, 然后开放它让大家共享, 一定是能获得最大快乐的办法, 我也是这么想的.
如何求解问题: 现代启发式方法 (How to solve it, Modern Heuristics)
这基本上是一本算法书, 是一本能够让人重新认识问题的算法书. 这本书首先是对传统方法的重认识, 接着是各种启发式方法的介绍.
这本书的好处是读起来不累, 这类书的一个常有毛病就是写得像论文, 一页一页的公式我看着就头晕, 而这本书很好地避免了这个问题, 虽然还是有各种必要的公式, 但还有大量的实例和图表做说明, 很容易理解. 这本书的另一个特点是每一部分前面的 IQ 迷题 --- 说 IQ 也好数学也好, 但它能通过这些迷题的问题和解答阐述出这一部分的观点, 让人对这部分所说的内容的作用有一个较早的认识.
Introduction to Information Retrieval
http://www-csli.stanford.edu/~schuetze/information-retrieval-book.html
这是一本没有出版的关于信息检索的书, 上面给出的连接有部分草稿下载, 不知道是学校网络问题还是怎么样, 我没有连上去. 我第一次看的时候他说预计今年 4 月能搞定, 结果我到五月的时候再去看, 发现网页更新过了, 对比了半天发现唯一的更新是把今年 4 月搞定改成今年夏天搞定, wish 之.
这是一本教材, 可能是给本科生的吧. 由浅入深, 讲了各种信息检索的方法, 从最核心的 inverted index 开始讲起, 然后是讲压缩和优化, 继而是进一步挖掘的各种方法. 书虽然没出完, 出了的章节我也没时间看完, 不过讲 inverted index 的部分真的讲得很好. 记得现有的章节 redhat 同学是看完了的, 请补充.
Information Retrieval 方面的书我知道的还有一本 Mordern Information Retrieval, 这本书的学习曲线就似乎比较陡峭. 其实它更像一本领域综述而不像一本教程, 还在啃ing.
UML 精粹 (UML Distilled: A Brief Guide to the Standard Object Modeling Language) 2nd editon
这也算是一本很经典的 UML 教程了. 译者徐家福似乎是个老人家, 他的这本书的翻译在国内似乎挺有口碑, 不过一些用语与常用译法有区别, 如用例 (use case) 他译的是用案, 是否更信达雅不敢妄评. 说说这本书吧, 这是一本薄书, 简明扼要地介绍了常用 UML 元素的用法 --- 而是不标准. 虽说 UML 不指定方法学, 但这本书其实给出了一些开发的范例, 这是值得学习的.
虽然我对 UML 之类的文档不大感兴趣, 但是这本书确实让我这个长着 papaya 脑袋的人比较好地了解 UML, 考系分的时候不至于一塌胡涂, 还是应该感谢 & 推荐的.
Analysis of Algorithms: An Active Learning Approach
算法分析方面的专著很多, 大部头教材也有不少. 虽然我只看了很少一部分的 TAOCP, 但似乎书中很多篇幅都在干这个活. 而这本书就能给各种经典算法的分析以一个简要的介绍.
基础知识之后, 当然是最简单的查找和排序的分析, 之后是数值算法和图算法, 以及算法在分布式条件下的分析等等. 这本书我这个算法白痴还能基本看懂, 说明它还是写得很浅显易懂的, 其中它的分析思路也非常可贵, 值得学习.
其他
写到这里就差不多了吧, 好书还有很多很多. 一些非常经典的书这里都没有涉及到, 比如 TAOCP 啦, Machine Learing 啦, 数据挖掘 --- 概念与技术等等等等 , 他们都是被时间和口碑证明是非常好的书. 但有的我没读过或读不懂, 例如 TAOCP, 有的只看过一本, 对那个领域也完全不熟悉, 不好做评价. 有的是太偏门, 都没有在这里写出. 大家心里肯定也有不同的最喜欢的书的列表, 如果写出来, 让版友们也能分享, 岂不乐事一件?
短文
No Silver Bullet --- Essence and Accident in Software Engineering
(没有银弹 --- 软件工程中的根本和次要问题)
这是一篇非常经典的也引发了很多讨论的文章. 前面我没有说作者的经典得不能再经典的 "人月" 一书, 但这里却不能不提这篇文章.
本文开篇即开宗明义: 没有一种技术或管理上的进步能在十年内带来软件工程生产效率的本质提高 --- 看来, 不止十年, 至今这个断言还是对的.
本文的论点是软件是有史以来最复杂的人造物, 复杂性是导致生产率低下的主要原因, 然而复杂性是软件的基本属性, 无可改变, 因此没有银弹. 而其他的一些技术和方法只能或多或少地解决次要问题而无助于根本问题的解决.
我想这个多少有点悲观的观点在当时应该是非常震撼的, 即使是现在, 第一次读它的时候可能也会感受到同样的震撼. 如果 Brooks 说的是对的, 人们对软件的需求和软件复杂度飞速提高, 而软件生产效率没有得到本质提高的话, 在软件生产上投入的成本将会越来越大直至无法接受而崩溃, 这是一个非常可怕的设想 . 然后至少到现在看来, Brooks 仍然是对的. 所以这篇经典的文章, 仍然值得我们不断地重读, 反思和争论.
The Roots of Lisp (LISP 之根源)
http://www.paulgraham.com/rootsoflisp.html 官方中译本: http://daiyuwen.freeshell.org/gb/rol/roots_of_lisp.html
这是一个简要的 LISP 历史和设计思想介绍和最简单的 LISP 入门文章. 我想被引用的最多的应该会是这段.
值得注意的是,麦卡锡所作的发现,不仅是计算机史上划时代的大事, 而且是一种在我们这个时代编程越来越趋向的模式.我认为目前为止只有两种真正干净利落, 始终如一的编程模式:C语言模式和Lisp语言模式.此二者就象两座高地, 在它们中间是尤如沼泽的低地.随着计算机变得越来越强大,新开发的语言一直在坚定地趋向于Lisp模式. 二十年来,开发新编程语言的一个流行的秘决是,取C语言的计算模式,逐渐地往上加Lisp模式的特性,例如运行时类型和无用单元收集.
接下来则是 LISP 语言的简要介绍, 这个介绍的目的是为了说明为什么用最简单的数据结构和极少数的几个操作符就足以构建一个强大的程序和为什么这样的构建方法是有效且高效的. 它把 LISP 严谨的数学性和美感表露无遗, 从几个最简单的公理 (原子操作符) 开始构建任何复杂的数据结构; 使用一个 lambda 算子就能构造函数以及命名空间 (LISP 中的各种命名空间定义, 如 let, 本质上都是 lambda 的语法糖衣, 可以完全用 lambda 构筑而成), 并能在如此之短的篇幅里演示如何使用 LISP 写一个 LISP 解释器, 展示元语言抽象的威力. 对 LISP 类语言有兴趣的同学, 这篇文章绝对值得一读.
Twenty Years of Berkeley Unix
http://www.oreilly.com/catalog/opensources/book/kirkmck.html
BSD 主力开发者写的 BSD 和 UNIX 历史, 但不包含 4.4BSD 之后 (即 CSRG 解散后) 的历史.
BSD 的发展历史中出现了很多根本不应该是这个时代的地球人的人物, 例如写出 vi, 后来是 SUN 的技术灵魂的 Bill Joy, 也产生了一些真正影响人类发展进程的技术, 如第一个 TCP/IP 实现, 所以 BSD 的历史确实应该独立出 UNIX 的历史之外分别论述的.
在这里不但能知道我们每天都要接触到的技术是怎么产生的, 可以看到传奇是怎么看似平淡无奇地谱写的, 也可以看出现实需要和限制是如何影响技术发展的 (如 vi 的奇怪的方向键设定与当时用的 terminal 很有关系), 更可以看出老一辈黑客高手对计算机科学的热情和无私奉献的精神. 再看看自己的现状以及环境 , 确实会突然有发奋图强的热情和冲劲的 --- 那个, 偶通常能保持几个小时...
The X Window System
这是由 XWindow 设计者撰写的描述 XWindow 设计的论文. XWindow 的设计在今天看来都是非常先进的: 它把现实设备看成一个 Server, 各种程序看成 client, 他们通过收发消息进行交互, 用这样的方法来实现平台硬件无关和远程显示 --- 注意, 这是二十年前的事情.
这篇文章是一个很好的设计范例, 作者把当前遇到的问题, 需求为了应对这样的需求采用什么设计都一一道来. 所以我们能够理解 XWindow 中每一项设计的根源. 我们会发现, 我们现在遇到的很多问题, 他们在二十年前就考虑到并着手解决了. 在 XWindow 的设计中, 也体现了优越的 Tools, not policy 的思想, 从第二章需求分析到第三章设计都能很好地体现这一点. 就因为坚持这样的思想, 所以二十年来 XWindow 的系统体系并没有什么改动, 从最原始的 twm 到最新的 Gnome 4.14 和最新的图形化程序他们用的东西并没有本质区别. 这在我们的开发工作中都是值得借鉴和参考的.
当然, 正因为这样的设计, XWindow 常常会受到效率和标准化方面的诟病 (当然了不是 XWindow 不标准, 是上面跑的东西不标准而已), 优秀而超前的想法往往不是当前的胜利者. 然而, 技术的发展却坚定地朝着文章所指明的方向前进, 瘦客户机, 基于 XML 的用户界面引擎等等时髦的概念和技术频频出现在大众媒体和软件厂商的广告词当中. 这时候, 我们应该来看看这篇二十年前的犹如达芬奇手稿的文章了.
EMACS: The Extensible, Customizable Display Editor
http://www.gnu.org/software/emacs/emacs-paper.html
这是关于 emacs 设计的论述, 作者显然是 RMS. emacs 毫无疑问是当今最强大的文本编辑器, 这与它优秀的设计是分不开的 --- 它首先用 C 写了一个 elisp 解释器, 这是一个 lisp 的方言, 能够完成最基本的文本操作, 然后编辑器的其他部分都主要用 elisp 脚本写成. 因而, emacs 拥有最高的可定制性和可扩展性 --- emacs 其实没有 "配置文件" 一说, 它的配置文件就是一个启动时运行的 elisp 程序, 是编辑器的一部分, 可由用户随意改动; 而用 elisp 可以给 emacs 添加几乎任何功能, 甚至改动非常核心的函数. 因而它有无限的可能性和威力.
这篇文章描述了 emacs 在设计中对比前人的主要进步: 彻底把编辑器的编辑语言和编程语言分开, 保证编辑简单易用的同时用编程语言 (elisp) 赋予用户最多的可能性. 文章还叙述了 emacs 的许多设计要点. 这也是一个非常好的设计参考, 而且有一个广受好评的实际例子可参考, 值得推荐.
阅读的权利
这篇短文是 RMS 写的一篇 "科幻" 文章, 说的是在未来人们连借阅图书也会被当作是犯罪, 并可能被投入监狱. 即使学术论文也要支付 10% 的阅读费, 而借债读书的学生还债的希望就在于能够写出被频繁引用的论文从而把阅读费给赚回来 --- 这似乎是一个无可想象的世界, 但是, 在软件行业领域不正是这样么?
我们无法想象买到一张新 CD 却被要求必须单独欣赏而不能和朋友分享的日子, 然而软件行业正是这样的, 甚至唱片行业也逐步有这样的趋势; Code Reading 那本书的前言说很难想象一个人练习写作时不去参考著名作家的作品, 然而软件行业就是这样的, 虽然我国法律允许对软件进行研究, 但是你读汇编干什么? 把似乎很合理的软件业的版权限制放到其他我们熟知的领域, 就能看到它们有多么的荒谬.
正是这篇文章使我认真思考关于自由软件的意义的问题, 而不是一种幼稚的反微软反商业情绪. 文章的结尾是煽动性的, 主角们移民到版权官尚无力控制的月球 , 暗示着 GNU 重新创建自己的自由软件世界的行动, 而后面的大起义, 其含义就很明确了.
Eric S. Raymond 的文章
Eric S. Raymond 是开源软件界的著名作家, 他的文章对开源软件社区及其他公众都产生了深刻的影响. 除了上面介绍过的 TAOUP 外, 它的经典文章还包括 "如何成为一名黑客", "提问的智慧" 等等. 篇幅有限, 这里只是简略提及, 所提到的所有文章在 Linux 版精华区有中文译文.
"提问的智慧" 是我最常引用的文章, 它不但是黑客社区中交流的指引, 更是一个对 "如何解决问题" 的引导, 是任何人都应该一读的文章. "Hacker 文化简史" 是一个传奇简述, 在传奇中表现黑客的精神. "如何成为一名 Hacker" 则是一个对计算机入门者如何成长的良好指引, 它着重讲两个方面: 黑客应有的态度和黑客应具备的技术, 这其实也是计算机专业学生应有的态度和技术. "开拓智域" 这篇文章有点难懂, 大概是从社会学和人性的角度分析开源软件社区的运作, 它解释了一下开源软件社区中的各种不同观点, 也解释了这个社区的文化, 规则及其成因. 这几篇文章对有点神秘的, 常常被误解的黑客社区做了深刻的刻画.
"大教堂和市集" 讲述两种不同的开发风格, 并说明为什么管理稍显杂乱的市集模式能够开发出优秀稳定的软件. 证明了开源软件开发模式的合理性. "魔法大熔炉" 则是从经济学的角度说明开源软件的发展与占领市场是合理且对业界有利的. 这可能可以算是面向大众的对开源运动的一个理性分析.
The Tao of Computer Programming
http://www.users.cloud9.net/~hennessy/tao.html
把这篇文章放在压轴的位置是特意的, 从标题看是想仿道德经的, 不过混杂了不少后世道家著作的改版, 比如那个 "图灵梦见自己变成了一台机器", 乃至其他著作的"三日不编程食肉无味" 之类. 和道德经一样, 它是一些对编程, 对设计乃至对计算机科学的格言, 有的发人深思, 有的可能是我段数不够, 看的莫名其妙.
作者在文中把握了一个重要的思想: 编程是一项处处渗透着哲学道理和哲学情趣的工作. 比如硬件和软件是计算机的两极, 没有硬件软件只是一堆臆想, 没有软件硬件只是一堆发热的元件, 脱离硬件谈软件和脱离软件谈硬件都是不可能的, 时间和空间是机器的阴阳两极, 得时间往往失之空间, 得空间往往失之时间, 只能权衡调和; 程序语言中的命名空间, 引用和实体的关系乃至 "引用对象的实体" 等等, 是典型的 "名" 与 "实" 之辨. 读点哲学书, 看看老祖宗的智慧, 可能会有新的启发.
具体的内容在这里不一一列举, 我们中国人读自己的作品, 应该更容易明白其中的引喻和微言大义. 这篇文章当然有很多的中文译本, 名字大抵都叫 "编程之道", 大家可以搜索一下. 道可道, 非常道, 计算机的大道不存在与让人眼花缭乱的技术名词中. 我们往往容易迷失在新技术和新技术名词中而不去追寻其真正的意义和所谓的 "道", 这篇文章大有返朴归真之意, 先不说是不是真的能够学到所谓的 "道", 但看着它, 确实能让你心平气和, 如沐春风.
posted on 2006-08-16 16:55
踏雪赤兔 阅读(1544)
评论(3) 编辑 收藏 引用 所属分类:
IT资讯