Year: 2013
做个懂产品的程序员
大概六年前,我在一家名为“抓虾”的在线RSS阅读网站工作(如果你不清楚RSS阅读网站是什么,可以参考Google Reader)。阅读器都需要显示当前用户的未读数,抓虾的做法是给出精确的数字,明确告诉用户“你还有2456篇文章没读过”,Google Reader则显示为10+、100+等形式,告诉用户“我还有十多篇/一千多篇文章没读过”。初看看来,这只是一种普通的差异,但产品人员提出10+、100+的形式更好,原因我如今记不太清楚了,似乎是说这样给用户的心理压力更小,因为如果数字比较大,用户就不需要知道具体的数值,所以阅读体验更好。虽然程序员都并不认同这种理论,但因为分工不同,最终做开发的大伙还是完成了这个功能。“可想而知”的是,这个功能上线之后并没有带来明显的正面反馈。更好玩的是,过了一周,Google Reader的未读数竟然改成了准确数字!
前几周,我在twitter上说起这个故事,本来只是凑兴当个玩笑,收到的反应却出乎我的意料,因为反馈大都是对产品经理一边倒的负面评价。我又想到自己的一个朋友,他在某家以产品经理文化著名的大公司做开发,谈到理想的工作,他的要求是“找个产品经理少的地方就好了”。这样看来,程序员和产品经理的矛盾是普遍而且深刻的。
漫漫降级路
前些年互联网上有篇叫《降级论》,建议广大IT从业者不要削减了脑袋挤移动互联网等等热门方向,换种思路,在“不起眼”的传统行业中寻找IT技术应用的广阔天地。这篇文章一登出来吸引了大量关注,按照作者的说法,降级论俨然是条通往幸福的康庄大道:
“这些原始而纯粹的行业,正在等待IT精英们的降级,如同蒲公英一般的伞兵,在黑夜里从天而降,长驱直入,用最智慧的产品、最优质的服务拯救这些早就该死的行业,屌丝的生命将会绽放出银色的羽翼,无比丰满,无比性感”
不幸的是,我见到的现象却非常奇怪:许多尚未投身的读者谈起“降级论”却满怀憧憬,真正敢于“降级下凡”并成功的却寥寥无几。仔细想想,无论从逻辑上分析,还是从自身经验来看,“降级”之路都不算坦途。根据我的归纳总结,IT从业者(“精英”这个说法略带刺激性,我觉得“从业者”更合适)走上降级之路,有几大困难是必然要经历的。
强关系,弱关系
人和人之间各种错综复杂的关系,归结起来,可以粗略分为两类:强关系,弱关系。典型的强关系有终日厮混的死党,还有无话不说的密友;而典型的弱关系,有远房亲戚,“知名但未谋面”的朋友等等。这么举例,大家都比较容易理解。在现实生活中,可能很难清楚地界定强关系和弱关系的标准。但如果把关系搬到虚拟世界里,或者说在(互联网上的)“社交网络”中,因为方便量化,两者的分别就要明确许多。用我的话说,能留出专属时间且保持比较密切频度联系的关系,都可归类为强关系。除此之外,又不同于“纯粹的陌生人”的关系,都属于弱关系。按照这种分类,QQ好友、MSN联系人,就属于强关系,而论坛版友、微博关注对象等,属于弱关系。我相信,这也符合大部分人的实际情况。
如果我们仔细观察就会发现,上面说的强弱关系是就关系本身而言,但最终体现出来是落实在具体工具上的。一般人与QQ好友、MSN联系人之间的联系,天然就比论坛版友、微博关注对象要密切很多;而且,无论用QQ、MSN来保持相对松散的联系,还是用论坛、微博持续高密度地联系,都会显得很别扭。所以大家会用合适的工具来保持合适的关系。经常看到的例子有,如果在论坛上聊得比较投缘,就加QQ或者MSN好友。再比如,“陌生人交友”应用中的好友往往很少加QQ好友,因为大家不愿意成为相对私密信任的强关系。
闲话命名
前几天在Twitter上有朋友问:ln的参数顺序要怎么记忆比较好,因为总是搞错。这个问题我也遇到过,以前每次都记不住两个参数的先后顺序,最终办法是花了点时间背诵命令模板,每次用到时心里默念就好了:
ln option target linkname
我没想到的是,搞混顺序竟然是个普遍问题,我本来以为哪怕有疑问,背背模板也好了,大家都应该是如此。仔细了解才发现,有疑问的朋友确实背下了OS X中的man,但这份文档写的是:
ln source_file target_file
看起来区别不大,用起来差别不小。因为做链接时,target既可以指“被链接的对象”,又可以指“生成的链接名”,和source_file之后就更容易混淆了。参与讨论的几位推友都认为我背的模板更好用(其实是我的运气更好,背诵时遇到了写得清楚的文档),因为另一个参数名是linkname,意义非常明确,所以哪怕target的意义和OS X中的完全不同,也不影响理解和使用。
迷失自我的API
说起API,做开发的人大概都知道也用过,我也是如此。不过除去使用,我还亲眼目睹过API制定,参与搭建过开放API平台,也与合作方商量确定过API方案;算是各个方面都有了解和经历,感受过让人啧啧称奇的赞赏,也经历过举步维艰的尴尬。目睹还有很多同行在API的泥泞里挣扎,我把自己的经验写在这里与大家分享。
大家都知道,API是Application Program Interface,也就是应用程序接口,看起来非常容易理解,实际却并非如此。据我观察,不少API方案之所以陷入了泥潭,就是程序员对API理解错误,把它看成了“对外开放的函数”:某个动作可能之前需要用户鼠标点击触发,现在开个口子给程序用消息触发,这就是API了;推广开来,现在流行的API化、开放平台的潮流,无非是多开一些这样的口子而已。
软件开发的人文关怀
几年前,我从温伯格的《技术领导之路》中学到一点:技术人员往往更喜欢和机器打交道,因为他们“认为”自己更适合和机器打交道;但是,优秀的技术人员必须(也必然)具备好的沟通能力。所以,温伯格鼓励各位技术人员多加练习和其他人打交道的能力。温伯格的这个观点我是非常赞成的,好的技术人员一定需要“勇敢”面对他人,不能被“自实现的预言”局限在机器的世界里。
不过我也发现,“技术人员(当然我主要说的是软件开发人员)不适合跟人打交道”的负面影响不止于此,它还成了一种刻板印象(stereotype),进而影响到开发团队之外的人。这个问题其实很严重,它会导致其他人和开发人员沟通时自觉或者不自觉地切换到“和机器沟通”的模式上来,比如单纯依赖邮件而避免见面沟通,比如“你只管这么做出来就好了,别管我用来干什么”。以面向机器的模式来与人沟通,结果往往是完整的项目(而不是狭义的“软件项目”)割裂开来,皆不欢喜。
不只偶然
对心理学有兴趣的朋友大都听说过《社会性动物》这本经典教材,我曾读过两遍并大力推荐,还买过几本送给朋友。照常理,经典教材应该是潜心写就的,可是最近读了《社会性动物》作者阿隆森的自传《绝非偶然》,才知道写作这本书的初衷,竟然是作者对当时的心理学教材不满意,在同事半开玩笑说“你自己去写一本嘛”的刺激下,抱着“我是科学家,可不是写书的”心态,随便写的几篇随笔。从随笔开端写出心理学经典教材,足见阿隆森是个很有趣味和学养的人,所以他的自传《绝非偶然》也是相当好看了。
阿隆森的家境并不富裕,加上他的犹太人身份,小时候遭遇了其他孩子的很多歧视,所以他经常思考,其他孩子为什么会欺负他,仅仅因为他是犹太人吗?这种欺负能不能改变?这种经历,正是促使他日后投入心理学怀抱的原因之一。另一方面,阿隆森的哥哥贾森对他影响很大,贾森身体强壮,有他在阿隆森就不会受欺负,而且贾森既有头脑又有知识,阿隆森高中毕业时,因为家里缺钱,几个舅舅希望他不要继续念书,去赚钱养家,只有贾森力主让阿隆森去念大学,从此改变了阿隆森的人生。
进入大学,阿隆森的感受几乎是全新的。这一点尤其体现在对麦卡锡的态度上:在家里,大多数人都相信并且支持麦卡锡,但是在大学,众多学生和老师却一边倒地反对麦卡锡。阿隆森认识到,原来对相同的事情可以有完全矛盾的看法,而且这竟然是一种常态,这或许是他进入大学的第一点重要收获。不过,他马上就会遇到更重要的收获。
从《图灵的秘密》想到的
托图灵诞生100年的福,去年出版了许多关于图灵的书籍。《图灵的秘密:他的生平、思想及论文解读》是其中的一本,前几周看完了,收获不小。说起来也惭愧,虽然自己学的是计算机专业,也知道图灵这个人,却不清楚他究竟做过什么,印象深一点的只有关于人工智能的“图灵检验”。看过《图灵的秘密》才弄清楚,图灵在计算机发展史上究竟作出了什么贡献,比如可计算性判定,比如通用图灵机,配合书中对他的论文的解读,又了解了他所处的时代和环境,以及他局限和所犯的错误。不过我最高兴的,还是通过阅读填补了自己知识结构中的若干鸿沟:原始的计算机都是专用于“计算”的,后来如何转变为能做任何事情的机器?大千世界的众多信息是怎样一步步进入计算机世界里,被表现和构建出来的?这些问题之前一直困扰着我,也找不到答案,看过这本书算是终于地摸到了答案,这本身就值得高兴;而且,填补断层有利于把所学的知识联接为统一的有机体,以后记忆和运用起来也更自如。
不过合上书本,也有遗憾:如果早能弄清楚这些问题该多好,在计算机科学中这些都应当是相当基本的常识,却需要花费这么多的周折,这么长的时间才弄明白。以前有位读中文的朋友说,老师在课堂上讲,《理想国》这样的书还有是什么好想的,直接买回来啃就对了。每每想起这句话,我都非常感慨:这位老师不一定有特别高水准,但至少在向学生推荐读本这一点上,他还算称职。相比之下,计算机专业在这方面实在差的太远了。一方面许多老师的知识水平不敢恭维,不过如果有好的教材供学生自学,这问题倒不算特别严重,偏偏在国内的计算机教育界既缺乏高水准的原创教材,也缺乏对国外经典教材的认知和推荐的气魄。情况真是再糟也没有了。
程序可以止步于接口,思维不能
“面向接口编程”是程序设计的规则之一,它可以将具体实现封装为具有一定逻辑意义的抽象行为。这样做的好处多多,比如有利于在较高层次上思考,而不必操心细节;比如避免外部代码因为具体实现变化而作修改。广大开发人员,不管自己设计程序时有没有注意“面向接口编程”,都会或多或少地从“面向接口编程”中获益——我上大学时曾听某师兄说:“编程还不容易,从网络上找一些类库来调用就好了”。接口隐藏了背后的实现,可是,许多开发人员不但写程序止步于接口,思维同样止步于接口。接口背后是什么,他们写的程序不关心,他们自己也不关心,而且振振有词“我这是面向接口编程”。但是,这真的是好事吗?
我刚工作时,所做的项目里有几个问题是自己搞不定的,甚至整个项目组也没有人能搞定。好在项目经理很有办法,找了他之前的同事兼职帮忙,写出最难的模块,我们只管调用现成接口就可以了。当时大家都松了一口气,至少不会因为自己水平不够,耽误项目进展了,内心也非常感激这位兼职的高人。可是,随着项目的进展,我们搞不定的问题越来越多,于是越来越依赖兼职的帮忙,整个项目也因此越来越被动。我仔细观察,发现这类搞不定的问题虽然反复出现,归结起来只集中在某几个领域,而每次这位兼职高人给过来的程序,尺寸变化并不大。所以我认定,这些问题并没有太多难度,只要解决其中一个,应该就可以举一反三,顺势全部解决。于是我花了一周的业余时间,逐行细抠接口之后的代码,终于尝试独立解决了一个这类问题,给项目经理看过,他非常高兴,从此甚至对我有些另眼相待。当时我想,他这么高兴,是因为我为公司省了钱,再也不必烦劳以前的同事兼职了罢。