梦断代码--一个程序员的自白 (三)

本文谢绝转载

梦断代码--一个程序员的自白 (三)


    "程序员是工程师吗"?这是我在大约10年前初次接触敏捷方法时,让我有醍醐灌顶之感的一个问题。那个时候,称呼程序员为码农,IT民工,吃青春饭的,周围充斥着三十岁后能不能做技术的质疑。这个问题让我真正想明白自己从事的是怎样的一个职业。已经忘了最初在哪里看到这篇文章的,很幸运,我今天在Robert Martin的那本《敏捷软件开发》的附录D《源代码就是设计》中又找到了。它回答回答了两个问题,一,程序员是工程师,二,源代码就是设计。工程师的本质在于产生文档,代码就是程序员的文档。工程师只需要产生一次文档,然后其他人在此文档上反复工作,比如技术员、生产线上的工人。甚至,程序员的某些工作应该被看作是科研工作,因为“分类是科研的最初级形式”。我想,这一点未来在开源社区会变得更为明显的,一个优秀程序员做出来的突破性的工作,会被全社会共享。我曾经和一位朋友说,如果说工业革命依靠的是工人,那信息革命依靠的则是程序员。程序员不该看轻自己。


    我是以工程师的心态看待自己的工作的,也是以文档的心态看待自己的代码的。说到文档,我必须对那些不愿付出努力,就想理解系统的人表示鄙视。那种微软让扫地大妈来测试可用性的故事就是个骗局,太多程序员不还是用不好Word?那些认为自己可以让一个“untrained eye”也能轻易理解自己工作的人,不是狂人,妄人,就是所作的事情不值一提。和其他行业一样,程序员的文档只对专业人士负责。所谓简单设计,简洁代码,也只能是对合格程序员说的,而不是让一个未入门的菜鸟觉得简单。菜鸟的唯一出路就是变成专业人士。我对自己写的代码的态度也是如此,只有代码表达不出来的东西,比如系统的高层设计,如问题分析,动机,原理这些无法在代码中体现的东西才需要文档。最多再有个别技术难点需要点解释文档。此外的部分,所有文档都在代码内,用用doxygen这一类工具抽取出来方便阅读就够了。要求给vec.erase(unique(vec.begin(),vec.end()), vec.end())这样的C++语句写注释的人,一概鄙视之。


    当时的ADP也是很多琐碎的工作。QA的团队刚刚设立起来,如何做测试其实并没有什么经验。虽然我不认同测试、开发分离的组织模式,但这不是我能改变的。我对软件质量的态度也许偏执,但我坚持认为:逻辑,绝不会因为你写一个要求不高的程序就心慈手软,网开一面。在我看来,软件缺陷就是你的债务,而高质量、高可靠就是软件的不动产。当软件投向市场的那一刻起,你就必然,也必须不停地偿还债务和兑现资产。那种认为要求软件高质量就意味着的更多资源,更多投入的观点根本就是错误的。那种拿航空器、生命支持系统软件来说明高质量软件代价高昂的人,根本就是在说外行人的胡话。高质量软件开发过程非但不会增加投入,反而提高开发效率。只有高质量的代码,你才能,才敢于写完后忘记。只有忘记实现的细节,程序员才能将自己的智力解放出来,真正投入到分析问题,设计问题解决方案上去。那些总是纠缠与Debug,修Bug,各种Special Case的程序员,我无法想象怎么才能有精力去分析问题?怎么才能有勇气说,写下的所有不完善的代码,全都可以随时丢掉重新来过?在公司,我往往是作为一名C++专家,或者是能解决棘手问题的人被大家知道。其实这对我来说,不是什么褒奖而是诋毁。因为这无异于说我是“Language Lawyer”,而语言律师向来是我最为鄙视的。同样,对于Debug也是我深恶痛绝的,甚至我刻意地不去学习debug的技巧,事实上我也没有这样的技巧。我充分理解当年Linus为什么反对kgdb,而我也持有类似的观点。  。Debug必须被视为可耻的,是坠入地狱前最后的救赎,但却是不可靠的。所以,那些请我帮忙调试程序的同学们,每次你们都该请我吃饭以抚慰受伤的心 :P。


    言归正传。

    当时公司迅速扩张,我的另一件事情是面试,每周都有好几个。直到那一年年末,我大概面了近百人,虽然不是面试最多的人,但也名列前茅了。很多人不喜欢干这事,但是对我来说非但可以放松一下,还可以从来面试的人那里学习到许多有意思的东西。我是抱着找比自己优秀的人的心态去面试的,也是代表公司的,所以反复提醒自己,必须给予面试者足够的尊重。我后来听说有来面试的人因为对面试官很恼火,回去后在网上骂人的。然而,我面过的人当中居然有两三个发邮件来感谢我,有一个还是通过别的部门同事辗转联系到我的。这让我觉得非常意外,但是也很开心的事。我好像当时还做着给刚毕业的同事做些培训,可惜老板的要求太急功近利了,实际没什么效果。


    在我的极力主张下,把单元测试搞起来了,用的是boost.test作为测试框架。QA最初也使用boost.test。但是很不幸,首先是美国同事在UT中输出性能测试数据,后来又更过分地输出许多的log信息,这让我极为崩溃。即使多年以后,我仍不免要说:他妈的!中国的同事年轻,没有经验,算是情有可原的话,那么美国资深的,经验丰富的同事们呢?居然也连UT都不知道怎么做!难道还要我来给他们讲如何写UT?更何况这事儿是他们开的头!我给中国的同事解释为什么不能这么写UT,他们还是能虚心接受的,可是美国同事根本不理这茬。相反,后来代码出了Bug,或是Build break了,美国同事指责我们说为啥不写UT,或者是为啥不检查UT的结果。我勒个去!不客气地说,绝大多数开发和QA,对什么是软件测试,有那些类型,分别是干什么的和怎么干完全是一脑袋浆糊(包括但不限于ADP)。这是我第一次觉得自己给自己上了个套。除此外,还有另一个更让我抓狂和沮丧的事情就是引入DBC(design by contract)。


    在没有正确实践过DBC之前,我不确定程序员是否能理解DBC的美妙。当我在过去的项目中同时运用DBC和异常安全时,我得到了如同编程初学者所写的那种简单直白的代码。所不同的是,我不露痕迹地完成了错误处理。整个代码几乎完全由Happy Path构成,逻辑主干突出,分支语句比例大幅度下降(if语句比例可下降2/3。一个极端的例子是1400多行代码缩减到不足200行)。那些代码看上去简单质朴,但实际上都是深思熟虑的。反璞归真,我认为我的代码是有能力达到这个境界的。对许多程序员,甚至是资深程序员来说,如何设计软件是两眼一抹黑的。“设计之道,不在增无可增,而在减无可减”,不理解这话的人都还在纠结加什么功能特性上,要处理那些错误和特例呢。然而DBC虽好,还必须让运用的程序员能立刻从中收益,才能被愉快地接受。


    我为ADP写了一个contract的库,提供了PRE_CONDITION,POST_CONDITION,和INVARIANT三个宏,而且说明,只有一个PRE_CONDITION是必须的,提供三个只是为了概念的完整。可以等同于assert来使用,搞不懂的时候,就只用PRE_CONDITION,用错了也出不了大事儿。唯一要牢记的是PRE_CONDITION(expr)中的expr不能有副作用,这对于理解assert的人来说,应该完全没有记忆负担。本来,我还打算继续在此基础上,讲述如何设计API,如何划分API职责,要注意些什么。最好,能推行异常安全代码。我把Contract库,一些资料的链接,以及解释写了封长邮件给美国的架构师G同事。他先是回了封邮件说很好,说质量很重要。但是,过了个周末,他又回了一封信,这是让我彻底抓狂的信。


    在我看来,一个技术,如果带给程序员很大的心智负担,那也不能算好。按照Brooks,并且我也认同的观点,软件开发自身的困难未来都是可以解决的,而要解决的问题域所含的困难是本质性的,永恒的。一切软件技术的进步都要以解放程序员的智力、精力,使之可以更多、更好地投入到分析问题中去。这就是为什么我只推荐一个PRE_CONDITION的原因,也是我不喜欢繁琐而严格的命名规范的原因。G同事的回信中,他把contract库重写了,然后提供了大约几十个宏。这些宏和assert完全不同。有类似_ADP_CONTRACT_PRECONDITION_RETURN_VOID,  ADP_CONTRACT_SIDE_EFFECT, _ADP_CONTRACT_POSTCONDITION_EX_MSG_ENFORCE这样的名字超长,不知所云的东西。特别是XXX_SIDE_EFFECT,XXX_RETURN这种的,摆明了是逻辑混乱的产物啊,怎么能这么干呢?SIDE_EFFECT,哼哼,成功了给个副作用吗,还是失败了给个副作用?然后信里面还给了两个DBC的链接,一个是Wiki的,还给我解释了一下什么才是DBC。我实在无语的很。那时,我已经接触和使用DBC好几年了,相关的文章也读了不少,他一个周末就可以在这方面指导我,然后弄出这么个奇葩的东西而不自知。这种自信是怎么来的呢?不管怎么说,G同事的回信就是决定。他写的那些宏,直到ADP结束我也没记住。我唯一死心的是,我不需要说怎么写异常安全代码了,甚至都不需要去提。事实上,ADP早期还用着异常规范呢,这可是2007年了。我后来还是忍不住,从《Exceptional C++》里面扣出几条,说明别用那悲催玩意儿了,这才把异常规范去掉。TMD,又做了一次语言律师!



--回头看一下这篇文章,成了炫耀贴了。炫就炫吧,对上这些人,我还真有炫耀的资本呢。

你可能感兴趣的:(C/C++)