2009年10月30日星期五

读书:风云《游戏之旅-我的编程感悟》

对于一本技术图书的好坏我有两个最简单的评断标准,一是是否能吸引人,这本书就像一个好游戏一样让人沈浸其中,不能自拔,上个一个周末分“两口气”把它仔细读完了。第二个标准就是我是否做很多笔记,在读这本书的过程中我在我的Google docs做了非常多的笔记。以我的标准来说这本书绝对是五星级的好书。虽然我不是游戏程序员,但是我也得到了非常多的收获,我不仅从风云的亲切自然的文笔中了解他的一些成长经历,而且还“似乎”进入了一个陌生但是令人兴奋的游戏设计领域。通过阅读这本书还有一个收获,就是进行了一些关于游戏开发的方法,游戏引擎,游戏引擎中的优化等等知识的“扫盲”。
s2198972 “第二章算法,程序的灵魂”是我最喜欢的章节。如何进行算法层面的优化,本书也谈到了几点,看完深有体会,以下是部分书摘。

1 数学方法的改进

2 预运算来节省时间(空间换时间来避免重复运算)或是重复运算来节省时间。

3. 简化算法求得近似解来取代精确解(或最优解)

4. 改进数据组织方式,用更少的操作处理更多的数据,甚至避免冗余数据的处理

我也非常喜欢“第九章C和C++”和“第十章 调试”,强烈推荐仔细阅读。我们使用C和C++,但是有没有在不同的层面去*思考*一下它们而不是仅仅使用它们,书中关于C和C++的一些精彩诠释也令我得到很多启发,以下是部分书摘:

“C++和C一样,都是最贴近计算机固有模型的,C++的每一行代码,都和C一样有明确的目的,没有去干多余的事情。”

“C语言是对汇编语言的一种抽象,正如汇编语言是对机器底层指令的一个最小幅度的抽象一样,是为了人类能更方便地控制机器。但是,人在使用C语言控制机器时,并没有比汇编语言有观念上的不同,也就是说,程序员依旧是按机器模型来思考问题。在面对问题时,问题的描述往往并不符合机器思考的模型,程序员的工作也就是在两者之间搭上一座桥梁,让问题的描述可以用机器的思维来解决。”

“C++则采用了另一套方法来减轻程序员解决问题的复杂度,那就是面向对象。它是一种通用的方法,面对问题,我们把问题中的事物都表示为对象,对象有自己的行为,对自己遇到的问题提出符合机器模型的解决方案,或把自己划分为更小的对象集合。这样,程序员就可以在对象的级别用对象本身的术语描述问题,而这些术语最终都会被直接对应到机器模型上。”

八卦一下,书中有一些关于一些编程语言的有趣观点:

“JAVA更像一个实验室研究出来,有着浓厚的学术气味,外观优美超过它本来应该具有的人们所期望的实用性。”

“而C#则是工程师的结晶,外加了许多商业味道,被微软强烈地推广。”

“脚本语言如Python会像C++这样的主体开发语言的一种有益的补充。”

风云来自实践的这本书,是我读过最有趣生动,亲切的本土技术图书,同时也是一本极好的教材。

在这本书中,我最有感触并最喜欢的一句话是“多年的编程经历让我明白了一个道理:绝大多数情况下,没有解决不了的问题,只有因为平时缺少练习而惧怕问题的复杂度,畏惧的心理让我们选择避让,采取并不那么好的方案去解决问题。”一句很平实的大实话。真正的“高手”之路,无论什么领域,其实就是多思考,多动手,知难而进吧。

2009年10月25日星期日

读书:梁肇新《编程高手箴言》

s2301239上个星期读了超级解霸的作者梁肇新的这本书。这本书行文亲切自然,国人写的书显然比国外的图书的中文版更具有“亲和性”。当然了,也许也会有很多人对文中的一些观点有不同的意见,但是不同的人一定会得到不同的启发,绝对值得一读。带着自己的思考和结合自身编程的实践经验去阅读这本书也许可以得到更多的收获。这里谈谈我从中得到的一点启发。
曾经参与一个项目开发经过多次失败,最后才发现对于实际应用软件项目,最适合的方法就是类似“实现核心-->增强功能-->测试”这样一个过程。强烈赞同书中的观点:
“我们不可能一开始就把所有的细节都考虑清楚,通常,开始只需要一个基本的框架,也就是核心的核心。如果这个核心都实现不了,即使再进行下去,整个项目也都是多余的,只是浪费时间而已。所以,一开始就要解决最核心的问题。当最核心的问题解决之后,就可以进行第二阶段。我们把软件开发分为设计规划阶段,功能设计阶段,测试阶段。所有的产品都可以划分为这三个阶段。事实上,如果最核心部分实现了,那么依赖于此核心,再实现增强一点功能就是第二阶段。第二阶段完成后,就可以进行第三阶段。”
还有例如书中谈到的关于界面和接口的“箴言”:
“界面是界面部分,接口是独立的一块。接口部分就是程序的实现内核,通常先用Console方法直接地实现程序,这样更便于分离界面和内核。如果开始就用Windows的界面去实现内核部分,这样就可能会把界面和内核混在一起,无法分开。所以,一开始做程序时,就不要考虑界面是什么样子。”
“接口的目的就是把外部条件和内部条件分离开来。外部条件由别的程序提供,别人可以用。做接口最好的方法,就是直接用Console程序先实现程序的主体,然后从中提炼出接口来。这样做提炼会简单明了。如果用可视界面先实现了程序的功能后再去提炼,就会比较困难,因为这样就会把界面和功能实现混在一起,很难区分。”
看完后深有体会,我在做一些应用软件项目时总是把界面和功能实现混在一起,的确会造成维护,修改,甚至是阅读的很大困难,程序结构也会不够简单明了。
我总是太过局限于“软件工程的思维框架”中,常常在抽象化的时候,总是想要把所有的事情都想全了,常常做一个巨大无比的对象,这本书对此也提出一些让人有所反思的观点,例如:
“做对象化时还有一条准则,既对不同的应用去设计程序,而不是针对一种所谓的虚拟模型去设计一个对象。所谓的抽象化,就是想着将来有可能会用的某个功能。这样设计出的软件又庞大又耗时,运行也很慢。这就是杀鸡取卵(教科书会教你这种方法)。”
“杀鸡取卵就是指设计的软件提供了很多的功能,其实用到的功能只是那么一丁点。可能做了一个巨大无比的对象,但是只用到对象的很小的一些功能而已。因为做抽象化的时候,要把所有的事情都想全了,但是这是不现实的,实际上也是没有必要的,且是浪费的。如果凡是思考问题都是为了将来的大而全,这样出错的可能性也会成倍的提高。一般来说,代码越大,出错的地方也就越大,如果代码越小,出错的地方也就越小。将功能模块做成API函数与做出对象就不一样,做成一个对象时,该模块出错的机会就多一些,因为对象还有一个动态的过程,但做成一个函数时,调用函数就可以了,模块出错的机会就会比较小。所以,程序越简单,越不容易出错。”
书中的“程序主干和分支”的概念,也令人很有启发:
“核心就是整个系统中最重要,最基础,最简单的部分。首先要把程序的核心提炼出来,在给它添加附加的部分,它就能成为一个完整的软件。主干是最核心的核心,其后在添加的其他的部分就是枝叶了。”
“编程就是要保证核心的核心不出错,那剩下的枝叶都是一层一层地构建出来的。”
读《编程高手箴言》,也是自己编程思想,习惯等等的一个“自审”的过程。你一定可以找到适合自己需要的“箴言”,用它去提高自己吧。

2009年10月24日星期六

读书: 成寒《躺着学英语:听力从零到满分》

最近因工作时发现自己的英语口语水平还是停留在n年前水平,阔别多年后又开始自学英语了,偶得这本英语励志书,n年就前看过一些英语励志书,其实内容光看这本书的书名和简介,就可以猜到十之八九。但是,正如书中所说的“如果一个人没有纪律,没有办法自动自发学习,一定要人用鞭子打才肯用功的话,再多的英语励志书,也不过是一帖安慰剂罢了。”

s2212962 “学英语,用什么方法都可以。只要这个方法能够挑起学习的乐趣,就一定会有成果。”作者推荐大家用一种轻松快乐的心态去学英文,这本书的行文也很清新流畅,不像一般的英语励志书教导式的文笔,而是让你感觉到作者就在身边和你聊聊她的经验,在短短的几小时就可以很轻松的一口气读完。

我非常认可书中的一些观点例如“自修英语,最大的好处是可以随心所欲。尽量找好听的,自己感兴趣的教材”。至于如何选择适合自己的教材这本书谈到“每页的生词不超过十个,也不低于五个,便是合乎自己程度的教程”。

顺带一提,通过阅读这本书我还纠正了一个长期以来的错误认知,原来晶圆厂例如FAB1是Fabrication(精密制造)的缩写,而不是Factory,象征着晶圆厂与传统工厂的层次有别。

2009年10月5日星期一

电子工程师乱弹编程-跳出迷思

和我一样电子专业毕业的学生,若投身到软件编程时,常常会有一些“迷思”,也许你和我一样也问过自己这些问题:
# 我是否一定需要使用模式
# 我是否应该使用“尝试错误法”
# 我应该为我的低生产力而担忧吗

# 我是否一定需要使用模式
什么是模式?《Head First 设计模式》里是这样定义的:“是在某情景(context)下,针对某问题的某种解决方案。”我认为:我们在设计软件时需要使用模式,但是应该先使用最简单的方式解决问题,在经验和知识增长后,我们在编程时就会知道在何时何处应该使用何种模式,然而这需要一定的时间积累。谈谈我的经验,我刚开始编程时,接触到一些比较大的项目,读了以前开发人员写的代码,里面包含了很多模式,除了一头雾水更多的还是担忧,我总是认为“如果没有使用模式在我的代码中,就说明我是个菜鸟程序员。”开始时我努力地看了很多关于模式的书,并在我的代码中加入了外观模式,工厂方法模式,命令模式......尽可能地使用模式,一段时间后,师兄看了我的代码后对我说“你不是在使用模式,而是用模式去装饰你的代码”。在得到得到师兄的一些指教,并随着自己编程经验的提高,才真正体会到了《C++编程规范》一书的一段话“我们设计的软件正确,简单和清晰第一,软件简单为美(Keep It Simple Software,KISS)正确优于速度。简单优于复杂。清晰优于技巧。安全优于不安全。”的真正内涵。我们使用模式只是为了让我们设计简单并且有弹性。正如《Head First 设计模式》所言“如果你能保持简单的设计,那么你将会得到其他开发人员的欣赏和尊敬。”

# 我是否应该使用“尝试错误法”
我认为:应该尽可能地减少使用“尝试错误法”。Trial and error-尝试错误法是一种用来解决问题、获取知识。因为我们这些外行人对一些编程的基础知识的缺陷和经验的不足,所以我们常常喜欢使用Trial and error来解决问题。尝试错误法常常就是靠巧合编程,使用着最低限度的知识去解决问题,这里产生的代码绝对是比较低质量的,不是最佳的。通过“尝试错误法”解决问题,其实只能带来一时之快,然而之后也许会带来“无限的痛苦”(我们很有可能要为这个低质量的解决方案付出大量的额外时间),因为没有深思熟虑,没有了解问题的实质,并掌握解决问题的根本知识。我很喜欢《程序员修炼之道》里的一句话 “Don't Program by Coincidence. 不要靠巧合编程。深思熟虑地编程。”我们应该常常问自己,是否有深思熟虑地编程。

# 我应该为我的低生产力而担忧吗
我认为:不应该担心。“程序员之间生产力比差10:1”,这句话在很多书提到了,很多大牛也是这样说。我刚开始编程的时候,和我的生产力和我的师兄不止差10倍,我认为甚至是20倍以上。因为同在一个项目组,当时每天我都很担心,也很痛苦。虽然现在我和我的师兄还是差距很大,但是我一点也不担心“低生产力”的问题,这不是一个问题,而是一个事实,只需要直面它,并通过不断的自我提升来减少差距。提高生产力,以下我粗浅地谈一下我认为比较重要的几点,自学,提高自己的工作效率和多实践多思考。

自学,常常积累知识
网络真是自学的天堂,而且我认为程序员行业是几乎就是最适合自学的行业。好记性不如烂笔头,自学时也许需要通过记事本或google doc记录一下,常常回顾一下,可能在一定的经验积累后看看以前的记录会对一些知识会有了更高一层的理解,以前的一些似懂非懂的部分也会豁然开朗。用纯文本保存知识绝对会是一个很重要的经验。

提高自己的工作效率,也许可以考虑一下两点:
# 提高自己的E-因子(E-因子=不被打扰的时间/体力出勤的时间)。
# 延长自己的flow的状态的时间(在一心一意动脑筋工作的时候,人们在意识上处于一种心理学家称为顺流flow的状态,顺流是一种陷入沉思的状态。)

多实践,多思考
提高编程水平决对是一个“蹲马步”的过程,我们要做的其实也很简单,就是专心致志的实践,多编程。多试着思考解决问题的方法也是提升自己的一个很重要方法,请常常反思。我认为,随着经验的积累和思考水平的提升,我们必然会从“低手”成为“中手”,最后一定能成为具有超高生产力的“高手”。

2009年10月3日星期六

在MinGW中安装并使用GCC4.4.0

一直懒得升级MinGW的GCC,因为嫌麻烦,这真是一个很不好的习惯,其实我们应该要常常提醒自己是否“是否在使用最好最新的工具?”,一直到前几天在我的一个小程序使用FFmpeg的avcodec_encode_video()函数发生崩溃(Crash)后才决定升级GCC。avcodec_encode_video()函数发生崩溃是因为堆栈定向问题(stack alignment issue),有兴趣的可以看这个网页里的讨论:
http://ffmpeg.arrozcru.org/forum/viewtopic.php?f=1&t=549如果使用gcc >= 4.2版本就可以解决问题。

MinGW在2009年6月份已经释出了GCC 4.4.0请到以下的站点:http://sourceforge.net/projects/mingw/files/下载如下的文件(假设你只是要使用gcc,c++编译器,如果要使用java,objc,请下载其他相关的文档)
gcc-ada-4.4.0-mingw32-dll
gcc-core-4.4.0-mingw32-bin
gcc-core-4.4.0-mingw32-dll
gcc-c++-4.4.0-mingw32-bin
gcc-c++-4.4.0-mingw32-dll
gmp-4.2.4-mingw32-dll
mpfr-2.4.1-mingw32-dll
下完后,请直接解压到MinGW的目录中去,例如C:\MinGW里。

然后重新安装msys,很简单以前的文章就提过了,不要忘了下载coreutils-5.97-MSYS-1.0.11-snapshot.tar.bz2并且解压到msys的目录中去,因为在默认状态下msys并没有完全安装coreutils的所有组件。为什么要安装完整的coreutils组件呢,这是因为有些make文件里的指令需要coreutils的一些组件才能正确识别。coreutils的最新版可以http://ftp.gnu.org/pub/gnu/coreutils/里找到。

现在有了MinGW5.16+GCC4.4.0+msys,我对我常用的几个库进行了重新编译(理论上不需要对所有所使用的库重新编译,因为高版本的GCC应该向下兼容低版本的GCC所编译的库):

Qt4.5.1已经用了挺长的一段时间,9月30日我下载了了Qt4.5.2然后编译了它,没想到10月1日Qt释出了4.5.3。哈,不想再编译一遍了,因为即使使用配置了Core i7的机器,编译Qt也需要很长的时间。编译的方法如下:先将C:\MinGW\bin和C:\Qt\4.5.2\bin加入环境变量的path里。然后进入Qt by Nokia v4.5.2 --> Qt 4.5.2 Command Prompt并输入configure(当然了,可以进行configure调整,具体请输入configure --help看说明),最后输入mingw32-make,就开始编译了。

LIVE555也于28-Sep-2009已经释出了新版本,可到以下站点下载。http://live555.com/liveMedia/public/然后重新编译,很简单,解压下载完的原文档,然后通过msys进入它的目录,先输入./genMakefiles mingw然后输入make,就搞定了。如果遇到问题可能要对config.mingw进行一些微调,例如将第三行C_COMPILER =           $(CC)的改成C_COMPILER =           $ gcc

对FFmpeg编译可以按照以前介绍过的方法,但是编译好我的项目并正确连接编译好的ffmpeg动态库后,运行我的程序会出现这样的错误:"The application failed to initialize properly - 0xc0000005" 很无奈,我的解决方法比较愚蠢,重新编译FFmpeg生成静态链接库(.a),然后在项目设定中使用静态链接库代替动态库(.dll),结果程序可以正常运行,只是我的主程序增肥了不少,这是暂时的解决方法。

还编译了一些库,使用gcc4.4.0编译和使用几乎没有问题,这里就不多谈了。在网上找了一下我使用过的一些库,很多开源库都陆续释出新的版本,我使用的版本真的很旧了,使用开源库要常常注意它们的更新,还是那句话要常常“提醒自己是否在使用的最新最好的库”,很多库的新版本已经解决了一些我以前遇到的问题,我下载了一些库的二进制版(bin),然后可以直接使用它里面的dll就可以了,连编译都不用了。