科学表明女性更适合当程序员:男码农情何以堪

文章来源:煎蛋

美国的研究人员分析了开源项目共享服务Github里约140万用户的资料。他们发现女性提出的请求代码合并通过率比男性更高。该研究正在等待同行评议。这意味着这一结果尚有待其他专家点评。

这些来自加州州立理工大学和北卡罗莱纳州立大学的研究人员们,从2015年4月1日登入Github中的400万名用户中抽取了140万名用户。Github是一个庞大的开发者社区,并不要求其1200万用户填写性别信息。

不过该团队依旧能够辨别他们抽取的这140万人的性别,因为用户资料或者他们的邮箱地址都能透露蛛丝马迹。研究人员们也承认这有隐私风险,因此他们并不打算公布原始数据。

该团队发现女性提出的请求代码合并接受率为78.6%,而男性提出来的仅74.6%。研究人员们考虑了各种因素,比如女知道某些问题的可能性是否更高,她们贡献的代码更短或者她们做的任务更容易以及她们使用的编程语言等等,但研究人员没有找到相关联系。

然而那些在Github社区里并不出名的人中,性别资料显示自己是女性的人提出的请求代码合并通过率比那些性别不明显的人低得多。

性别偏见

从局外人的角度来看,我们看到了性别偏见的痕迹:当女性的性别资料中立的时候,她们提出的请求代码合并通过率为71.8%,可一旦她们表明自己是女性,她们的通过率立刻降至62.5%。男性的通过率也有相似的下降,但并没有这么明显。

总体来看女性提出的请求代码合并通过率比男性更高,可当她们成为外来者且她们的性别可被鉴定出来的时候,她们的通过率比男性低。研究人员们总结道:“我们的结果表明虽然Github里的女性总体来说更能干,但她们还是会遇到性别偏见。”

虽然有各种高调的倡议,但科技公司依旧面临着员工多样性的问题(从性别和种族这方面来看)。根据2015年的数据,脸书的技术人员里仅16%为女性,谷歌仅18%。

计算机科学家Sue Black OBE博士表示,即便如此这一结果依旧令人鼓舞。她说:“我认为这些表明女性对编程的兴趣在复苏,在接下来的几年时间里,女性也会慢慢对其它与技术相关的 职业感兴趣。知道女性擅长编程,会让更多女性进入科技领域工作。最开始提出软件概念的Ada Lovelace也是一名女性,知道这一点才能更好地鼓励并支持女性进入软件行业。”

开源项目的正确打开方式:如何发明完美符合自己业务特点的轮子?

2016-02-25 技术社区 InfoQ

「不重复造轮子」是软件开发的原则之一,在速度就是生命的互联网领域,越来越多的公司引入开源项目。但是,贵司真的清楚开源项目的正确打开方式吗?

软件开发领域有一个流行的原则:DRY,Don’t repeat yourself,我们翻译过来更形象通俗:不要重复造轮子。开源项目主要目的是共享,其实就是为了让大家不要重复造轮子,尤其是在互联网这样一个快速发展的领域,引入开源项目,可以节省大量的人力和时间,大大加快业务的发展速度,何乐而不为呢?

然而现实往往没有那么美好,开源项目虽然节省了大量的人力和时间,但带来的问题也不少,相信绝大部分同学都踩过开源软件的坑,小的影响可能是宕机半小时,大的问题可能是丢失几十万数据,甚至灾难性的事故是全部数据都丢失。

除此以外,虽然DRY原则摆在那里,但实际上开源项目反而是最不遵守DRY原则的,重复的轮子好多,尤其是国外,一看哪个开源方案不爽,自己就吭哧吭哧搞一个差不多的:你有MySQL,我有PostgreSQL;你有MongoDB,我有Cassandra;你有Memcached,我有Redis;你有Gson,我有Jackson;你有Angular,我有React。总之放眼望去,其实相似的轮子很多!相似轮子太多,选择就是让人头疼的问题了。

怎么办?完全不用开源项目几乎是不可能的,我们需要更加聪明的去选择和使用开源项目。形象点说:不要重复发明轮子,但要找到合适的轮子!你开的是保时捷,可别找个拖拉机的轮子。

接下来我将根据加入UCWeb 5年与开源项目有关的经历,总结出一些“如何正确使用开源项目”的经验和教训。有的项目是我亲身经历,有的是我接触到的,有的是我观察的,其中部分描述细节可能并不完全准确,大家可以结合自己的经历一起探讨。

以下内容主要分3个部分进行描述,分别是「选」、「用」、「改」。

三字诀之「选」
如何正确选择一个开源项目?

1.聚焦是否满足业务

我们在选择开源项目的时候,一个头疼的问题就是相似的开源方案较多,而且后面的总是要宣称比前面的更加牛逼。我们在选择的时候有点无所适从,总是会担心选择了A方案而错过了B方案,或者反过来。这里我们的经验是聚焦于是否满足业务,而不需要过于关注开源方案是否牛逼。

案例:当时尝试一个社交类业务时,我们发现了TT(Tokyo Tyrant)这个开源方案,觉得既能够做缓存取代Memcached,又有持久化存储功能,可以取代MySQL,很牛逼,很高大上,于是就在业务里面大量使用了。但后来的使用过程让人很蛋疼,主要表现为:

  1. 不能完全取代MySQL,因此有两份存储,设计的时候每次都要讨论和决策。
  1. 功能上看起来很高大上,但相应的bug也不少,而且有的bug是致命的,例如所有数据不可读,后来是自己研究源码写了一个工具才恢复了部分数据。
  1. 功能确实牛逼,但需要花费较长时间熟悉各种细节。
  2. 后来我们反思和总结,其实当时的业务Memcached + MySQL完全能够满足,且大家都熟悉,当时的业务完全不需要引入TT。

简单来说:如果你的业务要求1000 TPS,那么一个20000 TPS 和50000 TPS的方案是没有区别的。有的人可能会担心我TPS不断上涨怎么办?其实不用担心,我们的架构会不断演进的,等到真的需要这么高的时候我们再来架构重构,记住:不要过早优化,过早优化是万恶之源 —— 《UNIX编程哲学》

2.聚焦是否成熟

很多新的开源项目往往都会声称自己比以前的项目更加牛逼:性能更高、功能更强、引入更多新概念。看起来都很诱人,但实际上都有意无意的隐藏了一个负面的问题:都更加不成熟!不管多牛逼的程序员写出来的项目都会有bug,千万不要以为作者牛逼就没有bug,Windows、Linux、MySQL的开发者都是顶级的开发者吧,一样很多bug。

不成熟的开源项目应用到生产环境,风险极大。轻则宕机,重则宕机后重启都恢复不了,更严重的是数据丢失都找不回了。还是以上面提到的TT为例:我们真的遇到异常断电后,文件被损坏,重启也恢复不了的故障,还好当时每天做了备份,于是只能用1天前的数据进行恢复,但当天的数据全部丢失了。后来我们花费了大量的时间和人力去看源码,自己写工具恢复了部分数据,还好这些数据不是金融相关的数据,丢失一部分问题也不大,否则就有大麻烦了。

所以在选择开源项目的时候,尽量选择成熟的开源项目,降低风险,形象点说:宁要2.0的熟女,不要0.2的处女!一般建议除非特殊情况,否则不要选0.X版本的,至少选1.X版本的,版本号越高越好。

3.聚焦运维能力

我们在选择开源项目的时候,基本上都是聚焦于技术指标,例如性能、可靠性、功能这些方案,而几乎不会去关注运维方面的能力。但如果要将方案应用到线上生产环境,运维能力是必不可少的一环,否则一旦出问题,运维、研发、测试都只能干瞪眼,求菩萨保佑了!

可以从以下几个方案去考察运维能力:

  1. 开源方案日志是否齐全:有的开源方案日志只有寥寥启动停止几行,出了问题根本无法排查。
  1. 开源方案是否有命令行、管理控制台等维护工具,能够看到系统运行时的情况。
  2. 开源方案是否有故障检测和恢复的能力,例如告警、倒换等。
三字诀之「用」
如何正确使用开源方案?

1.深入研究,仔细测试

很多人用开源项目,其实是完完全全的“拿来主义”,看了几个Demo,把程序跑起来就开始部署到线上应用了。就好像看了一下开车指南,知道了方向盘是转向、油门是加速、刹车是减速,然后就开车上路了,其实是非常危险的。

案例1:我们有团队使用了elasticsearch,基本上是拿来就用,倒排索引是什么不太清楚,配置都是用默认值,跑起来就上线了,结果就遇到节点ping时间太长,剔除异常节点太慢,导致整站访问挂掉。

案例2:UC很多团队最初使用MySQL的时候,也没有怎么研究过,经常有业务部门抱怨MySQL太慢了,其实经过定位,发现最关键的几个参数(例如innodb_buffer_pool_size, sync_binlog,innodb_log_file_size等)都没有配置或者配置错误,性能当然会慢。

可以从如下几方面进行研究和测试:

  1. 通读开源项目的设计文档或者白皮书,了解其设计原理。
  1. 核对每个配置项的作用和影响,识别出关键配置项。
  1. 进行多种场景的性能测试。
  1. 进行压力测试,连续跑几天,观察cpu、内存、磁盘io等指标波动。
  2. 进行故障测试:kill,断电、拔网线、重启100次以上、倒换等。

2.小心应用,灰度发布

假如我们做了上面的“深入研究、仔细测试”,发现没什么问题,是否就可以放心大胆的应用到线上了呢?别高兴太早,即使你的研究再深入,测试再仔细,也还是要小心为妙,因为再怎么深入的研究,再怎么仔细的测试,都只能降低风险,但不可能完全覆盖所有线上场景。

案例:还是以TT为例吧,其实我们在应用之前专门安排一个大牛看源码、做测试,做了大约1个月,但最后上线还是遇到各种问题。线上生产环境的复杂度,真的不是测试能够覆盖的,必须小心谨慎。

所以,不管研究多深入、测试多仔细、自信心多爆棚,时刻对线上要有敬畏之心,小心驶得万年船。我们的经验就是先在非核心的业务上用,然后有经验后慢慢扩展。

3.做好应急,以防万一

即使我们前面的工作做得非常完善和充分,也不能认为就万事大吉了,尤其是刚开始使用一个开源项目,运气不好的话就可能遇到一个之前全世界的使用者从来没遇到的bug,导致业务都无法恢复,尤其是存储方面,一旦出现问题无法恢复可能就是致命的打击。

案例(此案例是听说的):某个业务使用了MongoDB,结果宕机后部分数据丢失,无法恢复,也没有其它备份,人工恢复都没办法,只能接一个用户投诉处理一个,导致DBA和运维从此以后都反对我们用MongoDB,即使是尝试性的。

虽然因为一次故障就完全反对尝试是有点反应过度了,但确实故障也给我们提了一个醒:对于重要的业务或者数据,使用开源项目时,最好有另外一个比较成熟的方案做备份,尤其是数据存储。例如:如果要用MongoDB或者Redis,可以用MySQL做备份存储。这样做虽然复杂度和成本高一些,但关键时刻能够救命!

三字诀之「改」
如何基于开源项目做二次开发?

1.保持纯洁,加以包装

当我们发现开源项目有的地方不满足我们的需求的时候,自然会有一种去改改的冲动,但是怎么改是个大学问。一种方式是投入几个人从内到外全部改一遍,将其改造成完全符合我们业务需求。但这样做有几个比较严重的问题:

  1. 投入太大,一般来说,redis这种级别的开源方案,真要自己改,至少要投入2个人,搞个1个月以上。
  2. 失去了跟随原方案演进的能力:改的太多的话,即使原有开源项目继续演进,我们也无法合并了,因为差异太大。

所以我们的建议是不要改动原系统,而是要开发辅助系统:监控、报警、负载均衡、管理等。以Redis为例,如果我们想增加集群功能,不要去改动Redis本身的实现,而是增加一个proxy层来实现,Twitter的Twemproxy就是这样做的,而Redis到了3.0后本身提供了集群功能,原有的方案简单切换到Redis 3.0即可。

如果实在想改到原有系统,怎么办呢?我们的建议是直接给开源项目提需求或者bug,但弊端就是响应比较缓慢,这个就要看业务紧急程度了,如果实在太急那就只能自己改了,不过不是太急,建议做好备份或者应急手段即可。

2.发明你要的轮子

这点估计让很多人大跌眼镜,怎么讲了半天,最后又回到了「重复发明你要的轮子」呢?

其实选与不选开源项目,核心还是一个成本和收益的问题,并不是说选择开源项目就一定是最优的方案,最主要的问题是:没有完全适合你的轮子!

软件领域和硬件领域最大的不同就是软件领域没有绝对的工业标准,大家都很尽兴,想怎么玩怎么玩,不像硬件领域,你造一个尺寸与众不同的轮子,其它车都用不上,你的轮子工艺再高,质量再好也是白费;软件领域可以造很多相似的轮子,也基本上能到处用,例如你把缓存从Memcached换成Redis,不会有太大的问题。

除此以外,开源项目为了能够大规模应用,考虑的是通用的处理方案,而不同的业务其实差异较大,通用方案并不一定完美适合具体的某个业务。比如说Memcached,通过一致性hash提供集群功能,但是我们的一些业务,缓存如果有一台宕机,整个业务可能就被拖慢了,这就要求我们提供缓存备份的功能。

但Memcached又没有,而Redis当时又没有集群功能,于是我们投入2~4个人花了大约2个月时间基于LevelDB的原理,自己做了一套缓存框架支持存储、备份、集群的功能,后来又在这个框架的基础上增加了跨机房同步的功能,很大程度上提升了业务的可用性水平。如果完全采用开源方案,等开源方案来实现,是不可能这么快速的,甚至都有可能开源项目完全就不支持我们的需求。

所以,如果你有钱有人有时间,投入人力去重复发明完美符合自己业务特点的轮子也是很好的选择!毕竟,土豪们很多都是这样做的,否则的话我们也就没有那么多好用的开源项目了。


本文首发于阿里百川公众号,授权InfoQ发布。

如何从菜鸟程序员成长为高手

2016-02-24 蛋疼的axb ACSE
关注上方“ACSE”来及时了解中国理工科留学生联盟的最新动态以及新鲜科技好文章
小编有话说
从今天开始ACSE公众号每天会更新一篇科技相关的精选好文章来帮助大家了解科技前沿以及提高自己的技术水平。
今天这篇文章是由大神级别程序员总结的学习方法,值得收藏起来每周看一遍,只要照着一一做到,总有一天能够成为高手。
1.摘要
最近有一些毕业不久的同事问我:“你工作的时候有没有什么窍门?怎么才能快速成为高手?”
想起当初刚入职,新人培训的时候,也跟其他同事讨论过这个问题:如何才能成为业界大牛?当时自己只是觉得兴趣是最好的老师,思路方法什么的没有多想。
加 入微博平台架构部的时间也不短了,趁着快过春节总结了一下自己入职微博以来的工作情况,从互联网开发的半个门外汉,到如今能设计一些架构、排查一些问题、 分享一些经验,收获颇多,感想颇多,也逐渐意识到思路和方法的重要性,在此跟大家分享一下。主要分为学、做、想三方面。
2.学会学习
学习无疑是程序员最为重要的素质之一,尤其是互联网这种日新月异的行业,把学习当做工作的一大半也不为过。
2.1.自主学习
最近发现身边的人并不是不想学习,只是每天都在纠结自己到底学什么好:简单的没挑战,复杂的看不懂;旧技术怕过时,新技术没方向…… 
讲 讲自己毕业后的经历,毕业之后去了个不大不小的公司,工作主要是做一些XX管理系统之类的东西,没什么挑战,也用不上什么技术,基本上前端用个extjs 后面套个sql server就解决了。工作稳定了几年,业余时间除了wow没别的事情做,觉得这么闲下去不是办法,于是之后一年的时间里,用上班摸鱼和下班休息的时间学 了这些东西:
1. 闲着无聊想做个小游戏,发现游戏相关的书大多是英文的,看不懂,一咬牙翻译了《Real-time rending 3rd》的前几章,刚开始前言都看不懂,只能一个词一个词的翻字典,一句话要琢磨几个钟头到底作者说的到底是什么意思。翻译了几百页英文书之后,发现自己 看英文书没什么障碍了,于是开始每天用休息和摸鱼的时间看书。
2. 看完游戏引擎的书之后,把irrlicht引擎的代码看了一遍,然后自己山寨了一个3d渲染的场景管理器,还有个朴素的渲染引擎。
给自己的游戏引擎写了个基于脚本语言的解释器,为此看了不少编译原理和虚拟机的书,了解了程序究竟是什么东西,这是我觉得收益很大的一件事情。
3. 看编译原理的书的时候发现操作系统的知识有些欠缺,又去看了linux内核相关的书。之后买了个开发板天天修改内核玩,毕业以后又一次了解了内核的cpu 调度、内存管理和文件系统,了解了应用是怎么跑在操作系统上,操作系统又是怎么运行在硬件上的,这也是收益很大的一件事情。
4. 看完操作系统又顺着看网络相关的书,之后把lighthttpd的代码看了一遍,用c写了个linux下的http服务器,把几种网络编程模型挨个实现了一遍。
5. 实现http服务器的过程中觉得自己编码能力还是有欠缺,把代码大全翻了一遍,顺着又去看了设计模式的书,并且用自己的理解把每个模式用文字重新描述了一遍。
6. 中间还看了很多语言和框架相关的书,就不一一列举了。可以参考这里。
我把学习的方向分为三类:
1. 为了工作,满足当前工作所必备的知识
2. 为了提升,与当前工作相关的知识(深度)
3. 拓展视野,与当前工作无关的知识(广度)
学习(1)之后只是个熟练工,2和3才是提升自己的途径,伴随着知识储备的提升,接触新事物时更容易找到相似的知识加以类比,加快理解,也更容易掌握本质。如果每天都在纠结“到底学什么”,那么只能说明还是学的太少了。(真正没什么可学的大牛们应该不会读到这里吧……)
所 以,如果觉着没什么东西可以学的时候,那么可以考虑一下学一下更有深度的知识(比如虚拟机或编译器),或者完全不同的知识(新的语言或当前比较火的方 向),甚至完全不相干的知识(单纯练习英文阅读,学习ppt排版之类)吧。随着知识储备增加,自己的不足和未来的学习的方向也会更加明确起来。
2.2.向历史学习
以微博为例,在微博发展的过程中经历了不少波折,并逐渐衍生出了目前的系统架构。很多新人最喜欢问的问题便是“现在线上是怎么做的?”
这 个问题不错,但是还不够好。在程序员的世界里罕有能解决所有问题的“银弹”,当前的做法用不了多久也会被替换掉,如果想了解一件事情,那么就多关注一下 “它是怎么变成今天这样的”吧。学会用发展的眼光看问题,了解一些经历过的经验教训,收获会比单纯学会一件什么事情多的多。
那么,如何向历史学习?
1. 公司内部的资料库、wiki等大都会有旧时的资料,刚入职时大多不会太忙,这些资料库简直是挖不完的宝藏
2. 部门内部分享,比如我当初入职时经常去听“微博XXXX架构演化历程”之类的内部分享
多问一下自己”它为什么不那么设计“
3. 老员工忆苦思甜吹牛逼的时候多奉承几句_(:з」 ∠)_
2.3.向他人学习
这里有两个极端,
1. 有的人喜欢自己闷头捣鼓,什么也不问,这必然是不利于自己提高的;
2. 也有人碰到问题就问,这也有问题,浪费他人时间不说,更关键的是说明这人向他人学习的思路错了,要学习他人的并不是具体某个知识(要学知识看书就能解决了),而是学习别人的思维方式。
但是思维方式这种东西很难通过交流的方式学到,后来我发现有个很简单的学习方式:口头禅。举几个例子,大家体会一下:
“这个其实是两个问题”
“有没有更好的方案”
“能不能举个例子”
“能不能给个一句话总结”
除了口头禅,很多牛人都会有非常鲜明的思维方式和处事原则,如果有幸与业界的大牛共事,那么恭喜你,只要多交流、多观察、多思考,那么提升速度会提升好几个数量级。
3.多做有意义的事情
有的人每天时间浪费在跟问题本身无关的事情上,比如我要设计架构的时候还要考虑架构图怎么画,写完代码还要反复部署测试好几轮才pass,查bug的时候把时间浪费在扫日志上。人的精力总是有限的,把时间浪费在这些事情上面,让自己提高的时间就变得少了。
3.1.练习,更多的练习
这里有个误区:“做有意义的事情”不等于“只做自己没做过的事情”。
对于程序员来说,写代码是基本功中的基本功,编码的规范、设计的权衡、甚至顺手的IDE快捷键都要靠平日的试错和积累,很难通过几本书或者几天培训领悟到。
曾 经目睹一些人写代码一年之后开始做一些小项目的设计,然后就迫不及待的把重心全都转移到设计甚至架构上,这种没有基础能力支撑做出的设计和架构最多只能算 是高级意淫,大多没等落地就荒废了,意义不大。究其原因,大多是设计出来的东西“不好做”或者“不好用”,就像是只看过一遍课本就去参加高数考试,现实 吗?(学霸们我错了……)
举 个例子,几年前在看设计模式的过程中,用qt做了个看漫画的应用,把能用的模式都试了一遍,当然有很多用的不合适的地方,正是这些不合适的地方让我对面向 对象编程和设计模式的思考深入了很多,如何权衡灵活性和复杂性也有了新的认识。之后在设计很多系统的时候少走了很多弯路,既保证了时间点又保证了质量。如 果当时指望着“用的时候再说”,大概已经被项目坑的不能自理了。
3.2.善用工具
工具能解决的事情就用工具去解决,好的工具能节约大把的时间用在更有意义的事情上。
工具的范畴很广,比如linux的各种命令、比如团队内部的各种系统、比如顺手的应用、甚至包括上下班骑的自行车。只要能节约时间、提高效率,那就值得一试。
在这里我列举几个大幅度提升了我的效率的东西:
1. 双屏显示器
2. 顺手的键盘
3. google(不是baidu!不是bing!)
4. mac
5. mac上的应用:idea、alfread、omnifocus、甚至synergy和istats menus之类跟开发本身关系不大的应用。
我更倾向于把“使用工具”作为一种生活态度:是否希望让自己的生活专注于有意义的事情。如果你认同这个观点,那么想一想投入和回报比例,还是很可观的。
(当然,为了不花钱而自己破解应用的大神也是极叼的……)
3.3.提高时间的利用率
时间是所有期待提升自己的人最宝贵的资源,效率再高,没时间做也没意义。
网上有个流传挺广的图:打扰程序员的成本。事实上我每天的工作时间非常碎片化,来到公司之后可能不断的接电话、被问问题、被拉去开会、回复邮件等等;也经常会有时间不够用或者没事做的困惑,这里分享一下心得:
1. GTD可以整合很多碎片时间。除了把事做完之外,把上下文相关的事情集中在一起完成也很有帮助。比如把几件想去其他办公室做的事情整合成一趟完成。
2. 减少无意义的时间浪费,比如家住在公司边上可以每天节省几个小时的时间用来学习或者做别的事情。(但如果节省下来的时间用来刷微博,那就没有必要了。)
另外一个很有趣的现象:一个软件的注册费就10几刀,贵些的几百刀,把日常用到的所有工具的费用全加起来都顶不上一个肾6贵,但是很多人还是坚持着没有破解不用的观念,为了几百块钱浪费了大把时间。
3. 加班可以创造很多时间,并且能有效减少被打扰的几率,但是也会给身体和精神带来很大负担。因此加班做的事情必须能对个人进步产生足够多的收益。如果加班只是用来处理无意义的工作的话,那应该是日常工作出了什么问题。
4. 事情可以分成紧急重要、紧急不重要、重要不紧急、不重要不紧急四类,在todo列表里随时要有重要不紧急的事情。
4.学会思考
4.1.深究
当有什么问题解决不了的时候,很多人会有畏难或者拖延的情绪,典型口头禅就是“就这么凑合着用吧”或者“先这样吧,以后有时间再研究”,说这些话的人大多并不是真的那么忙,甚至有人一边刷着微博一边跟我说没时间研究……(你tm在逗我?)
要克服畏难情绪其实很简单,找一个具体的似懂非懂的问题,想尽办法把问题研究清楚,体会几次解决问题时的愉悦感,建立自信。
大部分问题其实没有什么高深的科学原理,甚至只要翻几页书就解决了,但是遇到问题不深究,久而久之会形成自我暗示:这些问题是我懂的,那些是我不懂的,自己反而把自己进步的路给堵上了。
说到如何深究,也有几条心得:
1. 遇事多想为什么,并且要反复问为什么。很多貌似理解了的问题过一阵再重新想想,往往会发现之前还有没考虑到的地方
2. 问题要有明确答案,哲学之类的就别纠结了
3. 查找资料时选权威的书籍或者网站,避免被误导
4. 找人讨论,或者直接拉小伙伴入伙,既可以互相交流,又可以互相监督
5. 分享你的成果
6. 不要所有事情全都深究,会给自己太多压力
4.2.多说,多写,多交流
平常工作中有一个感受,有交流和写作习惯的人思路会更清晰一些,能接触到的观点也会多一些。这方面其实属于我的弱项,大概总结几个观点。
1. 隔一段时间最好能书面形式总结一下最近的工作,比如说写个心得感悟,或者持续更新自己的简历
2. 写作的时候有两个难点:对要说明的事情做总结和抽象,形成观点统一、调理清晰的主线;从对方的视角考虑,把事情说明白,避免自言自语。
3. 找人讨论之前自己先要有个基本完整的思路,否则大部分的时间都要耗在解释原理之类的上网查反而更快的事情上。
4. 讨论之后要有一句话就能说明白的结论和描述清晰的时间点。
5. 有些人喜欢纠结于“这个不是我的问题,为什么要我处理”之类的事情。在我看来这是很好的机会。既能增长见识,又能展示水平,还能留个认真负责的好名声,何乐而不为呢。
5.最后
最后分享一下关于我理解的程序员的自我修养,在我看来,可以总结为:负责任,重名声。
负责任,说的更具体些:写的代码自己有没有测过、做的框架自己有没有用过、设计的架构自己有没有认真权衡过。
重名声,说的直接些:没有测过的代码、没有用过的框架、没有权衡过的方案有没有脸交付给别人。
与各位共勉。
作者:蛋疼的axb

原网址:http://blog.2baxb.me/archives/1077
中国理工科留学生联盟(ACSE)
致力于推动留美各校理工科留学生间的相互交流以及资源共享和对接

程序员,你的安全感呢?

作者:杨栋

链接:http://www.cnblogs.com/yangdong/p/5190818.html

同病相连

最近跟一位同事谈心,他非常热爱技术,是一个不折不扣的极客,不仅如此他有很强的执行力,并能持之以恒,从他的身上我看到了未来几年将会成长起来的一个技术牛人。但是,他有比较严重的焦虑症,比如:几天没有看书就会非常纠结,通常情况是他需要花时间来陪孩子和家人,他会感觉自己浪费了宝贵时间,精力无法集中在当前所做的事情上。我接触的同事中,越是对技术有追求,好像越是有这样的感觉,算起来这种不安的感觉应该属于特定程序员群组中一种典型现象,其实做为导师的我也是常年被这种感觉所困扰。 他是这么描述自己的:

我已经工作4年了,但是我在数据库底层,HTTP协议,并发,分布式系统都没有深入地理解,我觉得特别害怕。

不用讨论工作4年的程序员应该有什么样的表现,掌握多上技术,深度如何,视野是否开阔,我们来看看别人眼中的他吧:

  • 对技术极度有热情
  • 学东西非常快,几周时间就搞定了Ansible, Chef, Puppet
  • 阅读非常广,除了技术之外,涉足项目管理,金融,心里,社会等

看看他的书单(我截取了其中1/4的一年要读完的书单,实际上他读完的书比计划要多),也会对他有更深刻的认识:

  • 像外行一样思考,像专家一样实践:科研成功之道(修订版)
  • 古今数学思想(新版·典藏本)(套装全3册)(第1~3册)
  • 思考,快与慢
  • 数据化管理:洞悉零售及电子商务运营
  • 探索复杂性
  • 日志管理与分析权威指南

心理学上的安全感

安全感是心理学研究中的重要概念之一,最早见于弗洛伊德精神分析的理论研究。虽然国内外对此做过诸多研究,然而对于“安全感”至今尚未达成共识,以下列举了一些关于安全感的定义:

  • 弗洛伊德认为当个体所受到的刺激超过了本身控制和释放能量的界限时,个体就会产生不安全感。换句话说,在弗洛伊德的精神分析理论中,冲突、焦虑、防御机制等是由个人幼年、成年阶段某种欲望的控制与满足方面缺乏安全感造成的。
  • 人本主义心理学家马斯洛最早对安全感作出了明确界定,指出“安全感”是一种从恐惧、焦虑中脱离出来的信心、安全和自由的感觉,特别是满足一个人现在和未来各种需要的感觉。
  • 安莉娟等对精神分析理论、人本主义心理学理论中的安全感理论进行总结,提出安全感的定义为:安全感是对可能出现的对身体或心理的危险或风险的预感,以及个体在应对处置时的有力无力感,主要表现为确定感和可控制感。

从以上的定义我们大致能够看出安全感大致有两大要素:负面的外部刺激,正面的内在能量。简单来说当内部能量能够抵消负面的外部刺激,人是有安全感,因为我的“能量结界”没有消散,反之则没有安全感,没有人会在“能量结界”被打穿之后还怡然自得。那么这个“能量结界”的大小就是所谓的舒适区域了,如果用绿色表示很安全的话,那么舒适区域应该是中心是深绿色周边是浅绿色的圆。理所当然,随着它的范围的增大,个人的舒适区域也就不断的增大。

为什么会焦虑

人为什么会焦虑,当某一件能够刺激内心产生负面影响的事情发生时,人们就有可能会产生焦虑的情绪。这是一种缺乏安全感的情绪和典型表现。在学生时代,我们会因为惧怕考试失败而焦虑;在职场上,我们会因为无法完成某项工作而焦虑;在孩子的教育过程中,我们会因为担心无法找到合适的学校而焦虑;在人到中年时,我们为因为身体的退步而焦虑。因为我们无法确定能否处理这种情形。因此对于一些场景,我们到会显得十分从容,“开卷考试,有书在手心中无忧”,“跟自己的下属沟通绩效问题,轻车熟路”,“住在一个教育资源较为发达的地区,孩子的教育问题就显得不那么明显”,“每天花半小时来做慢跑,非常显著的改善身体状况”。

奇普•康利(Chip Conley)在他的《如何控制自己的情绪》很好的阐释了为什么会焦虑:

焦虑 = 不确定性 * 无力感

在讲述如何控制焦虑者众情绪时,他分享了一段TED上的经历:

TED曾要求我谈谈幸福的无形资产,以及商界和政界领导人应如何开始学习衡量和重视人生最有意义的东西。这似乎是一个无情的讽刺,我的任务是登上讲坛,以一个专家的身份,探讨一个那时连我自己都觉得难以捉摸的主题。尽管我在《巅峰》一书中宣称要以自我实践的方法来经商,但我已经失去了那种神奇的感染力。“我陷入了觉得自己无用的思维定式,而能够克服这一挑战的唯一办法就是写下有关我人生经历的演讲词并练习无数遍。我以为追求完美是缓解焦虑的良药。你也许有过类似的遭遇,认为设定目标会让自己舒服。但事实是,追求完美只会放大焦虑。在接下来的几个月里,我一直痛苦地写着一份以幸福为主题的演讲词,这一次和我正常准备演讲的经历完全不同。我的风格是倾向于即兴发挥和贴近听众,而非机械式和反复演练。于是越临近TED大会,我就变得越焦虑。我的演讲被安排在会议的最后一天(就在电影导演詹姆斯·卡梅隆之前)。所以当我抵达会场时,我还有5天痛苦难熬的日子,要在聆听其他演讲者发言中度过,这使我越发焦虑。”

因此,越是不确定或者超出自己能力的事情,焦虑的情绪就越容易产生,而越是这样,从这种焦虑情绪正挣脱的信心就越低,不安全的感觉就越强。

哪样的程序员更有安全感

每个人都有一个自己的舒适区域,结合内部舒适区域和外部期待,下图能说明一些问题:

根据上图所示,具有安全感的程序员一般长这样:

跃跃欲试,接受挑战, 扩展自己的舒适区。我们的身边总是不乏这样的人,他们跃跃欲试,脸上总是挂着自信的笑容,总是各种场合中的焦点,从来不满足现状,每每有新挑战时,总会看到他们的身影。 如果用动态的眼光来看待他们的话,我们会发现他们的舒适区域始终处于一个动态的过程——始终在扩张之中,或者说他们在不断GET新技能。随着舒适区域的扩张,个人追求不断实现,而个人追求的实现,又带动其自身的扩张,还有什么比实现自己目标多带来的自信和成就感更足呢。等待的,将是社会期待的增加,也就是你的同事,领导对你有了认可,并提升了他们对你的期待,随之而来的将是更有挑战的工作,又一个扩展自己舒适区域或者GET新技能的机会便发生了。

快速学习, 迅速减小社会期望和舒适区的差别。程序员的一个非常厉(ku)害(bi)的技能就是学习能力。除去被逼迫的成分外,这是一个非常实用,堪称看家本领之一。因为IT行业技术迭代速度之快令人发指,当某一项技术还没有熟悉的时候,关于该技术的缺陷以及改进方案已经吵的很热了;当你刚刚为掌握某个软件开发实践而洋洋得意时,突如其来的xxx已死之说,真是让你死的心都有了。其中的例子数不胜数,我们不妨看看(一个例子说明)。ThoughtWorks对员工有这么一个要求,每年至少学习一门编程语言,其实真是不多,实际上每年学习的都要远远多于要求。因此,强悍的快速学习能力,能够快速武装自己,胜任新的工作,提神核心竞争力,迅速扩大舒适区同时减小社会期望与其的差别。当然,并非所有新技术都值得学习,但是有两点值得提出:1. 新技术的思想能够扩展自己的视野,拓宽自己的思路;2.新技术的获取,能够大大提升自己的学习能力,你会越学越快,这个加速度会一直保持到你的大脑达到生理水平的巅峰。

很强的执行力, 减小不确定性. 它的反义词大概是“拖延症”,俗称懒病。某百科上给出了这样的解释:

严重的拖延症会对个体的身心健康带来消极影响,如出现强烈的自责情绪、负罪感,不断的自我否定、贬低,并伴有焦虑症、抑郁症等心理疾病,一旦出现这种状态,需要引起重视。

看到这里,相信很多人都中招了吧。无限的拖延,无法正面改变即将发生的事情,但是它却能极大的增加事情的不确定性,并且随着事情的临近,这种不确定性在内心中的焦虑反应呈指数级增长,反过来,这种情绪又反哺拖延,除非有强大的外部力量介入,强行打破这种负能量闭环。说的这么高端,有没有实际的例子呢。不仅有,而且非常多,很多人大概都有这样的经历吧,在年终总结的截止日期的前一天晚上,奋笔疾书加班加点的写总结,又或者在做演讲的前一天晚上,开始写PPT。

获取安全感

Rule #1: 学习那些自信满满地程序员们

当然也需要甄别一下啦,有的人可能只是看起来很自信。不过上面提到的三个特征应该是妥妥的能够提升你的安全感的办法。其实我在写这条建议是,很是纠结。纠结在哪呢?我觉得内心没有安全感的程序员极度“肤浅”的分成两类:懒和其他。据非常不负责任统计(看看周围的人),其实很多时候还是因为懒,如果是真的懒,那就没救了。

Rule #2: 通过焦虑情绪公式来提升安全感

发动数学天赋,当某人或事情让人感到焦虑时,这两件事情能够帮忙:

制作一张平衡表列出你知道的和你能影响的,它可以帮助你消除不确定性,去掉你对不知道的事情的神秘感,明确你所面临的是什么。因为焦虑只会潜藏在黑暗中,人们对不了解的事物有一种天然的恐惧,就好比美味的螃蟹在一开始的时候并不是每个人都敢吃的。然而黑暗中的不明事物也有可能真的是你所恐惧的事物也说不定,但这又有什么关系呢!当你知道原来在黑暗之中潜藏了一个恐怖猎人——霸王龙,你的对手已经清晰了,接下来要考虑的是你是否有能力对付的了它。你的焦虑情绪现在全部由无力感组成了。

当你把所有的相关因素归类到这四个象限后,也就意味着能够帮助你消除的计划产生了:你不需要对不能影响的事情做出任何反应,因为只是徒劳而已;你需要做两件事情,弄清楚那些不知道的因素,做一些能够对解决当前问题产生正面影响的行动。

想想最极端的结果,降低无力感,如果最快的结果也是能够承受的,那还有什么是输不起的呢,更何况通常最坏的结果都不是最坏的,最坏的是由最坏的结果所引发的内心恐惧,焦虑和不安的负面情绪。当然每个人的无力感是不同的,因为每个人的舒适区域是不同的,舒适区域越大,无力感想对会越小。这很好理解,因为从概率的角度来讲,你能处理的问题范围,把握度会随着舒适区域的增大而增强。但直面极端结果是一个普适的方法。一方面,往往当最坏的事情发生时,你却释然了,反而一身轻松,能够坦然面对。这正是该公式所表达的核心思想之一,当结果发生时,不确定性为0,焦虑的情绪得到了释放,你当然会前所未有的轻松,这也是为什么人们到了让TA抓狂的事情发生时,却能坦然处之,临危不乱。另一方面,想想最极端的结果,有助于你评估失败的代价,很多时候人都是被自己或者他人吓怕了,一旦评估的结果并没有那么不可接受,自然也就没有必要战战兢兢的过着了。

Rule #3: 匹配外部期待和个人能力

左图是一张耶基斯-多德森定律图,其中包含三个要素:效率,动机和任务难易程度。在一般情况下,动机愈强烈,工作积极性愈高,潜能发挥的愈好,取得的效率也愈大;与此相反,动机的强度愈低,效率也愈差。因此,工作效率是随着动机的增强而提高的。然而,心理学家耶基斯和多德森的研究证实,动机强度与工作效率之间并不是线性关系,而是倒U形的曲线关系。具体体现在:动机处于适宜强度时,工作效率最佳;动机强度过低时,缺乏参与活动的积极性,工作效率不可能提高;动机强度超过顶峰时,工作效率会随强度增加而不断下降,因为过强的动机使个体处于过度焦虑和紧张的心理状态,干扰记忆、思维等心理过程的正常活动。

因此,你需要做的是让别人更好的了解自己,如果你觉得自己很厉害但是确没能让别人知晓,那么别人对你的期待就会低于你的预期,你将要做的工作的难度也不太可能匹配你所掌握的技能,当然面对这样的工作,估计大部分人也没有新鲜,激动,亢奋,大鸡血的感觉吧。另外一方面,如果你给别人的感觉是很牛X,结果有可能让你面临超出自己技能很多的任务,这会增加你的焦虑,降低你的效率,影响个人的名声。

Rule #4: 焦虑,焦虑着也就没那么焦虑了。

说了这么多,感觉焦虑是一种要完全消灭,即便不能消灭也叫尽量避免的情绪,但凡事没有绝对,完全没有焦虑这种情绪也是不可取的,程序员需要适时地扩大自己的舒适区,而且焦虑也有它正能量的一面。

走出舒适区会增加人的焦虑程度,从而产生应激反应,其结果是提升对工作的专注程度。在这个区域中被称作最佳表现区——在这个区域之中,人的工作表现将会得到改善,并且他们的技巧也会被优化。但是罗伯特 耶基斯(1907)的报告中提到“焦虑可以改善工作表现,但是当超过某一最佳激励状态之后,工作表现就开始恶化”,如果一个人离开最佳表现区,他将进入一个危险区,在危险区中焦虑程度的上升或者舒适程度下降会带来工作表现的快速恶化。

所以在绩效管理之中管理者,或者是教练应该让人进入最佳表现区,并且维持一段足够的时间,从而达到更好的工作表现,提升他们的技巧,并且将这些表现和技巧固定下来。同样的道理,在目标设定之中改变焦虑的程度就会改变工作表现。

程序员的编程能力层次模型

来源:良少的博客(@虚拟化良少)

网址:http://blog.csdn.net/shendl/article/details/43835421

前言

程序员的编程技能随着经验的积累,会逐步提高。我认为编程能力可以分为一些层次。

下面通过两个维度展开编程能力层次模型的讨论。

一个维度是编程技能层次,另一个维度是领域知识层次。

编程技能层次

编程技能层次,指的程序员设计和编写程序的能力。这是程序员的根本。

0段—非程序员:

初学编程者,遇到问题,完全是懵懵懂懂,不知道该怎么编程解决问题。也就是说,还是门外汉,还不能称之为“程序员”。计算机在他面前还是一个神秘的黑匣子。

1段—基础程序员:

学习过一段时间编程后,接到任务,可以编写程序完成任务。

编写出来的代码,正常情况下是能够工作的,但在实际运行中,碰到一些特殊条件就会出现各类BUG。也就是说,具备了开发Demo软件的能力,但开发的软件真正交付给客户使用,恐怕会被客户骂死。

程序员程序是写好了,但到底为什么它有时能正常工作,有时又不行,程序员自己也不知道。

运行中遇到了bug,或者需求改变,需要修改代码或者添加代码,很快程序就变得结构混乱,代码膨胀,bug丛生。很快,就连最初的开发者自己也不愿意接手维护这个程序了。

2段—数据结构:

经过一段时间的编程实践后,程序员会认识到“数据结构+算法=程序”这一古训的含义。他们会使用算法来解决问题。进而,他们会认识到,算法本质上是依附于数据结构的,好的数据结构一旦设计出来,那么好的算法也会应运而生。

设计错误的数据结构,不可能生长出好的算法。

记得某一位外国先贤曾经说过:“给我看你的数据结构!”

3段—面向对象:

再之后,程序员就会领略面向对象程序设计的强大威力。大多数现代编程语言都是支持面向对象的。但并不是说,你使用面向对象编程语言编程,你用上了类,甚至继承了类,你就是在写面向对象的代码了。

我曾经见过很多用Java,Python,Ruby写的面向过程的代码。

只有你掌握了接口,掌握了多态,掌握了类和类,对象和对象之间的关系,你才真正掌握了面向对象编程技术。

就算你用的是传统的不支持面向对象的编程语言,只要你心中有“对象”,你依然可以开发出面向对象的程序。

如,我用C语言编程的时候,会有意识的使用面向对象的技巧来编写和设计程序。用struct来模拟类,把同一类概念的函数放在一起模拟类。如果你怀疑用C语言是否能编写出面向对象的代码,你可以看一下Linux内核,它是用C语言编写的,但你也可以看到它的源代码字里行间散发出的浓浓的“对象”的味道。

真正掌握面向对象编程技术并不容易。

在我的技术生涯中,有两个坎让我最感头疼。

一个坎是Dos向Windows开发的变迁过程中,框架的概念,很长一段时间我都理解不了。Dos时代,都是对函数库的调用,你的程序主动调用函数。Windows时代,则换成了框架。就算是你的main程序,其实也是被框架调用的。UI线程会从操作系统获取消息,然后发送给你的程序来处理。Java程序员熟悉的Spring框架,也是这样一个反向调用的框架。

现在因为“框架”这个术语显得很高大上,因此很多“类库”/“函数库”都自称为“框架”。在我看来这都是名称的滥用。

“类库”/“函数库”就是我写的代码调用它们。

“框架”就是我注册回调函数到框架,框架来调用我写的函数。

另一个坎就是面向对象。很长一段时间我都不知道应该怎么设计类和类之间的关系,不能很好的设计出类层次结构来。

我记得当时看到一本外国大牛的书,他讲了一个很简单、很实用的面向对象设计技巧:“叙述问题。然后把其中的名词找出来,用来构建类。把其中的动词找出来,用来构建类的方法”。虽然这个技巧挺管用的,但也太草根了点,没有理论依据,也不严谨。如果问题叙述的不好,那么获得的类系统就会是有问题的。

掌握面向对象思想的途径应该有很多种,我是从关系数据库中获得了灵感来理解和掌握面向对象设计思想的。

在我看来,关系数据库的表,其实就是一个类,每一行记录就是一个类的实例,也就是对象。表之间的关系,就是类之间的关系。O-Rmapping技术(如Hibernate),用于从面向对象代码到数据库表之间的映射,这也说明了类和表确实是逻辑上等价的。

既然数据库设计和类设计是等价的,那么要设计面向对象系统,只需要使用关系数据库的设计技巧即可。

关系数据库表结构设计是很简单的:

1、识别表和表之间的关系,也就是类和类之间的关系。是一对一,一对多,多对一,还是多对多。这就是类之间的关系。

2、识别表的字段。一个对象当然有无数多的属性(如,人:身高,体重,性别,年龄,姓名,身份证号,驾驶证号,银行卡号,护照号,港澳通行证号,工号,病史,婚史etc),我们写程序需要记录的只是我们关心的属性。这些关心的属性,就是表的字段,也就是类的属性。“弱水三千,我取一瓢饮”!
4段—设计模式:

曾经在网上看到这样一句话:“没有十万行代码量,就不要跟我谈什么设计模式”。深以为然。

记得第一次看Gof的设计模式那本书的时候,发现虽然以前并不知道设计模式,但在实际编程过程中,其实还是自觉使用了一些设计模式。设计模式是编程的客观规律,不是谁发明的,而是一些早期的资深程序员首先发现的。

不用设计模式,你也可以写出满足需求的程序来。但是,一旦后续需求变化,那么你的程序没有足够的柔韧性,将难以为继。而真实的程序,交付客户后,一定会有进一步的需求反馈。而后续版本的开发,也一定会增加需求。这是程序员无法回避的现实。

写UI程序,不论是Web,Desktop,Mobile,Game,一定要使用MVC设计模式。否则你的程序面对后续变化的UI需求,将无以为继。

设计模式,最重要的思想就是解耦,通过接口来解耦。这样,如果将来需求变化,那么只需要提供一个新的实现类即可。

主要的设计模式,其实都是面向对象的。因此,可以认为设计模式是面向对象的高级阶段。只有掌握了设计模式,才能认为是真正彻底掌握了面向对象设计技巧。

我学习一门新语言时(包括非面向对象语言,如函数式编程语言),总是会在了解了其语法后,看一下各类设计模式在这门语言中是如何实现的。这也是学习编程语言的一个窍门。

5段–语言专家:

经过一段时间的编程实践,程序员对某一种常用的编程语言已经相当精通了。有些人还成了“语言律师”,擅长向其他程序员讲解语言的用法和各种坑。

这一阶段的程序员,常常是自己所用语言的忠实信徒,常在社区和论坛上和其他语言的使用者争论哪一种语言是最好的编程语言。他们认为自己所用的语言是世界上最好的编程语言,没有之一。他们认为,自己所用的编程语言适用于所有场景。他们眼中,只有锤子,因此会把所有任务都当成是钉子。

6段–多语言专家:

这一个阶段的程序员,因为工作关系,或者纯粹是因为对技术的兴趣,已经学习和掌握了好几种编程语言。已经领略了不同编程语言不同的设计思路,对每种语言的长处和短处有了更多的了解。

他们现在认为,编程语言并不是最重要的,编程语言不过是基本功而已。

他们现在会根据不同的任务需求,或者不同的资源来选择不同的编程语言来解决问题,不再会因为没有使用某一种喜爱的编程语言开发而埋怨。

编程语言有很多种流派和思想,有一些编程语言同时支持多种编程范式。

静态类型编程范式

采用静态类型编程范式的编程语言,其变量需要明确指定类型。代表语言:C,C++,Pascal,Objective-C,Java,C#,VB.NET,Swif,Golang。

这样做的好处是:

1、编译器可以在编译时就能找出类型错误。
2、编译器编译时知道类型信息,就可以提高性能。

这种范式认为,程序员肯定知道变量的类型,你丫要是不知道变量的类型,那你就别混了!编译时,程序会报错。
Swift和Go语言都是静态类型编程语言,但它们都不需要明确指定类型,而是可以通过推断由编译器自动确定其类型。

动态类型编程范式

采用静态类型编程范式的编程语言,其变量不需要明确指定类型。任意变量,可以指向任意类型的对象。代表语言:Python,Ruby,JavaScript。

动态类型的哲学可以用鸭子类型(英语:ducktyping)这个概念来概括。JamesWhitcombRiley提出的鸭子测试可以这样表述:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”

这种范式认为,程序员肯定知道变量的类型和它支持的方法和属性,你丫要是不知道变量的类型,那你就别混了!运行时程序会崩溃!程序崩溃怨谁?怨你自己呗,你不是合格的程序员!

动态类型的好处是:

不需要明确定义接口和抽象类型。只要一个类型支持需要的方法和属性,那么就OK。程序会相当灵活和简单。C++,Java,C#视之为命脉的接口/基类,在动态语言这里都视如无物!

缺点是:

1、如果类型不对,编译器也无法找到错误,而是运行时程序崩溃
2、因为编译器不知道变量的类型,因此无法优化性能。

面向对象编程范式

面向对象编程范式,从上世纪70年代末开始兴起。它支持类和类的实例作为封装代码的模块。代表语言:Smalltalk,C++,Objective-C,Java,C#,VB.NET,Swift,Go,Python,Ruby,ActionScritp,OCaml.

早期编程语言都是面向过程的。就是顺序,条件,循环,构成一个个函数。随着代码规模的增大,人们发现有必要对代码进行模块化。一个概念对应的代码放在一个文件中,这样便于并发开发和进行代码管理。

人们还发现了“程序=数据结构+算法”的规律。因此,一个概念对应的数据结构和函数应该放在一个文件中。这就是类的概念。

面向对象编程范式,确实极大地提高了生产效率,因此得到了广泛的应用,因此在语言层面支持面向对象编程范式的语言是极多的。

C语言尽管在语言层面上并不支持面向对象编程范式,但现代的C语言开发都会应用面向对象的模块化思想,把同一类的数据结构和函数放在一个文件中,采用类似的命名方式。

毕竟C语言没有在语言层面上支持面向对象,因此就有很多程序员想给C语言添加面向对象支持。其中的代表是C++和Objective-C。

C++是一种新的语言,但大部分语言元素是和C兼容的。

Objective-C是完全兼容的C的。Objective-C是给C添加了薄薄的一层语法糖以支持接口(就是其他语言的类)和协议(就是其他语言的接口)。甚至,Objective-C一开始的实现,就是一个C语言的预编译器。Objective-C坦白讲,除了添加的语法不太符合C流外,实际上其面向对象系统设计是相当精妙的。乔布斯早年慧眼识珠,把Objective-C收人囊中,因为封闭于Apple/NextStep系统内,因此少有人知。随着iOs系统的普及,Objective-C近几年才名满天下。

函数式编程范式

函数式编程范式,是一些数学家发明的编程语言,他们认为程序就是数学函数嘛。代表语言:Lisp,Erlang,JavaScript,OCaml,Prog。

有很多大牛极力鼓吹过函数式编程语言,认为其极具革命性。但我认为他们过高估计了函数式编程范式的威力,我并不认为函数式编程范式相对于面向对象编程范式有何高明之处。

函数式编程语言,核心就是函数,它们没有Class类的概念。但它的函数又不是传统面向过程语言的函数,它的函数支持“闭包”的概念。

在我看来,函数式编程语言的函数,也就是“闭包”,说白了,其实就是“类”。编程语言发展到今天,就是需要模块化,就是需要把“数据结构”和“算法”结合起来。不论何种语言,不把它们结合起来的编程方式,都是没有出路的。

面向对象编程语言,用类把“数据结构”和“算法”结合起来。类的核心是“数据结构”,也就是其“属性”,而不是“算法”,其“函数”。在类中,是函数依附于属性。

而函数式编程语言,用闭包把“数据结构”和“算法”结合起来。是函数能够抓取外部的字段。是“属性”依附于“函数”。

“类”本质上和“闭包”是等价的。现在很多面向对象编程语言都加上了对闭包的支持。观察其代码,我们可以发现,它们实际上都是用“类”来实现“闭包”的。

“类”和“闭包”谁更易用?明显是“类”。

而“闭包”更简洁一些,因此“闭包”在面向对象编程语言中常用来替换匿名类。只有一个函数的类,写成一个类太麻烦,不如写成闭包,更加简洁。

吐槽一下OCaml语言,其前身Caml语言本身是一种挺好的函数式语言,硬生生添加了一套完整的面向对象机制,同时支持面向对象和函数式编程范式,很容易像C++一样脑裂的。

也有很多面向对象语言控看着JavaScript嫌烦,总是想把面向对象支持添加到JavaScript上。ActionScript就是其中一种尝试。我用过,真的是和Java没多少区别了。

再吐槽一下ExtJS。当初选型Web前端开发框架时比较了ExtJS和JQuery。

ExtJS明显是Java高手开发的,硬生生用JavaScript模拟Swing的设计思想,搞了一套UI库。

JQuery开发者明显是领悟了JavaScript的函数式编程范式,依据JavaScript的动态函数式编程语言的特点打造了一套UI库,立刻秒杀ExtJS。

由ExtJS和JQuery的故事,我们可以看到多语言编程能力是多么的重要。ExtJS的作者精通并喜爱Java,因此他把手术刀JavaScript当做锤子Java使,一通乱敲,费力不讨好。

函数式编程语言,还有尾递归等一些小技巧。尾递归可以不用栈,防止递归调用时栈溢出。

模板编程范式

模板编程,就是把类型作为参数,一套函数可以支持任意多种类型。代表语言:C++。

模板编程的需求,是在C++开发容器库的时候发明的。因为容器需要保存任意类型的对象,因此就有了泛型的需求。

C++的模板编程,是在编译时,根据源码中的使用情况,创建对应类型的代码。除了C++这种方式,Java,C#也有类似的机制,叫做“泛型”,但它们的实现方式和C++的模板很不同。它们的编译器不会生成新的代码,而是使用强制类型转换的方式实现。

在没有模板/泛型的编程语言中,怎样在容器中存放对象呢?存取公共基类类型(Java,C#)的对象,或者void*指针(C)即可,取出时自己强制类型转换为实际类型。动态类型语言,不关心类型,更是无所谓了,随便什么对象直接往容器里扔进去,取出来直接用即可。

一些C++高手又在模板的基础上搞出了“模板元编程”。因为模板编程,就是C++的编译器搞定的嘛,模板元编程就是让编译器运算,编译完结果也就算出来了。我不知道除了研究和炫技,这玩意有啥用?

小结

一门语言是否值得学习,我认为有几个标准:

1、是否要用,要用就得学,这么没有疑问的。毕竟我们都要吃饭的嘛。

2、其语言特性是否给你耳目一新的感觉。如果是,那就值回票价了。如Go语言废掉了异常,改用返回多值。我深以为然。我其实已经主动不用异常好多年了。因为,我觉得既然C不支持异常也活得很好,为什么需要异常呢?出错了,返回错误码。无法挽回的错误,直接Abort程序就可以嘛!而且,异常实际上是违反面向过程编程原则的。一个函数应该只有一个入口一个出口。抛出异常就多了出口了。

3、是否擅长某一个领域。如果你手里只有一把锤子,那么你就只能把所有任务都当做钉子猛锤一通。但如果工具箱里有多种工具,那面对不同的任务就得心应手多了。

7段—架构设计

还需要掌握架构设计的能力,才能设计出优秀的软件。架构设计有一些技巧:

1、分层

一个软件通常分为:

表现层–UI部分
接口层–后台服务的通讯接口部分
服务层–实际服务部分
存储层—持久化存储部分,存储到文件或者数据库。

分层的软件,可以解耦各个模块,支持并行开发,易于修改,易于提升性能。

2、SOA

模块之间通过网络通讯互相连接,松耦合。每一个模块可以独立部署,可以增加部署实例从而提高性能。每一个模块可以使用不同的语言和平台开发,可以重用之前开发的服务。SOA,常用协议有WebService,REST,JSON-RPC等。

3、性能瓶颈

1)化同步为异步。

用内存队列(Redis),工作流引擎(JBpm)等实现。内存队列容易丢失数据,但是速度快。工作流引擎会把请求保存到数据库中。

通过化同步请求为异步请求,基本上99.99%的性能问题都可以解决。

2)用单机并行硬件处理。

如,使用GPU,FPGA等硬件来处理,提高性能。

3)用集群计算机来处理。

如,Hadoop集群,用多台计算机来并行处理数据。

自己的软件栈中,也可以把一个模块部署多份,并行处理。

4)用cache来满足请求。常用的内容加热cache后,大量的用户请求都只是内存读取数据而已,性能会得到很大的提升。

cache是上帝算法,记得好像它的性能只比最佳性能低一些,就好像你是上帝,能够预见未来一样。现在X86CPU遇到了主频限制,CPU提升性能的主要途径就是增加高速Cache了。

4、大系统小做

遇到大型系统不要慌,把它切分成多个模块,用多个小程序,通过SOA协作来解决。这秉承了Unix的设计思想。Unix上开发了大量单一目的的小程序,它主张用户通过管道来让多个小程序协作,解决用户的需求。当然,管道方式通讯限制太多,不够灵活。因此,现在我们可以通过URI,通过SOA的方式来让多个程序协作。Andorid和iOS上的应用程序,现在都是通过URI实现协作的。这也算是Unix设计思想的现代发展吧?!

5、Sharding切片

现在有一个潮流,就是去IOE。I-IBM大型机,O-Oracle数据库,E-EMC存储。之前,大型系统常用IOE去架构,在大型机上部署一个Oracle数据库,Oracle数据库用EMC存储保存数据。IOE是当今最强的计算机,数据库和存储。但他们面对海量系统也有抗不住的一天。

Oracle数据库是Shareeverything的,它可以在一个计算机集群(服务器节点不能超过16个)上运行。计算机集群都共用一个存储。

去IOE运动,标志着ShareEverything模式的破产。必须使用ShareNothing,系统才能无限扩展。

用MySQL数据库就可以应付任意规模的数据了。前提是,你会Sharding分片。把大系统切分成若干个小系统,切分到若干台廉价服务器和存储上。更Modern一些,就是切分到大量虚拟机上。

如,铁道部的12306网站。我们知道火车票都是从属于某一列列车的。那么我们把每一个列车作为一个单元来切分,就可以把12306网站切分成几千个模块。一台虚拟机可以承载若干个模块。当某些列车成为性能瓶颈之后,就可以把它们迁移到独立的虚拟机上。即使最终有部分列出服务不可用,系统也不会完全不可用。

12306网站,只有一个全局的部分,就是用户登录。这个可以交给第三方负责。如可以让用户用微信,微博,qq等账户登录。

也可以自己实现用户登录服务。还是用切片的方式用多台Redis服务器提供服务。Redis服务器存储每一个登录用户的sessionId和userId,角色,权限等信息。sessionId是随机生成的,可选择其部分bit用于标识它在哪一个Redis服务器上。用户登录后,把sessionId发给客户。用户每次请求时把sessionId发回给服务器。服务器把sessionId发给Redis服务器查询得到其用户信息,对用户请求进行处理。如果在redis服务器上找不到sessionId,则让用户去登录。即使所有注册用户同时登陆,也不需要太多的内存。而且,可以在session内存过多时,删除最早登陆的用户的session,强制他再次登陆。同时活跃的用户数不会太多。

领域知识层次

前面的所有层次,都是关注编程本身的技能,说白了,就是基本功,本身并不能产生太大的价值。但有太多的程序员浪费太多的时间在那些筑基的层次上。

有些程序员特别喜欢钻研编程语言,每有一种新的编程语言出来或者旧语言被热炒,就会投入精力进去研究。我就是其中之一,浪费了很多精力在编程语言上,在奇技淫巧上。

我觉得C++语言是一个特别大的坑。刚开始是作为面向对象的C被开发的。后来发现了模板编程,就大力鼓吹模板编程和进一步的模板元编程。最近又推出了C++11,C++14等新标准,进一步添加了很多新东西,函数式编程,类型推断等。C++过分复杂,太多的坑消耗了大量程序员的大量精力。我使用C++时,只使用面向对象部分和模板部分,其他过于精深的特性都不使用。

计算机科学是一个面相当广泛的学科,有很多领域知识需要和值得我们深入研究,我们才能写出有价值的程序来。软件必须要和行业结合起来,要落地才有价值。仅仅研究编程技巧,不懂领域知识是写不出有价值的程序的。

计算机科学领域有很多,列举一些如下:

存储—-块设备,文件系统,集群文件系统,分布式文件系统,光纤SCSI,iSCSI,RAID等。

网络—-以太网,光纤网,蜂窝网络,WIFI,VLAN等。

计算机体系结构,主要就是CPU指令集。x86,ARM等。

USB协议。需要知道URB包。

PCI协议,PCI-E协议。现代计算机的外设都是PCI协议和PCI-E协议的。显卡现在全是通过 PCI-E协议连接到计算机上的。相对来说减少了很多需要学习的知识。搞虚拟化就需要深入掌握PCI协议。

图像处理–图像压缩,视频实时编码等。

3D游戏
关系数据库
NoSQL数据库
操作系统
分布式操作系统
编译原理
机器学习–现在大数据要用哦!

了解这些领域知识,也包括了解该领域现有的商用硬件、商用软件和开源软件。很多时候,你要完成的工作,已经有现成的工具了。你只要使用现成的工具就可以完成任务,不需要进行开发。有时候,只需要组合现有的工具,写一些脚本就可以完成任务。

如,我一次要实现一个双向同步任务。找到了一个优秀的开源软件Unison,编写一下配置文件就圆满地完成了任务。不需要编写任何代码。

还有一次,要做高可用,用Python调用了几个开源软件就轻松实现了。

编写安装程序,定制操作系统,知道了操作系统的领域知识,写几行脚本就可以轻松搞定。

不具备领域知识的人,就可能不得不进行大量无谓的开发,甚至开发很久之后才发现,这根本就是一条死路。

另外,扎实的领域知识,可以大大提高编程调试、查错的能力。知道编译器和编程语言运行时工作原理,就能快速根据编译错误和警告信息修改代码。

知道操作系统底层运行机制,就能快速找到运行时错误的问题根源。如,有一次我编写一个windows升级服务程序。它是一个windows服务,需要执行dos脚本,这个脚本会替换掉这个windows服务本身。发现有时脚本执行无效,查了一晚上,发现当windows服务安装后,第一次启动就执行脚本时就会有权限问题,log都正确,但实际执行这个脚本没有任何效果。但一旦windows服务程序启动一次之后就ok。这必然是windows操作系统底层安全机制的问题,因为我对Windows内核了解不多,因此花了很长时间才发现这个问题,并对造成这个问题的根源并不清楚。

0段—领域知识菜鸟

对领域知识没有多少认知,通过搜索引擎找到一些该领域的软件和硬件的介绍性文章,按照文章指示配置和使用软件。勉强能够使用现有软硬件。

1段—领域知识行家

了解领域内常用硬件,深入掌握领域内常用软件的配置和使用技巧。能够使用现有软硬件熟练搭建解决方案,能够解决实际工作中遇到的种种问题。

2段—领域知识专家

当你不仅仅掌握了该领域的软件和工具,知道怎么用,还知道其原理,“知其然,也知其所以然”,就是该领域的知识专家了。

你知道网络协议的原理,你才能在网络出现问题时知道是哪里可能出现了问题。是mac冲突,ip冲突,还是网络环路?

你知道存储的原理,你才能知道为什么这种存储方式不适合虚拟化,那种存储方式适合虚拟化,另一种方式适合资料备份。

你知道PCI协议,你才能知道你怎样才能虚拟化一个硬件设备。

你知道网卡硬件协议,你才能模拟出一个虚拟机能正常使用的虚拟网卡。

你知道视频编码格式和原理,才能知道什么视频格式占用带宽最少,什么视频格式占用CPU最少。

你了解IntelVT/Amd V指令集,才能知道虚拟化是怎样实现的。

你明白工作流其实就是状态机,在遇到复杂工作流程时,你才能知道怎样设计满足要求的工作流引擎。

3段—科学家

你是领域知识专家,但你的知识都是来自于书本,来自于其他人的。

如果你满足于当领域知识专家,你只能拾人牙慧,永远别想超越。别人的研究成果,未必愿意告诉你。当别人告诉你的时候,它可能已经发现了更新的理论,并且新一代产品可能马上就要发布了。

科学家是探索未知,勇于创新的人,是推动人类社会进步的人。

传说,思科的一位高管曾经半开玩笑地说过:“如果思科停止了新技术的研发,华为就会找不着方向”。这是在嘲笑华为只是处在领域知识专家的水平,只能山寨无法超越。我不知道华为的实际情况,但希望现在的华为已经走到了领跑者的位置。

欧文·雅各布斯发现了CDMA码分多址的原理,并发现它在通讯上大有可为,组建了高通公司。高通公司主要以专利授权费为生,它雇佣了大量科学家在通讯领域展开研究。有人说高通是专利流氓。这些人不明白知识的价值。在他们眼里,Windows的合理价格就应该是5元钱,一张光盘的价格。iPhone就应该是1000多元裸机的价格。高通是专利流氓,那你也流氓一个CDMA,LTE出来给我看看!

X86芯片在设计上没有考虑虚拟化。因此会有所谓的“虚拟化漏洞”出现。就是说,一些CPU特权指令执行时,在虚拟机环境下不会抛出异常,因此就无法切换到Host。这样,X86芯片上就无法运行虚拟机。

VmWare公司是由美国的几位科学家在1998年创建的。他们发现可以使用二进制翻译的技术,在X86计算机上运行虚拟机。

Xen虚拟化软件也是几位科学家发明的。他们发现只要修改虚拟机操作系统和Host操作系统的内核,在需要执行“虚拟化漏洞”指令时直接调用Host的功能,就可以实现虚拟化,而且大大提高了虚拟机的运行性能。

后来,Intel为自己的芯片添加了IntelVT指令集,Amd为自己的芯片添加了AmdV指令集,弥补了“虚拟化漏洞”。于是就有了KVM虚拟机软件,它直接用CPU硬件指令实现虚拟化。

KVM在执行CPU指令时,是直接在物理CPU上运行的,因此效率极高。但是,虚拟机运行虚拟外设时,就必须用软件模拟,因此虚拟机的IO访问速度很慢。

IBM科学家RustyRussell,借鉴了Xen的研发经验,创建了VirtIO技术。就是在虚拟机中编写一套PCI虚拟设备和驱动,这套虚拟PCI设备有一块虚拟设备内存。这个虚拟设备内存Host是可以访问的,虚拟机通过VirtIO驱动程序也可以访问。也就是一块内存在虚拟机和Host中共享,这就解决了虚拟机的IO性能问题。

再讲一个搜索引擎的故事:

很久以前,我要给一个程序添加搜索功能。刚开始使用sql查询实现,发现实在太慢了。后来找了开源的Lucene项目。它使用反向索引技术,通过在文件中创建反向索引,大大提高了搜索速度。

Google的两位创始人发现了html中link的秘密,他们发现可以通过html页面的link关系来为每一个html页面设置权重。也就是PageRank算法。于是,Google的自动搜索引擎击败了Yahoo人工分类的搜索引擎。

OK,利用反向索引技术和PageRank,以及一个简单的html爬虫机器人,我们就可以创建一个搜索引擎了。但是,互联网很大,每天产生大量新网页,要为整个互联网建立反向索引是很困难的。

若干年后Google又公开了三篇论文:Googlefs,Mapreduce,Bigtable。于是Lucene项目的开发者根据Google的Mapreduce论文开发了Hadoop项目。MapReduce就是使用大量计算机存储数据并计算,最后汇总结果。使用Hadoop+反向索引+PageRank,就可以创建搜索引擎了。Yahoo,Baidu等公司纷纷基于Hadoop开发了自己的搜索引擎。

但是,其他公司的搜索引擎效果还是没法和Google相比。这一点我们程序员最清楚。像我,就总是翻墙出去,只为了Google一下。

Google黑板报上发表了吴军博士的一些文章,其中介绍了很多机器学习方面的知识。从文中可以知道,Google其实使用机器学习来分析搜集到的页面。Google明显不会把这个公式公开出来。即使有一天Google真的公开了这个公式,那么可以想见Google肯定又研发出了更加犀利的秘籍,山寨货的搜索引擎效果还是比不上Google的。

山寨是通向创新的必由之路。在成为领域的领头羊和领导者之前,必然要经过学习,模仿的阶段。但要成为行业的老大,成为Champion,必须勇于弯道超车,勇敢地走上创新之路,成为真正的科学家,真正的大牛!

总结

编程能力可分为两个维度:一个是编程技能水平,另一个是领域知识水平。

有些程序员可能把精力都花在提升编程技能上了,领域知识知之甚少,这其实在日常工作中也是极其有害的。有些需求可能早已经有了现成、开源免费的解决方案,或者只需要组合几个现有软件就可以快速搞定,而他们却不得不自己花大量时间去开发。另外,缺少领域知识,在程序出现非预期状况时,很难快速定位到问题的根源,很难解决bug。

什么是真正的编程能力

2016-01-18 转载自:知乎 开点工作室

问题:什么才算是真正的编程能力?

还在读书,也在实验室帮忙做了些东西,自己也搭过几个网站。在周围人看来似乎好像我很厉害,做了那么多东西,但是我发现这些东西虽然是我做的,但是实际上我手把手自己写的代码却并没有多少,很多都是用开源的东西,我写的代码无非是把别人的东西整合下,类似于胶水一样的工作。

我之前所认为的编程是全手动一行一行敲代码,但是现在我发现哪怕是工程上也有很多人是复制黏贴来解决问题的,并且提倡不要重复造轮子。

但是靠谷歌和复制别人的轮子,虽然我做出了很多东西,可是我并不觉得自己能力上有提升,倒是利用搜索引擎的能力的确提升了不少。而学校里另外一部分在搞ACM的人,他们每天都在刷题练算法,但单凭我个人的感受感觉他们似乎对工程上有些东西并不了解,或许算法的能力才算是实打实的编程能力?那”胶水”的能力和整合轮子的能力算不算编程能力呢?

所以我现在就很困惑,所谓的编程能力到底是什么,我该如何提升自己的编程能力?

回答:

作者:刘贺

链接:http://www.zhihu.com/question/31034164/answer/61625952
来源:知乎

非常好的一个问题。这可能是我在知乎见到过的问编程有关的问题中问得最好的一个了。我非常喜欢这个问题。

计算机科学有两类根本问题。一类是理论:算法,数据结构,复杂度,机器学习,模式识别,等等等。一类是系统:操作系统,网络系统,分布式系统,存储系统,游戏引擎,等等等等。

理论走的是深度,是在追问在给定的计算能力约束下如何把一个问题解决得更快更好。而系统走的是广度,是在追问对于一个现实的需求如何在众多的技术中设计出最多快好省的技术组合。

搞ACM的人,只练第一类。像你这样的更偏向于第二类。其实挺难得的,但很可惜的是第二类能力没有简单高效的测量考察方法,不像算法和数据结构有ACM竞赛,所以很多系统的苗子都因为缺少激励和正确引导慢慢就消隐了。

所以比尔盖茨才会说,看到现在学编程的人经常都把编程看作解各种脑筋急转弯的问题,他觉得很遗憾。

做系统,确实不提倡“重复发明轮子”。但注意,是不提倡“重复发明”,不是不提倡“重新制造”。恰恰相反的,我以为,系统的编程能力正体现在“重新制造”的能力。

能把已有的部件接起来,这很好。但当你恰好缺一种关键的胶水的时候,你能写出来吗?当一个已有的部件不完全符合你的需求的时候,你能改进它吗?如果你用的部件中有bug,你能把它修好吗?在网上繁多的类似功能的部件中,谁好谁坏?为什么?差别本质吗?一个开源代码库,你能把它从一个语言翻译到另一个语言吗?从一个平台移植到另一个平台吗?能准确估计自己翻译和移植的过程需要多少时间吗?能准确估计翻译和移植之后性能是会有提升还是会有所下降吗?

系统编程能力体现在把已有的代码拿来并变成更好的代码,体现在把没用的代码拿来并变成有用的代码,体现在把一个做好的轮子拿来能画出来轮子的设计蓝图,并用道理解释出设计蓝图中哪些地方是关键的,哪些地方是次要的,哪些地方是不容触碰的,哪些地方是还可以改进的。

如果你一点不懂理论,还是应该学点的。对于系统性能的设计上,算法和数据结构就像在自己手头的钱一样,它们不是万能的,但不懂是万万不行的。

怎么提高系统编程能力呢?土办法:多造轮子。就像学画画要画鸡蛋一样,不是这世界上没有人会画鸡蛋,但画鸡蛋能驯服手指,感受阴影线条和笔触。所以,自己多写点东西吧。写个编译器?渲染器?操作系统?web服务器?web浏览器?部件都一个个换成自己手写的,然后和已有的现成部件比一比,看看谁的性能好,谁的易用性好?好在哪儿?差在哪儿?为什么?

更聪明一点的办法:多拆轮子。多研究别人的代码是怎么写的。然而这个实践起来经常很难。原因:大部分工业上用的轮子可能设计上的思想和技术是好的,都设计和制造过程都很烂,里面乱成一团,让人乍一看毫无头绪,导致其对新手来说非常难拆。这种状况其实非常糟糕。所以,此办法一般只对比较简单的轮子好使,对于复杂的轮子,请量力而行。

轮子不好拆,其实是一个非常严重的问题。重复发明轮子固然是时间的浪费,但当轮子复杂而又不好拆的时候,尤其是原来造轮子的人已经不在场的时候,重新发明和建造轮子往往会成为无奈之下最好的选择。这是为什么工业界在明知道重复发明/制造轮子非常不好的情况下还在不断重复发明/制造轮子的根本原因。

程序本质是逻辑演绎的形式化表达,记载的是人类对这个世界的数字化理解。不能拆的轮子就像那一篇篇丢了曲谱的宋词一样,能读,却不能唱。

鄙人不才,正在自己研究怎么设计建造一种既好用又好拆的轮子。您没那么幸运,恐怕是等不到鄙人的技术做出来并发扬光大了。在那之前,多造轮子,多拆好拆的小轮子,应该是提高编程能力最好的办法了。

以上。嗯。
(文章属个人观点,与本人工作雇主无关。)

回答:

作者:家飞猫
链接:http://www.zhihu.com/question/31034164/answer/61625952
来源:知乎

编程能力是一种解决问题的能力。如果问题没能被很好地解决,知道再多也没用。
编程能力是一种运用机器解决问题的能力。首先是要判断问题在什么程度上可被机器解决,比如理论计算机科学会告诉我们什么可做、什么理论上不可做、什么理论上可做实践上不可做。然后是让机器更好地理解问题,比如计算机都是(图灵-冯诺依曼模型)等价,但不同的问题可能会适用不同的编程语言。再后是让机器能更高效率地解决问题,比如同样的问题可能会有效率差别巨大的算法。
编程能力是一种抽象问题的能力。借用轮子是很好的办法,省力省时间。今天任何软件工程师都会有意无意地使用很多轮子,从操作系统编译器数据库网络到算法数据结构。想高效地借用轮子,就需要将问题分解再分解,抽象再抽象。任何一个实用的系统(不包括教科书上的示例程序和简单的脚本程序)都需要进行大量的分拆和组合。所以系统设计是编程能力里的高级技能,加合理的假设简化问题尤其有难度,此处不展开讨论。高手和新手的区别在于新手往往不知道轮子的适用范围,而高手的手上轮子数量多且熟知各种轮子的差异,所以对不同的问题可以轻松地找到合适的轮子,当实在找不到合适的轮子时可以自己动手改造现有的轮子。平时有时间拆装和改造已有的轮子会对水平提升有较大帮助。当然能知道怎样快速在搜索引擎里搜出轮子也是一种能力。
编程能力是一种需要考虑扩展性的能力。算法竞赛中的很多算法考虑的是单机的内存算法,计算模型经过高度抽象,在实践中机器的模型更为复杂。比如单机的多级结构带来的各种时间空间复杂度的取舍平衡,多机网络中如何能在提高单机性能外进一步优化整体性能。除了在机器端的扩展,在程序员一端的扩展也很重要。复杂的问题和工程往往意味着团队协同以及更长时间的开发维护,团队分工和设计沟通这里暂且不论。举个容易被忽视的例子,程序中的注释。高手会更在意完整且表达清楚的注释,因为这是写给现在和未来的团队(包括自己和其他成员)看的,直接影响到长期的整体开发维护效率。
编程能力是一种取舍的能力。局部的最优解未必是全局的最优解。如果一个美妙的解决方案需要将完工时间向后推迟一两个月,需要考虑是否先使用平凡方案解决问题,之后再进行优化。当你的工作延后会阻碍别人的工作时尤其如此。发现一个绝妙的优化方案时先想想这个优化是否真的有价值,如果只是系统中很小的部分,那么不要为了追求心理满足而花很多时间放一个漂亮的轮子上去(参考Amdahl定律)。
编程能力是一种预见未来的能力。目前的方案有哪些假设和局限性,在何种情形下会遇到问题甚至崩溃。在未来出现问题时问题是否需要重新定义,系统是否需要重新设计,代码是否需要重构或优化等等都需要未雨绸缪。
编程能力是一种工程能力。无它,唯手熟尔。

编程能力是一种解决问题的能力。如果问题没能被很好地解决,知道再多也没用。
编程能力是一种解决问题的能力。如果问题没能被很好地解决,知道再多也没用。
(重要的事情说三遍,重要的事情说三遍,重要的事情说三遍)

据说 JS 是世界上最好的编程语言?

作者:伯乐在线 – 伯小乐

网址:http://web.jobbole.com/84693/

【伯乐在线导读】:2016年1月中旬,Stack Overflow发起本年度的开发者调查。调查结果于近日公布,伯乐在线翻译组黄小非完整翻译了的调查报告。本文盘点 JS 开发者应该会关心的部分数据。

Stack Overflow 技术排行榜:

在2015年6月,JavaScript超越了Java成为Stack Overflow上最热门的标签。

Stack Overflow 技术趋势

新潮的Web开发技术,比如React,Node.js,还有AngularJS正在逐渐起势。

从 2013 至 2016 年,JS 四年蝉联最热门技术

程序员最想要的技术,Node 和 Angular 排第二和第三

全栈工程师最青睐的技术,JS 第一

前端开发者最青睐的技术,JS 自然第一

后端开发者最青睐的技术,JS 第一

学生程序员最青睐的技术,JS 第二

JavaScript 是这个星球上最受欢迎的编程语言。而且后端开发者甚至更喜欢使用JavaScript来工作。

多个相关的技术:

每一个开发者(在日常工作中)平均要使用四五种主流编程语言、框架或者技术。最常规的双技术组合是 JavaScript和 SQL。最常见的三技术组合是 JavaScript、PHP 和 SQL。

根据职业划分的技术栈

看到栈了没?全栈开发者选择使用PHP作为后端原因,比任何其他语言都多。(紧接着的是C#和Java)。

JavaScript是如此普及,以至于后端开发者不管用什么类型的3技术组合都包含了JavaScript。这也说明有很多后端开发者其实也就是披着后端外衣的全栈开发者。我们的内部统计显示,有60%的职业开发者实际上是在做全栈的工作的。

按职位分类看程序员的报酬:

在用 JS 的全栈工程师中

在用 JS 的前端工程师中,

按职位分类的报酬:

懂得使用JavaScript并在为云平台工作的全栈开发者,以及使用React或者Redis技术的开发者比其他的开发者报酬更多。

懂得使用JavaScript和React,Node或者Angular技术的前端开发者比其他前端开发者的报酬更高。

开发环境(2016):

根据职位分类的开发环境:

数据科学家使用Vim和Notepad++。全栈开发者使用Visual Studio和Sublime。学生则使用Notepad++和Visual Studio和Notepad++。

操作系统:

去年,在开发者们使用的操作系统中,Mac系统比Linux的份额多了一点点,排在第二名。今年形势则非常明朗而且操作系统的发展趋势也很明显。如果这种趋势依然保持下去的话,那么明年Windows系统的使用量将会低于50%。

开发者希望在工作中学到什么?

一旦开发者找到了工作,他们就会去尝试学习新东西或创造新东西。对于印度开发者来说,得到升职的优先级要比其他国家的开发者来得高。

工作中的挑战:

不切实际的预期,糟糕的文档,不够详细的需求,这些都是开发者日常要面对的烦心事。听上去熟悉吧?

《StackOverflow 2016 年开发者调查》完整版中还有关于女程序员的数据,请查看:http://blog.jobbole.com/98977/

程序员必读书单 1.0

作者:Lucida

原文链接:http://lucida.me/blog/developer-reading-list/

本文把程序员所需掌握的关键知识总结为三大类19个关键概念,然后给出了掌握每个关键概念所需的入门书籍,必读书籍,以及延伸阅读。旨在成为最好最全面的程序员必读书单。

前言

Reading makes a full man; conference a ready man; and writing an exact man.

Francis Bacon

优秀的程序员应该具备两方面能力:

  • 良好的程序设计能力:
    • 掌握常用的数据结构和算法(例如链表,栈,堆,队列,排序和散列);
    • 理解计算机科学的核心概念(例如计算机系统结构、操作系统、编译原理和计算机网络);
    • 熟悉至少两门以上编程语言(例如C++,Java,C#,和Python);
  • 专业的软件开发素养:
    • 具备良好的编程实践,能够编写可测试(Testable),可扩展(Extensible),可维护(Maintainable)的代码;
    • 把握客户需求,按时交付客户所需要的软件产品;
    • 理解现代软件开发过程中的核心概念(例如面向对象程序设计,测试驱动开发,持续集成,和持续交付等等)。

和其它能力一样,程序设计能力和软件开发素养源自项目经验和书本知识。项目经验因人而异(来自不同领域的程序员,项目差异会很大);但书本知识是相通的——尤其是经典图书,它们都能够拓宽程序员的视野,提高程序员的成长速度。

在过去几年的学习和工作中,我阅读了大量的程序设计/软件开发书籍。随着阅读量的增长,我意识到:

  • 经典书籍需要不断被重读——每一次重读都会有新的体会;
  • 书籍并非读的越多越好——大多数书籍只是经典书籍中的概念延伸(有时甚至是照搬);

意识到这两点之后,我开始思考一个很功利的问题:如何从尽可能少的书中,获取尽可能多的关键知识?换句话说:

  • 优秀的程序员应该掌握哪些关键概念?
  • 哪些书籍来可以帮助程序员掌握这些关键概念?

这即是这篇文章的出发点——我试图通过程序员必读书单这篇文章来回答上面两个问题。

标准

进入必读书单之前,我先介绍下书单里的书籍选择标准和领域选择标准。当然你也点击这里直接跳转到书单开始阅读。

书籍选择标准

  1. 必读:什么是必读书籍呢?如果学习某项技术有一本书无论如何都不能错过,那么这本书就是必读书籍——例如Effective Java于Java,CLR via C#于C#;
    • 注意我没有使用“经典”这个词,因为经典计算机书籍往往和计算机科学联系在一起,而且经典往往需要10年甚至更长的时间进行考验;
  2. 注重实践,而非理论:所以这个书单不会包含过于原理性的书籍;
  3. 入门—必读—延伸:必读书籍的问题在于:1. 大多不适合入门;2. 不够全面。考虑到没有入门阅读和延伸阅读的阅读列表是不完整的——所以书单中每个关键概念都会由一本入门书籍,一本必读书籍(有时入门书籍和必读书籍是同一本),和若干延伸阅读书籍所构成。

概念选择标准

  1. 全面:全面覆盖软件开发中重要的概念;
  2. 通用:适用于每一个程序员,和领域特定方向无关;
  3. 注重基础,但不过于深入:优秀的程序员需要良好的计算机科学基础,但程序员并没必要掌握过于深入的计算机科学知识。以算法为例,每个程序员都应该掌握排序、链表、栈以及队列这些基本数据结构和算法,但计算几何、线性规划和网络流这些算法可能就不是每个程序员都需要掌握的了;

通过这几个标准,我把程序员应掌握的关键概念分为程序设计,软件开发,以及个人成长三大类,每一大类均由若干关键概念组成。

快速通道

自从开博以来,经常会有朋友在论坛,微博,和QQ上提问学习X技术读什么书合适(例如:学习Java读什么书合适?如何学习程序设计?)所以我在这 里列出了一个“快速通道”——把常见的问题集中在一起,点击问题,即可直接进入答案。(当然,如果你把本文从头读到尾帮助会更大 :–))

程序员必读书单

入门书籍

程序设计:

  1. 基础理论编码:隐匿在计算机软硬件背后的语言
  2. 编程语言
  3. 编程语言理论编程语言实现模式
  4. 程序设计程序设计方法
  5. 算法与数据结构算法(第4版)
  6. 程序调试调试九法——软硬件错误的排查之道

软件开发:

  1. 编程实践程序设计实践
  2. 面向对象程序设计Head First设计模式
  3. 重构重构
  4. 软件测试How to Break Software
  5. 项目管理极客与团队
  6. 专业开发程序员修炼之道:从小工到专家
  7. 大师之言奇思妙想:15位计算机天才及其重大发现
  8. 界面设计写给大家看的设计书
  9. 交互设计通用设计法则

个人成长:

  1. 职业规划软件开发者路线图
  2. 思维方式程序员的思维修炼:开发认知潜能的九堂课
  3. 求职面试金领简历:敲开苹果微软谷歌的大门
  4. 英语写作The Only Grammar Book You’ll Ever Need

必读书籍

程序设计:

  1. 基础理论深入理解计算机系统(第2版)
  2. 编程语言
  3. 编程语言理论程序设计语言——实践之路(第3版)
  4. 程序设计计算机程序的构造与解释(第2版)
  5. 算法与数据结构编程珠玑(第2版)
  6. 程序调试调试九法——软硬件错误的排查之道

软件开发:

  1. 编程实践代码大全(第2版)
  2. 面向对象程序设计设计模式
  3. 重构修改代码的艺术
  4. 软件测试xUnit Test Patterns
  5. 项目管理人月神话
  6. 专业开发程序员职业素养
  7. 大师之言编程人生:15位软件先驱访谈录
  8. 界面设计认知与设计:理解UI设计准则(第2版)
  9. 交互设计交互设计精髓(第3版)

个人成长:

  1. 职业规划软件开发者路线图
  2. 思维方式如何把事情做到最好
  3. 求职面试程序员面试金典(第5版)
  4. 英语写作风格的要素

这个阅读列表覆盖了软件开发各个关键领域的入门书籍和必读书籍,我相信它可以满足绝大多数程序员的需求,无论你是初学者,还是进阶者,都可以从中获益:

  • 基础理论包括了程序员应该掌握的计算机基础知识;
  • 编程语言对软件开发至关重要,我选择了CC++JavaC#Python,和JavaScript这六门主流编程语言进行介绍,如果想进一步理解编程语言,可以阅读编程语言理论里的书目;
  • 在理解编程语言的基础上,优秀的程序员还应该了解各种程序设计技巧,熟悉基本的算法数据结构,并且能够高效的进行程序调试
  • 良好的程序设计能力是成为优秀程序员的前提,但软件开发知识也是必不可少的:优秀的程序员应具备良好的编程实践,知道如何利用面向对象重构,和软件测试编写可复用,可扩展,可维护的代码,并具备软件项目管理知识和专业开发素养;
  • 就像我们可以从名人传记里学习名人的成功经验,程序员也可以通过追随优秀程序员的足迹使自己少走弯路。大师之言包含一系列对大师程序员/计算机科学家的访谈,任何程序员都可以从中获益良多;
  • 为了打造用户满意的软件产品,程序员应当掌握一定的界面设计知识和交互设计知识(是的,这些工作应该交给UI和UX,但如果你想独自打造一个产品呢?);
  • 专业程序员应当对自己进行职业规划,并熟悉程序员求职面试的流程,以便在职业道路上越走越远;
  • 软件开发是一项需要不断学习的技能,学习思维方式可以有效的提升学习能力和学习效率;
  • 软件开发是一项国际化的工作,为了让更多的人了解你的代码(工作),良好的英语写作能力必不可少。

尽管我尽可能的去完善这个书单,但受限于我的个人经历,这个书单难免会有所偏颇。所以如果你有不同的意见,或者认为这个书单漏掉了某些重要书籍,请在评论中指出,我会及时更新。:–)

程序设计

1. 基础理论

编码:隐匿在计算机软硬件背后的语言

编码:隐匿在计算机软硬件背后的语言这本书其实不应该叫编码——它更应该叫“Petzold教你造计算机”——作者Charles Petzold创造性的以编码为主题,从电报机和手电筒讲到数字电路,然后利用数字电路中的逻辑门构造出加法器触发器,最后构造出一个完整的存储程序计算机。不要被这些电路概念吓到——编码使用大量形象贴切的类比简化了这些概念,使其成为最精彩最通俗易懂的计算机入门读物。

深入理解计算机系统(第2版)

深入理解计算机系统(第2版)这本书的全名是:Computer Systems:A Programmer’s Perspective(所以它又被称为CSAPP),我个人习惯把它翻译为程序员所需了解的计算机系统知识,尽管土了些,但更名副其实。

深入理解计算机系统是我读过的最优秀的计算机系统导论型作品,它创造性的把操作系统,计算机组成结构,数字电路,以及编译原理这些计算机基础学科中的核心概念汇集在一起,从而覆盖了指令集体系架构,汇编语言,代码优化,计算机存储体系架构,链接,装载,进程,以及虚拟内存这些程序员所需了解的关键计算机系统知识。如果想打下扎实的计算机基础又不想把操作系统计算机结构编译原理这些书统统读一遍,阅读深入理解计算机系统是最有效率的方式。

延伸阅读:

2. 编程语言

编程语言是程序员必不可少的日常工具。工欲善其事,必先利其器。我在这里给出了C,C++,Java,C#,JavaScript,和Python这六种常用编程语言的书单(我个人不熟悉Objective-C和PHP,因此它们不在其中)。

需要注意的是:我在这里给出的是编程语言(Programming Language)书籍,而非编程平台(Programming Platform)书籍。以Java为例,Effective Java属于编程语言书籍,而Android编程权威指南就属于编程平台书籍。

C

C和指针

忘记谭浩强那本糟糕不堪的C程序设计,C和指针才是C语言的最佳入门书籍。它详细但又不失简练的介绍了C语言以及C标准库的方方面面。

对于C语言初学者,最难的概念不仅仅是指针和数组,还有指向数组的指针和指向指针的指针。C和指针花了大量的篇幅和图示来把这些难懂但重要的概念讲的清清楚楚,这也是我推荐它作为C语言入门读物的原因。

C程序设计语言(第2版)

尽管C程序设计语言是二十多年前的书籍,但它仍然是C语言——以及计算机科学中最重要的书籍之一,它的重要性不仅仅在于它用清晰的语言和简练的代码描述了C语言全貌,而且在于它为之后的计算机书籍——尤其是编程语言书籍树立了新的标杆。以至于在很多计算机书籍的扉页,都会有“感谢Kernighan教会我写作”这样的字样。

延伸阅读:

  • C专家编程:不要被标题中的“专家”吓到,这实际是一本很轻松的书籍,它既包含了大量C语言技术细节和编程技巧,也包含了很多有趣的编程轶事;
  • C陷阱与缺陷:书如其名,这本书介绍了C语言中常见的坑和一些稀奇古怪的编程“技巧”,不少刁钻的C语言面试题都源自这本小册子;
  • C语言参考手册:全面且权威的C语言参考手册,而且覆盖C99,如果你打算成为C语言专家,那么这本书不可错过;
  • C标准库:给出了15个C标准库的设计思路,实现代码,以及测试代码,配合C程序设计语言阅读效果更佳;
  • C语言接口与实现:这本书展示了如何使用C语言实现可复用的数据结构,其中包含大量C语言高级技巧,以至于Amazon上排行第一的评论是“Probably the best advanced C book in existance”,而排行第二的评论则是“By far the most advanced C book I read”。

C++

C++程序设计原理与实践

作为C++的发明者,没有人能比Bjarne Stroustrup更理解C++。Bjarne在Texas A&M大学任教时使用C++为大学新生讲授编程,从而就有了C++程序设计原理与实践这本书——它面向编程初学者,既包含C++教程,也包含大量程序设计原则。它不但是我读过最好的C++入门书,也是我读过最好的编程入门书。

比较有趣的是,C++程序设计原理与实践直到全书过半都没有出现指针,我想这可能是Bjarne为了证明不学C也可以学好C++吧。

C++程序设计语言(第4版)

同样是Bjarne Stroustrup的作品,C++程序设计语言是C++最权威且最全面的书籍。第4版相对于之前的版本进行了全面的更新,覆盖了第二新的C++ 11标准,并砍掉了部分过时的内容。

延伸阅读:

  • A Tour of C++:如果你觉得C++程序设计语言过于庞大,但你又想快速的浏览一遍新版C++的语言特色,那么可以试试这本小红书;
  • C++语言的设计与演化:C++的“历史书”,讲述了C++是如何一步一步从C with Classes走到如今这一步,以及C++语言特性背后的故事;
  • C++标准库(第2版):相对于其它语言的标准库,C++标准库虽然强大,但学习曲线十分陡峭,这本书是学习C++标准库有力的补充;
  • 深度探索C++对象模型:这本书系统的讲解了C++是如何以最小的性能代价实现对象模型,很多C++面试题(包括被问烂的虚函数指针)都可以在这本书里找到答案;
  • Effective C++More Effective C++:由于C++的特性实在繁杂,因此很容易就掉到坑里。Effective系列既讲述了C++的良好编程实践,也包含C++的使用误区,从而帮你绕过这些坑。

Java

Java核心技术(第9版)

平心而论Java核心技术(即Core Java)并不算是一本特别出色的书籍:示例代码不够严谨,充斥着很多与C/C++的比较,语言也不够简洁——问题在于Java并没有一本很出色的入门书籍,与同类型的Java编程思想相比,Java核心技术至少做到了废话不多,与时俱进(Java编程思想还停留在Java 6之前),矮子里面选将军,Java核心技术算不错了。

Effective Java(第2版)

尽管Java没有什么出色的入门书籍,但这不代表Java没有出色的必读书籍。Effective Java是我读过的最好的编程书籍之一,它包含大量的优秀Java编程实践,并对泛型和并发这两个充满陷阱的Java特性给出了充满洞察力的建议,以至于Java之父James Gosling为这本书作序:“我很希望10年前就拥有这本书。可能有人认为我不需要任何Java方面的书籍,但是我需要这本书。”

延伸阅读:

  • 深入理解Java虚拟机(第2版):非常优秀且难得的国产佳作,系统的介绍了Java虚拟机和相关工具,并给出了一些调优建议;
  • Java程序员修炼之道:在这本书之前,并没有一本Java书籍系统详细的介绍Java 7的新特性(例如新的垃圾收集器,try using结构和invokedynamic指令),这本书填补了这个空白;
  • Java并发编程实践:系统全面的介绍了Java的并发,如何设计支持并发的数据结构,以及如何编写正确的并发程序;
  • Java Puzzlers:包含了大量的Java陷阱——以至于读这本书时我说的最多的一个词就是WTF,这本书的意义在于它是一个反模式大全,Effective Java告诉你如何写好的Java程序,而Java Puzzlers则告诉你糟糕的Java程序是什么样子。更有意思的是,这两本书的作者都是Joshua Bloch

视频教程:

  • Java语言学习极速之旅:系统全面的Java语言教程,6个阶段Java基础入门,循序渐进掌握Java面向对象精髓。3个Java进阶方向,Java SE、Java EE、Android开发,每一个都包含相应的知识点精讲和项目开发实例,快速上手。
  • Android 0基础极速养成计划:Android开发快速入门视频教程,通过对Android基础知识讲解,详细介绍Android开发环境搭建,同时包含Android实战案例解析,通过全新实战的Android课程,系统学习Android开发。

C#

精通C#(第6版)

可能你会疑问我为什么会推荐这本接近1200页的“巨著”用作C#入门,这是我的答案:

  1. C#的语言特性非常丰富,很难用简短的篇幅概括这些特性;
  2. 精通C#之所以有近1200页的篇幅,是因为它不但全面介绍了C#语言,而且还覆盖了ADO.NET,WCF,WF,WPF,以及ASP.NET这些.Net框架。你可以把这本书视为两本书——一本500多页的C#语言教程和一本600多页的.Net平台框架快速上手手册。
  3. 尽管标题带有“精通”两字,精通C#实际上是一本面向初学者的C#书籍,你甚至不需要太多编程知识,就可以读懂它。

CLR via C#(第4版)

CLR via C#是C#/.Net最重要的书籍,没有之一。它全面介绍了.Net的基石——CLR的运行原理,以及构建于CLR之上的C#类型系统,运行时关系,泛型,以及线程/并行等高级内容。任何一个以C#为工作内容的程序员都应该阅读此书。

延伸阅读:

  • 深入理解C#(第3版):C#进阶必读,这本书偏重于C#的语言特性,它系统的介绍了C#从1.0到C# 4.0的语言特性演化,并展示了如何利用C#的语言特性编写优雅的程序;
  • .NET设计规范(第2版):C#专业程序员必读,从变量命名规范讲到类型系统设计原则,这本书提供了一套完整的.Net编程规范,使得程序员可以编写出一致,严谨的代码,
  • C# 5.0权威指南:来自O’Reilly的C#参考手册,严谨的介绍了C#语法,使用,以及核心类库,C#程序员案头必备;
  • LINQ to Objects Using C# 4.0Async in C# 5.0:LINQ和async分别是.Net 3.5和.Net 4.5中所引入的最重要的语言特性,所以我认为有必要在它们上面花点功夫——这两本书是介绍LINQ和async编程的最佳读物。

JavaScript

JavaScript DOM编程艺术(第2版)

尽管JavaScript现在可以做到客户端服务器端通吃,尽管JQuery之类的前端框架使得一些人可以不懂JavaScript也可以编程,但我还是认为学习JavaScript从HTML DOM开始最为适合,因为这是JavaScript设计的初衷。JavaScript DOM编程艺术系统的介绍了如何使用JavaScript,HTML,以及CSS创建可用的Web页面,是一本前端入门佳作。

JavaScript语言精粹

JavaScript语言包含大量的陷阱和误区,但它却又有一些相当不错的特性,这也是为什么Douglas Crockford称JavaScript为世界上最被误解的语言,并编写了JavaScript语言精粹一书来帮助前端开发者绕开JavaScript中的陷阱。和同类书籍不同,JavaScript语言精粹用精炼的语言讲解了JavaScript语言中好的那部分(例如闭包,函数是头等对象,以及对象字面量),并建议读者不要使用其它不好的部分(例如混乱的类型转换,默认全局命名空间,以及奇葩的相等判断符),毕竟,用糟糕的特性编写出来的程序往往也是糟糕的。

延伸阅读:

Python

Python基础教程(第二版)

Python的入门书籍很多,而且据说质量大多不错,我推荐Python基础教程的原因是因为它是我的Python入门读物——简洁,全面,代码质量很不错,而且有几个很有趣的课后作业,使得我可以快速上手。

这里顺便多说一句,不要用Python学习手册作为Python入门——它的废话实在太多,你能想象它用了15页的篇幅去讲解if语句吗?尽管O’Reilly出了很多经典编程书,但这本Python学习手册绝对不在其中。

Python参考手册(第4版)

权威且实用的Python书籍,覆盖Python 2和Python 3。尽管它名为参考手册,但Python参考手册在Python语法和标准库基础之上对其实现机制也给出了深入的讲解,不容错过。

延伸阅读:

3. 编程语言理论

编程语言实现模式

大多数程序员并不需要从头编写一个编译器或解释器,因此龙书(编译原理)就显得过于重量级;然而多数程序员还是需要解析文本,处理配置文件,或者写一个小语言,编程语言实现模式很好的满足了这个需求。它把常用的文本解析/代码生成方法组织成一个个模式,并为每个模式给出了实例和应用场景。这本书既会提高你的动手能力,也会加深你对编程语言的理解。Python发明者Guido van Rossum甚至为这本书给出了“Throw away your compiler theory book!”这样的超高评价。

程序设计语言——实践之路(第3版)

程序员每天都要和编程语言打交道,但是思考编程语言为什么会被设计成这个样子的程序员并不多,程序设计语言——实践之路完美的回答了这个问题。这本书从编程语言的解析和运行开始讲起,系统了介绍了命名空间,作用域,控制流,数据类型以及方法(控制抽象)这些程序设计语言的核心概念,然后展示了这些概念是如何被应用到过程式语言,面向对象语言,函数式语言,脚本式,逻辑编程语言以及并发编程语言这些具有不同编程范式的编程语言之上。这本书或极大的拓宽你的视野——无论你使用什么编程语言,都会从这本书中获益良多。理解这一本书,胜过学习十门新的编程语言。

延伸阅读:

  • 七周七语言:理解多种编程范型:尽管我们在日常工作中可能只使用两三门编程语言,但是了解其它编程语言范式是很重要的。七周七语言一书用精简的篇幅介绍了Ruby,Io,Prolog,Scala,Erlang,Clojure,和Haskell这七种具有不同编程范式的语言——是的,你没法通过这本书变成这七种语言的专家,但你的视野会得到极大的拓宽;
  • 自制编程语言:另一本优秀的编译原理作品,自制编程语言通过从零开始制作一门无类型语言Crowbar和一门静态类型语言Diksam,把类型系统,垃圾回收,和代码生成等编程语言的关键概念讲的清清楚楚;
  • 计算的本质:深入剖析程序和计算机:披着Ruby外衣的计算理论入门书籍,使你对编程语言的理解更上一层楼。

4. 程序设计

程序设计方法

现代编程语言的语法大多很繁杂,初学者使用这些语言学习编程会导致花大量的时间在编程语言语法(诸如指针,引用和类型定义)而不是程序设计方法(诸如数据抽象和过程抽象)之上。程序设计方法解决了这个问题——它专注于程序设计方法,使得读者无需把大量时间花在编程语言上。这本书还有一个与之配套的教学开发环境DrScheme,这个环境会根据读者的程度变换编程语言的深度,使得读者可以始终把注意力集中在程序设计方法上。

我个人很奇怪程序设计方法这样的佳作为什么会绝版,而谭浩强C语言这样的垃圾却大行其道——好在是程序设计方法第二版已经被免费发布在网上。

计算机程序的构造与解释(第2版)

计算机程序的构造与解释是另一本被国内大学忽视(至少在我本科时很少有人知道这本书)的教材,这本书和程序设计方法有很多共同点——都使用Scheme)作为教学语言;都专注于程序设计方法而非编程语言本身;都拥有相当出色的课后题。相对于程序设计方法计算机程序的构造与解释要更加深入程序设计的本质(过程抽象,数据抽象,以及元语言抽象),以至于Google技术总监Peter Norvig给了这本书超高的评价

延伸阅读:

  • 编程原本STL作者的关于程序设计方法佳作——他把关系代数和群论引入编程之中,试图为程序设计提供一个坚实的理论基础,从而构建出更加稳固的软件。这本书是程序设计方法计算机程序的构造与解释的绝好补充——前者使用函数式语言(Scheme)讲授程序设计,而编程原本则使用命令式语言(C++);
  • 元素模式设计模式总结了面向对象程序设计中的模式,而元素模式这本书分析了程序设计中的常见模式的本质,阅读这本书会让你对程序设计有更深的理解;
  • The Science of Programming:会编程的人很多,但能够编写正确程序的人就少多了。The Science of Programming通过前条件——不变式——后条件以及逻辑谓词演算,为编写正确程序提供了强有力的理论基础,然后这本书通过实例阐述了如何应用这些理论到具体程序上。任何一个想大幅提高开发效率的程序员都应阅读此书。

5. 算法与数据结构

算法(第4版)

我在算法学习之路一文中提到我的算法入门教材是数据结构与算法分析:C语言描述,我曾经认为它是最好的算法入门教材,但自从我读到Sedgewick算法之后我就改变了观点——这本算法才是最好的算法入门教材:

  • 使用更为容易的Java语言作为教学语言;
  • 覆盖所有常用的数据结构和算法,并均给出其完整实现;
  • 包含大量的图示用于可视化算法——事实上这是我读过的图示最为丰富形象的书籍,这也是我称其为最好的算法入门书籍的原因。

编程珠玑(第2版)

编程珠玑(第2版)是一本少见的实践型算法书籍——它并非一一介绍数据结构/算法的教材,而是实践性极强的算法应用手册。作者(Jon Bentley)从他多年的实际经验精选出一些有趣而又实用的问题,然后展示了他解决这些问题的过程(分析问题,选择合适的算法,解决问题,以及验证答案)。任何程序员都可以从中获益。

延伸阅读:

  • 编程珠玑(续):严格来说这本书并非编程珠玑的续作,而是一本类似于番外篇的编程技巧/实践手册;它不像编程珠玑那般重视算法的应用,而是全面覆盖了程序员所需的能力;
  • 算法导论(第3版):尽管我在这边文章开头提到会尽量避免理论性的书籍,但没有算法导论的算法阅读列表是不完整的,我想这本书就不需要我多介绍了; :–)
  • 算法设计与分析基础(第3版):侧重于算法设计,这本书创新的把常见算法分为分治,减治,变治三大类,并覆盖了动态规划,回溯,以及分支定界等高级算法设计方法,属于算法设计的入门佳作;

6. 程序调试

调试九法——软硬件错误的排查之道

一个让非编程从业人员惊讶的事实是程序员的绝大多时间都花在调试上,而不是写程序上,以至于Bob大叔调试时间占工作时间的比例作为衡量程序员开发能力的标准。调试九法——软硬件错误的排查之道既是调试领域的入门作品,也是必读经典之作。调试九法的作者是一个具有丰富实战经验的硬件工程师,他把他多年的调试经验总结成九条调试法则,并对每一条法则都给对应的实际案例。任何程序员都应通过阅读这本书改善调试效率,即便是非程序员,也可以从这本书中学到系统解决问题的方法。

延伸阅读:

  • Writing Solid Code最好的调试是不调试——Writing Solid Code介绍了断言,设计清晰的API,以及单步代码等技巧,用于编写健壮的代码,减少调试的时间;
  • 软件调试的艺术:调试工具书——这本书详细的介绍了常见的调试器工具,并通过具体案例展示了它们的使用技巧;

软件开发

1. 编程实践

程序设计实践

Brian Kernighan是这个星球上最好的计算机书籍作者:从上古时期的Software Tools,到早期的Unix编程环境C程序设计语言,再到这本程序设计实践,每本书都是必读之作。

尽管程序设计实践只有短短200余页,但它使用精炼的代码和简要的原则覆盖了程序设计的所有关键概念(包括编程风格,算法与数据结构,API设计,调试,测试,优化,移植,以及领域特定语言等概念)。如果你想快速掌握良好的编程实践,或者你觉着900多页的代码大全过于沉重,那么程序设计实践是你的不二之选。我第一次读这本书就被它简洁的语言和优雅的代码所吸引,以至于读研时我买了三本程序设计实践——一本放在学校实验室,一本放在宿舍,一本随身携带阅读。我想我至少把它读了十遍以上——每一次都有新的收获。

代码大全(第2版)

无论在哪个版本的程序员必读书单,代码大全都会高居首位。和其它程序设计书籍不同,代码大全用通俗清晰的语言覆盖了软件构建(Software Construction)中各个层次上所有的重要概念——从变量命名到类型设计,从控制循环到代码结构,从测试和调试到构建和集成,代码大全可谓无所不包,你可以把这本书看作为程序员的一站式(Once and for all)阅读手册。更珍贵的是,代码大全在每一章末尾都给出了价值很高的参考书目(参考我之前的如何阅读书籍一文),如果你是一个初出茅庐的程序员,代码大全是绝好的阅读起点。

延伸阅读:

  • 编写可读代码的艺术:专注于代码可读性(Code Readability),这本书来自Google的两位工程师对Google Code Readability的总结。它给出了大量命名,注释,代码结构,以及API设计等日常编码的最佳实践,并包含了很多看似细微但却可以显著提升代码可读性的编程技巧。这本书的翻译还不错,但如果你想体会书中的英语幽默(例如Tyrannosaurus——Stegosaurus——Thesaurus),建议阅读它的英文影印版
  • 卓有成效的程序员:专注于生产效率(Productivity),它既包含源自作者多年经验的高生产率原则,也包含大量的提高生产率的小工具,每个追求高生产率的程序员都应该阅读这本书;
  • UNIX编程艺术:专注于程序设计哲学,这本书首先总结出包括模块化,清晰化,可组合,可分离等17个Unix程序设计哲学,接下来通过Unix历史以及各种Unix编程工具展示了这些原则的应用。尽管个人觉的这本书有些过度拔高Unix且过度贬低Windows和M$,但书中的Unix设计哲学非常值得借鉴。

2. 面向对象程序设计

Head First设计模式

无论是在Amazon还是在Google上搜索设计模式相关书籍,Head First设计模式都会排在首位——它使用风趣的语言和诙谐的图示讲述了观察者,装饰者,抽象工厂,和单例等关键设计模式,使得初学者可以迅速的理解并掌握设计模式。Head First设计模式在Amazon上好评如潮,就连设计模式原书作者Erich Gamma都对它给出了很高的评价。

需要注意,Head First设计模式是非常好的设计模式入门书,但千万不要把这本书作为学习设计模式的唯一的书——是的,Head First设计模式拥有风趣的语言和诙谐的例子,但它既缺乏实际的工程范例,也没有给出设计模式的应用/适用场景。我个人建议是在读过这本书之后立即阅读“四人帮”)的设计模式Bob大叔敏捷软件开发,以便理解设计模式在实际中的应用。

设计模式

设计模式作为设计模式领域的开山之作,Erich Gamma,Richard Helm,Ralph Johnson等四位作者将各个领域面向对象程序开发的经验总结成三大类23种模式,并给出了每个模式的使用场景,变体,不足,以及如何克服这些不足。这本书行文严谨紧凑(四位作者都是PhD),并且代码源自实际项目,属于设计模式领域的必读之作。

需要注意:设计模式不适合初学者阅读——它更像是一篇博士论文而非技术书籍,加上它的范例都具有很强的领域背景(诸如GUI窗口系统和富文本编辑器),缺乏实际经验的程序员很难理解这本书。

延伸阅读:

3. 重构

重构

任何产品代码都不是一蹴而就,而是在反复不断的修改中进化而来。重构正是这样一本介绍如何改进代码的书籍——如何在保持代码行为的基础上,提升代码的质量(这也是重构的定义)。

我见过很多程序员,他们经常声称自己在重构代码,但他们实际只做了第二步(提升代码的质量),却没有保证第一步(保持代码行为),因此他们所谓的重构往往会适得其反——破坏现有代码或是引入新bug。这也是我推荐重构这本书的原因——它既介绍糟糕代码的特征(Bad smell)和改进代码的方法,也给出了重构的完整流程——1. 编写单元测试保持(Preserve)程序行为;2. 重构代码;3. 保证单元测试通过。重构还引入了一套重构术语(诸如封装字段,内联方法,和字段上移),以便程序员之间交流。只有理解了这三个方面,才能算是理解重构。

修改代码的艺术

这里再重复一遍重构的定义——在保持代码行为的基础上,提升代码的质量。重构专注于第二步,即如何提升代码的质量,而修改代码的艺术专注于第一步,即如何保持代码的行为。

提升代码质量并不困难,但保持代码行为就难多了,尤其是对没有测试的遗留代码(Legacy Code)而言——你需要首先引入测试,但遗留代码往往可测试性(Testability)很差,这时你就需要把代码变的可测试。修改代码的艺术包含大量的实用建议,用来把代码变的可测试(Testable),从而使重构变为可能,使提高代码质量变为可能。

延伸阅读:

  • 重构与模式:这本书的中文书名存在误导,它的原书书名是Refactoring to Patterns——通过重构,把模式引入代码。这本书阐述了重构和设计模式之间的关系,使得程序员可以在更高的层次上思考重构,进行重构。

4. 软件测试

How to Break Software

关于软件测试的书籍很多,但很少有一本测试书籍能像How to Break Software这般既有趣又实用。不同于传统的软件测试书籍(往往空话连篇,无法直接应用),How to Break Software非常实际——它从程序员的心理出发,分析软件错误/Bug最可能产生的路径,然后针对这些路径进行残酷的测试,以保证软件质量。

我在第一次阅读这本书时大呼作者太过“残忍”——连这些刁钻诡异的测试招数都能想出来。但这种毫不留情(Relentless)的测试风格正是每个专业程序员所应具备的心态。

注意:如果你是一个测试工程师,那么在阅读这本书前请三思——因为阅读它之后你会让你身边的程序员苦不堪言,甚至连掐死你的心都有 :-D。

xUnit Test Patterns

How to Break Software注重黑盒测试,而这本xUnit Test Patterns则注重白盒测试。正如书名所示,xUnit Test Patterns覆盖了单元测试的每个方面:从如何编写良好的单元测试,到如何设计可测试(Testable)的软件,再到如何重构测试——可以把它看作为单元测试的百科全书。

延伸阅读:

  • Practical Unit Testing with JUnit and Mockito:尽管xUnit Test Patterns覆盖了单元测试的方方面面,但它的问题在于不够与时俱进(07年出版)。Practical Unit Testing弥补了这个缺陷——它详细介绍了如何通过测试框架JUnit和Mock框架Mockito编写良好的单元测试,并给出了大量优秀单元测试的原则;
  • 单元测试的艺术(第2版):可以把这本书看作为前一本书的.Net版,适合.Net程序员;
  • Google软件测试之道:这本书详细介绍了Google如何测试软件——包括Google的软件测试流程以及Google软件测试工程师的日常工作/职业发展。需要注意的是:这本书中的测试流程在国内很可能行不通(国内企业缺乏像Google那般强大的基础设施(Infrastructure)),但它至少可以让国内企业有一个可以效仿的目标;
  • 探索式软件测试James Whittaker的另一本测试著作,不同于传统的黑盒/白盒测试,这本书创造性的把测试比喻为“探索”(Exploration),然后把不同的探索方式对应到不同的测试方式上,以便尽早发现更多的软件错误/Bug。

5. 项目管理

极客与团队

很多程序员都向往成为横扫千军(One-man Army)式的“编程英雄”,但卓越的软件并非一人之力,而是由团队合力而成。极客与团队就是这样一本写给程序员的如何在团队中工作的绝好书籍,它围绕着HRT三大原则(Humility谦逊,Respect尊重,和Trust信任),系统的介绍了如何融入团队,如何打造优秀的团队,如何领导团队,以及如何应对团队中的害群之马(Poisonous People)。这本书实用性极强,以至于Python之父Guido van Rossum都盛赞这本书“说出了我一直在做但总结不出来的东西”

人月神话

尽管人月神话成书于40年前,但它仍是软件项目管理重要的书籍。人月神话源自作者Fred Brooks领导并完成System/360OS/360这两个即是放到现在也是巨型软件项目的里程碑项目的经验总结。它覆盖了软件项目各个方面的关键概念:从工期管理(Brooks定律)到团队建设(外科团队),从程序设计(编程的本质是使用正确的数据结构)到架构设计(概念完整性),从原型设计(Plan to Throw one away)到团队交流(形式化文档+会议)。令人惊讶的是,即便40年之后,人月神话中的关键概念(包括焦油坑,Brooks定律概念完整性外科团队第二版效应等等)依然适用,而软件开发的核心复杂度仍然没有得到解决(没有银弹)。

延伸阅读:

  • 人件(原书第3版):从人的角度分析软件项目。人件从雇佣正确的人,创建健康的工作环境,以及打造高效的开发团队等角度阐述了如何改善人,从而改善软件项目;
  • 门后的秘密:卓越管理的故事:这本书生动的再现了软件项目管理工作的场景,并给出了各种实用管理技巧,如果你有意转向管理岗位,这本书不容错过;
  • 大教堂与集市:这本书从黑客的历史说起,系统而又风趣的讲述了开源运动的理论和实践,以及开源软件项目是如何运作并发展的。了解开源,从这本书开始。

6. 专业开发

程序员修炼之道:从小工到专家

不要被庸俗的译名迷惑,程序员修炼之道是一本价值极高的程序员成长手册。这本书并不局限于特定的编程语言或框架,而是提出了一套切实可行的实效(Pragmatic)开发哲学,并通过程序设计,测试,编程工具,以及项目管理等方面的实例展示了如何应用这套开发哲学,从而使得程序员更加高效专业。有人把这本书称之为迷你版代码大全——代码大全给出了大量的优秀程序设计实践,偏向术;而程序员修炼之道给出了程序设计实践背后的思想,注重道。

程序员职业素养

程序员修炼之道指出了如何成为专业程序员,这本程序员职业素养则指出了专业程序员应该是什么样子——承担责任;知道自己在做什么;知道何时说不/何时说是;在正确的时间编写正确的代码;懂得自我时间管理和工期预估;知道如何应对压力。如果你想成为专业程序员(Professional Developer)(而不是码农(Code Monkey)),这本书会为你指明前进的方向。

延伸阅读:

7. 大师之言

奇思妙想:15位计算机天才及其重大发现

奇思妙想:15位计算机天才及其重大发现是一本极具眼光的技术访谈书籍——在这本书访谈的15位计算机科学家中,竟出现了12位图灵奖获得者——要知道图灵奖从1966年设奖到现在也只有六十几位获奖者而已。

奇思妙想把计算机科学分为四大领域:编程语言;算法;架构;人工智能。并选取了每个领域下最具代表性的计算机科学家进行访谈。因为这些计算机科学家都是其所在领域的开拓者,因此他们能给出常人无法给出的深刻见解。通过这本书,你可以了解前三十年的计算机科学的发展历程——计算机科学家做了什么,而计算机又能做到/做不到什么。从而避免把时间浪费在前人已经解决的问题(或者根本无法解决的问题)上面。

编程人生:15位软件先驱访谈录

同样是访谈录,同样访谈15个人,编程人生把重点放在程序员(Coders at work)上。它从各个领域选取了15位顶尖的程序员,这些程序员既包括Ken ThompsonJamie Zawinski这些老牌Unix黑客,也包括Brad Fitzpatrick这样的80后新生代,还包括Frances AllenDonald Knuth这样的计算机科学家。这种多样性(Diversity)使得编程人生兼具严谨性和趣味性,无论你是什么类型的程序员,都能从中受益良多。

延伸阅读:

  • 图灵和ACM图灵奖(1966-2011):通过图灵奖介绍整个计算机科学发展史,非常难得的国产精品图书;
  • 编程大师访谈录:可以把这本书看作为二十年前的编程人生,被访谈者都是当时叱咤风云的人物(例如微软的创造者Bill Gates,Macintosh的发明者Jeff Raskin,以及Adobe的创始人John Warnock等等)。有趣的是这本书中大量的经验和建议到如今依然适用;
  • 编程大师智慧:类似于编程人生,不同的是被访谈者都是编程语言的设计者——这本书覆盖了除C语言以外的几乎所有主流编程语言。通过这本书,你可以从中学到编程语言背后的设计思想——编程语言为什么要被设计成这样,是什么促使设计者要在语言中加入这个特性(或拒绝那个特性)。从而提升对编程语言的理解。

8. 界面设计

写给大家看的设计书

书如其名,写给大家看的设计书是一本面向初学者的快速设计入门。它覆盖了版式,色彩,和字体这三个设计中的关键元素,并创造性的为版式设计总结出CRAP四大原则(Contrast对比,Repetition重复,Alignment对齐,Proximity亲密)。全书使用丰富生动的范例告诉读者什么是好的设计,什么是不好的设计,使得即便是对设计一无所知的人,也可以从这本书快速入门。

认知与设计:理解UI设计准则(第2版)

写给大家看的设计书强调实践,即如何做出好的设计;认知与设计:理解UI设计准则强调理论,即为什么我们会接受这样的设计而反感那样的设计。如果你想要搞清楚设计背后的心理学知识,但又不想阅读大部头的心理学著作,那么认知与设计是你的首选。

延伸阅读:

  • GUI设计禁忌 2.0:这本书指出了GUI设计的原则和常见误区,然后通过具体范例指出了如何避免这些误区。如果你的工作涉及到用户界面,那么这本书会为你减少很多麻烦;
  • 界面设计模式(第2版):这本书将用户界面中的常见元素/行为组织成彼此关联的模式,以便读者理解并举一反三,从而将其运用到自己的应用中;
  • 移动应用UI设计模式:类似于界面设计模式,但面向移动平台。它给出了iOS,Android,以及Windows Phones上常用的90余种界面设计模式,从而使得你不必把这些平台的应用挨个玩一遍也可以掌握各个平台的设计精髓。如果你主攻Android平台,那么Android应用UI设计模式会是更好的选择;
  • 配色设计原理版式设计原理:如果你读过写给大家看的设计书之后想继续深入学习设计,这两本书是不错的起点。

9. 交互设计

通用设计法则

书如其名,通用设计法则给出了重要的125个设计原则,并用简练的语言和范例展示了这些原则的实际应用。每个原则都有对应的参考文献,以便读者进一步学习。我之所以推荐这本书,是因为:1. 程序员需要对设计有全面的认识;2. 程序员并不需要知道这些设计原则是怎么来的,知道怎么用即可。这本书很好的满足了这两个要求。

交互设计精髓(第3版)

交互设计精髓是交互设计领域的圣经级著作。交互设计专家(以及VB之父)Alan Cooper在这本书中详细介绍了交互设计的原则,流程,以及方法,然后通过各种范例(主要来自桌面系统)展示了如何应用这些原则。

需要注意的是这本书的第4版已经出版,它在第三版的基础上增加了移动设计以及Web设计等内容。

延伸阅读:

  • The Design of Everyday Things:交互设计领域的另一本经典之作,它通过解读人类行动背后的心理活动,展示了设计问题的根源,并给出了一系列方法用以解决设计问题(需要注意,尽管这本书有中译版,但中译版对应的是02年的旧版,而非13年的新版);
  • The Inmates Are Running the AsylumAlan Cooper的另一本经典,这本书非常辛辣的指出让不具备人机交互知识的程序员直接编写面向用户的软件就像让精神病人管理疯人院(The Inmates Are Running the Asylum),然后给出了一套交互设计流程以挽救这个局面;
  • 简约至上:交互式设计四策略:专注于把产品变的更加简单易用。作者通过删除,组织,隐藏,和转移这四个策略,展示了如何创造出简约优质的用户体验。

个人成长

1. 职业规划

软件开发者路线图

软件开发者路线图是一本优秀且实用的程序员职业规划手册。这本书由若干个模式组成,每个模式都对应于程序员职业生涯中的特定阶段。通过这本书,读者可以很方便的找到自己目前所处的模式(阶段),应该做什么,目标是什么,以及下一个模式(阶段)会是什么。如果你时常感到迷茫,那么请阅读这本路线图,找到自己的位置,确定接下来的方向。

延伸阅读:

  • 卡耐基全集:非常著名的为人处世书籍。很多人把这本书归类到成功学,但我并不这么认为——在我看来,这本书教的更多的是如何成为一个让大家喜欢的人。作为天天和机器打交道的程序员,这套书会帮助我们与人打交道;
  • 沃顿商学院最受欢迎的谈判课:这本书不是教你去谈判,而是教你通过谈判(Negotiation)去得到更多(Getting more,这也是这本书的原书书名)。小到买菜砍价,大到争取项目,这本书中的谈判原则会让你收益良多;
  • 程序员健康指南:作为长期与计算机打交道的职业,程序员往往会受到各式各样疾病的困扰,这本书正是为了解决这个问题而出现:它从改善工作环境,调整饮食结构,预防头痛眼痛,以及进行室内/室外锻炼等方面出发,给出了一套全面且可行的程序员健康改善计划,以帮助程序员打造健康的身体。

2. 思维方式

程序员的思维修炼:开发认知潜能的九堂课

作为程序员,我们需要不断地学习——既要学习新技术,也要学习如何解决各种领域的问题。为了提升学习效率,我们需要学习如何学习程序员的思维修炼正是这样一本讲如何学习的书,它集合了认知科学,神经学,以及行为理论的最新研究成果,并系统的介绍了大脑的工作机制。通过这本书,你将学会如何高效的使用自己的大脑,从而提高思考能力,改善学习效率。

如何把事情做到最好

Mastery is not about perfection. It’s about a process, a journey. The master is the one who stays on the path day after day, year after year. The master is the one who is willing to try, and fail, and try again, for as long as he or she lives.

为什么同样资质的人,大多数人会碌碌无为,而只有极少数能做到登峰造极?如何在领域内做到顶尖?如何克服通往顶尖之路上的重重险阻?如何把事情做到最好回答了这些问题,并极具哲理的指出登峰造极并不是结果,而是一段永不停止的旅程。阅读这本书不会让你立刻脱胎换骨,但它会指引你走向正确的道路——通往登峰造极之路。

延伸阅读:

  • 怎样解题:数学思维的新方法:不要被标题中的“数学思维”吓到,它并不仅仅只是一本数学解题书,它所提出的四步解题法(理解题目->拟定方案->执行计划->总结反思)适用于任何领域;
  • 暗时间刘未鹏所写的关于学习思维方法的文章集,既包含了他对学习方法的思考,也包含了大量进一步阅读的资源;
  • 批判性思维:带你走出思维的误区:这本书系统的分析了人类思维的常见误区,并针对各个误区给出了解决方案,从而帮助程序员养成严谨正确的思考方式;
  • Conceptual Blockbusting: A Guide to Better Ideas:与批判性思维相反,这本书专注于创造性思维(Creative Thinking),它分析了阻碍创造性思维的常见思维障碍(Blockbuster)以及这些思维障碍背后的成因,并给出了各种方法以破除这些障碍。

3. 求职面试

金领简历:敲开苹果微软谷歌的大门

知己知彼,百战不殆。金领简历:敲开苹果微软谷歌的大门是程序员求职的必读书籍,它覆盖了程序员求职的方方面面:从开始准备到编写简历,从技术面试到薪酬谈判。由于该书作者曾在Google,微软,和苹果任职并进行过技术招聘,因此这本书的内容非常实用。

顺便吐个槽:这本书翻译的还不错,但我实在无法理解封面上的“进入顶级科技公司的葵花宝典”这段文字——找个工作而已,用不着切JJ这么凶残吧。-_–#

程序员面试金典(第5版)

同样是来自金领简历作者的作品,程序员面试金典(第5版)专注于技术面试题,它既包含了IT企业(诸如微软,Google,和苹果)的面试流程以及如何准备技术面试,也包含了大量(超过200道)常见技术面试题题目以及解题思路。无论你打算进入国内企业还是外企,你都应该把这本书的题目练一遍,以找到技术面试的感觉(我在求职时就曾经专门搞了一块白板,然后每二十分钟一道题的练习,效果很不错)。

延伸阅读:

  • 编程之美:微软技术面试心得:恐怕是国内技术面试第一书,这本书里面的多数题目都曾经是国内IT企业面试的必问题目。这本书的缺点是它太旧而且被用滥了(以至于一些企业开始避免使用这本书上的题目)——但你可以把它当成一本算法趣题来读;
  • 剑指Offer:名企面试官精讲典型编程题:相对于东拼西凑的XX面试宝典,剑指Offer是一本少见的国产精品技术面试书籍,尽管这本书的技术面试题目不多(60余道),但作者为大多数题目都给出了不同方式的解法,并分析了这些解法之间的优劣,此外作者还以面试官的视角分析了技术面试的各个环节,从而帮助读者把握技术面试;
  • 人人都有好工作:IT行业求职面试必读:可以把它看做金领简历的补充阅读——这本书的特点在于它给出了非常详细的简历/求职信/电子邮件编写技巧,而这正是不少国内程序员所缺乏的。

4. 英语写作

The Only Grammar Book You'll Ever Need

词汇量决定阅读能力,语法决定写作能力。计算机专业词汇并不多,但精确性非常重要,因此每个程序员都应具备良好的英语语法,但程序员并不需要过于专业的英语语法——掌握常用语法并把它用对就可以。The Only Grammar Book You’ll Ever Need正好可以满足这个需求,尽管它篇幅不大(不足200页),却覆盖了英语中的关键语法以及常见错误。把这本书读两遍,它会大幅度提高你的英语写作能力。

风格的要素

既是最畅销的英语写作书籍,也是计算机书籍中引用最多的非计算机书籍。风格的要素用极其简练的语言讲述了如何进行严肃精确清楚的英语写作。从这本书中,你不仅可以学到英语写作,更可以学到一种严谨至简的处事态度,而这正是专业开发所必需的。

延伸阅读:

  • 牛津英语用法指南(第3版):全面且权威的英语用法指南,它覆盖语法,词汇,发音,以及修辞等方面,并兼顾口语和书面语,以帮助读者掌握合理的英语用法(Proper English Usage)。不要被这本书的篇幅(1000多页)吓到——原书并没有这么厚,因为这本书被翻译成中文但又得保留原有的英文内容,所以它的篇幅几乎翻了一倍。考虑到这本书使用的词汇都很基础,所以我认为具有英语基础的读者直接阅读原版(Practical English Usage)会更合适;
  • 写作法宝:非虚构写作指南(30周年纪念版):详尽的非虚构(Non-Fiction)写作指南,无论你要写地方,技术,商务,运动,艺术,还是自传,你都可以从这本书中找到珍贵的建议;
  • 中式英语之鉴:中国人使用英语最大的问题就是会把中式思维掺杂其中,从而形成啰里啰嗦不伦不类的中式英语(Chinglish)。中式英语之鉴系统的探讨了中式英语以及其成因,然后根据成因对中式英语进行归类,并对每个类别给出了大量的实际案例以及修改建议。如果你想摆脱中式英语,那么这本书是绝好的起点。

如何使用这个书单

学而不思则罔,思而不学则殆。

不愤不启,不悱不发。举一隅不以三隅反,则不复也。

不闻不若闻之,闻之不若见之,见之不若知之,知之不若行之,学至于行之而止矣。

来自他人的书单

它山之石,可以攻玉。我在本文最后给出其他中外优秀程序员的书单,以便参考&补充。

刘未鹏(暗时间作者)

以下同一条目下用“/”隔开的表示任选,当然也可以都读。

  1. 编码:隐匿在计算机软硬件背后的语言
  2. 深入理解计算机系统 / Windows核心编程 / 程序员的自我修养
  3. 代码大全 / 程序员修炼之道
  4. 编程珠玑 / 算法概论 / 算法设计 / 编程之美
  5. C程序设计语言
  6. C++程序设计语言 / C++程序设计原理与实践 / Accelerated C++
  7. 计算机程序的构造与解释
  8. 代码整洁之道 / 实现模式
  9. 设计模式 / 敏捷软件开发(原则模式与实践)
  10. 重构

云风(中国游戏编程先行者,前网易游戏部门资深程序员,简悦创始人)

  1. C++编程思想
  2. Effective C++
  3. 深度探索C++对象模型
  4. C++语言的设计与演化
  5. C专家编程
  6. C陷阱与缺陷
  7. C语言接口与实现
  8. Lua程序设计
  9. 链接器和加载器
  10. COM本质论
  11. Windows核心编程
  12. 深入解析Windows操作系统
  13. 程序员修炼之道
  14. 代码大全
  15. UNIX编程艺术
  16. 设计模式
  17. 代码优化:有效使用内存
  18. 深入理解计算机系统
  19. 深入理解LINUX内核
  20. TCP/IP详解

洪强宁(豆瓣技术总监)

  1. 代码大全
  2. 人月神话
  3. 编码:隐匿在计算机软硬件背后的语言
  4. 计算机程序设计艺术
  5. 程序员修炼之道
  6. 设计模式
  7. 计算机程序的构造与解释
  8. 重构
  9. C程序设计语言
  10. 算法导论

陈皓(CoolShell博主)

  1. 点石成金:访客至上的Web和移动可用性设计秘笈
  2. 重来:更为简单有效的商业思维
  3. 黑客与画家
  4. 清醒思考的艺术
  5. TCP/IP详解
  6. UNIX环境高级编程
  7. UNIX网络编程

张峥(微软亚洲研究院副院长)

  1. 算法概论
  2. Data Structure and Algorithms
  3. C程序设计语言
  4. UNIX操作系统设计
  5. 编译原理
  6. 计算机体系结构:量化研究方法
  7. 当下的幸福
  8. 异类:不一样的成功启示录

Jeff Atwood(Stackoverflow联合创始人)

  1. 代码大全
  2. 人月神话
  3. 点石成金:访客至上的Web和移动可用性设计秘笈
  4. 快速软件开发
  5. 人件
  6. The Design of Everyday Things
  7. 交互设计精髓
  8. The Inmates Are Running the Asylum
  9. GUI设计禁忌 2.0
  10. 编程珠玑
  11. 程序员修炼之道
  12. 精通正则表达式

Joel Spolsky(Stackoverflow联合创始人)

软件项目管理

  1. 人件
  2. 人月神话
  3. 快速软件开发

编程技艺

  1. 代码大全
  2. 程序员修炼之道

编程哲学

  1. 禅与摩托车维修艺术
  2. 哥德尔、艾舍尔、巴赫:集异璧之大成
  3. 建筑模式语言

界面设计

  1. 点石成金:访客至上的Web和移动可用性设计秘笈
  2. 交互设计精髓
  3. The Design of Everyday Things

资本运作

  1. 漫步华尔街

图形设计

  1. 写给大家看的设计书

思维方式

  1. 影响力
  2. Helplessness On Depression, Development and Death

编程入门

  1. 编码:隐匿在计算机软硬件背后的语言
  2. C程序设计语言

DHH(Ruby on Rails创始人)

  1. Smalltalk Best Practice Patterns
  2. 重构
  3. 企业应用架构模式
  4. 领域驱动设计
  5. 你的灯亮着吗?发现问题的真正所在

参考

  1. 怎样花两年时间去面试一个人
  2. What is the single most influential book every programmer should read?
  3. Recommended Reading for Developers
  4. Book Reviews — Joel Spolsky
  5. The five programming books that meant most to me

 

 

作者:Lucida

原文链接:http://lucida.me/blog/developer-reading-list/

一个程序员的顿悟:这6点带来的差距真的不是一点点

来自:建造者说
链接:
http://guoze.me/2015/03/02/excellent-programmer/
作者:微博:@GavinBuildSomething

我算是靠坑蒙拐骗进了程序员的门,然后一路狂奔。26岁之前几乎没有任何写代码的经验,研究生毕业却意外选择了一家不可能提供培训的初创公司,在每日担忧公司倒闭、害怕被炒鱿鱼以及同事冷落白眼的三重压力下逆流而上,一年半后离职,已是拥有500万用户产品的后台主程。从前我对计算机技术心怀畏惧,认定技术高人一定有佛光笼罩,昼夜不息运键如飞日吐代码上万行。现在也算见过一些世面了,回首那段忐忑不安宛如初夜的过程,我却不发觉有任何的励志意味,而是视为一种理所当然。理想的程序员,和理想的建筑师、理想的财务师、理想的按摩师没有任何的差别,他们本质上都是一群手艺人。我相信理想的程序员人人皆可成为。

近三年总在互联网圈厮混,我认识过一些程序员,共事过一些程序员,领导过一些程序员,又面试过一些程序员。他们学历不同,有的来自北大,有的来自培训机构,有的是博士,有的是高中肄业;资历也不同,有的来自BAT,有的来自某破产基金公司(还是一个销售);年限也从 0 到 15年不等。但我认为程序员只需分三类:天才的程序员、理想的程序员、平庸的程序员。天才的程序员我只敢说接触过 3 个,这是天命。7分由你是颗精子的时候就已决定,拥有绝佳的数学天赋、冷静致密的逻辑、为解决难题宁愿不眠不休而深以为乐的技术热情;3分来自起步要早早早,恨不得同龄人玩泥巴的时候就得开始玩电脑,大学毕业前就突破一万小时法则,后面的已是游戏人生。

天才的程序员可遇不可求,更不能长有,我看到的90%仍是平庸的程序员。IT时代的膨胀,已让程序员如同文艺复兴时的印刷匠一样的普通,多数投入祖师爷门下的人,仅是为了更大的饭碗,更高的待遇,更好的生计。平庸的程序员编写腐烂的代码,没有规范和一致性,固守旧世界的语言,还好谈论大的架构和性能,说的比做的漂亮。而毫无例外的,他们认定技术没有出路,做产品、营销和管理的是更高大上的手艺,而他们当中的99%,又会自然的流露出自己恰巧具备了那方面的天赋,至于进程为什么会崩溃这样的小问题是不屑于去了解的。

而我最喜欢和理想的程序员相处,恨不得与他们同吃同住,如果允许,我希望我的队伍能插满他们的旗帜。理想的程序员心眼儿不坏(他们从来都不是办公室政治的宠儿,是一群单纯明亮快乐的手艺人),有天真烂漫的好奇心(他们的眼睛里经常闪着 「哇,这个是怎么做到的!」),永远精益求精(他们的口头禅是「我再研究一下」),还乐于分享(他们活跃于GitHub、各大问答社区和你的身边,舍得将 宝贵时间用于帮助新手)。是的,他们不需要被管理,只需要给一个大的方向,总能回报以意想不到的结果。

理想的程序员与平庸的程序员只有一墙之隔。两者的差距只有 6个一点点,而人与人的差距,正是在这日积月累的一点点中,被永远拉开了。有意思的是,我发现这 6个一点点都和意识有关,也就是程序员和其他一切新兴产业的工种一样,只需要意识加上时间的锤炼,人人皆可达到理想的阶段。理想的程序员必然也是一个优秀的problem-solver。

第1个一点点:专注眼下

见过太多心猿意马的程序员,我不得不把「专注眼下」作为天字第一条。他们往往有各式各样的小梦想,比如做个小茶农、做个小鹅贩、做产品、做销售、做投 资,却被程序员的高薪或是没有转行的魄力「耽误」了,而因为不专注,他们不在意做好自己的本分,不在意锤炼自己的技能,不在意学习新兴的技术。不可否认, 这世界上存在着伟大的产品(像乔老爷)、伟大的销售(像埃里森)、伟大的投资客(像彼得菲),而他们毫无例外都是程序员出身。可你听说过巴菲特评价盖茨的 话么,比尔盖茨如果转行去卖狗,那他一定是全世界最大的狗贩。我坚信除了少数的天才外,冥冥众生均可以在多个领域取得成功,只要保持足够的专注。而哪怕你 下一年就想卖狗去,程序员的经验仍然能训练你强大的逻辑、谨慎和耐心,放在哪个行业都是相当可观的竞争力。

第2个一点点:思考力与推动力

我认为处理bug、崩溃、调优、入侵等突发事件比编程本身更能体现平庸程序员与理想程序员的差距。当面对一个未知的问题时,如何定位复杂条件下的核心问 题、如何抽丝剥茧地分析问题的潜在原因、如何排除干扰还原一个最小的可验证场景、如何抓住关键数据验证自己的猜测与实验,都是体现程序员思考力的最好场 景。是的,在衡量理想程序员的标准上,思考力比经验更加重要。

有时候小伙伴跑过来,问我「提交了一个任务被卡住了,怎么办」的时候,我总觉得他可以做得更好。比如,可以检查试验别的任务,以排除代码自身的原因;可以通过 Web UI 检查异常(如果没有账号,可以让我提供);可以排查主机日志或删除缓存,再不济,总应该提供任务 ID和控制台日志给我。理想的程序员永远不会等事情前进,他们会用尽一切方法让事情前进。

第3个一点点:Never Say No

记得从前厂离职之前,找老板谈话,他说我最大的优点就是从来不和他说这个做不到。后来我发现在很多团队里,都存在一种技术和产品的对立,程序员往往以 「技术上无法实现」来挡产品的需求,而产品也往往以「Facebook可以为什么我们做不到」来奚落程序员。这两句话应该属于禁语,从根本上都不利于程序 猿和产品狗的相亲相爱。

一句「技术上无法实现」是容易出口,可有多少人在说出这句话的时候,心里是100% 肯定的?如果不肯定,为什么不能回去谷歌一下再回答?原本我以为程序员是充满想象力,在因为有想象力,才能诞生那么多改变我们生活的软件和互联网产品。见 识多了,才了解大部分程序员已经在与bug的对抗中变得保守而不愿担当风险,与此同时许多团队也不愿意宽容失败。于是「Say No」变成一种习惯性的抵触,还记得曾国藩为什么解散湘军么?他说那支军队已「暮气渐深」,不能打仗了。要做理想的程序员,就不能给自己滋生暮气的机会, 如果面对不合理的需求,可以把时间成本摆出来,把曲线救国方案亮出来,简单粗暴「Say No」是不可取的。

第4个一点点:投资未来

程序员是一个非常残忍的职业。你所学所用的语言、框架、模式,很可能在数年内就成昨日黄花了;你现在嘲笑的另一群程序员,可能马上就能转身来嘲笑你了。 所以理想的程序员除了做好自己的本分,还要花费时间来投资未来。什么是「投资」?投资就是你现在投入的时间,在未来会以更多的时间或者金钱(看看早几年学 习iOS的程序员现在的薪酬!)回报你。举我自己的领域 — 数据挖掘为例,08年左右Hadoop开始兴起,一时「大数据」概念火热,Hadoop工程师万金难求,各互联网公司纷纷把数据统计、数据分析和数据 挖掘的业务切换到分布式平台上。这几年眼看 Hadoop 还在不断迭代,Spark又异军突起,一举刷新了 Hadoop 保持的排序记录,以内存存储中间数据带来的性能优势和丰富的数据结构让人爱个不停,各种奇异的小 bug和陡峭的学习曲线又让人打退堂鼓。那么,明眼人都知道 Spark 是未来的趋势(内存会越来越便宜),在主业务放在 Hadoop的条件下,就可以适当把一些小模块切换到 Spark 上,同时留意 Spark 社区的发展。很快从 Spark 获得的性能收益就能把之前投入的学习时间挣回来。

第 5 个一点点:善用工具

善用工具可以分为4个层面:

  • 搜索引擎
  • 不相信重复
  • 代码片段
  • 自动化

我刚入行那会,一个计算机专业却当了公务员的朋友问我,你一点都没学过编程,平时怎么 写代码?我说,谷歌,于是遭到无情的耻笑,以至于我在哪里的账号都叫2shou,告诫自己是一个无耻的二手程序员。这是一个笑话,但如果现在问我,我还是 要回答谷歌。程序员的成长就像膨胀的圆饼,外面是无边无际的大海,圆饼越大,与大海接触的面也越大,懂的越多,不懂的越多,而计算机科学又是一门更新换代 异常迅速的学科,同时也是知识互联网化最好的学科,很难利用传统的科班式有教有学的方法,相反通过搜索引擎则很容易获取到最新的知识。

不相信重复,大师的话叫DRY原则(Dont repeat yourself),代码写多了,会有人为的直觉判断好的和烂的代码,我的标准是简洁和规范,简洁并不是美感上的标准,重复越少,给自己出错的机会也越少,后期维护的成本也越少。

如果你不幸丢了三周前的代码,也许你能凭着过人的记忆力把脑子里残余的片段复写出 来,但如果丢的是三个月前的代码,恐怕就没有那么好的运气了。理想的程序员会着力找寻有效的资料保存方式,把工作里灵光闪现写下的代码、脚本、配置、 经验等短的片段保存起来,以便任何时候都能复查。

理想的程序员必须懒惰。对他们来说,重复的步骤和重复的代码一样丑陋,如果意识到一项工作有可能长期要重复,那么自动化的时间总是越早越好。

第6个一点点:管理时间

之所以管理时间会对程序员这个行当特别重要,是因为在完成任务时你必须像荒野里的狼一样,「独行」。没有外界约束的情况下还能稳定控制自己,保证能高效率地工作和学习,那么日积月累你肯定会变得比一般人厉害。

程序员干的是高强度的脑力活,一般每天集中4-5 个小时应对本职工作就足够了,但工作之外,一定要安排时间用于学习。除了学习,留点时间放空自己也是必要的,利用泡茶或者喝咖啡的间隙,把弥足珍贵的时间留给自己,往前想往后想,事半功倍。

说了这么多,想必有人会问,费劲心思成为一个理想的程序员,又有什么用处?会有高薪吗?不。能升职吗?也不见得。迎娶白富美呢?不如去卖狗。

稻盛和夫曾经说过一个故事,明治时期的手艺人被天皇召见,虽然都是不读书的乡下人,但一辈子兢兢业业地做一件事情,自然有一股高贵的气质。理想的程序员,应该就是循着这种高贵的气质而去的吧。

CMU大师对软件工程师的系统建议

2016-04-16 新智元 新智元

 新智元翻译1

来源:Quora

【新智元导读】软件工程师想学机器学习,有什么好建议?机器学习专家、卡耐基梅隆大学教授、1-Page公司首席科学家 Alex Smola 在 Quora 上给出了系统、具体的回答,还列出了推荐图书和论文。当然,如果你认为还有其他值得推荐的内容,留下评论,欢迎补充!

 

问题:你对想要学习机器学习的软件工程师有哪些建议?(What would be your advice to a software engineer who wants to learn machine learning?)

Alex Smola: 这 很大程度上取决于软件工程师的背景及其具体想掌握机器学习的哪部分知识。简而言之,我们以一名拥有四年本科学位和一到两年行业经验的初级程序员为例,并假 设这位程序员希望学习计算广告学、自然语言处理、图像分析、社交网络以及搜索和排序。那么,我们先说掌握机器学习有哪些基本要求(致学术界同仁的免责声 明:下列内容并不完整,如果未列入你的论著,在此提前致歉)。

线性代数

机器学习以及数据统计和优化都需要这方面知识。这也是为什么GPU(图形处理器)远比CPU(中央处理器)适合进行机器学习。作为程序员,至少需要基本掌握以下内容:

  • 标量、向量、矩阵、张量
    把它们看作你可以组建并相互转换的零维、一维、二维、三维和更高维物体,有点像乐高玩具,它们使得基本的数据转换成为可能。
  • 特征向量、范数、矩阵近似、分解
    这些概念本质上是让你习惯线性代数的用法。如果你希望分析一个矩阵的情况(比如,检查为何循环神经网络中出现梯度消失,为何增强学习算法中控制器出现分歧(diverge)),你就必须要理解在应用矩阵和向量时可能出现的增长和减小范围是多少。如果你希望代码表现出色和稳定,那么低秩等矩阵近似算法或乔列斯基分解就很有用。
  • 数值线性代数

    如果你需要做很多最优化计算,那么这部分知识就很有用。对核方法和深度学习来说如此,对图像模型和采样器而言则不那么重要。

最优化(和基本演算)

在许多情况下,设置要问的问题是相当容易的,但得出答案却没没那么简单。举例来说,如果要对一些数据进行线性回归(即找到一条线),你可能希望尽量减少与观测值的距离平方的总和。同样,如果想获得一个好的点击率预测模型,你就得最大化对于人们点击广告概率预测的准确性。这意味着我们通常会有一些目标、一些参数和大量数据,而我们需要通过一种方式来解决问题。这一点很重要,尤其因为我们常常不会有一个闭合式解决方案。

凸优化

很多时候,在优化问题不存在许多局部解决方案的情况下是不错的。当问题为凸时就会发生这种情况。(若你能在一个集合内任意两点间画出一条直线且这条直线处于该集合内,则这一集合就是凸的。若你能在图上任意两点间画出一条直线且这条直线位于图形上方,则这一函数是凸的。)

也许这一领域的经典书籍是这本由Steven Boyd和Lieven Vandenberghe所撰写的 Convex Optimization 。本书免费且非常棒。(回复041501下载,共730页)此外,Boyd的课程里也有许多很不错的幻灯片集。Dimitri Bertsekas也已经编写了关于最优化、控制等的宝典。这些应该足以供任何人开始了解这个领域了。

随机梯度下降算法

这一算法早期在很大程度上只是凸优化的一种特殊情况(至少早期定理是这样的),但最近发展很大,并且绝非是由于数据的增多。原因是,想象一下你有一些数据要处理,而你的算法需要将所有的数据都浏览一遍后才能继续新的步骤。而如果我故意给你10份同样的数据,那么你就必须重复10次工作,却没有什么实质性用处。显然,现实情况不会如此糟糕,但如果你需要操作多次小的新步骤,而每个小步骤之后都需要观测,它就能帮上忙。这在机器学习领域带来了相当大的变革型影响。此外,许多关联算法都容易得多。

我们面临的挑战是如何将其并行化。也许这个方向的第一步之一就是我们2009年的 Slow Learners are Fast 论文(回复041502下载)。最新版本是无锁变异型,例如Niu等于2013年所著的Hogwild论文(回复041503下载)。简而言之,这些算法通过人工计算机计算局部梯度并以异步方式更新共识参数集来运作。

另一个挑战是如何应对控制过度拟合的各种方法,例如通过正则化来实现。对于凸罚函数来说,有一种所谓近端梯度算法。一种比较流行的选择是Amir Beck和Marc Teboulle的FISTA算法。部分代码参见Francis Bach的SPAM toolbox(http://spams-devel.gforge.inria.fr/)。

非凸方法

许多机器学习问题都是非凸问题。从本质上来说,任何与深度学习相关的问题都是。但聚类、主题模型和几乎任何潜变量方法和当前几乎所有在机器学习领域有意思的问题也都是。部分加速技术可以提供帮助。例如,我的学生 Sashank Reddy最近展示了在这种情况下如何获得收敛的良好比率。

有许多被称为谱方法的技术可以使用。 Anima Anandkumar在她最近的Quora session中已经非常详尽地回答了这一问题。请参阅她的回复,因为其回复无比详细(https://www.quora.com/profile/Anima-Anandkumar-1)。概括地说,凸问题并非唯一能够确切解决的问题。在某些情况下,可以得出一个难题的数学表达式以显示只有某一组特定的参数能找到所有的集群、主题、相关比例、神经元或所有数据中的任何东西。这仅在你有能力且愿意花很多数学的功夫时才有效。

在培训深层网络方面(Deep Networks),最近有许多新技巧。我会在后面的内容中提及这些,但在某些情况下,目标不仅仅是优化,而是制定出一套具体的解决方案(几乎像是那本题为The Journey is the goal《旅程即是目的》的书)。

系统

机器学习正在成为大部分有关于人、测量、传感器和数据的关键要素,这与过去十年标度算法(scaling algorithms)的突破密不可分。Jeff Dean去年出了六套机器学习教程,也并非偶然。如果有人过了十年与世隔绝的生活,在这里给补充一下,他就是MapReduce、谷歌文件系统、BigTable和其他十多项成就了谷歌的关键技术背后的男人。

说笑归说笑,关于系统的研究为解决分布、异步、容错、可扩展和简易问题提供了宝贵的工具。后者是机器学习研究人员常常忽视的一点。简易是一种特性,不是一个错误。一些基本的技巧将带给你很多:

分布式哈希表

这实质上是如分布式缓存(memcached)、dynamo、 pastry和orceph等方法

构建的基础。它们都解决同一个问题——如何在避免访问之前数据输往的中央储存库的情况下向多台机器发布数据。为了达到这一目的,你需要将地址以一种随机又确定的方式编码(也就是哈希)。此外,你需要解决如果任何一台机器出现故障时谁将负责处理。

这就是我们在参数服务器(Parameter Server)中使用的数据布局。我的学生李沐是这个项目背后的智囊。工具组合参见DMLC(http://dmlc.ml/)。

一致性和信息传送

所有这一切的教父是Leslie Lamport的PAXOS 协议。它解决了在不是所有机器任何时候都可用或有些机器出现故障时如何达成共识的问题(是的,我在这儿就一句带过了)。如果你曾经使用过版本控制,你可能靠直觉知道它是如何工作的——大量机器(或开发者)产生更新(或代码段),而你希望将这些都结合成有意义的信息(例如,你不该两次运用微分),但又不需要所有机器与其他所有机器一直传递着信息。

在系统中,解决方案是使用向量时钟(参见例子:谷歌的Chubby)。我们在参数服务器中使用它的一种变体。关键的区别在于(均引自李沐)在参数范围内使用向量时钟。这可以确保不会因为时间标识耗尽内存,就像一个文件系统并不需要为每一个字节都记录一个时间标识。

容错、Scaling和云


最简单的自学方法就是在亚马逊AWS、谷歌GWC、微软Azure, 或你可以找到的各个其他平台上运行算法。当你第一次启动1000个服务器,意识到你正在向一个实际上的合法僵尸网络发送大量指令时,还是很令人激动的。我在谷歌工作时,我们控制了欧洲某处了5000个高端机器,用于主题模型中的推理。我们所调用的能源价值如果和一个核电站相比,也要占很大的比重了。我的经理当时把我叫到一旁,说这真是个昂贵的实验……

或许最容易起步的是学习docker。为了让scaling更容易,人们热火朝天地开发了不少工具。Docker Machine和Docker Cloud或许是近来最好的新工具,使你能像更换打印机驱动一样方便地连接不同的云端。

硬件


这似乎显而易见,但如果你了解自己算法所运行的硬件,的确会很有帮助。这会让你知道你写的代码是否已经接近峰值性能。初学者可以阅读Jeff Dean的Numbers every engineer should know一书。我在面试时最喜欢问的问题(曾经)是,应聘者的电脑有多快。知道算法的局限大有裨益:是缓存、内存带宽、延迟时间还是硬盘等等。Anandtech上有非常棒的介绍性文章,以及对微处理器架构等相关内容的测评。只要英特尔、ARM、AMD发布新硬件时,都可以去看一看。

统计学


我特意把这点留到最后。因为每个人都知道这是关键(的确如此),然后就忽略了其他所有东西。统计学确保你能问出好问题,同时帮助你理解自己在数据建模时用了多少估算。
从图像模型、核方法到深度学习等等,很多改进其实来自提出对的问题,也即定义了合理的优化目标,从而进行最优化。

Statistics Proper


Larry Wasserman的《统计学完全教程》(All of Statistics)是不错的入门教材。另外也可以看一下 David McKay 的 Machine Learning 一书。该书免费(篇幅很长、内容全面,回复041504下载)。其他还有不少好书,比如说 Kevin Murphy, Chris Bishop, Trevor Hastie, RobTibshirani 以及 Jerome Friedman 的著作The Elements of Statistical Learning:Data Mining, Inference, and Prediction。是的,Bernhard Scholkopf 和我也写了一本Learning with Kernels

随机算法和概率统计


本质上就是用计算机科学解决一样的问题,关键区别在于他们是设计算法的一种工具,而非用来适配参数的一个问题。我特别喜欢 Michael Mitzenmacher 和Eli Upfal 写的书Probability and Computing: Randomized Algorithms and Probabilistic Analysis ,非常易读但同时谈到了许多深刻的问题。如果你想更深入地了解这些工具,还有 Rajeev Motwani 和 Prabhakar Raghavan 的书Randomized Algorithms,写得很好,不过如果你没有较好的统计学背景,可能较难读懂。

我的回答可能已经够长了,很少有人会一直读到这里。所以我接下来说得比较简短。网上有许多非常棒的视频资料。许多教授现在有自己YouTube频道,并上传自己的课程视频。如果你在学习比较复杂的工具,这些视频会有所帮助。我的视频在这里(https://www.youtube.com/user/smolix/playlists),Nando de Freitas的要好很多。

 

其他还有一些工具。DMLC是好的起点,其中有许多用于分布式可扩展推理的算法,包括基于MXNET的神经网络。

 

还有很多没谈到的:编程语言、数据源等等。但这个回答已经太长了,我会在其他问题中继续讨论。

附录,Alex Smola 著书:

  • G. Bakir, T. Hofmann, B. Schölkopf, A.J. Smola, B. Taskar, and S.V.N. Vishwanathan, editors. Predicting Structured Data. MIT Press, Cambridge, MA, 2006.
  • S. Mendelson and A. J. Smola, editors. Machine Learning, Proceedings of the Summer School 2002, Australian National University, volume 2600 of Lecture Notes in Computer Science. Springer, 2003.
  • B. Schölkopf and A. J. Smola. Learning with Kernels. MIT Press, 2002.
  • B. Schölkopf, C. J. C. Burges, and A. J. Smola, editors. Advances in Kernel Methods–Support Vector Learning. MIT Press, Cambridge, MA, 1999.
  • A. J. Smola, P. L. Bartlett, B. Schölkopf, and D. Schuurmans, editors. Advances in Large Margin Classifiers. MIT Press, Cambridge, MA, 2000.

Slow Learners are Fast 论文(回复041502下载)。最新版本是无锁变异型,例如Niu等于2013年所著的Hogwild论文(回复041503下载)

关于这一讨论,你认为还有其他值得推荐的内容?留下评论,欢迎补充!

购书可扫二维码或点击 阅读原文 获取促销链接