-
2004-04-18
原始武器
你是程序员吗?你会用debugger吗?
我似乎已经看到了你轻蔑的笑容,程序员哪有不会玩debugger的。原本我也这样认为,但如果一切遂人愿,那早就天下太平了,我也就没了这次的话题。刚开始自己程序人生的时候,我手上的工具是那个为Borland开创了一个时代Turbo Pascal。除了语言本身,我最先学会就是TP自带的就是debugger,每当程序无法按照我预想的方式运行,大脑最先出现的总是debugger的经典词汇:设断点、单步调试、观察变量值……于是,debugger成了我屡试不爽的看家本领,从TP、TC、VC到现在的Java。
和一个同事协助开发一个模块。
有一次,单元测试出了问题,他束手无策,把我叫了过去。
“快看看这是怎么回事,为什么就是过不去?”
“你单步调试过吗?”
“单步调试?”,他像发现了外星人一样看着我。“什么叫单步调试?怎么单步调试?”
这回轮到我像发现了外星人一样地看着他了。
迟疑了片刻,我假装没事人一样把如何运用debugger给他演示了一遍。
“哦,原来可以这样啊!”这位同事有种哥伦布发现了新大陆的感觉。
“你没用过debugger吗?你以前开发C程序不用吗?”
“没有,我以前写C程序都是在里面加打印语句。”如果这是一次偶然的意外,我的大脑很快就会把它遗忘。可就在我大脑还没来得及完成这个需要时间的工作时,又一个同事找到了我。
“帮我看看这里为什么总是空指针?“
瞪了半天眼睛,未果。
于是,我选择了debugger。
很快一个未赋值的引用被我抓了出来,就当我准备炫耀一番的时候,这位同事发话了。
”原来可以这么调啊!我以前从来没用过。“
我无语……我的这两位同事都不算上新手了,最短的写代码也超过了半年。而他们竟然对debugger——这件程序员的原始武器没有丝毫的概念。很难想象他们是如何编写调试代码的,且不说代码的质量如何,单单想象他们的调试手法,我都会替他们觉得累。
或许看过Robert Martin的《Debuggers are a wasteful Timesink》之后,你会站出来为我这两位同事说说好话:Uncle Bob都说debugger浪费时间了。没错,这篇文章多多少少也颠覆了debugger在我心目中的高大形象。但不要忘了,Uncle Bob认为debugger浪费时间需要建立良好的单元测试基础之上。况且,他也并没有把debugger一棒子打倒在地,一旦发现实在无法解决的问题,我们依然要祭起这件原始武器。
-
2004-04-15
二三有别
Martin Flower在他的那篇《Inversion of Control Containers and the Dependency Injection pattern》中,提到了三种Injection的形式,它们分别是Interface Injection、Setter Injection和Constructor Injection,对应着IoC中谈到的type 1、type 2、type 3。除了Interface Injection由于较强的侵略性让我有些反感,其它的两种形式,我并没有看出什么不同。Spring和Pico都实现了这两种形式的Injection,只是Spring推崇Setter Injection,而Pico倾向于Constructor Injection。
一个有趣的小问题向我展示了二者之间一些差别。
问题是这样的,两个组件,如果A需要B,B也需要A。那么Setter Injection和Constructor Injection是否都能很好的解决问题呢?
如果你明白了我要说什么,就不必再浪费时间了。如果没有,继续往下看。先来看看Setter Injection的代码。
public class A {
private B b;public void setB(B b) {
this.b = b;
}
}public class B {
private A a;public void setA(A a) {
this.a = a;
}
}接下来是配置文件。
<bean id="a" class="A">
<property name="b">
<ref bean="b"/>
</property>
</bean><bean id="b" class="B">
<property name="a">
<ref bean="a"/>
</property>
</bean>如果用Constructor Injection来完成,代码就变成了这样。
public class A {
private B b;public A(B b) {
this.b = b;
}
}public class B {
private A a;public B(A a) {
this.a = a;
}
}配置文件也随之发生了变化。
<bean id="a" class="A">
<constructor-arg>
<ref bean="b"/>
</constructor-arg>
</bean><bean id="b" class="B">
<constructor-arg>
<ref bean="a"/>
</constructor-arg>
</bean>显然,我们无法从字面上看出问题来,事实上,即便编译器也无法发现问题所在。那就让我们把代码运行起来。我们的测试代码也不用很复杂,读文件之后,取个bean就可以了。
InputStream is = new FileInputStream("config.xml");
BeanFactory factory = new XmlBeanFactory(is);
factory.getBean("a");看到什么了?
Setter一切正常,而Constructor疯狂的滚屏,直至堆栈溢出。解释这个现象很容易。想想如果我们是Spring的作者,我们如何来完成这两个组件间的组合。
如果是Setter,遇到A,我们用缺省的构造函数将它构造出来,发现它需要B作为它的一个属性,因为B不存在,我们构造B。B的构造过程用的也是缺省的构造函数。发现B需要A作为它的一个属性,因为A已经存在了,就把A加进来。B完成了,回头用它把它加入到A中。
而Constructor则有所不同。遇到A,我们构造A,但A的构造参数需要B,因为B不存在,我们构造B,结果B又需要A,我们只好再构造A,而A需要B,如此反复,直至堆栈溢出。由此可见,如果需要两个组件互相知晓,通过上面的这种Constructor Injection方式显然行不通。当然,我们可以找到其它的变通手法。
或许你会问,为什么这两个组件要互相知晓?这是一个很正常的需求,比如在MVC框架中,用户在View上的操作显然要View知道Controller在哪里才能传递过去,而Controller也需要知道View在哪才能将一些处理结果让View反映给用户。
总结一下。当两个组件需要相互知晓时,Setter Injection表现得明显要比Constructor Injection好,属于心理素质好,能够正常发挥的那种,这种精神值得中国足球队的小伙子们好好学习一下。
-
2004-04-14
先作用户,后作程序员
作为程序员的我们是否常常忽略自己计算机用户的身份呢?否则,怎么会有那么多蹩脚的软件横冲直撞呢?
白天,尝试隐藏一篇blog,把管理界面翻了个遍,未果。
晚上,看到RssView,一个开源的Java RSS Reader。down下来,试了一下,差点吐了。想起来前几天体验SUN的Java Studio Creator的经历。
Java Studio Creator,这个代号Wave的IDE,号称可以简化Java程序员开发。鉴于SUN ONE Studio给我留下印象实在不好,加上《Borland传奇》中Java Workshop的故事,我实在不敢对这个产品抱有太高的期望值。结果,它果然不负众望,一如SUN之前的几个IDE一样,令人失望。
比起SUN ONE Studio来说,界面效果稍微强了一点,有点Delphi的味道,但无论与Eclipse还是JBuilder相比,都相去甚远,更不用说我心目中最舒服的Java开发环境IntelliJ IDEA了。创建项目时只有一个Web应用可选,我想写个Hello World都不成吗?更可恨的是,安装的时候缺省地把Sun的AppServer给装上了,之前因为安装SUN ONE Studio,我的机器上就已经装了一套SUN ONE AppServer。
很难相信这是一套要与Visual Studio的IDE,如果不好好改进一番,它能在Java的IDE市场出头就已经很不容易了。当然,它肯定会有一部分市场,毕竟SUN还是会通过各种渠道把它送到一些开发者面前的。回到最初的话题上。
在越来越强调架构、模式的今天,我们是否考虑还过我们的用户呢?
曾经和gigix谈论G-Roller,gigix认为对于我们最难办的就是View一层,因为程序员的强项不在于此,但我们不该因为不擅长而忽略它。
为什么现在Linux在桌面环境上还无法于Windows抗衡?简单易用美观是Windows的取胜法宝。普通用户才不会理会哪个操作系统内部结构更合理,性能更强大。这和我们开发软件有着异曲同工之妙,比之于内部结构,老板更在乎的是功能完成得如何。
这就叫“眼不见,心不烦”!编写一个面向普通用户的应用要承担比其它应用更严格的考验。作为一个程序员,在精心设计一个优美的技术架构的时候,能否给自己点时间站在用户的角度考虑一下。往往这种程序员的第一个用户就是自己,折磨自己也就罢了,把别人也捎带上,这不太合适吧!
有一种说法,“长得难看不是你的错,出来吓人就不对了”。提出这个问题,我更多的是站在用户的立场上,因为我写的多半是根本无需与普通用户打交道的服务器程序。如果你和我一样,至少我们没有危害劳苦大众的机会。
-
2004-04-12
会调程序的福尔摩斯
知道福尔摩斯吧!即便无缘拜读柯南·道尔的大作,如果你敢说自己没听说过福尔摩斯,周围人一定会把鄙夷的目光赏赐给你。
那你知道福尔摩斯是个程序高手吗?
在看了新一期《程序员》杂志的王咏刚先生所写的《打印机疑案》之前,我也不知道。
在这篇文章重,福尔摩斯先生重回人间,这次他又掌握程序技术,以高超的调试技巧,帮人侦破了打印机疑案。
这是我头一次看到以侦探小说的形式写出来的技术文章。早就听说,国外有高手曾经有如此惊人之举,如今看到国人的一篇另类技术文章,着实让我欣喜了好长时间。
对我来说,单凭这一篇文章,就已经值回整本《程序员》的价值了。在《技术的文字》中,我曾提到,许多程序员们受了太多的文字折磨。以致于面对优美的文字,脑子里首先闪现的是“废话太多”。如果把王先生的这篇文章,放到他们面前,恐怕得到的评价不会好到哪去。
以个人喜好来说,我非常喜欢这种“废话太多”的文章。
注意王先生的文字有一段时间了。王先生的文字一向是幽默而富有内涵,阅读的过程很是享受,常常在会心一笑之际,体会到一些软件开发的基本道理。
最初认识王先生是他所著的那本《凌波微步——软件开发警戒案例集》。一本关于计算机技术的书,敢命名为“凌波微步”,本身就是一种不凡。
让我下定购买决心的是他的那篇自序《青年程序员的肖像》,我喜欢他那种不缊不火的幽默。《凌波微步》对我来说,短了些,意犹未尽。
2003年7月开始在《程序员》上连载的“凌波微步II”算是对这种遗憾的一种弥补。现在“凌波微步II”已经成了我每期《程序员》的必读,虽然碍于自己眼界,无法完全理解每一篇的精髓。在我看来,王先生的文字无疑于传统计算机技术写作的一种挑战。为什么我们还要忍受那些令人作呕的文字呢?
-
2004-04-10
酒香也怕巷子深
今天,和几个同学见了面。
工作快两年了,哥几个对自己所处的环境、获得的回报多多少少都流露出了一丝不满,有几位甚至已经开始计划自己改换门庭的时间表了。联想到近一段时间,公司里经常传出与我一同入司的某某离职的消息,似乎我们这一批人已经进入了一个换工作的高峰期。如果我说自己完全没有考虑过这个问题,包括我在内,谁都不会相信。寻找一份理想的工作也并非那么简单,高薪的工作需要至少在应聘时展现出与之相称的表现。
工作的朋友想必都知道应聘的艰辛。从简历上看,每个人几乎都是无所不能的超人,稍微谦虚一点都可能被当作弱智处理了。都说自己行,如何让别人相信自己才是货真价实?除了肚子里要真有货,懂得如何恰如其分的表现也是必不可少的。
于是,在这个“是骡子是马拉出来遛遛”的年代,学会自我展示,也成了我们这种小程序员的必修课程。梦想风暴就是一个例子。
梦想风暴的访问量达到第一个1000用了将近4个月时间,达到第二个用了不到3天。在《早到的祝福——新年快乐!》中,我曾经开玩笑的谈到“等梦想风暴再壮大一些,我就得宣传一下了”。天生的懒惰使我的想法仅仅停留在思想中。慢慢地,自己都忘却了这个曾经的抱负。
《我眼中的Spring》本来只是我自己为了准备部门内部交流而做的一些总结,贴出来之后,受到许多朋友的鼓励。为了与更多的人分享自己的心得,我先后将这篇blog贴到了Spring中文论坛和灰狐的论坛上。无意的宣传换来了更多的关注。
梦想风暴的变化,给了我继续努力的动力,也教会了我“广告”的力量。
不知道有多少人对电视上那个几乎每天扰民的送礼广告深恶痛绝,但有一点可以肯定,它的品牌已经深入民心,虽然可能不那么正面。我所结识的程序员大多对自己的技术都有充分的自信,但善于表现的确实不多。部门里,经常给大家讲东西的,也就是表现自己的,算来算去总是那么几个。大多数人都选择了沉默,如果说一点东西不懂,着实冤枉这些有着N年开发经验,甚至可以称之为资深的程序员们。除了我在《平凡也伟大》中讨论过的不屑于平凡之外,不善于表现也应该算是一条原因。我的另一个水平并不很高的同事,因其人来疯的表现,已经在公司内外声名鹊起,并且拿到了同来者中较高的工资。
最后再来说说梦想风暴。
它的出现始于我对blog的好奇,现在的结果早已超出了我最初的预计。
blog的威力已经由木子美和竹影青瞳发挥到了极致,限于本人的眼界、关心的范围和写下的文字,我不奢望梦想风暴能有那么恐怖的成就。
能通过梦想风暴结识几个朋友,对我来说,已经是很大的满足了。
如果梦想风暴中任何一篇让你的大脑细胞不再安分,那就信手评论一番,再不过瘾,就直接给我发信给我,我随时恭候!







