2012年3月2日星期五

计算机编程语言的掌握程度

在简历上,“精通”这两个字基本上起到的都是嘲讽和增加仇恨的效果。一旦你自称“精通”某一门技术或者编程语言,面试官如果不是直接在心里给你打一个不靠谱的标签,那就会努力的证明你是不靠谱的——“精通”这两个字一般都会引来最最困难的提问。所以我一直在想,到底应该怎么形容自己的掌握程度呢?某种技术我说不好。但今天偶尔的一次谈话让我觉得对一门计算机编程语言的掌握程度,是可以有以下四个层次的:

1、知道
在这个层次,你已经了解了这门语言的基本语法。虽然这很微不足道,但也足够你阅读这门语言的程序了。不同语言在语法层面还是有一些区别的,比如语言的类型是编译还是解释、强类型还是弱类型、代码段是用begin/end还是{}表示、声明一个函数是用function还是def等等。

2、熟悉
在这个层次,你已经学会使用了这门语言的基本类库。只有语法没有类库的语言是没有意义的,熟悉这些类库是正确运用语言的基础。熟练使用操作文件系统、socket、日志、并发等等的类库,知道什么时候该用链表什么时候该用哈希,你才能算“熟悉”了这门语言。

3、掌握
在这个层次,你已经使用这门语言写出了一些能够解决实际问题的程序了。在前面的层次,你的代码解决的可能都是一些toy problem,但是只有你的程序经受了实践和时间的考验,你才能够有机会去解决一些书本上永远不可能出现的问题,并且更加深入的了解这门语言的细节。

4、精通
在这个层次,你已经阅读了这门语言的源代码。你应该已经了解它的内部实现,并且有了恍然大悟的感觉。


用这个角度检视自己,我对于各种语言的认知程度又有几分呢?

A类:最接近于精通的
Python:感谢《Python源代码剖析》这本书,给了我一个很好的入门。不过一来这本书我也没看完,二来Python本身的代码也在快速变化着,完全理解Python的实现仍然是一个很艰难的任务。

B类:掌握
C语言: 把C语言列在这里有点勉强,因为我上大学之后就基本没有写过C的代码了,不过C给我的影响仍然是巨大的,它塑造了我对计算机和程序的认识。
Javascript:Javascript是我很喜欢的一门语言,更不必说在这个浏览器的时代,它简直就是世界的未来。Douglas Crockford的那本《Javascript: The good part》是每个js程序员都必读的一本书,而Coffeescript则可以看作是这本书的实现。

C类:熟悉
C++、Java: 把这两门重量级的语言放在这一类实在是让我脸红,不过面向对象程序设计的确仍然是我最弱的地方。类、继承、多态、虚函数、接口——这些都不是问题,我似乎只是不知道怎么把这些螺丝刀派上用场。
PHP:玩具语言。
VB:感谢这门语言陪我度过了紧张的高中时光。

D类:知道
这一类就多了,不一一列举。


显然,随着时间的推移,这些分类也总是在变化的。有的语言因为你不再使用而变得生疏,有些则越来越熟悉。门户之见最没有意义,最重要的是把它们运用在正确的地方。

2011年1月7日星期五

为什么Latex的宋体可以加粗但不能倾斜?

这的确有点奇怪。不过,稍微做一下关于中文出版业的功课就可以知道了。英文中,斜体用在需要强调的地方,在Latex中对应为\emph{}。但在出版上,中文是没有“斜体”这一说的。需要强调的文字不应该用宋体,而应该用楷体。这也就是为什么Latex的CJK包就安装了宋体和楷体两种简体中文字体。

2010年12月17日星期五

此daemon非彼daemon

跳槽之后被各种琐事缠绕,好久都没有写文章了,今天匆匆记一笔

最近被daemon折磨了很久。原来一个程序要成为一个合格的daemon也是很不容易的,不光要进行两次fork,还有一大堆注意事项(PEP-3143):
  • Close all open file descriptors.
  • Change current working directory.
  • Reset the file access creation mask.
  • Run in the background.
  • Disassociate from process group.
  • Ignore terminal I/O signals.
  • Disassociate from control terminal.
  • Don't reacquire a control terminal.
  • Correctly handle the following circumstances:
    • Started by System V init process.
    • Daemon termination by SIGTERM signal.
    • Children generate SIGCLD signal.

偏偏我碰到的情况更特殊一点。这段代码的作者肯定是没看过上面这些条条框框的,把自己fork了两次就变身daemon了,然后在某些时候还用multiprocessing模块把自己再复制了几份来异步的做一些事情。在调试一个bug的时候,我注意到了multiprocessing 模块里讲 Process.daemon 属性时是这么说的:
The process’s daemon flag, a Boolean value. This must be set before start() is called.

The initial value is inherited from the creating process.

When a process exits, it attempts to terminate all of its daemonic child processes.

Note that a daemonic process is not allowed to create child processes. Otherwise a daemonic process would leave its children orphaned if it gets terminated when its parent process exits. Additionally, these are not Unix daemons or services, they are normal processes that will be terminated (and not joined) if non-daemonic processes have exited.


这实在是一段很难懂的话。就像伞兵生来就是要被包围的,守护进程daemon生来就是要被父进程抛弃的,然后再被init进程收养,沉默的完成自己的任务。但这段话却明确的说,当进程退出的时候,它会把自己的子daemon进程都干掉……那daemon还守护个毛啊?而且这里还说守护进程是不能创建子进程的,这更离奇了,太不公平了吧?这是赤果果的歧视啊。

后来我发现自己有点先入为主了。daemon只是一个概念而已,而非一个实际的标签,系统中的进程实际都是一样的。multiprocess模块的 Process.daemon 只是 Process 对象的一个属性而已,是需要开发者自己设置的而非linux帮你产生啊。理解了这一点,上面的这段说明就完全可以理解了。daemonic 类型的 Process 对象就是具有这些属性而已。这里的 daemon 和我们平常理解的 daemon 虽然有联系,但确是不同的了。

有个和我有相同困惑的人09年在python-list发了一封邮件问这个问题,后来又自己理解了,我也是看到他的邮件才领悟的。

* http://www.python.org/dev/peps/pep-3143/#correct-daemon-behaviour
* http://mail.python.org/pipermail/python-list/2009-May/1203871.html

2010年8月2日星期一

介绍一个Vim的插件:Slime.vim

http://technotales.wordpress.com/2007/10/03/like-slime-for-vim/

Slime不是Vim的原生插件,它的创意来自于玩Emacs的阶级兄弟。它的功能很简单,就是将Vim的一个寄存器中的内容传送到screen的一个window中去执行。

这东西有什么用呢?最有用的地方在于简化REPL(read-eval-print loop)这个循环,降低程序员调试代码的时间成本。对于Python这个问题其实不是那么突出,因为Python的命令行程序对于以文件形式作为输入的 python代码很友好。但是其他语言的命令行程序似乎不是这样。Slime的动力就是Ruby和Lisp这样的语言。开一个Clojure的命令行交互界面麻烦的很,而且它的功能和Python命令行没得比,更不用说ipython了。所以Slime看起来就非常好用了。

2010年7月6日星期二

读《Coders At Work》前三章

我水平比较低,看了前几章就感觉学到了许多,不由得想写一写,为自己总结一下。

人在不同的时间、环境和机遇下所渴望得到的知识是不同的,这些只是现在的我所体味到的好东西。但书中还讲了很多,但也许我以后再读才能品出其 中的滋味,也许你现在就能品出来。这也就是一本好书的魅力所在吧。

第一章出场的大牛是Jamie Zawinski。对他的采访给我印象最深刻的地方是他的成长。他高中接触计算机之后通过参加地方性的 User Group聚会认识了卡耐基梅陇大学(CMU)的老师,然后屁颠屁颠的跑去“实习”。Jamie在CMU读了本科,然后仍然是依靠这位老师找到 了自己的第一份工作。之后他又遇到了Peter Norvig,并跑到Berkerly去了。他的学会的第一门计算机语言是Lisp,他写出了 XEmacs,他从不信任gdb,他是Netscape的主要开发者之一,我们每天看到的XScreenSaver也是他的习作。这需要怎样的天分、机遇 和努力,才能成就这一切呢?现在的Jamie是一家夜店的老板,已经不再写程序了。这似乎真的有一丝“哥已不在江湖,而江湖上还流传着哥的传说”的意味啊。

第二位出场的大牛是Brad Fitzpatrick。对他的采访给我印象最深刻的地方是他的创业历程。LiveJournal从无到有,从小到大,都是他努力的成果。他可以今天写 Javascript,第二天却考虑Linux内核的网络算法。Things are always on fire! 今天经验不足的程序员时常会犯过 度设计的毛病,而那时的他却没有任何可以参考的东西。他也提到如果知道自己的网站能有这么大的发展和负载,肯定会好好的考虑架构啊算法啊之类的东西。但是 世界是没有如果的,他的网站很幸运的生存了下来。这就是一个产品是如何进化的。

第三位出场的大牛是Douglas Crockford。对他的采访给我音像最深刻的地方是他对代码阅读的强调。什么是好代码?在他看来,好 代码的第一要义就是可读性(readability),其次是正确性(currectness),最后才是效率(efficiency)。当然,这可能和 Javascript的特性有关,毕竟这的确是一门非常难以驾驭的语言。他谈到了他和他的同事们是如何进行code reading的,也谈到了他在面试 时对面试者有怎样的偏好。我在看这本书之前由于Javascript的缘故就看过几部Douglas的演讲,他是一个非常可爱的白胡子老头。即使你没有时间,至少也应该看看他的《The JSON Saga》 的分享,非常有意思。

这三篇采访都提到了一些共有的话题,其中一个是问你是如何设计一个系统的,是top-down,还是bottom-up,抑或是 middle-out?不同的人有不同的习惯。我对这么问题的印象这么深是因为在我注意到它之前,有人问过我一个类似的问题,而我的回答很悲剧。回头再读 此书看到这个问题,不由的生出“从前有一份答案摆在我的面前,而我没有珍惜……”的哀叹啊。

2010年6月22日星期二

Things I learned from python-list recently

1. 有了list comprehension还要map函数干什么?需要么?不需要么?

map函数只在一种情况下比list comprehension有优势,那就是它可以被当做一个参数被传递给其他函数。当然,一般来说大家也很少这么干……


2. ord() 只能产生无符号整数(unsigned char, 0-255),如果你在一个字节一个字节的读取流,那么把这每个自己转换成有符号整数的方法有很多:

(a) 用标准库里的 array 模块
(b) 用标准库里的 struct 模块
(c) 用 bytearray 数据类型
(d) signed = unsigned if unsigned <= 127 else unsigned - 256
     signed = (unsigned & 127) - (unsigned & 128)
     signed = (unsigned & 127) * 2 - unsigned
     signed - unsigned - 2 * (unsigned & 128)


3. evaluate 1^2+2^2+3^2-4^2-5^2+6^2+7^2+8^2-9^2-10^2+...-2010^2, where each three consecutive + must be followed by two - (^ meaning ** in this context)

>>> sum((1, 1, 1, -1, -1)[(x-1) % 5] * x**2 for x in xrange(1, 2011))


4. 应该小心的将反斜杠(\)作为行延续符(line continuation)使用。虽然我在pep8中和其他关于pythonic的文档中都看到了这一点,但我在维护现有代码的时候并没法更多的实践这一点,因为这些代码的作者甚至不知道pep8的存在,更不用说什么将每行长度限制在80个字符以内的狗屁龟腚了。

5. 函数也是可以被pickle的,但是不能被marshal

2010年6月5日星期六

让url适应浏览器

今天看到一篇有趣的文章:http://benlast.livejournal.com/29164.html

起因是Firefox缓存哈希算法的一个bug,会使资源不能够充分的缓存。Google意识到了这一点,并且对自己的url做了一些相应的变化,以避开Firefox的这个bug,使更多的网站图片的到缓存,改善用户体验。

一般来说我们优化网站的思路都是从网站本身去找原因,缓存、js、静态页面等等,这是我第一次意识到不仅浏览器应该适应网站,网站也可以主动去适应浏览器。

当然,也只有像Firefox这样开源的项目才可以让你去适应,IE的bug你可能知道么?

当然,也只能敬佩Google中的强人能想到这个主意,哪个公司的工程师能在维护这样一个网站的同时还熟悉浏览器的各种缺陷?