程序员生存定律
1. “博”与“专”上的迷失
假设说一个人的学习已经聚焦,并且学习的内容和自己实际参与的项目也相吻合,那么是不是就没有问题了?很不幸,答案仍然是否定的,在任何一个子领域里,仍然需要进一步去考虑“博”与“专”的均衡。
对于软件开发而言,设计是再常见不过,再简单不过的一个词了。可如果把视角拔高一点就会发现,单以设计而论仍然是一个不可穷尽的领域,我们可以快速扫描一下和设计相关的部分概念:
-
面向对象分析与设计
-
结构化分析与设计
-
模型驱动开发
-
契约式编程
-
面向方面的开发
-
基于组件的开发
-
元编程
有些时候方法论也会和设计牵扯到一起:
-
测试驱动开发
-
敏捷软件开发
如果感觉这个还不够多,那可以去Wiki上查编程的范式(paradigms )这个条目,那里列了47种范式,每个都和设计多少有点关系。
上述这些还只是说了设计,如果横向展开,那么在特定领域中必然还会牵涉到框架的选用、辅助工具的使用等等。这也就意味着,从博的角度来看,即使是在设计这样一个看似狭小的领域中仍然是没边界的。
与此同时,把一个API研究的再透,也是低值人群,因为这种深入理解和单纯会用某个API相比,从创造价值的角度看,差别不大。
这也就意味着对于大多数软件开发人员而言,要去寻找广博与精专间的均衡点:既不能闭上眼睛,也不能就用显微镜来看世界。而这一均衡点的价值则可用反木桶原理来说明:木桶原理说的是桶里的水是由最短的一块板决定的,但考量人的价值时却是适用于反木桶原理,即人的价值往往由最长的一块板决定。
考虑博和专的问题不能离开产品开发进行考虑,前面曾经提到过,产品开发往往和公司的现金流绑定的更紧,能为现金流贡献力量的技术才是有价值的技术。而产品开发本身事实上对博和专的程度提出了最基本的要求,这种要求往往具有迭代的特质。为了形象的说明这一点,这里举一个通用的例子来进行一点说明:
在第一次跌代里,往往需要达到两个最基本的目标。第一个目标是可以为产品贡献自己力量,但代码质量普通。这个目标如果达不到,一个人会失去自己的存在价值。
这时候最少需要了解某种语言(比如:C++)、某个平台(比如:Windows)、某个IDE(比如:Visual Studio)和某些业务相关的知识(比如:打印体系)。这个范围可以尽可能圈的小点,但用到的则要学透。比如:不管接触到那个框架,都要去了解它的内存机制、线程机制、异常处理组件构建和国际化处理这些全局性的机制,而不能只是了解某个接口怎么用。
这并非是很高的要求,没有这些就变成了“靠运气编程”,写完程序后还要祈祷他能跑起来。了解这些之后就可以负担起部分开发工作,否则的话只能做旁观者,没法参与到实际工作中来。
第二个目标是把事情做好,并能负担些层次更高的工作。这时候要比较深入的了解面向对象、结构化方法、设计模式、理解设计原则,并能把它们用好。至少要能判定,这个程序写的好,那个程序写的不好,同时面对需求能把工作进行下去。
前两个目标是基础,一般来讲学校中基础打的越好,这个阶段越短。达成这两个基本目标之后就可以结合情境来做进一步的选择,可以认为这是博与专选择上的第二次迭代。当然这时候也要谨记不要和实践分开。
完成上述两个层次后,可以有两个方向可供选择。
-
可以进一步考虑专的问题,比如在特定领域里把知识深化下去。做驱动就要理解操作系统的核心机制,做打印的就要了解页面描述语言等,但这个时候要适当警惕边际效应。
边际效应是说,你让一亩地从亩产500斤增加到1000斤可能只需要投入100块;让亩产从1000增加到1500可能就需要200块;让亩产从1500增加到2000则需要400块了。
一个典型的例子是对C++的学习,C++是公认的复杂,如果想做C++的律师,那么估计搞个10年可能够资格了,但问题是把时间都投在这个上,投入产出比可能不好。而停在那里合适则是个尺度问题,大致来讲是可以靠时间弥补的细节问题,并不适合专到最底层。比如对于100万行的程序,预先花时间去了解每一处细节,就有点过了。
-
可以把博再推进一步,比如:熟悉专门领域的专业知识、熟悉多种既存框架的特性、熟悉提高用户体验的关键点。熟悉多种既存框架的特性的具体含义是:
设计某一种解决方案时,首先要考虑的就是是自己开发还是使用现有的模块。一旦决定使用现有的模块(包,框架等),那就要进一步考虑究竟用那个。
做这类工作时,如果没有一定广博的知识,做选择的时候就会特别的艰难。
假使说现在公司内部要导入一套项目管理系统,那么做决定的负责人必须至少考虑所有下面这些事情:
自己从头造,还是用现成的做二次开发?
用现成的,是用开源产品,微软的还是其他公司的?
用微软的话,是用MS Project还是基于SharePoint,还是混合?考虑License费用的话真的划算么?
用开源产品,有这么多选项究竟导入那一个?
如果自己从头造,那么是基于微软的技术,还是基于LAMP这样的技术?
使用什么框架?
如果要做,用什么语言?
一个人很难精通上面所有的领域,但当做选择时,完全没有概念也是灾难性的。
此外,考虑博与专平衡点时似乎有一种特例,钻研特定算法的人,从一开始就只往专的方向发展,并不会考虑其他。比如:钻研TTS的人,可能几十年如一日只要专注于TTS就完了。
至于具体选择那个方向,则要根据自身情形来定。总的原则是要以当下工作为根基,以实用为目的甄选各种知识,并追求平衡点。
大致上讲,期望做技术专家的更适合前一个方向,而期望做技术管理的则更适合后一类方向。
学习软件工程的时机与必要性
简单来讲越是没实践经验的人越不适合学习软件工程,越需要规划整体把握全局的时候越需要学习软件工程。
软件工程中覆盖的元素非常繁杂,可以有管理、流程、开发模型、估算、分析设计方法等。这无疑会把知识面扩展的很宽,一旦没有根底,就很容易变成纸上谈兵,夸夸其谈。
在众多软件相关的知识中,软件工程绝对是很特别的一个。很多人很鄙视软件工程,说:我一看到软件工程的书就直接略过;与之相对应,很多人很推崇软件工程,会花很大的心思去研究敏捷、CMMI等。
刚入职场的程序员大致上是讨厌软件工程的,因为这东西离自己的实践有点远,并且主要是添加束缚。但既然更加复杂纷繁的历史都可以总结出规律,忽视软件开发的内在规律无疑的对有志于成为管理者的人是不利的。
真要学习软件工程,不太适合从抽象层次很高的教科书开始,而适合从《代码大全》这样与实际关联比较紧密的书籍开始。
在国内软件工程的落地似乎始终困难,软件工程相关名词始终在不停的变换(ISO,CMMI,敏捷等),但实际能落地起作用的却不多,这最终导致了一种吊诡的局面:刚对一个绝望,就开始对新的一个报以希望,并在这两个简单的步骤上做无限循环。这种状况也许有其更深层次的原因,比如生存压力过于强大导致工程力量的长远价值被漠视,进而使方法论并不为解决现实问题而存在,而是为了证书而存在。很难据此就说软件工程毫无价值。
2. 错过人生中的好时机
没毕业的程序员或者刚毕业的程序员往往感觉空余时间比较充沛,还很苦恼不知道如何打发时间,但实际上一个人一生中可以用于充电的时间远比想的少。一旦错过时机,往往悔之莫及。
对于大多数人而言,人生就像个模板,小处还有偏差,大处却基本相同。
20~30岁这个阶段可以讲是黄金时期,这个阶段里,家庭负担较小,可以自由支配的时间较多。当然撞到了很特别的、需要疯狂加班的公司只能另算。
30岁之后因为娃娃出生等,家庭上的时间开销增加,个人可支配时间变少。其中很大一部分人还有很大可能会面对电视剧里常说的婆媳矛盾,让你每天心绪不宁。
40岁之后,家庭琐事会进一步增加,典型的上有老下有小。实在运气不好的自己也会生点病---颈椎病、腰间盘突出、胃病大概可以入选程序员的三大职业病。
50岁之后,时间上会再次解脱,但可惜的是自己也老了,时机不在。
如果把人生按照年龄画一条抛物线的话,40岁左右一个人可以达到的人生的顶点,未来再突破的几率则变小。从历史人物来看,大器晚成的不是没有,但真的很少。
用心观察就会发现,招聘启示里经常会注明年龄要在35周岁以下或者40周岁以下,除非是招聘高层。这反过来意味着如果没有到高层,人生会在40之前定型,之后有下滑危险(如遭遇不景气、公司倒闭等)。对程序员而言,这种风险尤其的大,因为很可能你辛苦掌握的知识体系被更迭掉了。
学习本身无疑的是需要顺应这种自然规律的。
很多人很大的一个错误在于,在黄金时期,没做什么积累,就顾得享受生活了,而一旦意识到积累的必要性时,却又受困于诸多琐事而欲振乏力,最终人生高度有限,并迅速走低。这就是现代程序员版的“少壮不努力,老大徒伤悲”。
基本上讲,35岁以前要把需要花大量时间,比较硬的技能,学习曲线陡的技能掌握,具备工作所需要的所有主要技能,而35岁之后则主要关注知识的更新和某些软技能。
学习时添水战术效率真的很差,每次点一根火柴烧水,一亿年水也烧不开一壶。同时,比较硬的技能(比如:Donald Knuth的《计算机程序设计艺术》)往往是需要大块时间投入的,但年纪越大时间越呈现为碎片化,越难搞定硬的知识---先天就容易造就添水战术。比较软的技能,则可以用碎片时间来学习,比如:提高PPT的制作水平,提高表达能力。
如果能够安排好自己的时间和软硬知识的关系,那么就可以在特定基础上做积累,小步前进,使自己的价值越来越高。从这个角度看,年轻绝对是一种债务,大多数人必须在他没完全结束前,还掉所欠的东西。
那么具体来讲那些东西是比较硬的,要在35岁前搞定呢?这因目标而异,但下面这些项目应该具有非常高的通用性:
-
精通一门最常用的语言
-
了解一个最常用平台的基本机制,比如:内存管理、线程机制等
-
UML图和面向对象分析设计方法
-
设计原则,如:职责单一等
-
设计模式
-
《代码大全》里讲的一切
-
精读一个知名的,但有点规模的程序。这点上要感谢开源项目给我们提供了这么多优秀程序。但要谨防好高骛远,动辄挑战Linux内核,精读是关键。
-
累积一定的代码量,比如:独立的完整做过一个数万代码行的东西。这里的关键是完全自己打造,一定不要拷贝粘贴。
-
掌握基本算法和数据结构(可以不自己写,但至少要知道其复杂度和区别)
-
养成一种清晰的编码风格
-
有自己的专业(金融、高并发网站,图像处理,TTS等)
学习英语的时机和必要性
总的来看,程序员学习英语是一项投资回报率相对比较好的投入。从目标上来看,程序员未必一定要口语流利,但最低要达到阅读英文资料没有障碍的程度。这里面有一个微妙的事情,一旦英语阅读问题较大,查找问题会习惯用百度,这天然会限制一个人的视野。不是说百度自身有多不好,而是说英语的世界里有着更多更精彩的内容。不管喜欢不喜欢,我们必须承认一种现实,在IT的世界里英语是一种世界语,一方面是由于美国公司的强大,一方面则是由于开源选择了英语。这最终导致IT世界里的新动向、解决问题的小技巧、网站的架构等等都要到英语的世界里去找。在StackOverlow很容易找到各种小问题的答案,在Quora则很容易找到各种网站的架构。
从学习时机来看,这件事情特别应该在大学里面搞定,如果不行至少也要在毕业1~2年内达到阅读无障碍的程度,当然希望加入外企还需要额外的付出。从学习方法来看,学习外语真没什么特别的窍门,坚持并投入时间即可。
3. 停止知识更新
对程序员的增值而言,人生里最大的陷阱也许是为安全的假象所欺骗而彻底的放松自己。这种状况在生存环境比较恶劣的情形下不太会发生,但在垄断企业或某一领域中绝对领先的企业里则容易滋生。发现自己是否停止知识更新了并不困难,比如:一年一本书没看,一年一点新知识没接触,一年中工作负荷基本不满等都可以成为一种信号。
这真的是温水煮青蛙,一旦到了三十几岁,并在这种环境中呆习惯了,那么再想跳出来,基本没可能。唯一能做的事情是,祈祷公司不要挂掉,公司也不要来场运动,进行人员的大换血。孔夫子说:日当三省吾身,这是很有必要的,至于认识危险后能否做点什么,那就是事在人为了。
-
技术人员的知识更新
接触一个新的岗位后,大致要经历一个学习并逐渐胜任的过程,这个时间段里大多数人的学习热情是很高的。一旦基本胜任之后,事情就有了变化。
很大一部分人可能会感觉,反正工作也就用到这么些知识,学习其他的也用不上,因此开始把自己封闭起来,不太看书,不太看技术新闻。
这其实很危险,因为这种做法等于把自己绑死在当前这份工作上。而任何一个产品都有自己的生命周期,一旦一个产品的生命周期结束时,碰巧其所用的技术也已经过时,那么当事人就会很尴尬。因为产品可以结束,生活却还得继续。
这里面一个非常经典的例子是MFC。微软的这款产品的历史非常悠久,从1992年发布到2012年几近存在了20年时间。随着90后程序员的逐渐出现,马上这款技术就要变得比程序员的年纪还要大了。
即使到今天,很多桌面应用仍然是基于MFC开发的,这可以通过查看程序包的dll依赖来很容易的进行验证。MFC是一个很大的池子,有深度、有历史。想把MFC的类继承关系、消息机制、框架结构、RTTI、序列化都搞清楚还是要很花一点时间的。
现在我们假设一款庞大的企业应用是基于MFC开发的,一个程序员也通过几年的努力了解了MFC,了解了应用本身,并可以负担起Bug修正,新功能追加等任务了。
接下来这个程序员似乎没什么好学的了。因为MFC的更新几乎已经停滞,因此对MFC的学习几乎不需要花太多的时间了。现有代码也理清楚了,也不需要再花很多时间学习了。现有程序也比较好的满足了企业的需求,推倒重来的可能性几乎没有。
那这个时候这个程序员不需要学习了么?答案一定是否定的。
这里面蕴藏着一个天大的矛盾。
从企业的角度看,一定是需要一个团队来维持这个程序的开发的。但从个人的角度看,如果把所有的青春都耗费在老技术上,那么一旦老技术退出历史舞台,个人该何去何从?
还是上面的例子,假设说一个人持续投入在这类开发上,当他45岁的时候,当前产品生命周期结束,世界变的只有移动开发和云端开发,那么只擅长MFC的他该何去何从?
如果真的如此,这个人就被逼到了死角里,人生很可能产生巨大滑落。所以一定不能认为所学足够而停止技能的更新与学习。
从具体应对措施来看,一是要参照知识的地图,横向扩展知识的广度,比如不只要盯着代码,也要了解业务;不只关注开发也关注一点估算;二是提升可流动性比较好的东西的掌握程度,比如:面向对象分析与设计,这样跨越到其他技术时就能够比较平缓的进行过渡。三是要争取轮换岗位,争取多种实践机会。
-
管理者的知识更新
到现在为止大部分人认同,管理者是需要懂技术的。从逻辑上看“懂”基本上是不瞎指挥的前提,所以这可以称为中国版的“现场主义”,估计争议不大。
那关键问题就是究竟要“懂”到什么程度?
如果说两个人,一个选择了管理方向,一个选了技术方向。接下来要求管理方向上的人技术水平要和技术方向的一样,那么除非这个人特别天才,否则不太可能。正像前面所说,这是由于这两个方向的“Key”不同所造成的。
如果把目标设定为确保最终产品的成功,同时假设管理者有更高的决策权,那么管理者必须在下面这些方面有技术感觉。
从做产品来看,要想成功,有两个关键维度需要同时进行把握,一是产品的概念完整性的把握;一是用合适的手段去实现这个产品。
前一个话题很老,《人月神话》就有提及,但实践中却总是被人忘记。好的产品必须贯彻某一种统一意志,iPhone、微信又重新验证了这一个老的原则。 机械拼凑的产品虽然融合了很多人的想法,但往往是平庸的,并且在项目执行过程中,往往是出错的根源。很像是虽然有法律,但每个人有自己的理解,各行其是这样一个状态。这种概念完整性是管理者第一个需要有所把握的事情,其次就是解决如何去构建产品这个问题。为达成这一目标在下面这几个方面上,管理者要有自己的理解,至少要有自己的原则:
下面简单列举几个比较关键的考量,这和前面论及的如何往博的方向发展有点重叠:
使用现有产品还是自己开发
比如:那些模块适合自己搞定而那些购入就可以了。购入的时候要遵循怎么样的标准去选择。
使用那种平台技术
比如:是使用微软的技术,还是开源的技术。
现行架构是否可以达成产品目标
比如:在硬件加软件可以同时支撑的并发数目。
代码可维护性如何约束
这要求必须熟练掌握一些原则性的东西,比如:什么信息隐藏、正交分解、抽象是否充分等。以及一些无歧义指标,比如:圈复杂度,单元测试的收益平衡。
那些环节必须固化为流程,那些一定要团队自由决定
比如文档化要到什么程度才合适,不同阶段间什么是必须的输入输出。
... ...
假设说有人不这么认为,而是在做了管理后,表现出足够的惰性,不再持续更新自己的知识体系了,那么会发生什么事情?
这时候会很可能会管理倒置。即管理者是名义上的上级,但基本失去对现场的把握,所有的决策完全依赖于下属。得力下属不在,各种决定就只能靠瞎蒙,最终变成只会沟通的管理者---即使被食人族吃了也不会有人注意到,因为存在价值已经被无限稀释,变成了一个象征性的符号。也可能会和下属爆发激烈冲突。因为这类管理者没有自己的立场,上面有任务只能下压。结果同实际情况偏离万里,不具有可实现性,这类管理者无法对自己的上司陈述,也就只能向下转移压力。
不管是哪种,一旦到这种地步,其实是趋于失败,只能祈祷食人族不要来。
为什么中层管理者也要坚持知识更新?
在IT行业流传着一个很有名的关于食人族的笑话,这个笑话说的是:
两个食人族的人应聘进了某家大公司,公司人事主管知道这两个这伙每天都要吃人,于是警告他们:“如果你们胆敢在公司吃一个人,你们就会立即被炒掉!”两个食人族唯唯喏喏地答应,表示绝不会在公司吃人。两个月过去了,公司平安无事。
突然有一天,公司发现负责打扫公司卫生的清洁工不见了。于是人事主管非常气愤,找来两个食人族怒斥,并当场炒掉了他们。出了公司大门,一个食人族马上对另一个抱怨起来:“我一直警告你不要吃有在做事的人,你就是不听!我们两个月来每天吃一个经理,没人发现。你看现在吃了清洁工,他们马上就发现了!你真是个猪!”