【程序员职业发展】为什么我离开了管理岗位?
从2001年在网易成为一名项目经理,到2011年进入腾讯,我经历了从“领导”几个人到几百个人的好几种管理岗位,名字有的叫“总监”,有的叫“经理”,还有什么O之类的。但是在十年之后,现在的我没有一个下属,一般的人看来似乎有点不可理解。正常来说,中国人的传统是“学而优则仕”,管人的总比做事的看起来要“高级”一点。那么,为什么我要“急流勇退”呢?其实并不是我觉得做一般的管理工作力不从心,也不是因为厌倦了管人,或者想要做闲云野鹤,而是我发现,如果要真正的管理好一个技术团队,还是要从技术方面下手。而这些真正能对技术团队管理有帮助的技术,不实际的去学习和实践,是非常难以掌握和熟练的。
技术团队有多难管,从人员流动这个事上,就能最直接的体会到。我记得我第一次参加网易的校园招聘,招聘了的几十个应届毕业生,这些毕业生在一年之内,有70%都离职了。他们有的是去考研、有的去留学、还有继承家族生意和考公务员的。当然留下来的那批,也有一部分在两年之内跳槽了。按理说网易也算是不错的公司,尚且面临如此之高的离职率,其他的公司可能会更加严重。我在这个事情上,花了无数的精力希望打造一个“具备凝聚力”的团队,试图降低这种流动性。但是无论如何努力,技术团队还是会“维持”着某个流动率,所以我意识到,如何降低人员流动对工作的冲击,才是一个必须要做的事情。我们知道,软件开发的交接,不是一个简单的事情。因为软件开发的文档、代码、工作关系,甚至很多工作的经验,都是以一种智力形式存在的。这种智力产品,如何从一个人的大脑迁移到另外一个大脑,如果不借助任何工具,无异于师徒传授技艺,是一个效率很低,结果非常不确定的过程。所以我认为,技术知识在团队内的共享,必须要有一些强而有力的技术工具来保障,才能成功。
技术团队的管理除了要应付人员流动的挑战外,如何衡量技术人员的工作量,从而预估工期和掌控开发进度,这也是一个巨大的挑战。这方面关于“项目管理”的知识也算汗牛充栋了。在实际的工作过程中,我们也尝试各种方法,但是不管使用什么“项目管理”的方法,我们总会发现,在项目经理的表格,到产品里可运行的代码之间,总有一道深深的鸿沟。不管我们的开发进度预留多少buff,也不管我们的项目进度报告的周期,从月、周细化到日甚至小时,都无法真正准确的回答——现在项目开发到什么地步、将来的某个时间点,项目可能开发到什么程度。所以我开始承认,掌控技术项目开发进度,在一些需求变更特别频繁的领域,特别是互联网、游戏这类没有明确客户代表的领域,是一个非常模糊而且复杂的工作。我们必须抛弃工业时代对于某个“项目”的管理思路,而采用更新的思路,以及更有效的技术工具,才能真正的对项目管理提供有效的推动。
管理技术团队,我们就必须对技术团队的产出负责:软件的质量和开发效率。我们既需要稳定的软件质量,尽量少的BUG,尽量好的性能和扩展性,也需要能跟随市场快速变化的软件迭代速度。而我们的技术团队总会抱怨,需求变化太快,没有时间去重构系统,导致代码的质量下降,开发效率也受影响等等。如果我们仅仅是通过提高技术团队的个人技术能力,或者刺激开发者更多的“主观能动性”,结果还是会不尽人意的。因为个人的技术能力成长需要时间和实践经验,而且人员也很有可能会流动;如果主观能动性被刺激成无休止的加班,到头来最后还是会降低团队的工作效率,因为疲劳的开发者只会制造更多的BUG和怨言。因此我们不能单靠传统的工商管理的思路去解决技术团队的产品质量问题,而应该看到软件开发本身是一种具有鲜明特色的行业,要提高产品质量和生产效率,还需要使用更先进的软件生产工具和生产流程。
人员流动、项目进度控制、软件质量提升,是我在管理技术团队中,碰到的最多也是最大的三个挑战。在深刻的思考和做了大量的管理实践后,我深深的认识到,作为一个技术团队的管理者,最需要的往往不是所谓的“管理能力”,而是对软件开发这个行业,更专业的技术能力。这些技术能力,大体包含了所谓的“软件工程”知识,以及大量的软件开发工具以及最佳行业实践的经验。所以我认为认真的去研究、实践、开发这些,能有效提高技术团队开发效率、准确掌控项目进度、降低人员流动性影响的技术,是具有非常重要的意义的。我在这里所说的这种“技术”,具体包含些什么呢?概括一下,无非有这几类:软件模式知识、开发工具和实践、需求领域知识。
软件模式知识,主要是来自软件工程类,包括如何写出可读性好的代码,面向对象或者结构化编程的知识,设计模式、架构模式等等。其中最基础也最重要的,就是“编写可读性好的代码”,与其说这是一种知识,还不如说是一种态度。无可否认大多数工科、理科出身的程序员,对于写文章的训练都比较少,所以也不难理解为何对此没有“感觉”。其实要编写可读性好的代码,最简单的方式就是重视“命名”。顾名思义是人类最简单的阅读体验,代码中的变量、函数、类的名字如果是“有意义”的,那就会大大提高代码的可读性。但是,怎样才能定义一个有意义的名字,而不是仅仅根据技术功能实现的需求来设计名字呢?我知道我们都爱循环变量int i,但那是因为我们都熟悉它的这个含义。对于可能阅读代码的人来说,还有什么是确定大家都会比较熟悉的呢?肯定就是业务领域的内容,因为要接触这份代码,肯定就是那些要在这个业务领域工作的人,所以使用业务领域的内容词汇是最好的。但是,由于我们的代码往往会有很多层的抽象和封装,所以在某些层次也许无法找到业务领域词汇去对应,这确实需要一些想象力和抽象能力,但是不管这种想象的是否合理,一定会比不假思索的用Controllor或者Manager这样的名字来的“有意义”。
除了命名以外,代码可读性还有各种各样的需求,而业界也对这一类要求,总结出很好的规范,他们就是各种“代码风格规范”,最著名的有Google公司开放的规范,包含了多种编程语言的版本。更重要的是,我们还可以用类似cpplint这类的“代码静态检查工具”来自动的检查代码是否符合这样的规范。就连Google这样业界知名的公司,也会要求所有程序员写出来的代码,都要像是一个人写出来的那样(出自《Google软件测试之道》),我们还有什么理由去追求各种代码编写层面的奇技淫巧呢?除了静态代码检查工具,我们也可以组织一些代码检视(Code Reivew)来保障这个方面,所幸的是,市面上的大多数IDE都支持某些Code Review的插件,寻找一个好的代码检视工具,然后在实践中用好这个软件,也是一种让人愉快的体验。更重要的是,如果一个新入职的程序员,能发现自己的代码是受人关注的,在编码上的技巧和问题是有人指导的,也会加强对团队的信任和凝聚力,从另外一个意义上看,这也是一种有效的降低团队流动性的手段。反过来说,如果不时的参加代码检视或者其他代码监管的活动,管理者也能更准确的了解成员的编码水平,从而做到赏罚有据。
在良好的代码可读性基础之上,对于代码模块和模块抽象,也是需要一定的专门技术的。这里要接触到的就是“结构化编程”和“面向对象”两种概念。这两方面的书籍汗牛充栋,但是我觉得需要强调的是,“结构化编程”并不和“面向对象”是冲突的,它们之间的关系非常密切。如果你能把某个需求有逻辑性的细分下去,必须要有足够的抽象思考和业务领域理解知识。面向对象是一种面向名词的思考方式,结构化的思维同样需要用到。所以结构化编程的思维同样是面向对象设计的基础。这方面的专业论述有很多,但是最可惜的是,我们很多技术团队,仅仅把这些看成是程序员的“个人修养”,而不是一个团队的必要要求,所以我们的代码质量往往参差不齐。其实和“代码风格规范”一样,代码模块的设计也是必须要符合一定的规范的,这个在不同的团队和业务领域中可能不一样,但是没有规范或者指导思想,是最差的一种。因为这个层面的知识,由于业务需求和领域的不同,往往很难有完全统一的业界标准,所以更加需要团队的管理者来制订和执行。这也是对一个技术团队管理中最具挑战性的部分——如何定义、抽象、管理业务模型。而这部分也是很多管理者忽视的部分,他们有太多行政工作要做,反而认为这些事情应该交由其他人代劳。在这个事情上,如果不是有业务领域经验丰富的人去做抽象,就一定避免不了模型和需求不对应产生的修改工作量;如果不具备丰富的代码设计能力,如设计模式的人去设计,需求变更造成的工作量可能会毁掉整个项目。
优秀的程序员——往往都成了管理者,必须要发挥自己的这些智力优势来提高技术团队的产出,而不是去做别的一些没有什么“技术要求”的工作。况且这些设计工作是那么的有挑战性和趣味性,工作量(从开发时间看)也不是那么大。如果管理者在系统的设计过程中和团队密切的互动,解释和宣导自己的想法,在执行过程中监督这些设计的实施,本身也是对产品质量的一种把控,不管是评价下属的工作量,还是理解项目的进度和瓶颈,都是拥有第一手资料的。这种情况,就是我认为的技术管理工作,最后还是要落实到技术工作之中的重要理由。当然,你可能会说,如果一个非常大型的团队,CTO也是需要这样去管理吗?听起来似乎不太可能,但实际上任何一个团队,在某个时间点上,一定会有一些非常重点的项目,或者一些关键的问题要解决,CTO并不是简单的做做规划想想点子,而是要针对关键的业务问题,去做具体的解决方案的。这里提一点题外的例子,比如二战时德国装甲兵总监古德里安,除了多次打报告要求组建强大的装甲兵集团,还自己去找了两辆卡车装上铁皮,安排模拟的坦克训练。这类高级管理者做具体工作的例子非常多,最重要的是要抓到问题的关键点去做。我们最常见的毛病反而是不关注难点重点,一味高屋建瓴的提要求而不找解决方案,这是管理的大忌。
如果一个团队能关注代码模块的抽象,能经常的讨论诸如设计模式、重构这些设计问题,那么就能有机会在更高的抽象层次上,使用更有价值的设计理论,比如架构模式。最近几年无论是Webservice、SOA、restful,还是所谓云(PaaS, SaaS),这些流行的名词,从某种意义上来说,都是一种架构上的创新:结合最新的技术和最新的业务领域。使用什么技术,上什么架构,是一个技术团队管理者必须随时学习和思考的问题,固步自封肯定会有稳定可靠的好处,但也是让一个产品腐烂落后的原因。勇于挑战和尝试,才是一个积极向上的技术团队的应有的气氛,而这个气氛首先要考验的是管理者的勇气。
先进的开发工具和实践,一直以来都有推陈出新,从最简单的版本管理工具(《人月神话》中写到,由于没有版本管理工具,作者所在的团队花了巨大的努力,制定了各种管理规范,来解决代码分支和覆盖的问题,甚至要靠把源代码打印到纸上,堆的比人还高。)到各种高级的IDE软件、缺陷管理系统、知识库管理等等……但其中自动化测试技术,是最重要的一种。我们常常把测试认为是一种“质量检查”的工作,但实际上,测试是代码生产的生产线。我们如果以测试驱动开发的角度来看,需求首先变成测试用例代码,具体实现代码的首次运行也是在测试用例代码中,最后整体项目的运行,也是由测试代码来启动。这个过程中,测试代码就好像产品的模具,保障整个产品是设计的样子。可惜我们常常并不愿意花时间去打造模具,就好像我们直接用手工直接去做产品一样。但问题是,如果我们的产品只是一次做出来就好,但是软件系统往往需要大量的,不同部分的修改,没有测试系统的保障,我们肯定会改了A地方,B功能就会出错。一个项目如果测试用例足够全面,就算功能代码全部丢失了,凭借测试用例,也能很快的重建出功能代码来。更重要的是,测试代码还能保证多个层次的代码,都维持一个稳定的“样子”,这对于项目团队的人员交接,是有重要意义的。
我们在项目管理的过程中,常常会苦于不知道项目进度如何,但如果你有一个完整的测试驱动开发的流程,这个问题就不会那么棘手。首先,需求的明确工作可以看测试用例的编写进度。在编写测试用例的过程中,大量的模糊不清的需求,都会被落实成代码,这也排除了很多日后延期的可能。如果在比较复杂的系统中,代码的抽象层次有多个,所以测试用例也许同样会有很多组。但不管怎么说,每一层的设计最后都落实成为测试用例的话,整个项目的需求也会因此就稳定下来。然后,如果我们是针对这些测试用例去做开发,那么每天我们都可以统计到有多少个用例被完成,这比从或空洞或繁琐的程序员日报里,可以获得的信息准确的多。最后,在产品运营的过程中,我们可以把所有发现的故障和缺陷,都补充为测试用例,这样就可以确保项目的质量可以逐渐稳定下来,当我们真的需要重构的时候,只要有这些测试用例,就能放心大胆的去修改代码,因为只要通过所有的测试用例,项目的质量就一定是可靠的。所以一个自动化、高覆盖率的测试系统,是一个项目在管理上最有效的工具。
测试工作有那么多好处,但是为啥总会觉得有很多困难无法实践呢?关键点就是测试中的各种依赖很难构建,这就是一个比较专业的技术问题——Mock和Fake系统。所以我们的问题又一次回到了技术上,构建足够专业的Mock和Fake系统。
需求领域知识,从某种方面来说,不算是“纯技术”的领域,但是,对于特定开发某个业务领域的团队,这些知识的掌握程度,往往是至关重要的,因为只有在深刻的理解了需求,才能真正的用好各种抽象、模式等软件工程知识。程序员们往往都会有一些误区,认为只有技术领域才是自己应该关注的,有些人可以非常熟悉Linux内核的各种实现细节,但是却对最近的一个项目的市场情况漠不关心。很多程序员往往会认为,计算机科学中的那些知识,才是知识,而他们所接触的其他业务领域,都应该是他们关心的。可惜的是,大部分的程序员,也叫软件工程师,都是需要解决计算机科学以外的业务问题的。所谓工程师,就是利用已有的工具,去解决实际的问题。所以对于实际要解决的问题领域,不进行完整细致的学习理解是不行的。事实上,计算机科学,也是因为其他业务领域的需求而发展起来的,比如军事、金融等等。要深入的去学习一个业务行业领域的知识,也是需要很多时间的,这往往和程序员希望自己的技能通用化有冲突。但是我认为这个世界上没有那么多“通用”的知识可以用,能专心做好某一个领域已经很不错了。所以在花时间到具体的业务领域上,去学习和实践各种技术解决方案,会比只是空泛的“领导”一队人做事更能发挥作用。
技术团队的管理,如果仅仅从一般意义的“管理”上去解决问题,往往是无解的。但是彼得·德鲁克说:管理本质就是创新。我的理解是,管理就是要去找解决问题的方法,如果这个方法看起来很不像一般意义上的管理,那也无所谓,因为解决问题才是目的。打破对“管理”的看法,求真务实的去寻找解决问题之道,才是真正的“管理”。技术团队的管理问题用技术手段解决,是我切身体会的最好的解决方法。
以上是 【程序员职业发展】为什么我离开了管理岗位? 的全部内容, 来源链接: utcz.com/a/127233.html