作者:Phil Chu
作为软件工程师,你希望从工作中获得的是:稳定的薪水、参与好项目的机会、好工作的跳板或只是和其他程序师成为好基友。这里的“高效”,我指的是按时完符合要求的项目的能力。经历过不少软件编写工作后,我相信以下实践会帮助你学会“高效”,同时提高专业声望、拉长职业寿命,和获得个人满足。
1.理解你的需求
成为高效程序员的第一步是,保证时间的合理分配。没有什么比将时间花在完全没有前途的工作上更浪费的了。
尽快开工
尽快完成一个直观的系统。这意味着先创建界面,无论是程序界面还是用户界面,然后生成内部功能的存根代码(如果有必要的话)。这么做便于“客户”查看,通过执行用户界面或编写程序界面的代码,可以发现最初代码存在的矛盾或遗漏。甚至在第一次交付以前,你有可能会注意到问题或可改进的地方。
有一个经典观念认为,如果你提前设计好所有东西,那么之后你要做的就只剩写代码了。如果你之前做过完全相同的项目,那么这个说法当然正确。但如果不是,你很可能会陷入死角,也就是你只是在猜想或执行一个可疑的假设。
很早以前在一家无限网络的新公司工作时,我们开了两个月的会来设计一个将在6个月内发布的无线门户和网关。最终,我们厌烦了开会,开始编写代码。头两周内,我负责的部分与原始设计不符,两个月后的第一个无线连接测试表明,我完全误解了无线协议。
这不是说设计是没必要的。但在一定程度上,设计只是一种猜想。设计应该通实执行来确认,并且早执行总是比晚执行好。
即使原始设计是充分的,只要你发现可以调整的地方,你就要改进它。硬件产品、建筑和大型软件项目等会受到僵死的“预制”的损害,但对于软件,你可以在项目早期提炼项目要求,然后制作适合的界面。但是,这必须尽早完成。
尽早开工有利于树立你的职业形象。如果能向你的老板展示一些成果,他会很高兴的。另一方面,提早开工有助于缓解焦虑。
经常交付
一旦你完成一些可用的东西了,不要只是把它留作“概念实证”。要让其他人试执行它、看看他们的反应,然后让它指导开发过程的优先次序。观察人们如何使用你的软件,这是无可代替的方法。客户问卷调查和焦点研究可能会提供一些有用的意见,但有可能会让开发者的设计决定和特点被客户牵着鼻子走,这是一种冒险。
特别是要尽快将软件交付QA人员,经常提交成果,最好是按预定的时间间隔。让他们测试每天的成果,或至少是每周的成果也是好的。这会让QA人员觉得自己全程参与项目开发,从而培养职业责任感,更乐意发现和报告问题。最需要优先解决的是导致产品失效的问题,如崩溃或死循环——让问题尽可能涵盖多方面,熟悉整个产品,这样才有可能提早发现设计问题。
在一个小型3D软件公司,我负责移植从SGI出品的龙头产品到Windows NT。6个月后,移植没完成,倒有了崩溃的倾向,我很不情愿地将第一轮成果交付测试团队。幸运的是,因为漏洞太多,QA经理坚持要我立刻解决导致测试
人员无法有意义地使用程序的问题。如果是我自己测试,我应该会忙于看起来更困难更重要的核心3D问题,可能会怠慢看来起比较普通的问题,如用户界面、载入-保存功能和与计划支持的硬件之间的兼容性。
程序师常常不想过早将代码交付测试人员——他们不想听到自己已经知道的漏洞;而测试人员极有可能不想测试基本上行不通的东西。但测试人员的工作就是找到这些问题。如果程序师想尽快看到成果的话,应该把漏洞报告当成好东西。
2.把工作当真
将软件放在尽可能接近完工的状态下运行。你永远不知道你什么时候得演示系统、发送评估备份或甚至交付。
使用真实数据
如果你只用作为着冰山一角的样本数据作测试,那么,你的程序可能一撞上真实数据的大冰山就沉了。
我曾参与开发一种用于评估先进的半导体绝对值的供应链管理产品。跨过交付这道大坎后,我们接到消息说他们输入的第一批真实数据仍然在处理中——已经两天了。我同情主程序师,他不得不在管理人员和客户的催促之下忙活了两周。很高兴遇上这事的人不是我。
使用正式版本
记住,用你自己的机器创建的东西不是正式的。
在最近的一个游戏开发项目中,我负责用户界面,我陆续从QA那接到报告说有些颜色不对。最后,我发现问题只出现在交付版本中,另一位程序师使用专门的主机调试工具找到了漏洞。结果竟是一个我在两个月前犯下的愚蠢错误,没有指定初始颜色值。调试版本总是选择特定的默认值,但是交付版本会更改,最终结果是不太确定的。如果我注意经常地运行交付版本,我会立刻发现问题的,而不是损失大量的时间。
经常合并
及时将你的代码并入主代码库中——你拖得越久,这项工作就越累。
我曾与一名程序师共事,他觉得每天数据库中出现的所有新代码和数据变化都“很麻烦”。确实,这让所有其他程序师每天都要花一定时间合并,他才能够只扫视一下代码和数据就开始运行一些不错的独立样本。但每一次阶段性交付时,我们都要花好几天再次把单独的代码接到当前的代码库中,有时候甚至得拖延交付或冒着损失整个项目的风险。
将你的代码与正式版本分开意味着程序师不能评估你的代码,以及测试员不能尽早发现漏洞。可能你并不想其他人挑剔你的代码,但早发现问题总是比晚发现好的——所以,忍了罢。
3.理解你的代码
生活中充满了奇妙的神秘,但你的代码可不适合出现这些神秘。你不必知道你的车怎么工作的——如果引擎发出奇怪的声音,把它交给汽车技师就好了。但换成是你的代码,如果连你都不知道它是怎么运行的或出了什么错,那就没人知道了。
有自己的编写风格
我童年时的钢琴教师是这么评价我和我姐姐哥哥的:“你姐姐的时间感强,你哥哥的键盘打得不错。”然后他停顿了一下说:“你嘛,嗯,你很努力。”
编程是一种有些人能做有些人不能做的事,但还有一些人则是天才。虽然我有过多年的练习,钢琴还是弹不好;虽然我那么喜欢打球,水平仍然一般般。但我确实认为我有编程和写作的天赋。不要吃惊,我认为好程序就像好散文。散文和代码都是文本,有语法、句法、拼写和语义。对于大多数写代码的人和写作的人,有这些就够了,但好作家和好程序师还要有一种美感,他们的作品在结构和风格上是有特点的,往往能借此识别出作者。
许多Windows程序师都感到好奇:为什么坏脾气的老Unix/Mac/Amiga/Lisp程序师对Win32/MFC/.NET很不满,但如果所有应用界面都来自Microsoft,你可能就不知道还有什么东西是更好的。
复制粘贴
风格化编程的反面是复制粘贴。从什么地方复制一些可能有用的代码,稍作调整,合并,重复,然后就大功告成了。你的软件简直就是大杂烩。
离开一家公司的几个月后,一位前同事电邮问我,他复制粘贴了十页的代码组成一个算法,为什么运行不了。我实在不知道怎么回答了。如果你不能解释你自己的代码应该是怎么运行的,你还指望谁来拯救你?
我甚至在诊断自己从样本代码复制粘贴过来的代码时也犯过难。从复制粘贴开始新代码是合情理的,但你不能因为看起来能运行就放手不管了——你得返回去看看你是否读懂了每一条,根据自己的目的理清代码。
清理代码
保持你的房子/公寓/房间整洁的最好办法就是每天花一点时间清理它,或至少每周清理一次吧。如果等到住所乱到一定程度才打扫,那么这麻烦就非常大了。除非你雇个清洁工。
假设你没办法奢侈到雇一个人每天帮你清理代码的程度,那么你就应该定时地检查你的代码、清理累积的死代码、淘汰过时的注释和错误的名称,否则你必定会得到一份不敢拿出来见人的代码。如果你不觉得丢不起人,好吧,你行。
我指导过的一名程序员总是向我报告,她的代码“完成”了。这是管理者乐意听到的话,却让我非常抓狂。她的代码从来没有做完——你得调试它、维护它、改进它,直到它彻底没问题。
问题?注释?
有些人认为编程是一门手艺活,也有些人认为编程是一项工程。更经常的是,它是一门考古学。你挖掘代码的沉积物,想知道这些奇怪的人工产品是用来干什么的。为后来人着想一下,留点线索吧。
我问之前提到的那位程序员“完成”注释了没有。结果是,一个函数名称为“GetData”的注释居然是“Gets data”。这不只是废话——简直是侮辱。什么数据?什么格式?来自哪里?更不要提像服务器不可用或传送中断时会怎么样这种小细节了。
将你的代码做成文档,以防有人随时要拿来用。可能要用的人就是你本人——想想如果不这么做,你得重新访问代码多少次啊?
与之前的一个老板合作时,他叫我浏览一段没人有时间看的代码。一开始,我认为它很糟,不知道写的都是什么东西。之后我慢慢摸索出来这段代码是干什么的,所以我勉强同意它不算太糟。最后我终于认出这货竟是我两年以前写的。教训:多留点注释。
当你写代码时,记得注释,而不是等着出现什么方便的清理短语——注释你的代码,让它甚至可以清楚地反映你在编写时的想法。你可以成为自己的编写伙伴。
现在你可以用javadoc和doxygen等生成漂亮的HTML或来自源代码注释的其他格式化的文件。理想的情况是,你每天晚上做的就是doc生成的部分,可以通过你的内联网获得。
注意警告
无视编辑器和运行时间警告会害到你自己。有“警告”就有原因。
我曾做过一个基于Unix的应用,它不能成功地连接某些函数。我们通过在运行时再次连接这些函数解决问题。六个月后,当我们执行一个干净的新版本时,我们才发现原来我们关掉了能提醒我们未知连接漏洞的警告。在供应商的斥责下,我们将连接问题解决了。但结果是,原来我们只要通过重新排列库就能连接上了。
提高编辑器的警告水平,注释代码以及记录创建和运行时间的警告信息,最好包括解决警告的标准,这样你就会知道是否解决问题或忽略问题。
4.优化编程
带着目的写代码
复制粘贴代码的人的另一个极端是,只是为了让代码看起来更漂亮(至少对他们而言)而改变代码。虽然有编程审美感是值得赞扬的,但改变代码以便让你觉得漂亮只是浪费时间(无用的冒险)。浏览并改变别人写的代码,让它看起来更漂亮,真是让人生气。
我有一个挑剔的同事,浏览我们的代码库时将所有的附加语都删除了。如果他只是清理了入门级员工写的代码,那可能没人会说什么,但那些附加语是我们团队的技术领导写的,他可是我们公司最出色的人物之一。
不要搞破坏
“代码重构”现在十分流行,但程序员往往以为它是指代码清理或重新设计。这个技巧是指重新组织代码,同时不破坏其他东西。如果你以改进的名义破坏已经存在的功能,那么你的意思就是:要么你的时间比其他人的时间金贵,要么你不破坏就不会整代码。
我有一个特别讨人嫌的同事,他决定重新执行我们系统中的解析器,但结果让代码变成其他所有人都不知道怎么写了。我让他恢复原状,之后发现代码能编写了,却不能运行了—–问他怎么回事,他说“应你的要求”,他移除了整个解析器。真没团队精神。
保持代码运行需要一些耐心和额外的工作——你勤奋地回归测试你的工作,在将函数添加到新代码中时,你可能需要暂时留住老代码和界面。但对于所有与这个代码库有关的人来说,这是必须做的。
找到瓶颈
人们总是谈论“最佳”,但这不是一个正确的词。我们极少将最佳作为目标——相反的,我们的目标是改进和权衡以达到足够好的表现。
在谷歌的电话面试时,我被问到如何在一组有序的数字中搜索某个数字。显然,提问的人是在问二进制搜索法。但在现实生活中,我可能会做出“错误”的选择——从头找到尾。如果程序表现足够好了,还花两倍的时间写两倍的、必须维护和调试的代码,那是毫无意义的,特别是如果那段代码并非程序的瓶颈(我严重怀疑如果那个数据是瓶颈部分,你居然还会将它线性排列)。
如果你确实需要在程序的速度或空间方面达到最佳,折腾除了瓶颈以外的其他任何部分都只是浪费时间。
5.自我管理
你可能对你那位讨厌的老板有各种抱怨,你的抱怨可能没错。所以你得成为你自己的管理者。即使你的老板人不错,他也不会站在你背后告诉你该写什么、怎么写才会快(尽管我肯定许多老板恨不得这么做)。
估计时间
程序师不能提供有用的时间估计,这是出了名的。但我认为这是无理指责,因为管理层往往作出更差的预测,并且程序员的警告往往被无视(这可能是所有工程的共同灾难)。但是,合理的时间估计对于按时完成项目仍然是关键的。
在一个商业软件项目中,我的有些同事居然乐得忘了产品交付日期——有人问是否已经交付了,另一个人才很惊讶地发现,日子已经过去好几天了。
更糟的也更普遍的是,程序员能给出的时间估计是“只需要几天。”每次我听到这话,或者我自己说出这话,我都感到害臊。
一家图像软件公司的总裁想让产品支持VRML(那时它是下一件大任务),包括我们将在两个月内发行的产品也支持VRML。他可能想到(他是正确的)我会拒绝开始新项目,所以他问了另一个工程师,得到了他想到的回答:“只需要几天。”两天后,我告诉总裁,我们刚刚浪费了他和我的两天时间,因为有两百多个更重要的漏洞要修复,他认为我的理由算是充分。(后话:VRML没有太成功。)
另一位程序员完全没有时间估计的概念。但没有必要完全拒绝时间的模糊属性——毕竟只是估计,事实上你应该避免太确切。如果你是一名有经验的工程师,你就知道你以前做类似的工作需要多长时间,如果你不是,那你就问问有经验的人。
我有一个聪明的朋友,经常被指派去开发实验原型,他问我:“你怎么估计时间?”我认为这是一个反问句,但甚至纯研究人员也要估计时间。有人支付他们,希望得到结果,即使它是许多演示样本或某段时间发表的文章。
如果你确实估计不准需要多少时间,那么你就不是做这项任务的合适人选。
有时候程序师不情愿承诺时间是因为他们害怕保证。确实,这个世界没那么美好,经理会在时间上跟你讨价还价,竞争对手可能用严苛或不切实际的安排来挤兑你,希望你失败。在你承诺时间后,你就悲剧了,你别想得到任何你希望的结果。
我曾有个老板问完成时间后会追问一句:“你保证?”但问他硬件条件和其他相关事宜时,他会说:“我尽量。”
我能说的只有,抓紧时间以及给出现实估计。任何让步都应该根据实际的介于产品和资源之间的交易。要根据假设、相关事宜和资源做时间安排,找个地方写下来,这样以后你就不用麻烦你不太给力的记性了。
计划进度
在决定上哪去以前,你不会跳上车的,对吧?你在开车时心里可能就有路线了。相同地,在你开始用电脑写以前,你应该知道你今天想完成什么,有一些想法了。
每天都会遇到分心的事,所以你不可能总是完成你想完成的事。与那些将软件工程团队当作自动贩卖机的人的想法相反的是,有些任务不是一天就能完成的。所以想想你到周五要完成什么,如果你完成了,那么周末你就可以好好过了。
6.不断学习
一名社团足球队成员曾经问我,我们每天束紧防滑钉练习,你们“C语言编程的秘密是什么?”如果存在这样的秘密的话,我肯定会在晚间电视节目上宣传如何靠房地产发财。对不起,没有捷径——你必须学习、练习和犯错。你不一定得依靠团体训练或学校教育——有许多国立的和当地的专业团体、书籍,当然还有网络。
编程是科学
编程被称作“计算机科学”是有原因的。无需正规的计算机科学教育,任何人都可以轻易地开始编程(可能太容易了)。特别是,那些学过其他工程和理科的人,可以非常快地上手编程,然后以此谋生。但对于高效地处理重大任务,你必须知道软件的固有功能和限制、识别前提,这样你才不会白费力气地做重复的工作。你不必知道所有事,但你应该至少粗略地了解许多领域,必要时能做一些额外的研究。
例如,创建了新文件格式的人应该知道一些关于编辑器的事。我不是指所有代码生成的优化如循环展开,而是基本的问题和各种编辑的短语和大部分指定标记和语法的重要性。今天,大多数人会默认地使用XML,那是件好事,
但在那之前,一般是粗略地写一些文本格式,指向一些生成的样本文档作为文件,之后其他写了另一个解析器的人会补上一些在文档中阅读的东西,但不是全部。在出了差错的情况下,你有两种方式推卸责任——要么读者不行,要么作者太差。无论怎么样,更受欢迎的产品会赢。
我对3D图象行业最不能容忍的事情之一是,过多的文件格式不明。当我执行一个3D作品的OBJ文件解析器时,我测试的每份导出作品都生成明显不同的文件,比如空白和换行不同。与之形成对比的是,我的一个初出茅庐的同事用语法和词法分析器设计了一个新游戏交换格式(现在,这不再是什么大不了的事了—-大多数新图象文件格式好像都是基于XML的)。
只会将简单的脚本和用户界面放在一起的程序员和可以处理实际问题的程序员,如果说这二者有什么区别的话,那就是对复杂计算的理解能力,如算法怎么影响问题的大小。每一位程序员都应该知道基本的复杂性术语和对常见问题的复杂程度有常识性认识。
我的第一份工作是计算机辅助半导体设计,涉及许多可扩展性的问题,包括一些NP-complete问题(非常难处理)。但是,每次看到在线性时间中不能解决的问题,和我们自夸可能意味着大部分是线性时间的“线性”算法,有些工程师会兴奋地说:“这是旅行商问题!”(游戏邦注:旅行商问题,即TSP是一个有着重要工程背景、在图论中的典型组合优化问题,已被证实是一个NP完全问题。也就是,如果一个旅行商不得不到几个城市做生意,怎样走最短的路线使他一次到达这几个城市。)
免费啤酒、自由讨论、免费软件
好吧,其实没有免费啤酒;但现在程序员过得还不错(尽管经济衰退和外包业惹争议)——毕竟你需要的东西网上教程、讨论组上都有,还有免费软件可以用。你要解决的只有硬件和宽带问题。
7.尊重
高效软件工程师的要求之一是,被认真对待。你必须得到你的同事和老板的尊重,至少出于你的技术能力、对自己的工作有主导权、对他人有一定影响力。
愚蠢问题
真的,这个世界上存在许多愚蠢的问题。提出一个聪明的问题会增加别人对你的尊重,但这是一项技术活。一个揭露未解决的事的好问题会让别人看到你深刻的内涵,你敏锐的思维。要求说明关于技术参数的问题,显示了你阅读和发现问题的能力。
如果你的问题没有得到答案,可能是问题本身有误,所以不要再重复发问了。换一种方式提问,带上更多细节或背景。如果被提问的是你或花时间回复新手问题的是你,你会感谢上述考虑的。
能与技术支持人员保持良好关系,这是让我对自己都感到骄傲的事。但我确实记得一件往事,那时我抛出一个问题:“几周前提出来的那个问题是怎么回事?”你可以想象别人是多么恼火地回答——“你说的怎么回事是指什么,并且,你说的是什么问题?”
粗鲁无礼是没有回报的,特别是如果你是要求免费指导或咨询讨论组。即使你是在支持协议的保护之下发问,激怒了你的技术顾问对长期合作也会很不利。
我曾经向臭脾气的新人们解释为什么他们的问题有问题或者什么是他们从一开始就做错了的,真是太累人了。现在,我给你快速生效的傻瓜过滤器——“我想知道的只是……”或果断无视。
让所有人知道你读了文件和谷歌搜索了该问题。除了避免回复必然的“RTFM”(游戏邦注:RTFM意为:去读该死的指导手册。当你需要信息或者解决问题时,在请求对方帮助之前,应该花一些时间尝试自己去寻找需要的东西。)和“Google is your friend”,都显示了你做足了功课,那些帮助的人不必搜索相同的资源。如果你确实指望他们为你搜索那些资源,那你的意思就是,你的时间比他们的金贵,你在谋杀他们的时间。
白痴答案
如果你要表现得你知道自己在说什么,那么你确实应该知道你到底在说什么。工程师的交流有时候更多地是炫耀自己的知识而不是提供信息(如果你也能这么做,那我向你致敬)。这往往无益于求职面试,面试官其实是假借“发现你是怎么想的”的幌子,向求职者抛出空洞的问题。当然,如果求职者有一点自知之明的话,也可能产生出乎意料的结果。
有一位技术总监打电话面试我,要我概述C++编辑的结果堆栈框架,并且口头答复他。我一步一步地打草稿,每次我给他正确的答案,他都反过来要我说一个错误的答案,以便我们可以仔细检查为什么那个选择不管用。我不知道我这么写是不是在彰显我有多聪明或他有多聪明。
作为一名工程师,你不能太倚重钱财和长相——信誉才是你的资本。所以如果你犯错了,就坦率承认吧。
我有幸与一名资深工程师共事,他从来不犯错。当他的Java代码在多重处理器系统中崩溃时,原来是出现了大漏洞。当我拿代码指出UI代码不支持多线程运行时,他坚持说只有一个线程。当我列出代码中的7条线程(我能找出的)时,他同意不应该保留这么多线程,并且最好修改一下。但他还是按老样子编写代码——他没有修复任何漏洞,他只是用更多代码掩盖了漏洞。
最后,一个节省时间的建议:不要纠结于愚蠢的争论。愚蠢是会传染的。(本文为游戏邦/gamerboom.com编译,拒绝任何不保留版权的转载,如需转载请联系:游戏邦)
Seven Habits of Highly Effective Programmers
by Phil Chu
The following blog was, unless otherwise noted, independently written by a member of Gamasutra’s game development community. The thoughts and opinions expressed here are not necessarily those of Gamasutra or its parent company.
Want to write your own blog post on Gamasutra? It’s easy! Click here to get started. Your post could be featured on Gamasutra’s home page, right alongside our award-winning articles and news stories.
For my second gamasutra blog (I’ll stop counting at some point), I’m reposting one of the software development essays I wrote between my last salaried job and my first serious contract gig (during which my claims to be “self-employed” sounded like a euphemism) under the theory that if I wrote down all my opinions I wouldn’t have to repeat them during job interviews.
That turned out not to be a great theory, but anyway, here’s the first of those essays, and the most popular:
As a software engineer, you might want any number of things out of your job – a steady paycheck, the opportunity to work on interesting projects, a springboard to the next better job, or maybe you just like hanging out with other programmers. But by “effective”, I mean the ability to complete projects in a timely manner with the expected quality. After working on dozens of software releases, I believe the following practices will bring you there, and while they may involve sticking your neck out, I’d like to think they will also advance your professional reputation, career longevity, and personal satisfaction.
Understand Your Requirements
The first step in becoming an effective programmer is to ensure that you are spending your time wisely. And there is no greater waste of time than in working on something that is not useful or never shipped.
Build Early
Get a demonstrable system working as early as possible. This means establishing the interface first, whether it’s an API or user interface, and stubbing the encapsulated functionality as necessary.
This allows your “customers” to check it out, by exercising the user interface or writing code to the API, and any inconsistencies or omissions in the initial spec can be detected early. Chances are, you will notice problems or potential improvements even before releasing this first deliverable.
There is a classical school of thought that believes if you design everything up front, then all you have to do is write the code and you’re done. That works great if you’ve done the exact same project before. Otherwise, it’s more likely you’ll run into a point where you’re just guessing or operating on questionable assumptions.
Upon joining an early-stage wireless internet startup, I found myself in two months of design meetings for a wireless portal and gateway due to launch in six months. Eventually we got tired of meeting and finally started coding. Within two weeks, my part of the project had no resemblance to the original design, and the first wireless connection test two months later revealed a fundamental misunderstanding of the wireless protocol.
This is not to say that design is unnecessary. But after a certain point, design is just speculation. Design should be validated with implementation, and better to do that early and continuously than late and, well, too late.
Even if the original design is sufficient, once you have something you can tweak, you can improve upon it. Hardware products (who designed this VCR?), buildings, and large-scale software projects suffer from interfaces that were frozen in “preproduction”, but with software, you have an opportunity early in the project to refine your understanding of the requirements and produce a suitable interface. But it must be done early.
Getting something ready early is also good for your occupational well-being. Your boss will appreciate seeing evidence that something is actually getting done and having something available to demo. On the other hand, a drawn out period with nothing to show is a recipe for anxious management.
Deliver Often
Once you have something working, don’t just leave it as a “proof of concept”. Let people play with it, see their reactions, and let this guide and prioritize your development. There is no substitute for watching how people use your software. Customer questionnaires and focus studies might provide some useful input but run the risk of transferring feature and design decisions from the developer to the customer.
In particular get the software into the hands of the QA staff as soon as possible and feed them regular builds, preferably at scheduled intervals. Having them test automated daily builds is ideal, but even a weekly build is pretty good. This will help them feel involved in the full life-cycle of the project and they should be best-trained at identifying and reporting problems. The highest priority should be given to issues that prevent them from using the product, e.g. crashes or dead-end paths – you want them to cover as much as possible as soon as possible and get a feel for the whole product so design issues can be identified early.
At a small 3D graphics software vendor, I was put in charge of porting the flagship product from SGI workstations to Windows NT. After six months, the port was so incomplete and crash-prone that I was reluctant to give the first “alpha” build our test group. Fortunately, the QA manager insisted, and the resulting bombardment of bug reports forced me to immediately focus on the problems that prevented the testers from exercising the application in any meaningful way. Left to my own devices, I would have worked on what seemed to be the harder and more important core 3D issues, and probably delayed too long on seemingly mundane issues like the user interface, load-save functionality, and compabilility with all the varieties of consumer hardware we were planning to support.
Programmers often don’t want to release code to testers early – they don’t want to hear about a bunch of bugs they already know about, and quite possibly the testers don’t want to test something that barely works. But it’s the testers’ job to find these problems and programmers need to realize bug reports are a good thing, if they arrive early enough.
Keep It Real
Keep your software running in as close to a shipping state as possible. You never know when you’ll have to demo the system, send out an evaluation copy, or even deliver (“OK, time to wrap things up!”)
Use Real Data
If you just test with sample data, that big iceberg of real data out there is going to sink your program.
One of the leading semiconductor fabs evaluated a supply chain management product I was working on. After crunching out a milestone delivery to them, we got word back that the first batch of data they fed it from their own operations was still processing – for two days. I sympathized with the lead programmer, who had to dig down and emergency-optimized everything he could for two weeks with both management and client breathing down his neck. I’m just glad it wasn’t me on the line.
Use Real Builds
Remember the development build on your machine is not the real build.
On a recent game development project where I worked on the user interface, I got intermittent reports from QA that some colors were not correct. Eventually, I realized the problem only showed up in release builds and another programmer used the special console debugging hardware to track down the bug. Which turned out to be a silly mistake I’d made two months previous, failing to specify an initial color value in a few cases. The debug build always selected a specific default value, while the release build optimized that away and the result was less determinate. If I’d made a point of running the release build frequently, I would have spotted my mistake immediately, instead of losing it in the sands of time.
Merge Often
Don’t procrastinate on merging your code with the main code base – the longer you wait, the harder it gets.
I worked with a programmer who “couldn’t be bothered with” all the new code and data changes that showed up in the repository every day. And certainly, daily merges did take up some time for all the other programmers, and this programmer was able to run some impressive standalone demos with a snapshot of the code and data. But every time we had a milestone delivery, it took days to get the isolated code reattached to the current codebase again, sometimes compromising the milestone delivery and risking the funding for the entire project.
Keeping your code out of the official build means that programmers cannot evaluate your code and testers cannot spot bugs early. Maybe you don’t want people picking on your code or bugs, but it’s better to identify those issues early than later – suck it up.
Understand Your Code
Life is full of wonderful mysteries, but your code is not the place for them. You don’t have to know how your car works – if the engine starts making strange noises, you drop it off the mechanic.
When it comes to your code, if you don’t understand how it works, or doesn’t work, no one will.
Code with Style
My childhood piano teacher once commented to me, “Your sister has a good sense of timing, and your brother has a good feel of the keyboard.” Then he paused. “You, uh, you work hard.”
Programming is one of those things that a lot of people are more or less competent at, but some in particular have a flair for it. I’m a lousy piano player despite years of lessons, and I’m a mediocre basketball player although I enjoy playing it immensely. But I do like to think I have a flair for programming and writing. And not surprisingly, I think good programming is like good writing. Both prose and code are textual, have grammar, syntax, spelling and semantics and spelling. For most coders and writers, this is enough, but the best writers and coders have an esthetic and their work features structure and style that can often be identified with the author.
Many Windows programmers wonder why grumpy old Unix/Mac/Amiga/Lisp programmers rail against Win32/MFC/.NET, but if all the API’s you’ve seen are from Microsoft, you probably don’t know there’s anything better.
Perhaps not everyone is capable of writing stylish code – I’ve heard it said that good object-oriented programmers, in particular, are born and not made. But like fine music, wine, and literature, you can learn to appreciate good code.
Cut-and-Paste
The opposite of stylish programming is cut-and-paste. Grab some code from somewhere that is supposed to do something like what you want, tweak it until it sort of works, stir, repeat, and voila, you have the software equivalent of mystery meat.
A few months after leaving one company, a former coworker emailed me a single function consisting of ten pages of cut-and-paste code and asked why it wasn’t working. I could have very well asked why it should work at all. If you can’t explain how your own code is supposed to work, how can you expect anyone to help you with it?
I’ve even had trouble diagnosing my own code that was cut-and-pasted from sample code. It’s a reasonable way to start new code, but you can’t just leave it alone when it seems to work – you have to go back and make sure you understand it line by line and clean it up for your own purposes.
Keep it Clean
The key to keeping your house/condo/apartment clean is to spend a little time cleaning it every day, or at least every week. If you wait until your abode is an unsightly mess, it’s just too much damn trouble to clean it all up and you end up just doing a halfhearted job. Or your hire a cleaning service.
Assuming you don’t have the luxury of hiring someone to come in and clean up your code every week, you should periodically inspect your code, sweep up accumulated hard-coded numbers, outdated comments, misleading function names, or you’ll inevitably end up with uninhabitable code that’s embarrassing to show anyone else. And if you’re not embarrassed, well, you should be.
One programmer I supervised kept reporting to me that her code was “done”. This is what management normally likes to hear, but it drives me crazy. Code is never done – you have to debug it, maintain it, evolve it until it’s put out to pasture.
Questions? Comments?
Some like to think of programming as a craft. Others, engineering. More often than not, it’s archaeology. You dig through sediments of code and wonder what purpose all these strange artifacts served. Do future generations a favor and leave some clues.
I asked the aformentioned engineer whose code was “done” to add comments. The result, a function named GetData was prefaced by the comment “Gets data.” That’s not just useless – it’s insulting.
What data? (factory automation schedules) In what format? (a proprietary XML format) From where? (an in-house server, using TCP/IP) Not to mention little details like what happens when the server is unavailable or the transmission is broken.
Document your code as if someone else might have to take it over at any moment and know what to do with it. That person might actually be you – how often have you had to revisit your own code and thought to yourself, what was I trying to do here?
On a contract with a previous employer, I was asked to look over a piece of code that no one else had time to attend to. At first, I thought it was a mess and didn’t know what was going on in there. Then I gradually figured out what the code was doing, and I grudgingly admitted the code wasn’t too bad. And then I eventually realized that I had written the code two years ago. Note to self: need more comments.
With that in mind, annotate your code as you write it, instead of waiting for a convenient cleanup phase in “post” – annotating as you code can even clarify your thoughts while you’re programming.
You can be your own pair-programming buddy.
As a bonus, these days you can generate nice HTML or otherwise-formatted documentation from source code comments, using javadoc, doxygen, whatever. Ideally, the doc-generation is part of your nightly build and available via your intranet.
Full Warning
Ignore compiler and runtime warnings at your own peril. They are called “warnings” for a reason.
I shipped one Unix-based application that had a problem linking some functions successfuly – we worked around it by relinking those functions at runtime. When we performed a clean rebuild six months later for the next release, it was revealed that we had turned off linker warnings which would have alerted us of a known linker bug. In our defense, we had swept the linker problems under the carpet at the Unix vendor’s suggestion, (thanks, SGI!) but it turned out we could get the link to work just by reordering our libraries.
Crank up the warning levels on your compilers, sprinkle your code with assertions, and log the build and test-time warnings. Better yet, include a count of those warnings in your build metrics so you know if you’re dealing with them or letting them accumulate.
Optimal Programming
Code with Purpose
On the other extreme from cut-and-pasters are those who change code just to make it look prettier (at least to them). While it’s laudable to have a programming esthetic, it’s a waste of time (and a useless risk) to change code just so it looks better to you. It’s aggressively annoying to go through and change code that other people have written just so it looks better to you.
A fastidious coworker of mine went through our codebase and removed all the expletives. Probably no one would have complained if he had just cleaned up the code written by the entry level employees, but the expletives belonged to the technical lead of our group who was also one of the few distinguished Fellows at the company.
Do No Harm
“Refactoring” is all the rage, now, but programmers often take it to mean any code cleanup or redesign. The trick is in reorganizing code for the better without breaking anything. If you break existing functionality in the name of progress, you’re sending one of two messages: 1) your time is more important than everyone else’s, or 2) you’re incapable of touching code without breaking it.
I had one particularly contentious coworker who decided to reimplement the parser in our system but left the code in an unbuildable state by everyone else. I asked him to revert his changes and then found the code was buildable but not runnable – asked about it, he replied that he removed the parser entirely “per your request”. Not a team player.
Keeping the code functioning takes some patience and extra work – you have to be diligent about regression-testing your work and chances are you’ll need to keep old code and interfaces around for a while as you migrate functionality to your new code. But for everyone to work with the same codebase, that’s what you have to do.
Find the Bottleneck
People always talk about “optimization”, but that isn’t really a correct word. We’re rarely shooting for the optimum – instead, we make improvements and tradeoffs to achieve good-enough performance.
I was asked in a phone interview with Google how I would search for a number in an array of ordered numbers. Obviously, the questioner was asking for a CS 101 answer – binary search. But in real life, I would probably do the “wrong” thing – search the array from beginning to end. There’s no point in taking twice the time to write twice as much code that has to be maintained and debugged if the application performance is good enough, and in particular if that piece of code is not the bottleneck in the application. (And I seriously doubt you’d have that data laid out linearly in a fixed array like that if it was the bottleneck)
If you do need to optimize for speed or space in you application, attacking anything other than the bottleneck is a waste of time.
Manage Thyself
You probably have a lot of complaints about your boss being a lousy manager, and you’re probably right. So you have to be your own manager. Even if you have a decent boss, he’s not going to stand behind you telling you what to type and how fast (although I’m sure many would like to).
Are We There, Yet?
Programmers are notoriously inadequate at providing useful schedule estimates. I think this is a bad rap, since management, left to their own devices, often make even worse predictions, and unwelcome news from engineers is often ignored. (A common theme in any engineering disaster). But still, awareness of the schedule is critical to actually getting the project done on time.
On one commercial software project, some of my coworkers were blissfully unaware of the product release date – one inquired whether it had been released already, another was surprised to find it was going out in a few days.
The worst, and most common, schedule estimate that a programmer can give is “it should just take a couple of days”. Every time I hear that, even from my own mouth, I wince.
The president of a graphics software company really wanted support for VRML (at the time it was the Next Big Thing) included in the product we were releasing in two months. He probably figured (correctly) that I would resist starting a new feature, so he went to another engineer and got the answer he wanted: “a couple of days”. Two dayslater, I told the president we-just-wasted-two-days-of-his-time-and-mine-while-there-are-two-hundred-high-priority-bugs-to-fix, which he found to be a persuasive argument. (postscript: VRML didn’t exactly take off like gangbusters)
And then there are programmers who are unable to come up with time estimates at all. But there’s no need to get thrown off by the fuzzy nature of the request – it is an estimate after all, and in fact you should avoid using formulas. If you’re an experienced engineer, you know how long comparable tasks have taken you before, and if you’re not experienced, you can ask someone who is.
A smart friend of mine who was often assigned to developing experimental prototypes asked me, “how can you schedule research”. I think it was a rhetorical question, but even pure researchers have schedules. Someone is paying them and expects results, even if it’s a number of demos or published papers in a certain timespan. And if you really don’t have the foggiest idea how long something will take, then you’re the wrong person for the task.
Sometimes programmers are reluctant to commit to a schedule because they’re afraid of the accountability. It is true, in this imperfect world, managers will try to bargain you down on schedules, political factions may saddle you with tough or unrealistic schedules in the hopes that you will fail, and it is a sadly common story that after you commit to a schedule, you don’t get everything you need.
I had one boss who after asking for an estimated completion time would say, “do you promise?” But ask for a commitment on the required hardware and other dependencies, and it was “I’ll try.”
All I can say is, stick to your guns and give a realistic prediction. Any concessions should be based on pragmatic tradeoffs between features and resources. Be clear about the assumptions, dependencies and resources on which the schedule is based, and get it written down somewhere so you can jog defective memories later.
Plan Your Progress
You wouldn’t just hop into your car before deciding where you want to go, right? And probably you have a route in mind before you start driving, too. Similarly, before you sit down at our computer, you should know what you want to accomplish that day and have some idea how.
Distractions will come up day-to-day, so you won’t always be able to accomplish what you want. And contrary to those who treat software engineering groups as vending machines (they would probaby shake us vigorously if they could) some tasks take more than a day. So think about what you want to accomplish by Friday, and if you do, then you can enjoy the weekend that much more.
Continuous Education
A corporate soccer team member once asked me, as we were lacing up our cleats, “what’s the secret to C programming?” If there was such a secret, I’d be hawking it on late night TV along with ab machines and how to get rich in real estate. Sorry, there’s no shortcut – you have to learn and practice and make some mistakes. And you don’t necessarily have to rely on corporate training or going back to school – there are plenty of (inter)national and local professional groups, books, and of course, the Internet.
It’s Science
It’s called “computer science” for a reason. It’s easy (maybe too easy) for anyone to to start programming, without a formal computer science education. In particular, those from other engineering and science disciplines can pick up programming quickly and make a good living. But to effectively tackle non-trivial tasks, you need to know the inherent capabilities and limitations of software and recognize prior work, so you don’t waste time reinventing the wheel, badly. You don’t have to know everything under the sun, but you should have at least a cursory familiarity with many areas and be prepared to do some additional research as necessary.
For example, anyone who creates a new file format should know something about compilers. I don’t mean all the code-generation optimizations like loop unrolling, but the basic issues and various phases of compilation and most of all the importance of specifying the tokenization and grammar. Nowadays, most people by default will use XML, and that’s a good thing, but before then it was typical to cobble up some text format, point to some generated sample files as documentation, and then everyone else who wrote another parser would cobble something up that would read in some files but not all. In the problematic cases then you could point fingers either way – either the reader is bad or the writer is bad. Whichever product is more popular wins.
One of my pet peeves with the 3D graphics industry is the plethora of ill-defined file formats. When I implemented an OBJ file parser for a 3D content creation product, each exporting product that I tested against generated markedly different files, using different whitespace and newline conventions, for example. In refreshing contrast, a coworker of mine fresh out of school designed a new game interchange format using a grammar and lexer specification. (These days, it’s not much of an issue anymore – most new graphics file formats seem to be based on XML.)
And if anything differentiates programmers who can just put together simple scripts and user interfaces and those who can tackle real problems, it’s an understanding of computational complexity, i.e. how algorithms scale with the size of the problem. Every programmer should know basic complexity terminology and have a general knowledge of the complexity of common problems.
My first job was in computer-aided semiconductor design, which has a lot scalability issues, including some NP-complete (essentially intractable) problems. But some of the engineers would run around excitedly saying “it’s the traveling salesman problem!” every time they saw a problem that couldn’t be solved in linear time, and in other cases we boasted of “linear-time” algorithms which probably meant linear-time most-of-the-time. Or some of the time.
Free Beer, Free Speech, Free Software
OK, there’s no free beer, but this is a good time to be a programmer (well, recession and outsourcing controversy notwithstanding) – just about everything you need is on the Internet tutorials, discussion lists, and free software. All you need is the hardware and a broadband connection.
R-E-S-P-E-C-T
One requirement for being an effective software engineer is to be taken seriously. You need to have the respect of your peers and managers, at least for your technical capabilities, to have control over your own work and influence over others.
There is Such a Thing as a Stupid Question
Really, there are lots of stupid questions. Asking intelligent questions that enhance others’ respect for you is a professional skill. A good question that exposes unresolved issues tells people that you know your stuff and you’re sharp enough to catch all the implications. Asking for clarification about a specification shows you know how to find and read the spec and your ability to detect ambiguities.
If you don’t get any answers to your question, chances are there’s something wrong with the question, so don’t just repeat it. Ask the question differently, with more specifics, or more background.
If you’ve been on the other end of a technical support line or even just spent time on discussion lists answering newbie questions, you’ll appreciate the consideration.
I pride myself on cultivating good relations with developer support staff by submitting elaborate bug reports and precise questions. But I do remember one lapse where I tossed out something along the lines of “What’s the deal with that issue that came up several weeks ago?” You can imagine the prickly response – “What do you mean by what’s the deal, and what issue are you talking about?”
It doesn’t pay to be rude, especially if you’re essentially asking for free tutoring or consulting on a discussion list. Even if you’re asking under the auspices of a support contract, irritating your support contact isn’t going to help you in the long term.
I used to take pains to explain to belligerent newbies why their questions didn’t make sense or what they were fundamentally doing wrong. Now, the bozo filter kicks in quickly – one “All I want to know is….”, and they’re ignored.
Let everyone know that you read the documentation and googled the subject. Besides avoiding the inevitable “RTFM” and “Google is your friend” responses, this shows you’ve done your homework and those who want to be of assistance don’t have to search through the same resources. If you do expect them to search through those resources for you, then you’re saying your time is more important than theirs, and you are just one more perpetrator of the “tragedy of the commons”.
There is Such a Thing as a Stupid Answer
If you’re going to act like you know what you’re talking about, you really better know what you’re talking about. Engineers sometimes communicate more to show off their own knowledge rather than to inform (although, if you can do both, kudos to you). This is often inflicted in employment interviews, under the guise of “finding out how you think” the candidate is asked inane puzzle questions.
This can backfire, though, if the candidate has any self respect.
One CTO interviewed me over the phone by asking me to sketch out the resulting stack frame from a C++ compilation and then report the result back to him verbally. We went through it step by step and every time I gave him a correct answer he asked me to give a wrong answer instead so we could go over why that choice wouldn’t work. I couldn’t tell if we were trying to demonstrate how smart I was or how smart he was.
There’s also the blame game. As an engineer, you can’t rely on your money and looks – all you’ve got is your credibility. So if you make a mistake – ‘fess up.
I had the privilege of working with a senior engineer who was never wrong. When his Java code was crashing on multiprocessor systems, it was Sun’s bug. When I took over the code and pointed out the UI code was not supposed to run in multiple threads, he insisted there was only one thread. When I listed the seven threads (that I could find) in the code, he agreed I shouldn’t have all those threads and I’d better fix it. He programmed in that fashion too – he didn’t fix any bugs, he just covered them up with more code.
Finally, a bit of time-saving advice: Don’t get dragged into stupid arguments. Stupidity is contagious.(source:gamasutra)
from: http://gamerboom.com/archives/65164