程序员生存定律这系列的目录在这里:程序员生存定律–目录
喜欢从头瞄的,可以移步。
一旦度过了初始阶段,做过了前面说的那些事情,那么一个人算是基本入行了,接下来的目标就非常简单,要在选定方向上成为高手。高手意味着专业,而在分工无限细化的年代里,专业则是生存、发展好最为重要的一个前提。
1 高手的定义和养成关键
我估计如果问100个人“什么样的程序员是高手?”,那答案会有100多个。因为同一个人还可能给高手下不同的定义。
在这里我们认为,在特定领域里能搞定大部分人搞不定事情的就是高手。从这样一个定义出发,我们会发现在技术人员和销售人员眼里,高手的内涵是有很大差异的。
纯技术人员更多的关注性能能不能提到极致,并发能不能处理的很好,内存溢出Bug能不能很快搞定,类库的机理熟悉不熟悉等等。而在销售人员的眼里,则在技术外还多看了些东西,比如业务流程熟不熟悉、使用性好不好、能否迅速对应变化、能否在限定工期和预算下搞定任务等。
考虑到职场和产品销售有着非常紧密的关系,我们这里使用后一个视角,而非是单纯的技术视角。
有几类本质上很不同的人都会被视为高手,比如说:
能写出很牛的病毒的
这个不举例子,但当年读过CIH的代码,我是被其精巧给震住了。此外也许搞加密解密的也应该放在这个类别里。
能把一堆3D图形放到64K的
以前专门有个比赛是干这个的,64K大小的EXE能给你放10几分钟很酷的3D动画,第一次见绝对会很震惊。
能迅速调试出问题所在的
内存泄露、多线程同步这类问题往往让人纠缠很久也搞不定,但就是有人能很快的解决这类问题。
能仅靠几个人就架起高并发网站的
新兴Web2.0网站如:Flickr,甚至还可以包括Google,在初期往往是几个人搞起来的,这些人名声不显,但绝对是高手。
能主导开发出很牛的产品的
这个上可以想想Unix和Linux的作者等。
能主持大规模软件设计的
这个往往更有商业价值,我们常说的Martin Fowler应该可以算在这个类别。
能把一种语言研究的特别牛的
想想各个编程语言的创建者,想想C++的大牛们。当然创建某一门语言的也可以归到这个类别里。
能开辟自己方法论的
比如搞CMMI的Watts S. Humphrey
能写出很牛的书的
比如:Windows平台下写了Windows核心编程的Jeffry Richard
能写出很牛的算法的
比如:Donald Knuth
这个表应该还可以加长很多,单以大家认可这个角度来看确实高手可以从各个方面冒出来。
不管在那一方面,要想成为上面所描述的高手总是需要学习、思考、实践这些环节,这没什么可说的。但和软件相关的知识其实多如牛毛,完全不像小说里武功秘籍那么稀缺,几乎可以讲满地都是。这就使选择和集中成为难题。
软件的三个基本特征(技术更迭快、低介入门槛、多内部分野)就像铡刀一样,一旦选择出错,就会把个人的努力切的粉碎,一点价值也留不下来。而与此相对的,则是人的黄金学习时间其实并不多—不过是毕业后的10年左右的时间。
曾经有人希望自己能够从事嵌入式软件的开发,因此给自己买了ARM板,自己在家里花了很多时间来学习并实践相关知识,最终却因为其他的原因进入了一家做网络的公司。这个人等价于被软件的内部分野较多,而彼此间技能流动性较差这样的一个特质斩了一刀,被斩掉的倒不是ARM板,而是自己一年多的辛苦投入。这种情况下强调学的知识将来有用是没有太大意义的,因为还有两刀在等着:如果你三年都不做这个,你今天学到的知识可能会被更迭掉了,同时由于你年纪增长了,可能也不太适合与大批新介入这个行业的人员进行竞争。
这类事情使软件行业中的成为高手这事变得复杂了。
为了在成为高手这条路上走的顺畅,事实上有三个关键点:一是要有一张全局性的地图,以便选好方向;二是要知道都有那些坑,好绕开它,免得掉进去。三是要有足够的热情和动力,能坚持走下去。下面将分别从这三个方面来说明成为高手途径和方法,而这种途径和方法会因为具体目标不同而有所微调。
2 全局性的地图
清代著名学者曾对知识地图的必要性做过非常精确的表述:
凡读书最切要者,目录之学也。目录明,方可读书,不明,终是乱读。
—王鸣盛,《十七史商榷》
目录即是地图。
对于软件开发的知识,我更愿意使用下面的的“地图”,这不一定是最合理的,但确实对归纳各种软件开发知识有所帮助。
通用的领域知识
编程语言(C/C++,Java,C#,Python,Perl,PHP等)
框架和类库(Struts,Spring,OSGi的某个具体实现,MFC,Boost等)
平台(Windows API,POSIX,.Net Framework※1,Java API,C/C++ Runtime Library等)。恰如Jeffry Richter所说,大多时候可以从内存机制、线程机制、错误处理、异常处理、组件构建、组件组合等方面来进一步考察一个平台。
计算机体系结构(CPU指令,虚拟存储等)
数据库
实用技巧(调试方法,代码生成器等 )
… …
※1 有的时候子类别间的界限并不是很容易界定,其中一个主要原因就是存在着像.Net Framework这样涵盖了过多内容的概念。
概念和逻辑创建和优化
面向对象分析和设计/结构化分析和设计
设计模式
重构
契约式编程
UML ※2
… … ※2 从形式上来看UML更近似于一种编程语言,但从其目的上来看也许归在这里是更合适的一种选择。
专业领域知识
图形图像算法
网络协议
人工智能
数值/非数值类算法
财务知识
负载均衡
… …
关于软件的间接知识:
需求开发和描述
估算
估算法。比如,COCOMO, FP等。
估算术。比如,使用计数等原始办法。
软件工程和方法论
轻量型方法论。比如敏捷。
大方法论。比如CMMI
综合分析。比如,《人月神话》,《人件》所做的工作。
随着待解决问题越来越复杂,通用的领域知识中,几种技术往往会组成一种技术Stack,他们更需要被看做一组必须一起掌握的知识,比如:LAMP(Linux+Apache+MySQL+Python/PHP)。
当然上面罗列的远不是全部,这种罗列更多的是展示一种分类的方法。通过对这种分类方法的补充和完善,大多可接触到知识都可以被归入特定的类别,比如说:WinRT可以看做一种新的平台,HTML5则可以看做是一种语言等。
每个人可以根据自己的情形,参照上面的分类建立属于自己的地图,有点问题没关系,有就比没有要好很多。接下来依据这样的地图就可以选一条自己的线路,持续累积,寻求实践机会,最终就很可能会成为真正的高手。
而关于增值所需的动力,所要避开的陷阱,将下面陆续提到。
增值、读书与大局观
单纯从达成某一目的而言,读书往往非是绝对必要条件。
秦始皇把书一把火烧了,刘邦项羽一样造反并取得胜利。但读书无疑的可以加速一个人增值的过程,记不得是谁说过:实践无疑是人类最好的老师,但只靠实践来认知世界无疑也是愚蠢的。这是非常精辟的。除此之外,要想培养大局观,那就非读书不可。
每个人的亲身经历,在大的时空背景中往往只是一个简单的截面,这一截面中绝不会包含可以归纳出所有真理的事实,因此只依赖于自身的实践也就必然限定了一个人的视野。 这一点随着一个人的责任范围变大往往会体现为一种制约和限制。所以培根讲:有实际经验的人虽能够处理个别性的事务,但若要综观整体,运筹全局,却唯有学识方能办到。
即使从实践来看也是如此,要想培养出一种大局观,那就非读书不可。而大局观往往是成为将帅之才的必要条件。
具体到软件而言,有一本很有名的书对培养技术的大局观有帮助:《代码大全》。至于专业性较强的书,反倒是可以根据自己的情景比较容易的选择,这里就不提了。
基于上面这样的一张地图,我们就可以具体的去考虑几条进阶路径。
路径一:由程序员而架构师
架构师是一个很火的职位名字,但你很难给它下精确的定义。
下面所陈述的一切是我个人的理解和体会,我无法保证它和其他人的解释完全吻合。因为架构师,乃至架构设计实在是一种非常模糊的概念,如果你用心去找,可以找到各种定义(甚至IEEE和SEI的定义也不一致),这就导致你只能参照别人,相信自己。
本质来讲架构设计也是设计,所以凡是做设计的都可以称自己为架构师。
当一个系统的规模变大的时候,设计上的决策就具有了特别的价值,并且也越来越需要专门的人来做,架构设计也就越来越像是一种特别的设计。比如说:考虑架构设计的时候,可能需要考虑选用什么样的数据库、选用那个开源框架、选用什么样的硬件平台,这些东西在小规模程序中往往是居于次要地位的。
假设说一个人已经掌握了一门或几门编程语言、面向对象、设计模式、能够很熟练的写出质量较高的代码,接下来他想成为架构师,这个时候他需要做什么?
我个人认为,这时候这个人首先要有一个“专业”。这个专业可以是“金融”,“财务”,“电商”,“管理”等等。这是一种属于某一专业的领域知识,而不是编程技术。如果把需求和最终的代码,看成描述同一事物的一体两面,那么设计始终是要架起这两者间的桥梁。而架桥的时候,怎么可能只知道一端而不知道另一端。
接下来是深化设计所需要的各种通用领域知识(UML、面向对象、性能确保等)。这时和一般所说的设计的一个关键区别是,那就是架构设计要分心思去考虑那些东西用别人的就好了,而那些东西要自己开发。而一般所说的设计技术中,比较侧重自己应该怎么干(面向对象、测试驱动等)。为达成这一目的,就需要对现有技术的优劣有相对比较清晰的认识,比如要能分清楚那些是成熟稳定的技术,那些是处在实验阶段的技术。Pinterest网站就曾经进行过下列这样的架构改进,在这样的改进过程中,不知道各种技术的优劣是代价很大的:
早期阶段:
Rackspace
1 small web engine
1 small MySQL DB
2011/1:
Amazon EC2 + S3 + CloudFront
1 NGinX, 4 Web Engines (for redundancy, not really for load)
1 MySQL DB + 1 Read Slave (in case master goes down)
1 Task Queue + 2 Task Processors
1 MongoDB (for counters)
2 Engineers
2011/9:
Amazon EC2 + S3 + CloudFront
2NGinX, 16 Web Engines + 2 API Engines
5 Functionally sharded MySQL DB + 9 read slaves
4 Cassandra Nodes
15 Membase Nodes (3 separate clusters)
8 Memcache Nodes
10 Redis Nodes
3 Task Routers + 4 Task Processors
4 Elastic Search Nodes
3 Mongo Clusters
3 Engineers
2012/1:
Amazon EC2 + S3 + Akamai, ELB
90 Web Engines + 50 API Engines
66 MySQL DBs (m1.xlarge) + 1 slave each
59 Redis Instances
51 Memcache Instances
1 Redis Task Manager + 25 Task Processors
Sharded Solr
6 Engineers
2012/10:
Amazon EC2 + S3 + Edge Cast,Akamai, Level 3
180 Web Engines + 240 API Engines
88 MySQL DBs (cc2.8xlarge) + 1 slave each
110 Redis Instances
200 Memcache Instances
4 Redis Task Manager + 80 Task Processors
Sharded Solr
40 Engineers (and growing)
这个过程比较真实,大家可以参照着想想如果自己来主导,那还欠缺什么。
最后一点要说的是,做架构设计已经相对于在做技术管理工作,至少要适当涉猎估算并能做出合适的任务分解,这样一旦日程紧张,则可以通过增加人手等手段来在质量、成本和进度之间进行均衡。
由于知识面已经扩的比较大,架构师在具体某个专业领域上的深度可能会有所欠缺,比如:在做一款电子消费产品时用到了TTS,但架构师不一定能很好的了解TTS的算法—这是CodeGuru的领域。
架构师所需要达成的最终目标可以形象的描述为:产品经理考虑用户和市场建立了一个模型,那么架构师要能把这东西映射到技术的世界里来。如果是在互联网行业,那么在你的主导设计下要可以做出高并发的网站。换到其他行业也与此类似,从产品的的角度往回看,架构师要能解决和技术相关的所有问题,主导完成商业上有价值的产品或项目的开发工作。实现手段上倒并无限制,可以是购买,可以是组织人员进行开发,只要能平衡短期和长期利益,解决特定的问题即可。
路径二:由程序员而CodeGuru
与架构师相对应,在某些智力密集型的程序中,也需要技能高超的程序员,这种程序员往往被称为Guru。
这条路线里,程序员并不把自己擅长的领域扩的太宽,但在指定领域上会挖掘的很深。驱动、字库、图形库、算法库、OCR等都偏向于这一领域。
假如说,一个程序员在掌握基本语言之后,想往这个方向发展,那么需要的技能和架构师差别很大。比如:一个人如果想往驱动方向发展,那么就需要了解CPU的基本结构、内核调试方式、操作系统中与相应驱动所对应的机制、硬件侧的规格、通讯协议等。
这时候很可能由于程序规模并不十分庞大,面向对象、设计模式这类东西没有太大发挥空间,而是需要处理的是大量或麻烦或艰深的细节。
2013年1月,ITeye发布了一条信息说:Intel面向学生免费提供 C++ 开发工具,并简单的介绍了一下是那些工具免费向学生提供:
Intel C++ Composer XE,其中包括:
Intel C++编译器(高度优化的编译器)
Intel数学核心函数库(高性能数学库)
Intel线程构建模块(C++任务模型、最流行的C++并行方法)
Intel集成性能基元(多媒体基元库)
Intel Advisor XE(推荐的并行开发建模方法)
Intel VTune Amplifier XE(非侵入性的性能分析工具)
Intel Inspector XE(先进的线程和内存调试工具)
看到这张列表,我们可以思考下要开发这类工具需要什么样的程序员。上面这些工具的开发都属于高难度的工作,和开发大规模的MIS系统完全不同,如果不是某方面的专家,基本不太可能负担起相应的责任。而这类领域则正是Guru的天下。
路径三:由程序员而纯管理
纯管理工作和技术管理工作可以用是否接触乃至编写代码来区分。纯管理工作往往需要把精力放在预算编制、人员职业路径、考评、度量、流程改善这些工作上。一定程度上讲,这等价于和编程工作说拜拜,当然前提是你得有编程经验,有一些通用领域知识和概念创建乃至逻辑优化的知识,否则的话和程序员没法沟通,进而给工作造成障碍。
从需要读的书来看,这时候可能要看过PMBOK,《项目管理修炼之道》,《管理的实践》,《基业长青》等等。
但如果一个人认为想做管理要从PMP开始,那大概是还没太明白管理这项工作的本质。管理本身是一种借势,虽然有技术性的一面,比如要理解挣值曲线这类,但这方面知识其实并没有想的那么复杂—至少没有C++11复杂,只要有时间正常智商的人都可以在不太长的时间内掌握。所以如果你想做管理,并使用了和学习C++语言一样的方法,那基本上是偏离了方向。
抛开机缘这类东西不论,做好管理工作有两点很关键:
一是要把技术工作做的相对比较好。这好像有点学而优则仕的意味,但大多时候人们更愿意相信“将军起于行伍,宰相拔于州郡”,而不愿意相信单只会耍嘴皮子的人。过度务实的人容易迷失于道路,过度务虚的人则容易飘的太高而丧失根基。管理者正应该身处在这两者之间的一个平衡点。
二是要能够借势。要情商比较好,能把很多人组织在一起。这个时候要知道那些东西需要规则化,那些东西需要灵活把握。过度偏向规则是教条,过度偏向灵活则是人治,平衡点始终要根据具体人员的状况,工作特质这些不可改变的事情来把握。这有点微妙。但即使程序员这个群体相对简单,但并不能推翻先人后事这类规则。这不知道是不是东方特色,当你想做管理并想推进事情的时候,终究要理清人际上的关系,否则就和可能会欲速则不达。这点会在第五章进一步展开来谈。
下面我们来看一个具体点的例子,这个例子出自郭致星老师的博客,是一个学员的真实疑问(文字上有修饰),X入职后的现状如下:
开发部现在26个人。基本组织架构是由开发组、需求组、测试组、运维部四个部门组成。需求组的人收集需求,再通过系统指派给开发组,进行开发。开发组的文档严重缺乏。
现在公司内有技术总监和开发部经理的岗位。眼下全公司就X一个项目经理,目前是跟着开发部经理,在熟悉一个核心系统,由于没有任何文档的遗留,所以现在是相当于一个开发人员在开发一些实际的功能,一边开发一边熟悉现有系统。
现在X并没有项目的实际权力,而且整个项目组也只有开发部经理,加上2个开发,再加上1个测试和X共5个人。其中X和其中一个开发都是新来的。
与此同时,业务部门在搞一些流程,但还没做完,没有在开发部进行实施。工作气氛比较沉闷。技术总监和开发部经理,都是技术型的人,比较偏向技术,平时工作也多偏向于具体执行。
在使用一个Redmine系统进行项目管理和BUG跟踪。
这里的系统大部分都类似于产品线制,属于需要长期开发维护的,需求源源不断的来,相应人员也就需要不停的做,没有版本制度,也没有计划和规划。
系统现在主要的问题是性能问题。
问题就是在这样的一种环境下,X应该如何开始自己的管理工作?
这类问题通常并没有唯一答案,但确实有些通行的手段可供参考,最终做不做的好和个人能力乃至环境关联很紧:
1.了解现有系统的状况,包括规格、代码规模、代码质量、代码内部结构、工作流程、问题所在等。比如说:很可能这类系统缺乏一种整体设计,是靠单纯的增加代码的量堆积出来的,代码冗余非常厉害,数据库的表也创建的比较随意。
2.了解人员。包括人员的能力水平、工作意愿状况、性格。
3.了解公司。尤其是公司的运作风格,有的公司偏人治有的公司偏于规则。短期对这类现行秩序要考虑如何顺应,而不是如何改变。
4.对当前系统的状况和人的状况有所把握后,要对愿景进行描画,比如在功能上做那些改善,对速度做如何改善,目标的高低要适度,要能获得上司和下属的支持。这时候还要能平衡短期和长期目标,既不能长时间投入没有产出,也不能有产出但进步不可见。在这一步骤里最典型的忌讳是急功近利的做超出自己影响力范围的事情。比如:目标与现有人员的能力完全不匹配或者完全不顾及对销售可能产生的影响而单纯的做系统的优化。最理想的情形是,连续达成几个目标,提升自己的影响力。
5.搞清楚团队成员和公司的的基本诉求,在取得成绩的同时尽可能双赢的扩大自己的影响力,目标是确保团队的执行力。
6.逐步导入基本流程,使项目上轨道。但流程不能成为成绩的借口。
7.接下来进一步的规划愿景,看能否取得更大的成绩,比如:挑战是否能做出真正有特色比较优异的产品。
在不同类型的公司里,对应手段上会有不同。比如在规范性比较强的大公司,第4,5两步的权重就会比较低。在上述这样的场景下,PMP这类书籍中所提到的种种技术手段诚然是必要的,但和人打交道的部分(老板、直属上司、下属)往往会对最终的结果产生更大的影响,这是管理工作与纯粹技术工作不同的地方。