2014年总结——协作篇

  2014年,技术外的事情比技术内有更多波澜。


  年初,项目从零开始,团队也是由五湖四海拉来的一帮人组成;策划对ARPG没多少概念,美术对移动端斜45度视角没多少经验,程序和美术对Unity 3D则都不熟。这是最难熬的一个阶段,持续了大半年。

 


(一)  程序和美术/策划的协作


  项目刚开始的时候,可以感觉出与我合作的策划与美术都很想将产品做成精品。他们时常在琢磨,不时会提一些很炫的点子,希望我能实现。不过一方面大家从未磨合过,策划与美术可能吃不准程序能实现到什么程度;另一方面,可能很多第一次直接与程序合作的设计者会高估程序的实现能力或低估一些设计的实现难度,并且过早将精力放在了许多细枝末节上。这样一来,作为客户端新手的我有时就比较悲催。为了赢得伙伴的信任,我只好拼上自己几乎所有能用的时间精力,身心接近透支状态——Trust is earned。


  后来我和主管UI的美术同事聊过几次。他也提到,刚开始合作时确实不知道程序的实现和承受能力如何,所以的确也是在试探。对于这个想法,我大致还是认可的,尤其在项目初期阶段,什么都没有的情况下使劲做加法未尝不是好的做法,这样可以在项目内树立起产品设计上的高度或标杆。


  不过当项目进入后期,程序的精力要逐渐转到程序健壮性和运行效率的时候,我就不太希望策划和美术还会提出超越我既有经验、需要我花很多精力在前端表现上的需求。还好UI美术总体上还是比较配合,而且下半年有一位经验丰富老练的系统策划加入项目,并在后来成为主策,很大程度上解决了UI美术和程序之间的协作问题。协调能力真是衡量策划价值的重要指标。


  说起美术和程序之间的协作问题,技术篇总结已经提到,手游对前端技术的更高要求,引发了程序和美术之间的更多博弈甚至冲突。这里的协作问题主要有两点:一是很多纯美术表现的工作要靠程序实现,程序要花很多精力在表现上,而非逻辑和技术上;二是手机性能有限,能承载的资源有限,但美术追求表现的话往往要堆资源,因此对程序优化的要求极高。这两点合在一起共同增加了程序的复杂度。


  对于第一点,我很赞同《一像素的恩怨情仇》这篇文章的观点。我觉得在人手不够充足、工具不够强大的情况下,程序和美术相互之间都需要适当关注了解下对方的工作,不要太在意职业之间的界限,让沟通和理解更加紧密顺畅,这样才能让好的产品落地。加之项目初期时,出于好奇心和学习的目的,我是很愿意将精力投入到纯表现的实现工作中的;甚至会乐意在一段时间内放下代码,在编辑器中钻研各个参数的含义,摸索一些设计的实现方法,甚至偶尔会自己替美术构思一些细节设计。当然要项目中的每个程序和美术都这样“复合型”毕竟不现实,也不见得好,毕竟术业有专攻。一方面不是每个程序员都愿意花很多心思在编辑器里“绣花”;另一方面美术理解Unity和NGUI中各个组件和参数的作用也比较吃力。不过幸运的是,我们的程序员对拼界面调表现倒也不算很排斥;UI美术中万幸也有一位愿意学习,并且比大多数美术更能理解逻辑与参数的同事;策划也有分担此类工作的意愿,大家在这件事情上总体还是比较积极,像《一像素的恩怨情仇》里提到的开发不愿意帮设计调像素的情形基本没有;再加上我半年多的钻研也算是为中后期全民做UI做了些技术和方法上的积累。到了下半年,美术、策划和测试大都能理解Tween、深度、图集之类的概念。美术对实现有一定了解后,做出的设计也稍稍地不会那么天马行空难以落地。我们也没有为“UI表现是谁的分内事”这种问题产生过多少争执——美术可以做的,就让美术做,或者策划调;需要代码控制的,就由程序做;模棱两可的,就看大家的喜好和精力,比如有的程序员更喜欢由代码控制一切,那就都交给程序。不知是否有些敏捷的味道。


  在第二点,即性能问题上,我们程序和美术之间更是为此PK过多次。年初程序根据一些试验和推测制定了一些美术规范,可是常被美术忽视。从美术的角度讲,资源总是越多越好——模型面数越多越好,贴图越精细越好,粒子发射器越多越好。这样品质会更高,美术效果会更好(说到这里,我也是到2014年才真正理解了为什么很多时候外行觉得一款游戏画面太烂,其实是美术资源的缘故而不是引擎技术的缘故)。但是资源多则程序性能压力大。当然在这个问题上程序一般还是先从自己身上找原因,尽量在不减资源不影响体验的前提下优化程序性能。当程序扛不住,需要美术减资源或策划改设计的时候,事情往往就要捅到主策主程主美甚至制作人的层面了,这时程序往往要拿出足够有信服力的证据让美术妥协。目前为止UI方面经历过五次大规模性能优化,其中只有两次是程序扛不住要美术减资源——贴图精度从2048降到1440,又从1440降到1024。基本上每周做版本,性能指标都是快要爆表接近闪退临界值的节奏。我想我可以单独写一篇文章总结2014年我们做的UI性能优化。


 

(二)  程序员之间的协作


  程序和美术之间会碰撞,程序和策划之间会碰撞,程序和程序之间也会碰撞。如果说程序和美术、策划之间的碰撞是因为各自的立场和角度不同,那么程序与程序之间的碰撞则更多来源于每个人的习惯、思维方式和在意的事情不同。


  在命名风格上,有的程序员习惯linux的小写下划线风格,有的程序员习惯C#或Java的驼峰法,甚至有程序员习惯驼峰加下划线风格(比如Function_Name)。在排版上,有的程序员习惯加空格与换行,让排版空一点;有的程序员习惯空格与换行都不加,全部挤在一起。在大半年的时间内,程序内部都没有编码规范,框架方面也没有规划,基本上都是凭着感觉和各人自己的习惯写,代码风格眼花缭乱,颇有各自为战的感觉。对此我只能在动到别人代码的时候,看看已有代码是什么风格,然后与已有风格保持一致;而UI代码因为时常使用NGUI接口,所以就用NGUI风格;如果有人要动UI代码的话,我会跟他提一下(虽然对方也不一定会严格遵守)。还好接近年末的时候,在一轮人事变动和岗位调整之后,主程终于决定严抓代码风格,大家终于统一起来。


  比代码风格不统一更考验心智的是思路的不同。其实如果仅仅是交流讨论,百家争鸣,那事情还是好办很多。但当大家要落地做事,而且事情跟我的工作相关,和我的代码有交集时,我就不那么容易淡定了。一般当同事想实施某个方案,而你又觉得不妥时,仅从代码设计或策略的角度来讨论是基本不可能说服对方停手的。有一次UI性能优化,负责引擎与工具的客户端同事打算改动NGUI内部,使优化效果更彻底;而我基于谨慎少出bug的考虑,认为我们毕竟不是NGUI的作者,并不清楚NGUI在某些地方采用低效率做法的真正原因,而且这位同事很多时候做事情也不太仔细,因此我主张在使用层面进行优化,绕开NGUI内部的低效率逻辑。后来还是随了他,果然改动之后出了很多bug。不过本着“有bug就修”的态度,这些bug还是一个个逐渐被修掉了。虽然现在在使用上还有一点瑕疵,并且有些bug甚至是经过几个月并让我花了很多精力才揪出来的,但同事的优化现在看来已经没什么问题。


  所以平常吐槽归吐槽,同事身上有缺点也归有缺点(谁又没缺点?),但当技术方案有碰撞时,除非能明确指出对方方案中存在的逻辑漏洞或复杂度过大的地方,否则即便他要动的是我的代码,即便我在审美上不喜欢对方的方案,我也不应该轻易否定对方的方案。我又怎么知道自己的方案就一定更优呢?因此,虽然好些程序员会以“感觉怪怪的”表示他们对一些技术方案的看法(包括刚才提到的那位同事,有次为了实现界面中的一个小效果而再次改动NGUI内部,而对我提出的简单调整一下节点关系的方案提出“感觉怪怪的”),但我告诫自己不要这样看待其他人的方案。人一般总有思维定势,不符合自己思维习惯的思路在自己看来总有不顺眼的感觉。这时如果能放下有色眼镜,心平气和地分析呈现在眼前的新方案——无论它结果是好是坏,思路都会更开阔一些。


  其实如果对方的方案真的有问题,而自己又吃不准的时候,也不必过于纠结。如果对方坚持,那就随了对方,也算是作为试错的手段。如果真的有问题,大家自会抱怨,届时可拿出最初提出的各种方案重新分析,也会有新的观点。项目初期时曾有一位从其它行业跳来的老程序员与我一起写UI。出于对其资历的尊重,我曾将一些较底层的东西交给他写。但可能是他在以往工作中积累的思路定势的缘故,他写出来的很多逻辑在我看来都颇有过度设计的嫌疑,不易维护且容易出错。他离职后,留下的模块要么被策划废弃,要么在众人的吐槽和主程的同意之下,被我用更简单的逻辑重写了。

 

  正好此时工作室中的另一个项目因为采用了过多的面向对象风格,每添加一道业务流程都要新定义好些类,注册很多的回调,让人甚觉麻烦,所以也多次被吐槽。由此我也总结出,简单明了、易于理解、集中式管理的逻辑一般都受到众人的欢迎;非到十分必要的时候,不要随意采用虚函数、回调等会让逻辑分散在各地的浓厚的面向对象式做法。这让我想起了以往和师兄合作写Java软件的时候,我不时会大力重构他的过程式代码,将大段逻辑拆成一个个短小精悍的函数,并大量使用继承、多态和回调,结果师兄常看不懂我改过之后的代码,出bug的时候感觉无法下手颇为着急。那时他说我有过度设计之嫌,我还有点不高兴。现在看来当时真是给师兄添麻烦了。


  不过当然,产品上线运营之后就不能这样大胆试错了,一切改动就真的要谨慎又谨慎。

 

 

(三)  程序和测试的协作

 

  程序和测试之间当然也要打很多交道,不过一般不会碰撞。测试报bug,程序查bug修bug,天经地义。


  在老东家的时候,程序和测试在不同楼层,测试给程序报bug都是通过Mantis提单,邮件通知;单子会说明bug的重现步骤和优先级;程序可以根据优先级和自己手头的工作自行决定什么时候修什么bug;程序和测试之间一般通过Lync和邮件沟通。


  可是现在的团队里,所有工种都混坐在一起,测试发现bug时会立刻抓程序来看。虽然我们有Redmine可用来提单,但测试因为负担太重,所以不一定每个bug都会提上去;就算提上去,测试一般也不会将重现步骤写得那么详细,只是一两句话记下有这么个事而已,优先级更是没有。可以说,非常“敏捷”。


  所以测试找我看bug之后,我都会第一时间先把这个bug记下来——一些可以秒修的bug就马上修掉;不能秒修的,先记在自己的笔记里;如果这个bug比较重要或比较难查,我会嘱咐测试提单,并且测试提单后,我会在单子里补充上重现方法;待修掉后,记下修复的版本,如果是比较难查的比较复杂的bug,再补充上bug原因和解决方案,对应的svn日志里也写上。这样时间久后,一旦遇到类似bug或是要追查一段代码是为了修复怎样的bug时,就很容易查到。虽然现在团队还没有这方面的规范,其他同事也不会这么干,但我因为从学生时代编程起就亲身体会过这样做的好处,所以仍然坚持着。


  优先级和即刻抓人修bug的问题,有时稍微让我头疼。编程思路被打断倒是后话。但有时正在对本地代码做大改动的过程中,突然来了一个紧急bug需要修复,这时就要小心维护区分改动中的代码和用于修bug的代码。以前在老东家用Perforce,我可以先将本地进行到一半的改动shelve到服务端,回退本地,然后开始修bug。但到了新东家用svn,处理起这个问题就比较麻烦。不过年末我开始用git管理本地版本,通过git分支基本解决了这个问题,方案比Perforce还好,在这方面也就不怕紧急bug出现了。


  一般在游戏研发团队里,测试都是黑盒测试,并不懂代码和实现原理。然而,我们的测试会审查代码,了解一些功能的实现细节,写测试脚本,实际能顶半个程序(当然这也进一步加重了测试的负担)。这对程序来讲真是益处良多。每当写好一个系统或是一个比较重要的业务流程后,将代码逻辑给测试讲一遍。讲的过程中,思路会越来越清楚,而且有时还没讲完,测试还没反应过来,自己就会先发现有bug。这时测试同事就是小黄鸭调试法中的小黄鸭。有时测试会对某些功能的实现或对某段代码好奇,作为程序员也要能讲清楚。说起来以前做学术时,我很擅长这方面的表达,将某个业务或复杂逻辑给人解释清楚,甚至外行也能听懂。但2014年我在这方面退步很厉害,甚至几次阐述逻辑都被主程说“太绕太复杂”。想来如今的工作节奏不允许我花太多时间为这种表达做充足准备(以前准备一份ppt都至少要花上一周,并且反复预讲),而如今我又常钻进技术里出不来,将没有整理过的原始思路直接表达给别人听,自然会让别人听得云里雾里。

 

  有时测试会指出某段代码的不严谨之处,甚至是不好维护之处,这时偶尔就会产生程序与测试之间的碰撞。当然这种碰撞的激烈程度是远不及程序与程序之间以及程序与美术/策划之间的碰撞的。有次测试在QQ群里吐槽进入副本的代码逻辑太乱,相关程序对吐槽表示不爽,在QQ群里争论起来了;最后程序还是整理了那段代码,而且结果在我参与的起哄和主程的安排下,程序和测试全体当晚到烤羊排店里搓了一顿,吃了好几条大羊腿,又拉近了团队感情大笑


  因此和测试人员的协作可能是我在2014年经历的最愉快的协作了(虽然被bug砸的本能感受确实不太好)。



(四)  常被打断的节奏

 

  2014年我所经历的团队协作之紧密、节奏之快,是我以前从来没有经历过的。前面提到的所有工种混坐在一起,便是一个体现。不过让我感受最深的,还是编程中常被打断的节奏。打断我的可能来自策划/美术提需求;美术问工具方面的问题;其他程序员问接口或相关功能如何实现,或让我帮忙查他们不太好查的bug;测试抓我看bug,或向我了解一些功能的实现细节。有时被一位同事叫走之后,回到座位上屁股还没坐下,就立刻又被另一位同事叫走了。

 

  被打断的第一反应是情绪上的不爽,谁也不喜欢一件事做得正high的时候被别人拽出来。其次还有恢复思路的问题。有时做事情A的时候,被打断去做事情B,但做B的过程中又被打断要去做事情C,这堆栈嵌套太深,恢复上下文就比较麻烦。不过思路的恢复对我来说还是小事,更重要的还是时间被占用。有时候竟一上午全在被打断的过程中,半天只写了一行代码——真的只有一行代码!

 

  这当中,我曾对被其他程序员打断有点介意。按照我以往的习惯,当我的工作需要涉及别人负责的模块时,我一般会先自己翻翻代码和文档,尽量自己先摸熟,然后再问别人。这样对项目代码和相关技术的掌握也会更深刻。但是其他程序员不见得有这个耐心,遇到问题就问。不过后来我也想通了。一来不是每位程序员都有强求知欲,各人在意的事情也不一样,因此不是每个人都会关心模块内部的实现。二来,更重要的是,单纯从完成任务的角度考虑,有问题就问人也会节省不少时间精力,人家需要将省下来的时间精力用来做其它任务;现在基本上每位程序员的工作负荷都是满的,因此我不应该对人家这种做法有什么想法;相反,如果明明是别人几分钟就可以交待清楚的逻辑,我却花了太多时间自己摸索,反而有不知轻重缓急、影响工作进度之嫌。所以后来在我自己遇到问题时,我也会根据情况主动打断别人问问题。

 

  我曾就被打断的问题请教过主程和老东家的领导,他们均表示这是国内的常态,需要克服自己情绪去适应。这样也能锻炼出记忆需求和思路的能力。另外,实现功能时不要过于纠结方案是否完善;先写,把功能实现出来,以后再完善;在写的过程中思路也会越来越清晰。纠结于我而言是个大问题,我会另写文章总结。

 

  虽然我读过好些文章论述程序员被打断的代价,但理想很丰满,现实很骨感。在一个初创且快速迭代的项目和团队里,很多我从文字资料中读到的软件工程观点都不再适用。

 

  的确被打断的节奏在项目中前期尤其明显。项目进入后期,随着大家对项目相关的工具、代码和技术逐渐熟悉,随着各人岗位逐渐固化,随着各个模块逐渐稳定,被打断的节奏也就不那么频繁了。不过预计项目上线后,这个节奏又会紧张起来,而且到时候被打断的就不仅仅是编程过程了,休假也会被打断。

 


  这是我第一次用这么长的篇幅写纯协作方面的事情,看来2014对我来说真是纷乱而不平静的一年。协作过程中发生了很多人与人之间的碰撞和摩擦,我需要直面同事之间思维、观念和做事风格的不同。尽管我对这一切都有心理准备,但当我真正面对它们的时候,还是会有很多意外和失落,甚至可能会给同事添堵。因此这一年的心境比起前两年也是格外不平静。一年下来,有不少人离去,也有不少人进来,大多数人还是坚持了下来,彼此的磨合越来越顺,项目也终究有了走上正轨的感觉。我很欣慰可以跟着项目从最初走到现在,切身体验了整个过程。不过,事情还没完。2015,继续期待。


你可能感兴趣的:(2014年总结——协作篇)