CGDC“高效程序员”听课笔记

时间:2012年7月27日

讲师:樊尚福Jean-Francois Vallee

这堂课的讲师樊尚福是成都育碧的开发总监。他讲述了在成都育碧公司培养程序员的一些心得。一个公司招聘的程序员,具有不同的能力、经验和背景,要让他们在同一个环境下协同工作,是每一个注重程序开发的公司所面临的共同问题。

讲师将程序员的能力分为硬实力软实力两个方面。硬实力主要指程序员的专业能力,包括分析设计编程调试撰写文档优化重构等方面的能力;软实力则包括沟通协作学习适应坚持挑战把握细节的能力。对此,樊尚福坦言他更宁愿聘用软实力较强的员工。硬实力在工作的过程中可以培养,较强的软实力也会加速培养的进程;而想要提高软实力,则要困难得多。在现代的软件公司中,由于软件工程的应用,程序员硬实力的门槛正在渐渐降低,而对沟通协作、品质把控和学习等方面的能力要求则大大提高。一般而言,程序员都比较乐于提升自己的硬实力,而比较忽视对软实力的追求。

接下来,讲师讲述了一些开发中常见的问题和误区,以及相应的解决方法。

问题:过早考虑优化

过早考虑优化是在游戏开发中非常常见的问题。尤其是在我任职的公司的开发过程中,大家几乎言必称优化,视性能问题为洪水猛兽。这一方面是历史原因导致的,在开发前代游戏时,缺乏易用的性能评定(profiling)工具和方法,遭遇性能问题时容易束手无策;从架构上的约束不足,也容易写出性能低下的代码,因此逐渐养成了谨慎而拘束的开发氛围;另一方面则与程序员的固有思维有关:拿到一个问题,总是马上开始考虑最佳的解决方案,包括最佳的性能方案。而翻开软件工程相关的巨著,几乎无不反对这种做法(程序优化的第一条原则:不要优化。程序优化的第二条原则(仅对专家而言,请勿模仿!):暂时不要优化。——Michael A. Jackson)。广受倡导的优化原则是,仅当确定了某个地方的代码会导致性能问题,才应该去做优化;而是否有性能问题,应该由profiler说了算;而对于什么是“性能问题”,也需要明确定义(例如执行时间超过多少多少毫秒)。因此,讲师给出的解决方案包括:

  • 明确目标:什么样的问题算是性能问题,优化的目标是什么(避免无止境的优化);
  • 设定合适的每日监测指标:每天(或以其他的周期)监测程序的性能,便于发现和定位性能问题;
  • 先完成游戏功能:能工作的代码永远好过漂亮但不能跑的代码,当然也好过高效但无法完成功能的代码;
  • 应用帕累托原理(80/20法则):80%的工作(完成功能)只需要花费20%的时间来完成,而剩下20%的工作(优化效率)往往需要花费剩下80%的时间;而这20%的工作很可能是无的放矢的,因为没有数据支撑,你无法确信这些代码是否有效率问题(另外,一种常见的情况是,这段代码可能确实有性能问题,但是因为调用次数少,所以根本不会对整体性能产生明显影响,这种代码也不应该花时间来优化)。因此,在一定的周期内,应该优先完成功能,效率问题则应该留在profiling之后集中处理。

问题:临时代码

我们在开发的过程中,经常会因为遇到不明确的需求而编写临时代码,或者需要在代码正文中穿插调试代码。这些代码的存在本身并无可厚非,但是因为它们是临时的,编码人员就容易放松警惕,写出质量低下的代码;而当需求被确定,或者调试完成之后,这些代码很可能就会变成永久的代码。长此以往,整个代码库会因为这些代码而变得满目疮痍,缺乏可读性和健壮性。

  • 总是考虑代码的质量:即使是临时代码,也要以对永久代码的要求来编写(对于某些编写非临时代码都不注重质量的程序员,他们还有更长的路要走。赠言:永远要这样写代码,好像最终维护你代码的人是个狂暴的、知道你住在哪里的精神病患者。——Martin Golding);
  • 隔离但保留调试代码:显著区分开调试和普通代码。例如使用明显的注释、使用宏包围,或者使用IDE的折叠功能;
  • 可以稍后重构代码——但应该预估时间:对于不明确的需求,编写quick and dirty(有一个专有形容词代替这个词组:kludge)的代码是可以接受的,但是一定要预留出时间,以便需求明确以后对代码进行重构;
  • 学习阅读他人的代码:学习阅读他人的代码有利于提高自己的代码质量,也有机会向别人指出他的代码的品质问题。

问题:大规模重构

对于使用敏捷开发模型的项目来说,大规模重构其实是不可避免的事情。由于需求的快速改变,程序的架构自始至终都需要进行调整;而在两个迭代阶段之间(例如demo->pre-alpha),就容易产生大规模的重构需求。大规模重构会导致的关键性问题是,重构工作可能只由几个核心的技术人员来进行,但是会影响到其他每一个人的工作。对此,讲师提出了以下解决方案:

  • 在大的里程碑之间预留时间:大规模重构可能会影响到每一个人的工作,因此不宜随意进行。两个里程碑之间是进行重构的好时机;
  • 在独立的分支中重构:在独立的分支中重构可以避免对他人的工作产生影响,但也带来了额外的合并工作作为代价;
  • 渐进式重构:大规模重构可能会给项目中的其他成员带来新的学习压力。在自己不熟悉的环境中开发是一件缺乏安全感的事情。渐进式重构可以让这一学习曲线变得平滑,对其他开发人员更为友善(在实际工作过程中,重构可能会遭致某些团队成员的反感)。

问题:过度设计

与缺乏设计相对,与过早考虑优化相似,过度设计也是一个常见的问题,我个人也自问经常犯这种错误。过度设计常常体现为过分考虑灵活性,为寻找最灵活的解决方案,甚至单纯是为了最好看的代码结构,而浪费太多的时间。与过早优化一样,你所追求的灵活性常常不是项目所需要的,你不需要为你的假想敌(不可预见的需求)做好战斗的准备。未来的需求会定义你的设计,适时重构才是正确的方法。

当然这绝不是说不需要设计、不需要考虑灵活性。很多需求是可预见的,因此必须为它们提供足够的灵活性。准确地消化需求,也是一个重要的能力。

  • 从简单实用开始,适时迭代,保持简单:保证实现贴合需求,不需要为额外的灵活性操心;
  • 很多可以参考的书籍和网络资料:很多功能、系统的设计都是现成的,或者有相似者存在,参考它们的设计模式,可以帮助你合理地进行设计;
  • 准备多个方案,并搜集反馈

问题:尝试和犯错

不仅对于新晋的程序员,害怕尝试和犯错的情况在老程序员身上也非常常见,甚至尤为严重。这常常会导致他们坚守稳妥的开发方式,拒绝尝试新的技术和方法。对此,讲师建议程序员们应该勇于尝试,并给出以下建议(虽然是老生常谈……):

  • 失败是成功之母
  • 智慧=知识+经验
  • 经验=尝试->失败->学习->成功

问题:玩游戏

我认识的很多程序员都宣称自己不玩游戏,更不谈玩自己做的游戏了。

  • 必须的,尤其是你自己参与的游戏:讲师认为,作为一个游戏开发人员,玩游戏是一件非常重要的事情,尤其是玩自己参与的游戏。我也赞同这一点。玩游戏有很多好处,例如,可以帮助你更好地理解策划的需求;玩自己参与的游戏,还可以帮助你发现和理解自己所做的功能的缺陷和不足;
  • 不喜欢自己参与的游戏很正常:众口难调,我还没有参与过自己喜欢的游戏的开发;即使你一开始喜欢,除非你是制作人,否则游戏的设计也难免会发展到你不喜欢的方向。因此,无需要求自己喜欢自己参与开发的游戏,但这不是不玩它的借口;
  • 能帮你拓宽解决问题的思路
  • 和主管讨论安排游戏的时间:(对于像我们这样工作环境宽松的公司和团队似乎没啥必要)

问题:灵活性

与传统的瀑布式开发模型不同,游戏开发多使用敏捷开发模型(即使没有明确地套用某种模型,游戏开发也或多或少地在以这种方式进行)。在这种模型下,需求会频繁地变更,乃至推倒重来。因此,经常需要对已经完成的功能进行修改。

  • 项目中一切皆有可能,改变是无法避免的,学会拥抱改变:导致对已经确定的需求进行修改的原因有很多,例如策划案改变、重构、其他相关联的功能改变等。敏捷开发模型决定了这一切都是不可避免的,因此,最好的选择就是接受。不太有人喜欢这种不稳定感,但不要对此产生敌意;
  • 保持沟通,你会预知这些改变:保持与其他同事,尤其是与你开发的功能相关的同事沟通,了解他的开发内容,有助于帮你预知可能发生的改变,以提前做好应对策略。

问题:职业水准

  • 保持积极向上的心态
  • 尊重你的同事
  • 遵守你设定的任务期限
  • 工作时间不浏览和工作无关的网页
posted @ 2012-08-23 15:47  hillin  阅读(527)  评论(0编辑  收藏  举报