KDB2 开发小结

最近消失了好久,主要是考试吧,大三课程不多,但是都是学得累得很的那种。还有就是课程 Project ,最近这个就是很著名的 MiniSQL 了,经常都听学长们说,做一个 MiniSQL 下来确实会收获很多的。本来也是要认真做的,但是时间估计失误,在 6 号的时候才得知是 11 号截止,所以最后有些仓促了,不过最后还是做完了,已知的 Bug 都修正并且通过了压力测试,心里面也是很高兴的。这里写下一点总结吧,一是给大家分享一下,也是留给自己将来看的,我的 Blog 专门有一个分类就是 Bug Archive ,我主要就是想把自己平时实际开发中犯的错误和遇到的 Bug 都搜集起来,时而看看,希望能够不再遇到同样的问题吧。这次开发时间虽然很紧,但是其实主要开发时间和调试用的时间差不多也该对半分了,所以这篇小结也必须得放到这个分类里了。 :P

KDB2 就是 MiniSQL 了。其实同 MiniSQL 结缘也挺深的,大一上的 C 语言 Project 和大一下的 C 语言综合程序设计的 Project 都是做的 MiniSQL ,也都是同 moonykily 一起做的,其实大学挺多 Project 的,要找好的搭档也不太容易,有许多人就直接自己做了,或者组了一个队,仍然只有自己做,即使是几个很牛的人凑到一块儿,也不一定是好的组合。这一点还是觉得自己很幸运了,同 moonykily 几次合作都还算愉快,只是他总是不慌不忙的,有时候让人相当恼火。趁这个机会,我就把以前的东西也一块翻出来看一下吧,还是能找到许多比较有趣的东西的。

恩,越是去找越是能发现更多有趣的东西,不过也许我觉得很有趣,匆忙路过的人却没有心情去看,为了提高我 Blog 文章的质量,我还是把有趣的东西和有用的东西分成两篇文章吧。这里列举一下几次开发的教训吧,首先是第一次 MiniSQL ,以下是我当时写的总结文档里提到的问题:

  • 内存问题。这个也许是 C 之类的语言恒久不变的问题了,好像当时是因为一个 memcpy 将内存覆盖掉了,困扰了很久。因为内存整个坏掉了,调用堆栈看到的也全部都只是问号而已,又没有多少经验,在 GDB 下调试得异常郁闷。导致我后来对 memcpy 很敏感的样子。因为这样的 Bug 其实是防不胜防的,它就像感冒一样无处不在,发烧、头痛、喉咙痛、咳嗽、全身酸软无力……各种症状都是感冒引起的,内存问题也会引发一系列连锁反应,让问题隐藏得很深,而且最后改掉错误之后往往会发现其实是由一些很简单的问题造成的,甚至就只是一个拼写错误!
  • fopen 的 b 选项。熟悉 C 语言的应该都知道是什么了,就是那个让文件以二进制的方式打开的选项。我当然也是知道那个选项的,但是我似乎一直把它的存在当作是历史原因,因为在《The C Programming Language》上看到这样一句(P.178)In particular, our fopen does not recognize the “b” that signals binary access, since that is meaningless on UNIX systems, nor the “+” that permits both reading and writing. 于是就没有加那个选项。当时的情况是我在 Linux 机器上,而 moonykily 在 Windows 机器上,程序在我的机器上就能跑得很好,可是在他的机器上一运行就会疯狂出错:错误当然不会是那么明显地告诉你忘记加“b”选项了。我们为了这个 Bug 调试了大约三天,一次老师在上课的时候聊起他年轻时候的编程经历,就说起了这个选项,才让我们走出了困境。问题其实很简单了,在 Linux 上运行很好,因为它不区分文本和二进制格式,而在 Windows 下则被它做了一些诸如换行符转换之类的工作,结果造成了完全莫名其妙的错误。文件的内容用编辑器打开都是好好的,在程序里面读出来却又造成了错误,在经历了第一个问题之后不禁让人立马想到哪里又有内存覆盖了,可是却万万没有想到只是这么一个选项忘记了。
  • 设计。这个是大学的第一个 Project 了,当然是非常激动的,迫不及待地就开始写代码了,结果代码越写越乱,苦不堪言呢!现在,我觉得开发主要有三种方式:
    • 对于小程序,比如平时用的脚本之类的,立马动手开始写是不错的选择了,因为这样的程序通常是能用就行,太多顾虑可扩展性以及架构啊、OOP 啊、模式之类的乱七八糟的东西反而会陷入无边的深渊。
    • 对于中等大小的项目,需要事先经过谨慎地设计,尽量把握好各方面的问题,设计得不好,开发会变得越来越恶心的。
    • 对于大型甚至是超大型的项目,设计当然也是很重要的,但是最好不要把所有的时间都花在上面了,需要认识到一点:设计永远不可能的完美的。对应越大的项目这点越明显,各种不确定因素随时都有可能让你的设计毁于一旦,我们要做的不是在一开始把握住所有的方面,或者是去压制各种引起变化的因素,因为那是根本不可能做到的,这个时候需要从另一个方面来把握问题,引用那本著名的书的名字,就是:“拥抱变化”!极限编程、敏捷、重构这些东西现在也越来越得到重视了吧。
  • 版本控制。那个时候没有使用版本控制,也许也并不了很解这么一个东西吧,结果导致了很多问题。当时的情况是他使用 Windows + VS 2005 ,我则使用 Linux + GCC ,虽然我们的程序是 ANSI C 的,在哪里都能编译,开发过程却无限麻烦:
    • 代码同步。这个是最不好搞的,我写了一个脚本自动从他的 ftp 下载他更新过的源文件。可是有时候会不小心覆盖掉自己刚写的代码,或者是发现改过之后不如以前的版本好用,于是就手工做备份,时间一长备份的文件夹多了根本搞不清哪个是哪个了……
    • 代码转换。不止是换行符,因为在源代码里面使用了中文,还需要从他 Windows 的 GB2312 转化为我 Linux 里用的 utf-8 编码,幸好 Linux 下脚本非常方便,这些问题也好解决了。
    • Makefile 。他那边用 Visual Studio 管理工程,可是拿到我这边不能直接用,幸好项目不是很大,文件依赖关系也比较简单,我也是用脚本来处理这个问题的。总之当时的开发环境可以说是相当原始了。

第二次开发是在大一下学期,时间隔得比较近吧(其实似乎也不近了,从文件修改时间上来看似乎至少有六个月),总结了一些问题,重新设计了一番(例如,这次加上了页面缓存,上一个版本的 B+ 树操作是在没有任何 buffer 的情况下直接在文件里做的 -,-bb),便开工了。开工的时候异常兴奋,因为前面那个版本并不是很满意,想到能把那些毛病都去掉,做一个强大的系统出来,就非常兴奋。由于上一个版本写得太恶心了,我们代码全部重写。上次遇到的一些问题也得到了解决,例如我们使用 Subversion 来做了版本控制,用 qmake 来自动生成 Makefile ,并且都是在类 Unix 的环境下开发的,即使是在 Windows 下也是使用了 Cygwin 进行构建。最后的开发中有些什么具体问题已经记不清楚了,文档里也没有详细说,只是有一点还有挺深的印象:大概是太兴奋了,有些急于求成。本来是酝酿了很久的,设计得也比较清楚,采用了自底向上的方法,分了几个层次,可是总是想着做更多的东西,结果底层的东西没有经过什么测试就接着往上写,最后是写起来也不爽,因为心里对自己要用到的下面层次的东西也没底,跑起来就更不爽了,各个层次的未经过测试的 bug 混杂在一起,完全乱套了!

第三次就是这次了。时隔这么久,再做 MiniSQL 。本来上次做了以后说再也不要看到 MiniSQL 了,结果 C++ 的 Project 也没有做 MiniSQL ,这次却是我选了数据库系统设计这门课,必须要做 MiniSQL ,最后还是拉了 moonykily 来帮忙,说服他也选了这个课。

其实前面两次都遇到的问题就是程序的变动和调试等,后来也了解了许多软件开发的方法,就是关于迭代、重构以及单元测试之类的,都觉得很有道理,也许能比较有效地解决那些问题,便也想真正实践一下。甚至一开始准备做结对编程尝试的,因为我们两个住同一个寝室,也有这个条件,平时一起调试程序以及偶尔一起讨论一个问题

Comments (3)

moonykily November 12, 2007
嗯,深刻地体会到设计模式和单元测试的重要……
还有,vs挺好用的……除了编辑器不爽,嗯。
shawn November 12, 2007
真不错,话说当时写MiniSQL真是让人无比的怀念,在翠柏1-526通宵,白天起来去上软工+睡觉,下午回来继续写,继续通宵...= =
momo~好好加油
pluskid November 13, 2007
^_^ 谢谢鼠 mm ~