-
2004-04-29
规则思变
今天写了一个小工具,因为有一批数据要导。如果我勤快,我会选择手工来做,不过是几个文件里里面几十张表的几千条数据嘛!不过,我是个懒惰的程序员。
编写这个小工具的过程中,有一个有趣的小问题。
写完一段代码之后,产生数据是这个样子:
1234567=名称A1-B2
负责人对我说,我们只要前面的名称就成了。
在代码里,“名称A1-B2”存在了一个字符串中,于是我的工作变成了从这个字符串中删去后面“A1-B2”的部分。用伪码表示或许更清楚一些。
原来的是这样:
target="名称A1-B2";
我要的是这样:
target="名称";你想到了什么?
反正我第一个打消的念头是手工删除。实际的字符串肯定不只“A1-B2”,也许还有“C3-D4”、“E5-F6”,也可能是“G7”、“H8”,总之,要删除的部分是一个由ASCII码组成的字符串。所以,解决问题的关键是识别出要删除的字符串。识别出字符串,那么这个字符串必须满足一定条件,匹配?正则表达式?
没错,就是它。身处Java世界是幸福的,JDK 1.4中已经加入了对正则表达式的支持,只是……,我没有用过。
JDK的API不会用?没关系,Java Almanac是最好的答案,其中给出的例子让我可以很轻松的了解大部分JDK API的用法。它基本上已经成了我现学现卖的首选。定义一个用来匹配的Pattern,我们要匹配一个由ASCII字符组成的串,那就这么写:
Pattern pattern = Pattern.compile("(\\p{ASCII})+");
关于模式的含义,JDK的文档中写得很清楚。再说,我又不打算立即开始系统学习,只找自己需要的应该是很容易的一件事。
在文档中,匹配ASCII字符的模式是“\p{ASCII}”,因为在字符串里“\”又特殊含义,所以得多来一笔。有了模式,我们就可以在一个字符串中查找匹配的串了。
Matcher matcher = pattern.matcher(source);找到问题以后解决就容易多了,接下来就删了它。
我选择了替换来完成这个需求,没错,替换!
我用""替换了匹配出来的字符串,这和删除不是异曲同工吗?
matcher.replaceAll("");大功告成!
问题是解决了,兴奋之余,我想到正则表达式,想到了Perl。
Perl在文本处理上的强大,恐怕大家多少都有些耳闻,而正则表达式正是Perl强大实力的体现。年初的时候,信手翻了一些《Perl语言入门》,因为是兴之所致,没有具体的应用方向,所以没有很好的掌握。今天遇到的这个问题,如果以Perl来解决恐怕就不必劳烦Java的大驾,毕竟这不是Java的强项。
最近在看《The Pragmatic Programmer》,第三章就谈到了一个Text Manipulation的问题。可能许多程序员和我一样,习惯以编译语言解决问题,其实很多脚本语言也很强大,尤其在处理这种小问题的时候。我们写程序不就是为了解决问题吗?如果能够“多快好省”的解决,何乐不为?
-
2004-04-28
为了忘却的纪念
宿舍中又有两个人离开了。
虽然他们提出辞职已经有些日子,虽然大家吃散伙饭时还是嘻嘻哈哈。今天回到宿舍准备和这两位兄弟道声别离的时候,他们已经离开了。站在空空荡荡的房间里,我不禁有一丝惆怅。昨天晚上,愤青们聚在一起,开了最后一次“愤青会议”。
如果说刚到某个公司就对这个公司充满了失望,那一定怨不得公司,心甘情愿的让一个连表面功夫都做不好的公司给骗来,多半是精神不大好。
但如果一个个有志青年选择离开的原因都是因为心灰意冷,那一定是公司的问题了。
如果让员工产生一种“干多干少一个样,干与不干一个样”的大锅饭心理,谁还会愿意付出呢?更为幽默的是,干得不好也可以成为英雄。
一个负责人对手下的一个人说,你把这个做了,那人问,怎么做,负责人回答,你看着办吧!
于是,这个“看着办”的仁兄开始了自己的攻坚历程,由于水平太高,本来安排两周的进度,他短短三个月就做完了,给了其它模块开发人员以充分的休息时间。在此过程中,负责人给予了他充分的信任,省去了评审,省去了文档,结果是,做出来的东西包括他自己在内没有任何人完全了解。好戏就此开场。
由于他的模块在系统中的重要性和他创造bug的能力,他成了项目组中最繁忙的人,每天穿梭于开发大厅中,与每一个发现bug的人一同寻找他的经典之作。他繁忙的身影每天在领导眼前晃来晃去,于是领导得出结论,这是个好员工。为了鼓励先进,领导利用一次涨工资的机会大幅度提高了他的工资。下面就选取一个经典中的经典,供大家学习。
有一个表,系统运行时需要对它进行操作,这位仁兄选择的处理手法是把表中所有的内容一次加载到内存的一张Hash表中,可以肯定的是,每条数据也绝对不是一两个字节可以搞定的。经过这位仁兄的测试,这个模块发布了,结果是,真正到了现场跑起来,几乎总可以制造出OutOfMemory的经典错误。经过仔细研究,发现实际运行起来后,这张表里会有80万的数据,估计测试时,最多也就用了千八百的数据。问及这位仁兄,他的回答是,加内存。从需求开始,几乎步步精彩,结果更是让人叹为观止。
于是有得出结论,我们在这里得到了很多的教训。经验?没有。我们知道如何做不对,至于如何做是对的,不知道,因为我们从来就没有对过。现在我们彻底知道了“浪得虚名”的含义。这是一家对外宣称过了CMM 5的公司,而内部却是一个个小作坊的和。不过它并没有小作坊那种灵活,没有那种激情,因为它本身还是一个大公司,拥有着大公司通常具有的问题:等级森严,行动迟缓……
这篇blog的题目是一个离开的兄弟给的,纪念他们的离开,纪念在这里一起度过的日子。
-
2004-04-27
单元测试的习惯
potian关于“单元测试”的话题,一呼百应。没人会在乎再多我一个吧!
在我看来,单元测试只是一个习惯。
如果谁胆敢站出来指责单元测试存在的必要性,恐怕只会遭来骂声无数。
那为什么还有人拒绝着单元测试呢?
习惯。习惯中单元测试不是程序员的事
念书时最令我犯困的就是《软件工程》,而单元测试就是《软件工程》讲的东西,所以,单元测试一定属于那帮有闲心的专家才去研究的东西,跟我关系不大。就这样,单元测试就轻松的被划在程序员的基本技能之外。再说了,我们这里有专门的测试人员,我把测试的活都干了,他们岂不失业了,社会要有分工,不是吗?习惯中单元测试与XP联系在一起
每每提及单元测试,听说过诸如“测试先行、测试驱动开发”之类名词的我们总是情不自禁的把它和XP划上一个等号。我们这里不兴这一套,约束我们的是CMM、ISO之类的东西,没有条件,你叫我如何XP?既然不可能XP了,单元测试也算了吧!习惯中单元测试不正经
单元测试在最终运行的代码中不起任何作用,一点CPU时间都不占,让我花费时间编写这些最终不用的代码,还是省省吧!再说了,项目这么紧,上面的领导成天催我,只编写功能代码我都不敢保证按时完成,叫我编写单元测试,没时间。程序员的优点之一,就是懒惰,所以,我更不会去编写单元测试了。习惯中没有单元测试也很好
我写程序也不是一天两天,这么多年都没有单元测试,我的日子也不错,工资一点都不低。一旦出了bug,我操起debugger就可以搞定,虽然有时候花得时间稍微长了一些。再说,即便你写单元测试就能保证没bug了,你信吗?《The Pragmatic Programmer》有云:“You Can't Write Perfect Software”。习惯中不知如何单元测试
OK,我已经经历了太多关于单元测试的轰炸,我已经开始尝试在日常工作中编写单元测试。但是我该如何编写单元测试呢?这帮“广告人”都在宣传测试驱动开发,这到底是咋回事?我怎么能在编写代码之前编写测试呢?东西都没有,我测啥?习惯中有些单元测试编写起来困难重重
你看,这个部分需要这个部分、这个部分和那个部分,我把它们合起来和把整个系统整合起来难度差不多,这叫单元测试吗?那些书上写的例子,都是简单的功能,一点都不实在。要访问外部文件怎么测?要访问数据库怎么测?要和外部实体通信怎么测?我怎么会想到这些?没什么好奇怪的,我以前就是这么想的。
与其说是习惯,不如是一种误解。对于“不到黄河不死心”的程序员来说,没有什么比撞得头破血流更能刻骨铭心了。
以前我也知道单元测试,也知道它的重要,但我对空穴来风不是很感兴趣。
让我接受单元测试的是Martin Flower的《重构》,凭借单元测试保证代码重构的正确性,因为重构带来的优美让我顺便接受了单元测试。
让我接受测试驱动开发的是Robert Martin的《敏捷软件开发》,书中的一个例子刚好点了我的死穴,和我遇到的问题一摸一样。其实,测试驱动开发是个很简单的过程,只要掌握了”红、绿、重构”的节奏可以说就掌握了测试驱动开发,只是这不同于之前那种直取要害的做法,想要把它融入自己的血液中还是需要做一些思维习惯上的改变。
又是习惯! -
2004-04-22
DOOM之旅
终于读完了《DOOM启世录》。
我不是DOOM的玩家,也无缘Quake。这丝毫不妨碍我对这本书的喜爱。周六晚上,我开始了这次有趣的阅读旅程。
同住的兄弟买了这本书,本来我只是随便翻翻,谁曾想拿起来容易,放下去难。阅读的过程中,我不只一次的告诫自己,明天还要加班,读完了这一段就去睡觉吧!结果是一口气读了近一百页,时间已经超过午夜一点。如果不是要早起加班,我100%会把它读完,没办法,太精彩了。
接下来的几天太多乱七八糟的事影响了这个旅程。只有在每天醒来后,我能看上不到半个小时。好容易熬到一个没有事的晚上,我当然不会放过这一天赐良机,把剩余的部分一气清光。
《DOOM启世录》是计算机图书中一本难得的精彩译作,如果它还算是一本计算机图书的话。阅读的过程中,我几乎没有感受到语言的障碍,加之原作本身的精彩魅力,这是一次舒服的旅程。我给这本书的评价是“不愿意放手的书”。
这本书本身应该算是一部传记,记载了id software的天才们如何给世界带来一次又一次的震惊。书中的主角自然是天才中的天才:John Carmack和John Romero,两个John,一个是天才的程序员,一个是天才的设计师。正是二者的珠联璧合,这个世界才拥有了DOOM和Quake这样震惊一时的伟大游戏。
就个人感受而言,我更喜欢这本书的前半部分。那是id software的一部奋斗史。一群除了理想一无所有的年轻人,为了一个共同的目标走到了一起,打造“最好的游戏”。在那些不分昼夜的日子里,这些人带着激情追逐着自己的理想。
他们成功了!至于后半部分,只是为“共患难却不能同富贵”增加一个注脚而已。
就我从书中得到的感觉,我更喜欢John Carmack。
没人否认Carmack的天才,但有多少人了解他的付出呢?“要想人前显贵,必须背后受罪”,这句话又一次得到了证明,这里也不例外。Carmack总是付出最多的,正是他对技术不断追求,使得id software总是走在世界的前面。年少时对于黑客文化的了解,使得Carmack身体力行着黑客的精神。开放自己部分源代码,开放自己的计划,这在商业软件的世界里几乎是不可能的,但Carmack做到了。
但无可否认,Carmack也阻碍了id software的发展。虽然他的理想并不是像Romero那样创建的一个游戏帝国,虽然Romero的好大喜功使自己迷失了方向。正是Romero的离开,id software开始走了下坡路,尽管他们还有Carmack天才的技术。Carmack和Romero有如阴阳一般的互补:Carmack的技术只有在Romero的天才下才能得到最大限度的发挥,而Romero的设计也只有在Carmack的天才下才能得以实现。
如果你和我一样,平淡如水的生活需要一丝刺激,或许这本《DOOM启世录》是个不错的选择。
-
2004-04-20
内外兼修
之前的几篇blog,我谈到过文字的表现力、谈到过软件的可用性、谈到过程序员应该得自我表现。
仅仅宣扬“皮”的重要性,很容易造成不必要的误导,让人忘记“瓤”才是一切的根本。几年前,当我沉醉于Windows的时候,最吸引我眼球的技术是如何制作一个比较酷的界面。
今天看到杂志上一个新的界面效果,赶紧操起键盘;明天见到新软件的特别效果,立即动脑琢磨如何实现。
结果是,我学到的界面制作技术完全没有用武之地,因为每当我准备写一个程序发挥一下自己所学的时候,我发现自己竟然不知道如何下手。于是,那些界面技术成了过眼云烟,在我的大脑中渐渐散去。我的工作是编写服务器端的程序。
在这种开发中,我不必关心用户体验如何,因为我们的程序根本就没有界面。所谓的接口,只是通信协议。这种接口没有什么可用性而言,因为那完全是别人制定的规范,我们只能无条件的服从。
从那时起,我的精力转向了软件的“瓤”:如何写出漂亮的代码、如何设计更好的结构……工作的这段时间,我自觉水平得到了很大的提高。除了在项目中有了比以前更多的实践机会之外,将精力放在软件的“瓤”上,也使得自己对于软件开发的认识也发生了根本的变化。
如果现在让我去开发一个需要与用户打交道的程序,除了可能存在的技术点之外,我会先为搭建一个合理的结构,考虑功能如何实现,而不是我设计一个什么样的界面更能让用户感到舒服。前几天和Darwin聊天。他提到一个观点,从某种角度上来说,写文章与开发软件并没有什么不同,文字是用户界面,内容是界面背后的算法与机制。即使界面再友好,如果背后的算法一堆错误,或者不实用,或者根本有没有真正有用的功能,那么这个软件就是没有用的。
我赞同这个观点。追求表面功夫没有错,但缺少了内涵也就失去了方向。
除了我大学时所犯的错误,南北朝代时期盛行骈体文也是极好的例证。虽然不乏骈体佳作,但太多的辞藻华丽却内容空虚的骈体文,极大的影响了骈体文在后世人心目中的形象。如果把前后的几篇blog合到一起,我似乎把正反两个方面都给说了,真是“人嘴两张皮,咋说咋有理”。没错,我不否认“皮”的重要,也没有贬低“瓤”的意愿。儒家的中庸之道同样适合如我一般的程序员,所以,这篇blog的题目叫“内外兼修”。







