01 | 程序员如何用技术变现

把两篇文章读了三遍,总结了以下知识点:

1.通过在公司工作提高自己的技能,让自己可以更为独立和自由地生活。
2.对于没什么技术含量的工作内容,提高交付效率。把时间用来研究高技术含量的知识。
3.要写文章就写别人没有写过的,或是别人写过,但我能写得更好的。
4.看清市场需求(各个公司正在做什么,难题是什么)和技术趋势(首先要了解技术的历史,把本质吃透:看经典书籍,向前沿学习)
5.在学习技术的过程一定要多问自己两个问题:“一,这个技术解决什么问题?为什么别的同类技术做不到?二,为什么是这样解决的?有没有更好的方式?”另外,还有一个简单的判断方法,如果一个新的技术顺应技术发展趋势,那么在这个新的技术出现时,后面一定会有大型的商业公司支持(专门做此类技术的公司),这类公司支持得越多,就说明你越需要关注。
6.在一家高速发展的公司中,技术人员的价值可以达到最大化。比较好的成长路径是,先进入大公司学习大公司的技术和成功的经验,然后再找到高速成长的公司,这样你就可以实现自己更多的价值。
7.动手能力很重要,持续在前线工作。
8.关注技术付费点:一个是,能帮别人“挣钱”的地方;另一个是,能帮别人“省钱”的地方。
9.提高自己的能力和经历。
找到有价值的信息源(知识的源头:西方世界)
10.输出观点和价值观,只有输出了更先进的价值观,才会获得真正的影响力(厚积薄发的过程)
11.优质的朋友圈。

#Equifax信息泄露始末笔记


1.使用开源的框架必须实时关注其动态,特别是安全漏洞方面
2.任何公开的入口,都必须进行严格的安全检查
3.框架的选型十分重要,必须将安全考察进去

05技术领导力

那么作为一个软件工程师怎样才算是拥有“技术领导力”呢?我个人认为,是有下面的这些特质。能够发现问题。能够发现现有方案的问题。能够提供解决问题的思路和方案,并能比较这些方案的优缺点。能够做出正确的技术决定。用什么样的技术、什么解决方案、怎样实现来完成一个项目。能够用更优雅,更简单,更容易的方式来解决问题。能够提高代码或软件的扩展性、重用性和可维护性。能够用正确的方式管理团队。所谓正确的方式,一方面是,让正确的人做正确的事,并发挥每个人的潜力;另一方面是,可以提高团队的生产力和人效,找到最有价值的需求,用最少的成本实现之。并且,可以不断地提高自身和团队的标准。创新能力。能够使用新的方法新的方式解决问题,追逐新的工具和技术。

我们可以看到,要做到这些其实并不容易,尤其,在面对不同问题的时候,这些能力也会因此不同。但是,我们不难发现,在任何一个团队中,大多数人都是在提问题,而只有少数人在回答这些人的问题,或是在提供解决问题的思路和方案。是的,一句话,总是在提供解决问题的思路和方案的人才是有技术领导力的人。
那么,作为一个软件工程师,我们怎么让自己拥有技术领导力呢?总体来说,是四个方面,具体如下:

  1. 扎实的基础技术;
  2. 非同一般的学习能力;
  3. 坚持做正确的事;
  4. 不断提高对自己的要求标准;

06 | 如何才能拥有技术领导力?



第一,你要吃透基础技术。基础技术是各种上层技术共同的基础。
第二,提高学习能力。所谓学习能力,就是能够很快地学习新技术,又能在关键技术上深入的能力。
第三,坚持做正确的事。做正确的事,比用正确的方式做事更重要,因为这样才始终会向目的地靠拢。哪些是正确的事呢?下面是我的观点:
提高效率的事。
掌握前沿技术的事
知识密集型的事。
技术驱动的事。

第四,高标准要求自己。只有不断地提高标准 ,你才可能越走越高,所以,要以高标准要求自己,不断地反思、总结和审视自己,才能够提升自己。

16 | 时间管理:如何利用好自己的时间?


1.花时间学习基础知识,并阅读文档
2.把时间花在解放自己生产力的事情上
3.花时间在让自己成长的事情上
4.花时间在建立高效的环境上
5.定好优先级
6.最短作业有限
7.想清楚再做
8.做好长期利益规划
9.形成习惯
10.形成正反馈
11.举一反三

也就是说,你要学会规划自己的行动计划,不是短期的,而是一个中长期的。我个人建议是按季度来规划,这个季度做什么,达到什么目标,一年往前走四步,而不是只考虑眼下。

用好自己的时间

将军赶路不追小兔。

这个世界有太多的东西会让我们分心和跑偏。能专注地把时间投入到一个有价值的事上是非常重要的。确定自己的目标,专注达到这个目标,而不是分心。将军的目标是要攻城,而不是追兔子。所以,你要学会过滤掉与自己目标无关的事,不要让那些无关的事控制自己。

比如,不要让别人来影响自己的心情,心情被影响了,你一下就会什么都不想干了。做自己心情的主人,不要让别人 hack 了你的心情。再比如,知道哪些是自己可以控制的事,哪些是自己控制不了的事,在自己能控制的地方花时间。
再比如,知道哪些是更有效的路径,是花时间改变别人,还是花时间去寻找志同道合的人。不与不如自己的人争论,也不要尝试花时间去叫醒那些装睡的人,这些都是非常浪费时间的事。多花时间在有产出的事上,少花时间在说服别人的事上。

形成习惯。

再好的方法,如果没有形成习惯,不能在实际的工作和生活中解决实际问题,都将成为空谈。如果你是个追求上进的人,我相信一定看过很多时间管理方法的文章和书籍,并且看的时候还会有些振奋,内心有时还会不自觉地想,“嗯,嗯!这个方法不错,正是我需要的,可以解决我的问题……”但很多时候都坚持不了几天就抛之脑后了。
所以,在讲述完如何争取时间,及如何使用时间之后,我想分享一下如何将这些时间管理方法形成习惯,因为我坚信:“做”比“做好”更重要。养成一个好习惯通常需要 30 天左右的时间,尤其在最初的几天就更为重要了。这时,不妨将文章中提到的方法和几个要点,写在某本书或者笔记本的扉页上,方便查看,时刻提醒自己。

18 | 故障处理最佳实践:故障改进

故障整改方法

就故障整改来说,我比较喜欢亚马逊的那个 Ask 5 Whys 玩法,这个对后面的整改会有非常大的帮助。最近一次,在帮一家公司做一个慢 SQL 的故障复盘时,我一共问了近 9 个为什么。

  1. 为什么从故障发生到系统报警花了 27 分钟?
  2. 为什么只发邮件,没有短信?
  3. 为什么花了 15 分钟,开发的同学才知道是慢 SQL 问题?
  4. 为什么监控系统没有监测到 Nginx 499 错误,以及 Nginx 的 upstream_response_time 和 request_time?
  5. 为什么在一开始按 DDoS 处理?
  6. 为什么要重启数据库?
  7. 为什么这个故障之前没有发生?因为以前没有上首页,最近上的。
  8. 为什么上首页时没有做性能测试?
  9. 为什么使用这个高危的 SQL 语句?
  10. 上线过程中为什么没有 DBA 评审?

通过这 9 个为什么,我为这家公司整理出来很多不足的地方。提出这些问题的大致逻辑是这样的。
第一,优化故障获知和故障定位的时间。从故障发生到我们知道的时间是否可以优化得更短?定位故障的时间是否可以更短?有哪些地方可以做到自动化?
第二,优化故障的处理方式。故障处理时的判断和章法是否科学,是否正确?故障处理时的信息是否全透明?故障处理时人员是否安排得当?
第三,优化开发过程中的问题。Code Review 和测试中的问题和优化点。软件架构和设计是否可以更好?对于技术欠债或是相关的隐患问题是否被记录下来,是否有风险计划?
第四,优化团队能力。如何提高团队的技术能力?如何让团队有严谨的工程意识?具体采取什么样的整改方案会和这些为什么有很大关系。

总之还是那句话,解决一个故障可以通过技术和管理两方面的方法。如果你喜欢技术,是个技术范,你就更多地用技术手段;如果你喜欢管理,那么你就会使用更多的管理手段。我是一个技术人员,我更愿意使用技术手段。


找到问题的本质

最后,对于故障处理,我能感觉得到,一个技术问题,后面隐藏的是工程能力问题,工程能力问题后面隐藏的是管理问题,管理问题后面隐藏的是一个公司文化的问题,公司文化的问题则隐藏着创始人的问题……

所以,这里给出三条我工作这 20 年总结出来的原则(Principle),供你参考。

  1. 举一反三解决当下的故障。为自己赢得更多的时间。
  2. 简化复杂、不合理的技术架构、流程和组织。你不可能在一个复杂的环境下根本地解决问题。
  3. 全面改善和优化整个系统,包括组织。解决问题的根本方法是改善和调整整体结构。而只有简单优雅的东西才有被改善和优化的可能。

    19 | 答疑解惑:我们应该能够识别的表象和本质



    我发现,一个可以持久的兴趣,或是可以培养出来的兴趣,后面都有一个比较本质的东西,其实就是成就感,他是你坚持或者努力的最直接的正反馈。也就是说,兴趣只是开始,而能让人不断投入时间和精力的则是正反馈,是成就感。

我个人觉得一项有价值的技术,并不在于这项技术是否有技术含量,而是在于:能否低成本高效率地解决实际问题;是不是众多产品的基础技术;是不是可以支持规模化的技术。

对于我们搞计算机软件的人来说,也可以找到相对应的技术点。
比如:低成本高效率地解决实际问题的技术,一定是自动化的技术。软件天生就是用来完成重复劳动的,天生就是用来做自动化的。而未来的 AI 和 IoT 也是在拼命数字化和自动化还没有自动化的领域。

基础技术总是枯燥和有价值的。数学、算法、网络、存储等基础技术吃得越透,就越容易服务上层的各种衍生技术或产品。

支持规模化的技术也是很有价值的。在软件行业中,也就是 PaaS 的相关技术。

技术无贵贱。我只是想说,能规模化低成本高效率解决实际问题的技术及其基础技术,就算是很 low,也是很有价值的。

小结

在我们的生活和工作中,总是会有很多人混淆一些看似有联系,实则关系不大的词和概念,分辨不清事物的表象和本质。
比如文中提到的兴趣和投入。表面上,兴趣是决定一件事儿能否做持久的关键因素。而反观我们自己和他人的经历不难发现,兴趣扮演的角色通常是敲门砖,它引发我们关注到某事某物。而真正能让我们坚持下去的,实际上是做一件事之后从中收获到的正反馈,也就是成就感。
同样,人们也经常搞错学习和工作之间的关系。多数人都会认为,在工作中学习和成长速度更快。而仔细观察下来,你会发现,工作不过是提供了一个能够解决实际问题,能跟人讨论,有高手帮助的环境。
还有,技术和价值。人们通常认为技术含量高的技术其价值会更高,而历史上无数的事实却告诉我们,能规模化、低成本、高效率地解决实际问题的技术及其基础技术,才发挥出了更为深远的影响,甚至其价值更是颠覆性的,难以估量。
所以说,让我们成长的并不是工作本身,而是有利于学习的环境。也就是说,如果我们想学习,除了可以选择有助于学习的工作机会,开源社区提供的环境同样有助于我们的学习和提高,那里高手更多,实际问题不少。

再如,加班和产出,努力和成功,速度和效率……加班等于高产出吗?显然不是。很努力就一定会成功吗?当然不是。速度快就是效率高吗?更加不是。可以枚举的还有很多,如干得多就等于干得好吗?等等。

69 | 程序员练级攻略:开篇词

2018-05-29 陈皓
《左耳听风》

2011 年,我在 CoolShell 上发表了 《程序员技术练级攻略》一文,收到了很多读读者的追捧,同时,这几年时间里,我还陆续收到了一些人的反馈,说跟着这篇文章找到了不错的工作,他们希望我把这篇文章更新一下,因为毕竟行业的变化很快。
是的,老实说,抛开这几年技术的更新迭代不说,那篇文章写得也不算特别系统,同时标准也有点低,当时是给一个想要入门的朋友写的。所以,非常有必要从头更新一下《程序员练级攻略》这一主题

前言导读

升级版的《程序员练级攻略》会比 Coolshell 上的内容更多,也更专业。这篇文章有【入门篇】、【修养篇】、【专业基础篇】、【软件设计篇】、【高手成长篇】五大篇章。它们会帮助你从零开始,一步步地,系统地,完成从陌生到熟悉,到理解掌握,从编码到设计再到架构,从码农到程序员再到工程师再到架构师的进阶,实现从普通到精通到卓越的完美转身……
入门篇中,我先推荐的是把 Python 和 JavaScript 作为入门语言,并给出了相应的学习资源和方法。Python 语法比较简单,有大量的库和语法糖,是零基础的人学习编程的不二之选。而 JavaScript 是前端语言,更容易让你获得编程的成就感。
随后,我们需要学习使用操作系统 Linux、编程工具 Visual Studio Code 等入门必学内容。Web 互联网作为第三次工业革命信息化浪潮中最大的发明,也是每个程序员都不能错过的。而学习编程还是要多多动手,因此我给出了 Web 编程入门的学习要点,并给出了一个实践项目,帮助你理解和巩固所学的内容。
如果你跟着我的这个教程走过来,并能自己去解决遇到的问题,那么,我相信你能够做一点东西了,而且你还可能会对编程非常感兴趣了。但是你千万不要以为自己已经入门了。我只是用这些内容给你一些成就感,并激发你持续学习的兴趣。
正式入门,我推荐的语言是 Java,因为我认为,它是所有语言里综合实力最强的。随后,推荐了更为专业实用的编程工具,如编程的 IDE、版本管理工具 Git、调试前端程序和数据库设计工具等,并且给出了一个实践项目。我同时设置了业务和技术两方面的需求,跟着做一遍,相信你对学习编程会有更多的理解和感悟。
接下来,我要带你进入更为专业更为复杂的编程世界中。进入之前,我们需要树立正确的三观和心态,这对于程序员来说至关重要。这就好像民工建筑队和专业的工程队的区别,就好像小作坊和工厂的差别,他们并不仅仅是差别在技能和技术上,更是差别在做事的心态和三观上。
因此,在学习专业的软件开发知识之前,我们来谈谈程序员修养。它看似与程序员练级关系不大,实际上却能反映出程序员的工程师特质和价值观,决定了这条路你到底能走多远,是精髓所在。有修养的程序员才可能成长为真正的工程师和架构师,而没有修养的程序员只能沦为码农,这是码农和工程师的关键区分点。
在“修养篇”,我给出了一些相关的学习资料,并指出了我认为比较重要的几个方面:英文能力、提问的能力、写代码的修养、安全防范意识、软件工程和上线规范、编程规范等。这些能力的训练和培养将为后续的学习和发展夯实基础。
此时,相信你已经迫不及待地想进入专业基础篇了。这部分内容主要涵盖编程语言、理论学科和系统知识三方面知识。在编程语言方面,推荐学习 C、C++ 和 Java 这三个工业级的编程语言。理论学科方面,需要学习算法、数据结构、网络模型、计算机原理等内容。系统知识方面会讲述 Unix/Linux、TCP/IP、C10K 挑战等专业的系统知识。最后给出了你可以选择的几大从业方向。
如果你对操作系统、文件系统、数据库、网络等比较感兴趣,那么可以考虑从事底层方面的工作。
如果对分布式系统架构、微服务、DevOps、Cloud Native 等有热情,那么可以从事架构方面的工作。
如果是对大数据、机器学习、人工智能等比较关注,那么数据领域可以成为你一展身手的地方。
如果你对用户体验或者交互等更感兴趣,那么前端工程师也是个不错的选择。
此外,安全开发、运维开发、嵌入式开发等几大方向中,也为你提供了丰富多彩的发展空间。
以我之见,该如何选择应该完全遵从于你的本心,你更愿意在哪个领域里持续奋斗和学习。这个答案,在你的手中,在你的心中。这里我只想和你说两个观点:各种技术方向不是鱼和熊掌,是可以兼得的;很多技术是相通的,关键是你是学在表面还是深入本质。
软件设计能力是每个程序员都需要具备的基本素质。我结合各主流语言讲述了泛型编程、函数式编程、面向对象编程等多种编程范式,分享了 DRY- 避免重复原则、KISS- 简单原则、迪米特法则(又称“最少知识原则”)、 面向对象的 S.O.L.I.D 原则等等多个经典的软件设计原则。
同时,给出了软件设计领域的一些重要的学习资料。软件设计是工程师非常重要的能力,这里描述了软件工程自发展以来的各种设计方法,这是从工程师通往架构师的必备技能。
登峰造极,是每个武林高手都渴望达到的境界,对于每个有理想有追求的程序员也是如此。因此,我特意在《程序员练级攻略(2018)》这一系列内容的最后设置了高手成长篇
相较前面的内容,这部分内容相当全面和丰富,涵盖系统、数据库、分布式架构、微服务、容器化和自动化运维、机器学习、前端方向和技术论文等几方面内容,而且深度一下子拔高了好几个数量级。
同时,这也是我留给你的再一次做选择的机会,平凡还是卓越?自在悠闲,还是猛啃书本,不破楼兰终不还?还是遵循你内心的选择吧。偷偷地告诉你,我选择的是后者。
你应该不难看出这一系列文章比我在 CoolShell 上的那一篇更为专业,标准也会更高,当然,难度也会更大。但是,也会让你有更坚固的技术基础,并能有更高更广泛的提高。
通过这一系列文章,我主要想回答以下几个问题。
理论和现实的差距。你是否觉得自己从学校毕业的时候只做过小玩具一样的程序?走入职场后哪怕没有什么经验也可以把文中提到的这些课外练习走一遍。学校课程总是从理论出发,作业项目都看不出有什么实际作用,到了工作上发现自己什么也不会干。
技术能力的瓶颈。你又是否觉得,在工作当中需要的技术只不过是不断地堆业务功能,完全没有什么技术含量。而你工作一段时间后,自己都感觉得非常地迷茫和彷徨,感觉到达了提高的瓶颈,完全不知道怎么提升了。
技术太多学不过来。你是否又觉得,要学的技术多得都不行了,完全不知道怎么学?感觉完全跟不上。有没有什么速成的方法?
对此,我有如下的一些解释,以端正一下你的态度。
并不是理论和现实的差距大,而是你还没有找到相关的场景,来感受到那些学院派知识的强大威力。算法与数据结构、操作系统原理、编译原理、数据库原理、计算机原理……这些原理上的东西,是你想要成为一个专家必须要学的东西。这就是“工人”和“工程师”的差别,是“建筑工人”和“建筑架构师”的差别。如果你觉得这些理论上的东西无用,那么只能说明,你只不过在从事工人的工作,而不是工程师的工作。
技术能力的瓶颈,以及技术太多学不过来,只不过是你为自己的能力不足或是懒惰找的借口罢了。技术的东西都是死的,这些死的知识只要努力就是可以学会的。只不过聪明的人花得时间少,笨点的人花得时间多点罢了。这其中的时间差距主要是由学习方法的不同,基础知识储备的不同决定的。只要你方法得当,多花点时间在基础知识上,会让你未来学习应用知识的时间大大缩短。以绝大多数人努力的程度,和为自己不努力找借口的程度为参考,只要你坚持正常的学习就可以超过大多数人了
这里没有学习技术的速成的方法,真正的牛人不是能够培训出来的,一切都是要靠你自己去努力和持续地付出。如果你觉得自己不是一个能坚持的人,也不是一个想努力的人,而是一个想找捷径的人,那么,这篇文章并不适合你。这篇文章中的成长路径是需要思考、精力和相关的经验的,这都需要时间,而且是不短的时间。你先问问自己有没有花十年磨一剑的决心,如果没有,那这篇文章对你没有任何作用。
这里有一篇传世之文《Teach Yourself Programming in Ten Years》(中英对照版)。还有在我 Cooslhell 上的这篇《程序员的荒谬之言还是至理名言?》。
我希望你在学习编程之前先读一读这两篇文章。如果你觉得可以坚持的话,那么,我这一系列文章会对你很有帮助。否则,我相信你只要大致浏览一下目录及其中的某些章节,就会选择放弃走这条路的。是的,这个系列的文内容也会让一些想入行但又不愿意付出努力的同学早点放弃。
最后,给出我的几点学习建议
一定要坚持,要保持长时间学习,甚至终生学习的态度。
一定要动手,不管例子多么简单,建议至少自己动手敲一遍看看是否理解了里头的细枝末节。
一定要学会思考,思考为什么要这样,而不是那样。还要举一反三地思考。
不要乱买书,不要乱追新技术新名词,基础的东西经过很长时间积累,会在未来至少 10 年通用。
回顾一下历史,看看历史时间线上技术的发展,你才能明白明天会是什么样的。
另外,这篇文章的标准会非常高。希望不会把你吓坏了。《易经》有云:“取法其上,得乎其中,取法其中,得乎其下,取法其下,法不得也”。所以,我这里会给你立个比较高标准,你要努力达到。相信我,就算是达不到,也会比你一开始期望的要高很多……
下面是《程序员练级攻略》系列文章的目录。
开篇词
入门篇
零基础启蒙
正式入门
修养篇
程序员修养
专业基础篇
编程语言
理论学科
系统知识
软件设计篇
软件设计
高手成长篇
Linux 系统、内存和网络(系统底层知识)
异步 I/O 模型和 Lock-Free 编程(系统底层知识)
Java 底层知识
数据库
分布式架构入门(分布式架构)
分布式架构经典图书和论文(分布式架构)
分布式架构工程设计 (分布式架构)
微服务
容器化和自动化运维
机器学习和人工智能
前端基础和底层原理(前端方向)
前端性能优化和框架(前端方向)
UI/UX 设计(前端方向)
技术资源集散地

70 | 程序员练级攻略:零基础启蒙

2018-05-31 陈皓
《左耳听风》
课程介绍

image.png
image.pngimage.pngimage.pngimage.png

讲述:柴巍

时长09:44大小4.46M

如果你从来没有接触过程序语言,这里给你两个方面的教程,一个偏后端,一个偏前端。对从零基础开始的人来说,最重要的是能够对编程有兴趣,而要对编程有兴趣,就要有成就感。而成就感又来自于用程序打造东西,所以,我推荐下面这份不错的入门教程。
第一份入门教程,主要是让你体会到编程是什么。
《与孩子一起学编程》 ,这本书以 Python 语言教你如何写程序,是一本老少咸宜的编程书。其中会教你编一些小游戏,还会和你讲基本的编程知识,相当不错。
两个在线编程入门的网站:Codecademy: Learn Python 和 People Can Program ,你也可以在这两个网站上学习 Python,只不过是英文的。
然后,你可以到 CodeAbbey 上去做一些在线编程的小练习。
第二份入门教程,主要是让你做点实际有用的东西。嗯,做个网页吧。
MDN 的 Web 开发入门 ,MDN 全称是 Mozilla Developer Network,你可以认为是 Web 方面的官方技术网站。这个教程会带着你建立一个网站。然后,你可以把你的网页发布在 GitHub 上。
这两份教程都很不错,都是从零开始,带着你从环境准备开始,一点一点地从一些简单又有意思的东西入手,让你感觉一下编程世界是什么样的,相信这两个教程可以让零基础的你喜欢上编程。

编程入门

在这时,我们使用 Python 和 JavaScript 作为入门语言。Python 就不用多说了,语法比较简单,有大量的库和语法糖,是零基础的人学习编程的不二之选。而 JavaScript 则是前端的语言,为了让你更有编程的成就感,所以,这也成了一门要学习的语言。(注意:对于计算机专业的学生来说,一般会使用 Pascal 做为入门的编程语言,但我觉得编程入门还是要以培养兴趣为主,所以,还是选一些能让人有成就感的语言会更好)。

入门语言 Python

如果你想更为系统地学习一下 Python 编程,我强烈推荐你阅读下面这两本书。它们是零基础入门非常不错的图书,里面有大量的更为实用的示例和项目,可以快速给你正反馈。
Python 编程快速上手
Python 编程:从入门到实践
这两本书除了编程语法方面的讲述有所不同之外,其他都差不多,主要是通过书中的示例来强化你对编程的学习。第一本偏文本处理,包括处理 Word、Excel 和 PDF,第二本中有一些 Web 项目和代码部署方面的内容。如果可能的话,你可以把两本书中的示例都跑一遍。如果你时间有限的话,我推荐你看第二本。
[编辑植入:极客时间上也有 Python 入门的视频课程。]

入门语言 JavaScript

如果想入门学习 JavaScript,我主要推荐以下在线教程。
MDN JavaScript 教程,你可以认为这是最权威的 JavaScript 官方教程了,从初级到中级再到高级。
W3School JavaScript 教程,这个教程比较偏 Web 方面的编程。
JavaScript 全栈教程(廖雪峰),这是廖雪峰的一个比较偏应用的教程,也是偏 Web 方面的编程,同时包括涉及后端的 Node.js 方面的教程。

操作系统入门 Linux

学习编程你还需要会玩 Linux,虽然 Windows 占据着更多的桌面市场,但是你还是要了解 Linux。这里,你可以看一下,W3CSchool 上的在线教程 Linux 教程。

编程工具 Visual Studio Code

这里主要推荐时下最流行也是最好用的 Visual Studio Code,这个工具潜力十足,用它开发 Python、JavaScript、Java、Go、C/C++ 都能得心应手(教程) 。

Web 编程入门

如果玩到这里,你觉得有趣的话,可以学习一下 Web 方面的入门知识。为什么是 Web 而不是别的其他技术呢?因为你正身处于第三次工业革命的信息化浪潮中,在这个浪潮中,Web 互联网是其中最大的发明,所以,这是任何一个程序员都不能错过的
关于 Web 编程,有下面几个方向你要学习一下。
前端基础。要系统地学习一下前端的知识,也就是 CSS、HTML 和 JavaScript 这三个东西。这里还是给出 MDN 的相关的技术文档页面 CSS 文档 和 HTML 文档 。文档很大,你要学习的并不是所有的东西,而是了解 CSS 和 HTML 是怎么相互作用来展示数据的,然后,不用记忆文档中的内容,这两个文档是用来查找知识的。 另外,你可以简单地学习使用 JavaScript 操纵 HTML。理解 DOM 和动态网页(可以参看 W3Schools 的 JavaScript HTML DOM 的教程)。
后端基础。如果你想省点事,不想再学一门新的语言了,那么你可以直接用 Python 或者 Node.js,这两个技术在前面提到的廖雪峰的那个教程里提到过。当然,如果你想试试另外一种脚本型的也是比较主流的编程语言,那么可以搞搞 PHP,它也是很快就可以上手的语言。学习 PHP 语言,你可以先跟着 W3School 的 PHP 教程 玩玩(其中有连接数据库的 MySQL 的教程)。然后,以 PHP 的官网文档 作为更全的文档来学习或查找相关的技术细节。
下面是一些学习要点:
学习 HTML 基本语法。
学习 CSS 如何选中 HTML 元素并应用一些基本样式。
学会用 Firefox + Firebug 或 Chrome 查看你觉得很炫的网页结构,并动态修改。
在一台 Linux 机器上配置 LEMP - Ubuntu/Nginx/PHP/MySQL 这个环境。
学习 PHP,让后台 PHP 和前台 HTML 进行数据交互,对服务器响应浏览器请求形成初步认识,并实现一个表单提交和反显的功能。
把 PHP 连接本地或者远程数据库 MySQL(MySQL 和 SQL 现学现用够了)。
这里,你可能会问我,入门时有三个后端语言,一个是 Python,一个是 Node.js,一个是 PHP,你对这三门语言怎么看?老实说,Python 我还看好一些,PHP 次之,Node.js 最后。原因是:
Python 语言的应用面还是很广的。(当然,性能可能会有一些问题,但是用于一些性能不敏感的和运维或是一些小工具相关的,还是非常好用的。另外,Python 的应用场景其实还是很多的,包括机器学习和 AI 也有 Python 的身影。用 Python 来做一些爬虫、简单的中间件、应用或是业务服务也是很不错的。)
PHP 也是一个比较主流的简单的语言(PHP 在目前来说还是一个比较主流的语言,但其发展潜力有限,虽然可以让你找得到工作,但是一般玩玩就行了)。
Node.js 号称 JavaScript 的后端版,但从目前发展来说,在后端的世界里,并不能承担大任,而且问题很多。一些前端程序员用它来做后端的粘合层,我个人觉得这样做法只是掩盖前后端配合有问题,或是接口设计思维上的懒惰,我还是希望前端程序员应该认真学习一门真正的后端语言。
当然,这里只是让你感觉一下,Web 前端编程的感觉,只是为了入门而已。所以,对于这些语言你也不用学得特别精通,感觉一下这几个不同的语言就可以了,然后知道相关的文档和知识在哪里,这样有助于你查阅相应的知识点

实践项目

无论你用 Python,还是 Node.js,还是 PHP,我希望你能做一个非常简单的 Blog 系统,或是 BBS 系统,需要支持如下功能:
用户登录和注册(不需密码找回)。
用户发贴(不需要支持富文本,只需要支持纯文本)。
用户评论(不需要支持富文本,只需要支持纯文本)。
你需要从前端一直做到后端,也就是说,从 HTML/CSS/JavaScript,到后面的 PHP(Python/Node.js),再到数据库。这其中需要你查阅很多的知识。
这里有几个技术点你需要关注一下。
用户登录时的密码不应该保存为明文,应该用 MD5+Salt 来保存(关于这个是什么,希望你能自行 Google)。
用户登录后,对于用户自己的贴子可以有“重新编辑”或 “删除”的功能,但是无权编辑或删除其它用户的贴子。
数据库的设计,你需要三张表:用户表、文章表和评论表,它们之间是怎么关联的,你需要学习一下。这里有个 PHP 的 blog 教你怎么建表,你可以 前往一读。
如果你有兴趣,你可以顺着这个小项目,研究一下下面这几个事。
图片验证码。
上传图片。
阻止用户在发文章或评论时输入带 HTML 或 JavaScript 的内容。
防范 SQL 注入。参看PHP 官方文档 或 微软官方文档,或者你自己 Google 一下。
上面这些东西,不是什么高深的东西,但是可以让你从中学到很多。相信你只需要自己 Google 一下就能搞定。

小结

接下来,我总结下今天的内容。首先,我推荐了 Python 和 JavaScript 作为入门语言,以让你尽快上手,获得成就感,从而激发你想持续学习的热情。随后介绍了 Linux 操作系统、Visual Studio Code 编程工具、Web 编程入门等方面的学习资料,并给出了学习要点。最后,我给出了一个实践项目,帮助你理解和巩固今天所学的内容。
消化好了今天的内容,就准备好精力迎接后面的挑战吧。下篇文章中,我们将正式入门学习该如何编程。

71 | 程序员练级攻略:正式入门

2018-06-05 陈皓

学习了前面文章中的入门级经验和知识后,你可能会有两种反应。
一种反应可能是,你对编程有一点的兴趣了,甚至有一点点小骄傲,可能还会四处炫耀。我想说,请保持这种感觉,但是你也要清醒一下,上面的那些东西,还不算真正的入门,你只是入门了一条腿。
另一种反应也可能是,你被吓着了,觉得太难了。感觉不是一般人能玩的,如果是这样的话,我想鼓励你一下–“无论你做什么事,你都会面对各式各样的困难,这对每个人来说都是一样的,而只有兴趣、热情和成就感才能让你不畏惧这些困难”。所以,你问问你自己,是否从中收获了成就感,如果没有的话,可能这条路并不适合你。如果有的话,哪怕一丁点儿,你也应该继续坚持下来。
这篇文章,我主要是让你成为更为专业的入门程序员。请注意,此时,你可能需要读一些比较枯燥的书,但我想说,这些是非常非常重要的。你一定要坚持住。

编程技能

在系统地学习编程技能之前,我希望你能先看一下 “ The Key To Accelerating Your Coding Skills http://blog.thefirehoseproject.com/posts/learn-to-code-and-be-self-reliant/“, 这篇文章会告诉你如何有效地快速提高自己的编程能力。
然后接下来是下面几大块内容,但还只是入门级的。
编程技巧方面 - 你可以开始看怎么把程序写好的书了,这里推荐的是《代码大全》。这本书好多年没有更新了,其中有一些内容可能有点过时,但还是一本非常好的书,有点厚,你不需要马上就看完。在你的编程路上,这本书可以陪你走很久,因为当你有更多的编程经验时,踩过更多的坑后,再把这本书拿出来看看,你会有更多的体会。好的书和不好的书最大的区别就是,好的书在你不同的阶段来读,你会有不同的收获,而且还会产生更多的深层次的思考! 《代码大全》就是这样的一本书。
编程语言方面 - 这个阶段,你可以开始了解一下 Java 语言了,我个人觉得 Java 是世界上目前为止综合排名最好的语言。你一定要学好这门语言。推荐《Java 核心技术(卷 1)》,除了让你了解 Java 的语法,它还会让你了解面向对象编程是个什么概念(如果你觉得这本书有点深,那么,你可以降低难度看更为基础的《Head First Java》)。然后,既然开始学习 Java 了,那就一定要学 Spring,推荐看看《Spring in Action》https://book.douban.com/subject/26767354/或是直接从最新的 Spring Boot 开始,推荐看看《Spring Boot 实战》https://book.douban.com/subject/26857423/。关于 Spring 的这两本书,里面可能会有很多你从来没有听说过的东西,比如,IoC 和 AOP 之类的东西,能看懂多少就看懂多少,没事儿。
操作系统 - 这里你可以看看《鸟哥的 Linux 私房菜》,这本书会让你对计算机和操作系统,以及 Linux 有一个非常全面的了解,并能够管理或是操作好一个 Linux 系统。当然,这本书有很多比较专业的知识,你可能会看不懂,没关系,就暂时略过就好了。这本书的确并不适合初学者,你能看多少就看多少吧。
网络协议 - 你需要系统地了解一下 HTTP 协议,请到 MDN 阅读一下其官方的 HTTP 的文档。你需要知道 HTTP 协议的几个关键点:1)HTTP 头,2)HTTP 的请求方法,3)HTTP 的返回码。还有,HTTP 的 Cookie、缓存、会话,以及链接管理,等等,在 MDN 的这个文档中都有了。对于 HTTP 协议,你不需要知道所有的东西,你只需要了解这个协议的最关键的那些东西就好了。
数据库设计 - 你需要系统地了解一下数据库设计中的那些东西,这里推荐慕课网的一个在线课程:数据库设计的那些事。每个小课程不过 5-6 分钟,全部不到 2 个小时,我相信你一定能跟下来。你需要搞清楚数据的那几个范式,还有 SQL 语句的一些用法。当然,你还要学习和使用一下数据库,这里推荐学习开源的 MySQL。你可以看官方文档,也可以看一下这本书《MySQL 必知必会》https://book.douban.com/subject/3354490/
前端方面 - 前端的东西不算复杂,你需要学习几个东西。一个是和 JavaScript 相关的 jQuery https://jquery.com/,另一个是和 CSS 相关的 Bootstrap https://getbootstrap.com/,学习这两个东西都不复杂,直接上其官网看文档就好了。最重要的是,你要学习一下如何使用 JavaScript Ajax 请求后端的 API 接口,而不是再像前面那样用后端来向前端返回 HTML 页面的形式了。这里,你需要学习一下,JavaScript 的 Promise 模式。阮一峰翻译的 ES6 的教程中有相关的内容 https://es6.ruanyifeng.com/#docs/promise。当然,你 Google 一下,也可以找到一堆学习资料。
字符编码方面 - 在你处理中文时有时会发现有乱码出现,此时需要了解 ASCII 和 Unicode 这样的字符编码。这里推荐一篇文章 - “关于字符编码,你所需要知道的(ASCII,Unicode,Utf-8,GB2312…)” 或是英文文章 “The history of Character Encoding” 以及 Wikipedia - Character encoding。还有 GitHub 上的这两个 Awesome 仓库:Awesome Unicode 和 Awesome Code Points。

为什么转成 Java 语言?

相信你可能会问,为什么之前学习的 Python 和 JavaScript 不接着学,而是直接切到 Java 语言上来,这样会不会切得太快了。这是一个好问题,这里需要说明一下,为什么我会切到 Java 这个语言上来,主要是有以下几方面考虑。
Java 是所有语言里面综合实力最强的,这也是为什么几乎所有大型的互联网或是分布式架构基本上都是 Java 技术栈。所以,这是一个工业级的编程语言(Python 和 JavaScript 还达不到这样的水准)。
之所以没有用 Java 来做入门语言而是用了 Python,这是因为编程是一件比较费脑子的事,一开始学习时,兴趣的培养很重要。Python 比较简单,容易上手,能够比较容易地提起兴趣,而用 Java 则可能比较难。
在你有了一些编程语言的基础后,有了一些代码的逻辑后,切到工业级的编程语言上来,更为专业地学习编程,是非常有帮助的。像 Python 和 JavaScript 这样的动态语言用着是很爽,但是,只有像 C、C++ 和 Java 这样的静态语言才可以让你真正地进阶
对于一个合格的程序员,掌握几门语言是非常正常的事情。一方面,这会让你对不同的语言进行比较,让你有更多的思考。另一方面,这也是一种学习能力的培养。很多时候,一些程序员只在自己熟悉的技术而不是合适的技术上工作,这其实并不好,这会让你的视野受限,而视野会决定你的高度。综上所述,这就是在入门的时候我故意让你多学几门语言的原因。

编程工具

编程工具方面,你需要开始学习使用下面这些工具了。
编程的 IDE。传统一点的,你可以使用 Eclipse(教程https://www.runoob.com/eclipse/eclipse-tutorial.html)。当然,我推荐你使用 Intellij IDEA(教程https://www.gitbook.com/?utm_source=legacy&utm_medium=redirect&utm_campaign=close_legacy)。这两个工具都可以开发各种语言,但是主要用在 Java。如果你想玩得更时髦一些的话,使用 Visual Studio Code 也不错,这个工具潜力十足,用其开发 Python、JavaScript、Java、Go、C 和 C++ 都能得心应手(教程)。
版本管理工具。版本管理工具是非常重要的编程工具。传统的有 P4、 SVN、CVS 等,但都会被 Git 取代,所以,你就只用学习 Git 就好了。学习 Git 的教程网上有很多,这里我推荐非常系统的 Pro Git 第二版 (如果你觉得 Pro Git 比较枯燥的话,备选猴子都能懂的 Git 入门),然后你要学会使用 GitHub。关于一些 Git 环境安装和准备以及 GitHub 使用,你可以自行 Google(比如:这篇GitHub and Git 图文教程https://github.com/JiapengLi/GitTutorial 或是这篇Git 图文教程及详解https://www.jianshu.com/p/1b65ed31da97)。
调试前端程序。你需要学会使用 Chrome 调试前端程序,Google 一下会有很多文章,你可以看看 超完整的 Chrome 浏览器客户端调试大全http://www.igeekbar.com/igeekbar/post/156.htm
数据库设计工具。你需要学会使用 MySQL WorkBench,这个工具很容易使用。相关的手册,你可以看一下官方文档。

实践项目

这回我们需要设计一个投票系统的项目。
业务上的需求如下:
用户只有在登录后,才可以生成投票表单。
投票项可以单选,可以多选。
其它用户投票后显示当前投票结果(但是不能刷票)。
投票有相应的时间,页面上需要出现倒计时。
投票结果需要用不同颜色不同长度的横条,并显示百分比和人数。
技术上的需求如下:
这回要用 Java Spring Boot 来实现了,然后,后端不返回任何的 HTML,只返回 JSON 数据给前端。
由前端的 JQuery 来处理并操作相关的 HTML 动态生成在前端展示的页面。
前端的页面还要是响应式的,也就是可以在手机端和电脑端有不同的呈现。 这个可以用 Bootstrap 来完成。
如果你有兴趣,还可以挑战以下这些功能。
在微信中,通过微信授权后记录用户信息,以防止刷票。
可以不用刷页面,就可以动态地看到投票结果的变化。
Google 一些画图表的 JavaScript 库,然后把图表画得漂亮一些。

小结

上面那些书和知识你要看完,还要能理解并掌握,我估计你最少也要花 1-2 年左右的时间。如果你能够走到这里,把前面的那些知识都了解了,不用精通,能独立地做出上面的那些实践项目,那么,你就算是真正的入门了。
而且,你已经是一个“全栈工程师”的样子了,在这里我要给你一个大大的赞。如果这个时候,你对编程还有很大的热情,那么我要恭喜你了,你可能会是一个非常不错的程序员。加油啊!
上面的那些技术已经算是比较专业的了。如果你已经大致掌握了,我相信你可以找到至少年薪 20 万以上的工作了,而且你的知识面算是有不错的广度了。但是深度还不够,这个时候,是一个比较关键点了。
你可能已经沉醉在沾沾自喜的骄傲的情绪中,那么你也可以就此止步,加入一些公司,在那里按部就班地完成一些功能性的开发,成为一个搬砖的码农。你也可以开始选择一个方向开始深入。
我给你的建议是选择一个方向开始深入。因为你并不知道你未来会有多大的可能性,也不知道你会成为什么样的人,所以为什么不再更努力一把呢?
后面,我们就开始非常专业的程序员之路了。这也是一般程序员和高级程序员的分水岭了,能不能过去就看你的了。

72 | 程序员练级攻略:程序员修养

2018-06-07 陈皓
《左耳听风》
课程介绍
程序员的软能力:英文、问问题、写代码、安全规范、软件工程与测试、编程规范


在完成上述的入门知识学习之后,我们要向专业的计算机软件开发进军了。但是在学习那些专业的知识前,我们先要抽一部分的篇幅来说一下程序员的修养。这是程序员的工程师文化,也就是程序员的价值观,因为我觉得如果你的技术修养不够的话,你学再多的知识也是没有用的。
要了解程序员的修养,你可以先从 Quora 上的这个贴子开始 “What are some of the most basic things every programmer should know?”,我摘录一些在这里供你参考。
Bad architecture causes more problems than bad code.
You will spend more time thinking than coding.
The best programmers are always building things.
There’s always a better way.
Code reviews by your peers will make all of you better.
Fewer features for better code is always the right answer in the end.
If it’s not tested, it doesn’t work.
Don’t reinvent the wheel, library code is there to help.
Code that’s hard to understand is hard to maintain.
Code that’s hard to maintain is next to useless.
Always know how your business makes money, that determines who gets paid what.
If you want to feel important as a software developer, work at a tech company.
然后是 《97 Things Every Programmer Should Know》https://97-things-every-x-should-know.gitbooks.io/97-things-every-programmer-should-know/content/en/index.html,其中有 97 个非常不错的编程方面的建议。这篇文章是比较经典的,别被“97”这个数字吓住,你可以快速浏览一下,会让你有不同的感觉的。另外,在工作一段时间后再来读,你会更有感觉。

英文能力

必须指出,再往下走,有一个技能非常重要,那就是英文。如果对这个技能发怵的话,那么你可能无缘成为一个程序员高手了。因为我们所有的计算机技术全部来自于西方国家,所以如果你要想成为一个高手的话,那么必须到信息的源头去。英文的世界真是有价值的信息的集散地。你可以在那里,到官网上直接阅读手册,到 StackOverflow 上问问题,到 YouTube 上看很多演讲和教学,到 GitHub 上参与社区,用 Google 查询相关的知识,到国际名校上参加公开课……
如果你的英文能力有问题的话,那么基本上来说,你无法成为一个高手。因此,学好英文是非常有必要的,我说的不只是读写,还有听和说。相信你在学校里学过英文,有一定的基础。所以,我给你下面的这些建议。
坚持 Google 英文关键词,而不是在 Google 里搜中文。
在 GitHub 上只用英文。用英文写代码注释,写 Code Commit 信息,用英文写 Issue 和 Pull Request,以及用英文写 Wiki。
坚持到 YouTube 上每天看 5 分钟的视频。YouTube 上有相关的机器字幕,实在不行就打开字幕。
坚持用英文词典而不是中文的。比如:剑桥英语词典https://dictionary.cambridge.org/ 或是 Dictionary.com 。你可以安装一个 Chrome 插件 Google Dictionary。
坚持用英文的教材而不是中文的。比如:BBC 的 Learning English http://www.bbc.co.uk/learningenglish/ ,或是到一些 ESL 网站上看看,如 ESL: English as a Second Language https://www.rong-chang.com/ 上有一些课程。
花钱参加一些线上的英文课程,用视频和老外练习。

问问题的能力

提问的智慧(How To Ask Questions The Smart Way http://www.catb.org/~esr/faqs/smart-questions.html)一文最早是由 Eric Steven Raymond 所撰写的,详细描述了发问者事前应该做好什么,而什么又是不该做的。作者认为这样能让问题容易令人理解,而且发问者自己也能学到较多东西。
此文一经发出,就广受好评,被广泛转载并奉为经典。该文也有 简体中文翻译版 http://doc.zengrong.net/smart-questions/cn.html 被流传着,所以在华人界也是篇很有名的文章。有两个著名的缩写 STFW(Search the fxxking web)以及 RTFM(Read the fxxking manual)就是出自本文。
另外,还有一个经典的问题叫 X-Y Problem。对我来说,这是一个很容易犯的错误,所以,你也要小心避免(我曾经在我的 Coolshell 上写过这个事《X-Y 问题》https://coolshell.cn/articles/10804.html)。
然后,你可以到 StackOverflow 上看看如何问问题的一些提示 — “FAQ for StackExchange Site”。
作为一个程序员,不做伸手党,你必须要读一读这几篇文章,并努力践行。

对于X-Y Problem的意思如下: 1)有人想解决问题X
2)他觉得Y可能是解决X问题的方法
3)但是他不知道Y应该怎么做
4)于是他去问别人Y应该怎么做? 简而言之,没有去问怎么解决问题X,而是去问解决方案Y应该怎么去实现和操作。于是乎: 1)热心的人们帮助并告诉这个人Y应该怎么搞,但是大家都觉得Y这个方案有点怪异。
2)在经过大量地讨论和浪费了大量的时间后,热心的人终于明白了原始的问题X是怎么一回事。
3)于是大家都发现,Y根本就不是用来解决X的合适的方案。 X-Y Problem最大的严重的问题就是:在一个根本错误的方向上浪费他人大量的时间和精力

写代码的修养

除了《代码大全》外,你还需要补充一些如何写好代码的知识,有以下几本书推荐。
《重构:改善既有代码的设计》,这本书是 Martin Fowler 的经典之作。这本书的意义不仅仅在于 “ 改善既有代码的设计 “,也指导了我们如何从零开始构建代码的时候避免不良的代码风格。这是一本程序员必读的书。
《修改代码的艺术》,这本书是继《重构》之后探讨修改代码技术的又一里程碑式的著作,而且从涵盖面和深度上都超过了前两部经典(《代码大全》和《重构》)。作者将理解、测试和修改代码的原理、技术和最新工具(自动化重构工具、单元测试框架、仿对象、集成测试框架等),与解依赖技术和大量开发和设计优秀代码的原则、最佳实践相结合,许多内容非常深入。这本书不仅可以帮你掌握最顶尖的修改代码技术,还可以大大提高你对代码和软件开发的领悟力。
《代码整洁之道》,这本书提出一种观念:代码质量与其整洁度成正比。干净的代码,既在质量上较为可靠,也为后期维护和升级奠定了良好基础。本书作者给出了一系列行之有效的整洁代码操作实践。这些实践在本书中体现为一条条规则,并辅以来自现实项目正反两面的范例。
《程序员的职业素养》,这本书是编程大师 Bob 大叔 40 余年编程生涯的心得体会,讲解成为真正专业的程序员需要什么样的态度、原则,需要采取什么样的行动。作者以自己以及身边的同事走过的弯路、犯过的错误为例,意在为后来人引路,助其职业生涯迈上更高台阶。
另外,作为一个程序员,Code Review 是非常重要的程序员修养。 Code Review 对我的成长非常有帮助,我认为没有 Code Review 的公司都没有必要呆(因为不做 Code Review 的公司一定是不尊重技术的)。下面有几篇我觉得还不错的 Code Review 的文章,供你参考。
Code Review Best Practices
How Google Does Code Review
LinkedIn’s Tips for Highly Effective Code Review
除了 Code Review 之外,Unit Test 也是程序员的一个很重要的修养。写 Unit Test 的框架一般来说都是从 JUnit 衍生出来的,比如 CppUnit 之类的。学习 JUnit 使用的最好方式就是到其官网上看 JUnit User Guide(中文版)。然后,有几篇文章你可以看看(也可以自行 Google):
You Still Don’t Know How to Do Unit Testing
Unit Testing Best Practices: JUnit Reference Guide
JUnit Best Practices

安全防范

在代码中没有最基本的安全漏洞问题,也是我们程序员必须要保证的重要大事,尤其是对外暴露 Web 服务的软件,其安全性就更为重要了。对于在 Web 上经常出现的安全问题,有必要介绍一下 OWASP - Open Web Application Security Project。
OWASP 是一个开源的、非盈利的全球性安全组织,致力于应用软件的安全研究。其被视为 Web 应用安全领域的权威参考。2009 年,国际信用卡数据安全技术 PCI 标准将其列为必要组件,美国国防信息系统局、欧洲网络与信息安全局、美国国家安全局等政府机构所发布的美国国家和国际立法、标准、准则和行业实务守则参考引用了 OWASP。
美国联邦贸易委员会(FTC)强烈建议所有企业需遵循 OWASP 十大 Web 弱点防护守则。所以,对于OWASP Top 10 项目 是程序员非常需要关注的最基本的也是最严重的安全问题,现在其已经成了一种标准,这里是其中文版《OWASP Top 10 2017 PDF 中文版》。
下面是安全编程方面的一些 Guideline。
伯克立大学的 Secure Coding Practice Guidelines。
卡内基梅隆大学的 SEI CERT Coding Standards。
此外,有一篇和 HTTP 相关的安全文章也是每个程序员必须要读的——《Hardening Your HTTP Security Headers》。
最后想说的是 “ 防御性编程 “,英文叫Defensive Programming,它是为了保证对程序的不可预见的使用,不会造成程序功能上的损坏。它可以被看作是为了减少或消除墨菲定律效力的想法。防御式编程主要用于可能被滥用,恶作剧或无意地造成灾难性影响的程序上。下面是一些文章。
The Art of Defensive Programming。
当然,也别太过渡了,这篇文章可以看看,Overly defensive programming。

软件工程和上线

系统上线是一件比较严肃的事,这表明你写的软件不是跑在自己的机器上的玩具,或是实验室里的实验品,而是交付给用户使用的,甚至是用户付费的软件。对于这样的软件或系统,我们需要遵守一些上线规范,比如,需要认真测试,并做上线前检查,以及上线后监控。下面是几个简单的规范,供你参考。
关于测试,推荐两本书。
《完美软件:对软件测试的各种幻想》,这本书重点讨论了与软件测试有关的各种心理问题及其表现与应对方法。作者首先阐述软件测试之所以如此困难的原因–人的思维不是完美的,而软件测试的最终目的就是发现对改善软件产品和软件开发过程有益的信息,故软件测试是一个信息获取的过程。
《Google 软件测试之道》,描述了测试解决方案,揭示了测试架构是如何设计、实现和运行的,介绍了软件测试工程师的角色;讲解了技术测试人员应该具有的技术技能;阐述了测试工程师在产品生命周期中的职责;讲述了测试管理,并对在 Google 的测试历史上或者主要产品上发挥了重要作用的工程师的访谈,这令那些试图建立类似 Google 的测试流程或团队的人受益很大。
当你的系统要上线时,你是不是已经做好上线的准备了?这里有两个 Checklist 供你做上线前的一些检查。
Server Side checklist
Single Page App Checklist
《Monitoring 101》这是一篇运维方面的入门文章,告诉你最基本的监控线上运行软件的方法和实践。

小结

好了,总结一下今天分享的主要内容。程序员修养看似与程序员练级关系不大,实际上却能反映出程序员的工程师特质和价值观,决定了这条路你到底能走多远。有修养的程序员才可能成长为真正的工程师和架构师,而没有修养的程序员只能沦为码农
因此,在这篇文章中,我指出了我认为比较重要的几个方面:英文能力、问问题的能力、写代码的修养、安全防范意识、软件工程和上线规范等。这些能力的训练和培养将为后续的学习和发展夯实基础。

附录:编程规范

我们在写代码时,最好参考一些已有的最佳实践。为什么要有编程规范和最佳实践,要让所有人按一定的规范来编程呢?有下面几个主要原因。
可以让你的代码很规整,这有利于代码易读性,从而可以更容易地维护。
提升开发效率,我们知道,效率来自于结构化,而不是杂乱。
可以让你的软件避免一些容易掉坑的陷阱,也让 Bug 更少,质量更高。
可以让团队成员更高效率地协作。
如果一个程序员没有这类规范和最佳实践的沉淀,那么是很难成为真正的程序员,只能沦为码农。
当然,对于一些代码风格方面的东西,比如左大括号是否要换行,缩进是用 tab 还是空格等等,我觉得没有对错,只要团队统一就好了。
下面,我罗列了一堆各种语言的编程规范,供你参考。

编程语言相关

Google C++ Style Guide。
Go 语言
Effective Go ,Go 的语法不复杂,所以,Go 语言的最佳实践只需要看这篇官方文档就够了。
Java 语言
Code Conventions for the Java™ Programming Language ,Java 官方的编程规范。
Google Java Style Guide,Google 的 Java 编码规范。
JavaScript 语言
JavaScript The Right Way ,一个相对比较容读的 JavaScript 编程规范,其中不但有代码规范,还有设计模式,测试工具,编程框架,游戏引擎……
Google JavaScript Style Guide,Google 公司的 JavaScript 的编码规范,一个非常大而全的编程规范。
Airbnb JavaScript Style Guide,Airbnb 的 JavaScript 编程规范。没 Google 的这么大而全,但是也很丰富了。
jQuery Core Style Guide,jQuery 的代码规范。
JavaScript Clean Code,前面推荐过的《代码整洁之道》一书中的 JavaScript 的实践 。
还有一些其它相对比较简单的 JavaScript 编程规范。
JavaScript Style Guides And Beautifiers ,这是一篇推荐 JavaScript 编程规范的文章,你可以看看。
JavaScript Style Guide and Coding Conventions,这是 W3Schools 的 JavaScript。
Code Conventions for the JavaScript。
PHP 语言
PHP FIG,PHP 编码规范及标准推荐。
PHP The Right Way,除了编码规范之外的各种 PHP 的最佳实践,还包括一些设计模式,安全问题,以及服务部署,Docker 虚拟化以及各种资源。
Clean Code PHP,《代码整洁之道》的 PHP 实践。
Python 语言
Style Guide for Python Code,Python 官方的编程码规范。
Google Python Style Guide,Google 公司的 Python 编码规范。
The Hitchhiker’s Guide to Python,这不只是 Python 的编程规范,还是 Python 资源的集散地,强烈推荐。

Shell 语言
Google Shell Style Guide,Google 的 Shell 脚本编程规范。
Node.js 相关
npm-coding-style。
Microsoft + Node.js Guidelines。
Node.js Style Guide。
Mozilla 的编程规范
Mozilla Coding Style Guide,其中包括 C、C++、Java、Python、JavaScript、Makefile 和 SVG 等编程规范。

前端开发相关

CSS Guidelines,CSS 容易学,但是不好写,这篇规范会教你如何写出一个健全的、可管理的,并可以扩展的 CSS。
Scalable and Modular Architecture for CSS,这是一本教你如何写出可扩展和模块化的 CSS 的电子书,非常不错。
Frontend Guidelines,一些和 HTML、CSS、JavaScript 相关的最佳实践。
Sass Guidelines,Sass 作为 CSS 的补充,其要让 CSS 变得更容易扩展。然而,也变得更灵活,这意味着可以被更容易滥用。这里这篇 “ 富有主见 “ 的规范值得你一读。
Airbnb CSS / Sass Styleguide, Airbnb 的 CSS/Sass 规范。
说了 Sass 就不得不说 LESS,这里有几篇和 LESS 相关的:LESS Coding Guidelines、LESS Coding Guidelines、LESS coding standard。
HTML Style Guide,一个教你如何写出性能更高,结构更好,容易编程和扩展的 HTML 的规范。
HTML + CSS Code Guide,如何写出比较灵活、耐用、可持续改进的 HTML 和 CSS 的规范。
CoffeeScript Style Guide,CoffeeScript 的最佳实践和编程规范。
Google HTML/CSS Style Guide,Google 的 HTML/CSS 的编程规范。
Guidelines for Responsive Web Design ,响应式 Web 设计的规范和最佳实践。
U.S. Web Design Standards,这是美国政府网端要求的一些 UI 交互可视化的一些规范。
最后是一个前端开发的各种注意事项列表,非常有用。
Front-End Checklist ,一个前端开发的 Checklist,其中包括 HTML、CSS 和 JavaScript,还和图片、字体、SEO、性能相关,还包括关一些和安全相关的事项,这个列表真的是太好了。

移动端相关

Kotlin
Coding Conventions。
Objective-C 语言
Objective-C Style guide,Style guide & coding conventions for Objective-C projects。
Google Objective-C Style Guide。
NYTimes Objective-C Style Guide ,The Objective-C Style Guide used by The New York Times。
Swift 语言
API Design Guidelines。
Swift - 一个 Swift 的相关编程规范的教程。
Swift style guide。
Swift Style Guide - LinkedIn 的官方 Swift 编程规范。
Metova’s Swift style guide。
Xmartlabs Swift Style Guide,Xmartlabs 的 Swift 编程规范。

API 相关

HAL,一个简单的 API 规范教程。
Microsoft REST API Guidelines,微软的 Rest API 规范。
API Design Guide。
RESTful API Designing guidelines - The best practices。
JSON API - Recommendations,JSON 相关的 API 的一些推荐实践。
API Security Checklist ,API 的安全问题的检查列表。

开发工具相关

Markdown 相关
Google Markdown Style Guide。
Markdown Style Guide。
JSON
Google JSON Style Guide。
JSON Style Guide。
Git 相关
Git Style Guide。
Few Rules from Git Documentation。
正则表达式相关
RegexHQ。
Learn regex the easy way。


下载APP

73 | 程序员练级攻略:编程语言

2018-06-12 陈皓
《左耳听风》
课程介绍

image.png
image.pngimage.pngimage.pngimage.png

讲述:柴巍

时长17:30大小8.01M

为了进入专业的编程领域,我们需要认真学习以下三方面的知识。
编程语言。你需要学习 C、C++ 和 Java 这三个工业级的编程语言。为什么说它们是工业级的呢?主要是,C 和 C++ 语言规范都由 ISO 标准化过,而且都有工业界厂商组成的标准化委员会来制定工业标准。次要原因是,它们已经在业界应用于许多重要的生产环境中。
C 语言不用多说,现今这个世界上几乎所有重要的软件都跟 C 有直接和间接的关系,操作系统、网络、硬件驱动等等。说得霸气一点儿,这个世界就是在 C 语言之上运行的。
而对于 C++ 来说,现在主流的浏览器、数据库、Microsoft Office、主流的图形界面、著名的游戏引擎等都是用 C++ 编写的。而且,很多公司都用 C++ 开发核心架构,如 Google、腾讯、百度、阿里云等。
而金融电商公司则广泛地使用 Java 语言,因为 Java 的好处太多了,代码稳定性超过 C 和 C++,生产力远超 C 和 C++。有 JVM 在,可以轻松地跨平台,做代码优化,做 AOP 和 IoC 这样的高级技术。以 Spring 为首的由庞大的社区开发的高质量的各种轮子让你只需关注业务,是能够快速搭建企业级应用的不二之选。
此外,我推荐学习 Go 语言。一方面,Go 语言现在很受关注,它是取代 C 和 C++ 的另一门有潜力的语言。C 语言太原始了,C++ 太复杂了,Java 太高级了,所以 Go 语言就在这个夹缝中出现了。这门语言已经 10 多年了,其已成为云计算领域事实上的标准语言,尤其是在 Docker/Kubernetes 等项目中。Go 语言社区正在不断地从 Java 社区移植各种 Java 的轮子过来,Go 社区现在也很不错。
如果你要写一些 PaaS 层的应用,Go 语言会比 C 和 C++ 更好,目前和 Java 有一拼。而且,Go 语言在国内外一些知名公司中有了一定的应用和实践,所以,是可以学习的(参看:《Go 语言、Docker 和新技术 https://coolshell.cn/articles/18190.html》一文)。此外,Go 语言语法特别简单,你有了 C 和 C++ 的基础,学习 Go 的学习成本基本为零。
理论学科。你需要学习像算法、数据结构、网络模型、计算机原理等计算机科学专业需要学习的知识。为什么要学好这些理论上的知识呢?
其一,这些理论知识可以说是计算机科学这门学科最精华的知识了。说得大一点,这些是人类智慧的精华。你只要想成为高手,这些东西是你必需要掌握和学习的。
其二,当你在解决一些很复杂或是很难的问题时,这些基础理论知识可以帮到你很多。我过去这 20 年从这些基础理论知识中受益匪浅。
其三,这些理论知识的思维方式可以让你有触类旁通,一通百通的感觉。虽然知识比较难啃,但啃过以后,你将获益终生。
另外,你千万不要觉得在你的日常工作或是生活当中根本用不上,学了也白学,这样的思维方式千万不要有,因为这是平庸的思维方式。如果你想等我用到了再学也不晚,那么你有必要看一下这篇文章《程序员的荒谬之言还是至理名言?https://coolshell.cn/articles/4235.html》。
系统知识。系统知识是理论知识的工程实践,这里面有很多很多的细节。比如像 Unix/Linux、TCP/IP、C10K 挑战等这样专业的系统知识。这些知识是你能不能把理论应用到实际项目当中,能不能搞定实际问题的重要知识。
当你在编程的时候,如何和系统进行交互或是获取操作系统的资源,如何进行通讯,当系统出了性能问题,当系统出了故障等,你有大量需要落地的事需要处理和解决。这个时候,这些系统知识就会变得尤为关键和重要了。
这些东西,你可以认为是计算机世界的物理世界,上层无论怎么玩,无论是 Java NIO,还是 Nginx,还是 Node.js,它们都逃脱不掉最下层的限制。所以,你要好好学习这方面的知识。

编程语言

Java 语言

学习 Java 语言有以下入门级的书(注意:下面一些书在入门篇中有所提及,但为了完整性,还是要在这里提一下,因为可能有朋友是跳着看的)。
《Java 核心技术:卷 1 基础知识》,这本书本来是 Sun 公司的官方用书,是一本 Java 的入门参考书。对于 Java 初学者来说,是一本非常不错的值得时常翻阅的技术手册。书中有较多地方进行 Java 与 C++ 的比较,因为当时 Java 面世的时候,又被叫作 “C++ Killer”。而我在看这本书的时候,发现书中有很多 C++ 的东西,于是又去学习了 C++。学习 C++ 的时候,发现有很多 C 的东西不懂,又顺着去学习了 C。然后,C -> C++ -> Java 整条线融汇贯通,这对我未来的技术成长有非常大的帮助。
有了上述的入门后,Java 的 Spring 框架是你玩 Java 所无法回避的东西,所以接下来是两本 Spring 相关的书,《Spring 实战》和《Spring Boot 实战》。前者是传统的 Spring,后者是新式的微服务的 Spring。如果你只想看一本的话,那么就看后者吧。
前面推荐的几本书可以帮你成功入门 Java,但想要进一步成长,就要看下面我推荐的几本进阶级别的书了。
接下来,你需要了解了一下如何编写高效的代码,于是必需看一下《Effective Java》(注意,这里我给的引用是第三版的,也是 2017 年末出版的书),这本书是模仿 Scott Meyers 的经典图书《Effective C++》的。Effective 这种书基本上都是各种经验之谈,所以,这是一本非常不错的书,你一定要读。这里需要推荐一下 Google Guava 库 ,这个库不但是 JDK 的升级库,其中有如:集合(collections)、缓存(caching)、原生类型支持(primitives support)、并发库(concurrency libraries)、通用注解(common annotations)、字符串处理(string processing)、I/O 等库,其还是 Effective Java 这本书中的那些经验的实践代表。
《Java 并发编程实战》,是一本完美的 Java 并发参考手册。书中从并发性和线程安全性的基本概念出发,介绍了如何使用类库提供的基本并发构建块,用于避免并发危险、构造线程安全的类及验证线程安全的规则,如何将小的线程安全类组合成更大的线程安全类,如何利用线程来提高并发应用程序的吞吐量,如何识别可并行执行的任务,如何提高单线程子系统的响应性,如何确保并发程序执行预期任务,如何提高并发代码的性能和可伸缩性等内容。最后介绍了一些高级主题,如显式锁、原子变量、非阻塞算法以及如何开发自定义的同步工具类。
了解如何编写出并发的程序,你还需要了解一下如何优化 Java 的性能。我推荐《Java 性能权威指南》。通过学习这本书,你可以比较大程度地提升性能测试的效果。其中包括:使用 JDK 中自带的工具收集 Java 应用的性能数据,理解 JIT 编译器的优缺点,调优 JVM 垃圾收集器以减少对程序的影响,学习管理堆内存和 JVM 原生内存的方法,了解如何最大程度地优化 Java 线程及同步的性能,等等。看完这本书后,如果你还有余力,想了解更多的底层细节,那么,你有必要去读一下《深入理解 Java 虚拟机》。
《Java 编程思想》,真是一本透着编程思想的书。上面的书让你从微观角度了解 Java,而这本书则可以让你从一个宏观角度了解 Java。这本书和 Java 核心技术的厚度差不多,但这本书的信息密度比较大。所以,读起来是非常耗大脑的,因为它会让你不断地思考。对于想学好 Java 的程序员来说,这是一本必读的书。
《精通 Spring 4.x》,也是一本很不错的书,就是有点厚,一共有 800 多页,都是干货。我认为其中最不错的是在分析原理,尤其是针对前面提到的 Spring 技术,应用与原理都讲得很透彻,IOC 和 AOP 也分析得很棒,娓娓道来。其对任何一个技术都分析得很细致和全面,不足之处就是内容太多了,所以导致很厚,但这并不影响它是一本不错的工具书。
当然,学 Java 你一定要学面向对象的设计模式,这里就只有一本经典的书《设计模式》。如果你觉得有点儿难度了,那么可以看一下《Head First 设计模式》。学习面向对象的设计模式时,你不要迷失在那 23 个设计模式中,你一定要明白这两个原则:
Program to an ‘interface’, not an ‘implementation’
使用者不需要知道数据类型、结构、算法的细节。
使用者不需要知道实现细节,只需要知道提供的接口。
利于抽象、封装,动态绑定,多态。符合面向对象的特质和理念。
Favor ‘object composition’ over ‘class inheritance’
继承需要给子类暴露一些父类的设计和实现细节。
父类实现的改变会造成子类也需要改变。
我们以为继承主要是为了代码重用,但实际上在子类中需要重新实现很多父类的方法。
继承更多的应该是为了多态。
至此,如果你把上面的这些知识都融汇贯通的话,那么,你已是一个高级的 Java 程序员了,我保证你已经超过了绝大多数程序员了。基本上来说,你在技术方面是可以进入到一线公司的,而且还不是一般的岗位,至少是高级程序员或是初级架构师的级别了。

C/C++ 语言

不像我出道那个时候,几乎所有的软件都要用 C 语言来写。现在,可能不会有多少人学习 C 语言了,因为一方面有 Java、Python 这样的高级语言为你屏蔽了很多的底层细节,另一方面也有像 Go 语言这样的新兴语言可以让你更容易地写出来也是高性能的软件。但是,我还是想说,C 语言是你必须学习的语言,因为这个世界上绝大多数编程语言都是 C-like 的语言,也是在不同的方面来解决 C 语言的各种问题。这里,我想放个比较武断话——如果你不学 C 语言,你根本没有资格说你是一个合格的程序员!
这里尤其推荐,已故的 C 语言之父 Dennis M. Ritchie 和著名科学家 Brian W. Kernighan 合作的圣经级的教科书《C 程序设计语言》。注意,这本书是 C 语言原作者写的,其 C 语言的标准不是我们平时常说的 ANSI 标准,而是原作者的标准,又被叫作 K&R C。但是这本书很轻薄,也简洁,不枯燥,是一本你可以拿着躺在床上看还不会看着看着睡着的书。
然后,还有一本非常经典的 C 语言的书《C 语言程序设计现代方法》。有人说,这本书配合之前的 The C Programming Language 那本书简真是无敌。我想说,这本书更实用,也够厚,完整覆盖了 C99 标准,习题的质量和水准也比较高。更好的是,探讨了现代编译器的实现,以及和 C++ 的兼容,还揭穿了各种古老的 C 语言的神话和信条……是相当相当干的一本学习 C 语言的书。
对了,千万不要看谭浩强的 C 语言的书。各种误导,我大学时就是用这本书学的 C,后来工作时被坑得不行
在学习 C 语言的过程中,你一定会感到,C 语言这么底层,而且代码经常性地崩溃,经过一段时间的挣扎,你才开始觉得你从这个烂泥坑里快要爬出来了。但你还需要看看《C 陷阱与缺陷》这本书,你会发现,这里面的坑不是一般大。
此时,如果你看过我的《编程范式游记》那个系列文章,你可能会发现 C 语言在泛型编程上的各种问题,这个时候我推荐你学习一下 C++ 语言。可能会有很多人觉得我说的 C++ 是个大坑。是的,这是世界目前来说最复杂也是最难的编程语言了。但是,C++ 是目前世界上范式最多的语言了,其做得最好的范式就是 “ 泛型编程 “,这在静态语言中,是绝对地划时代的一个事
所以,你有必要学习一下 C++,看看 C++ 是如何解决 C 语言中的各种问题的。你可以先看看我的这篇文章 “C++ 的坑真的多吗?” ,有个基本认识。下面推荐几本 C++ 的书。
《C++ Primer 中文版》,这本书是久负盛名的 C++ 经典教程。书是有点厚,前面 1/3 讲 C 语言,后面讲 C++。C++ 的知识点实在是太多了,而且又有点晦涩。但是你主要就看几个点,一个是面向对象的多态,一个是模板和重载操作符,以及一些 STL 的东西。看看 C++ 是怎么玩泛型和函数式编程的。
如果你想继续研究,你需要看另外两本更为经典的书《Effective C++》和《More Effective C++》。 这两本书不厚,但是我读了 10 多年,每过一段时间再读一下,就会发现有更多的收获。这两本书的内容会随着你经历的丰富而变得丰富,这也是对我影响最大的两本书,其中影响最大的不是书中的那些 C++ 的东西,而是作者的思维方式和不断求真的精神,这真是太赞了。
学习 C/C++ 都是需要好好了解一下编译器到底干了什么事的。就像 Java 需要了解 JVM 一样,所以,这里还有一本非常非常难啃的书你可以挑战一下《深度探索 C++ 对象模型》。这本书是非常之经典的,看完后,C++ 对你来说就再也没有什么秘密可言。我以前写过的《C++ 虚函数表解析》,还有《C++ 对象内存布局》属于这个范畴。
还有 C++ 的作者 Bjarne Stroustrup 写的 C++ FAQ (中文版),也是非常值得一读的。

学习 Go 语言

C 语言太原始了,C++ 太复杂了,Go 语言是不二之选。有了 C/C++ 的功底,学习 Go 语言非常简单。
首推 Go by Example 作为你的入门教程。然后,Go 101 也是一个很不错的在线电子书。如果你想看纸书的话,The Go Programming Language 一书在豆瓣上有 9.2 分,但是国内没有卖的。(当然,我以前也写过两篇入门的供你参考 “GO 语言简介(上)- 语法” 和 “GO 语言简介(下)- 特性”)。
另外,Go 语言官方的 Effective Go 是必读的,这篇文章告诉你如何更好地使用 Go 语言,以及 Go 语言中的一些原理。
Go 语言最突出之处是并发编程,Unix 老牌黑客罗勃·派克(Rob Pike)在 Google I/O 上的两个分享,可以让你学习到一些并发编程的模式。
Go Concurrency Patterns( 幻灯片和演讲视频)。
Advanced Go Concurrency Patterns(幻灯片、演讲视频)。
然后,Go 在 GitHub 的 wiki 上有好多不错的学习资源,你可以从中学习到多。比如:
Go 精华文章列表。
Go 相关博客列表。
Go Talks。
此外,还有个内容丰富的 Go 资源列表 Awesome Go,推荐看看。

小结

好了,最后我们来总结一些今天分享的内容。在编程语言方面,我推荐学习 C、C++、Java 和 Go 四门语言,并分别阐释了推荐的原因。
我认为,C 语言是必须学习的语言,因为这个世界上绝大多数编程语言都是 C-like 的语言,也是在不同的方面来解决 C 语言的各种问题。
而 C++ 虽然复杂难学,但它几乎是目前世界上范式最多的语言了,其做得最好的范式就是 “ 泛型编程 “,这在静态语言中,是绝对地划时代的一个事。尤其要看看 C++ 是如何解决 C 语言中的各种问题的。
Java 是我认为综合能力最强的语言。其实我是先学了 Java,然后又去学了 C++,之后去学了 C 语言的。C -> C++ -> Java 整条线融汇贯通,这对我未来的技术成长有非常大的帮助。
在文章最末,我推荐了 Go 语言,并给出了相关的学习资料。
我认为,一个合格的程序员应该掌握几门语言。一方面,这会让你对不同的语言进行比较,让你有更多的思考。另一方面,这也是一种学习能力的培养,会让你对于未来的新技术学习得更快。
下篇文章中,我们将分享每个程序员都需要掌握的理论知识。敬请期待。

精选留言(93)

  • oji2018-06-12几个问题,
    1.您一下子提到了四门语言,我们这些后生究竟应该精通一门呢,还是多元呢?如果多元,深度是个问题?
    2.总有一些经常变和亘古不变的东西,数据结构,算法,网络,计算机基本原理,这些都是很少改变的,而且也需要花很多精力和时间去学习,您提到的几个语言都是经久不衰的,也需要花精力和时间去学习,而时间的总量是固定的,那么我们如何取舍呢?
    3.语言本身只是工具,能不能用学到的语言解决问题,这个很关键,不是吗?能不能这么理解,学另一个语言,是因为本语言在某些特定的问题上遇到瓶颈,只能用别的语言来解决?展开作者回复: 1)我把Java放在第一位,就是说Java很重要。C语言要学。C++可以跳过,学了C语言,Go语言很自然就学会了。编程语言不复杂的,多花点时间没坏处。
    2)不要取舍,排优先级。这些基础知识都是计算机科学专业大学本科的知识,4年你能拿得出来吗?
    3)Java语言让你不用关注底层,而关注业务和架构,C语言让你关注底层原理,Go语言介于C和Java之间,掌握多门语言会让你对他们有比较。他们各有各的适用场景。

如果你想成为一个高手,多学几门语言是必须的!_2_


74 | 程序员练级攻略:理论学科

进入专业的编程领域,算法、数据结构、网络模型、计算机原理等这样的计算机科学专业需要学习的理论知识是必须要学习的。下面我们先来看看数据结构和算法。

数据结构和算法

算法是比较难学习的,而且学习“算法”是需要智商的。数组、链表、哈希表、二叉树、排序算法等一些基础知识,对大多数人来说是没什么问题的。但是一旦进入到路径规划、背包问题、字符串匹配、动态规划、递归遍历等一些比较复杂的问题上,就会让很多人跟不上了,不但跟不上,而且还会非常痛苦。是的,解决算法问题的确是可以区分人类智商的一个比较好的方式,这也是为什么好些公司用算法题当面试题来找到智商比较高的程序员。
然而,在很多时候,我们在工作中却发现根本用不到算法,或是一些基本的算法也没有必要实现,只需要使用一下第三方的库就好了。于是,导致社会上出现很多“算法无用论”的声音。
对此,我想说,算法真的很重要。我这 20 年的经历告诉我,无论是做业务还是做底层系统,经常需要使用算法处理各种各样的问题。比如,业务上我需要用算法比较两个数组中差异的布隆过滤器,或是在做监控系统时实时计算过去一分钟的 P99 统计时的蓄水池算法,或是数据库的 B+ 树索引,还有 Linux 内核中的 epoll 的红黑树,还有在做服务调度里的“背包问题”等都会用算法,真的是会本质上帮助到你,也是会让你瞬间会产生成就感的事情。
虽然算法很难,需要智商,但我还是想鼓励你,这其中是有很多的套路是可以学习的,一旦学会这些套路,你会受益无穷的。
这里有几本书着重推荐一下。
基础知识。《算法》,是算法领域经典的参考书,不但全面介绍了关于算法和数据结构的必备知识,还给出了每位程序员应知应会的 50 个算法,并提供了实际代码。最不错的是,其深入浅出的算法介绍,让一些比较难的算法也变得容易理解,尤其是书中对红黑树的讲解非常精彩。其中,还有大量的图解,详尽的代码和讲解,也许是最好的数据结构入门图书。不好的是不深,缺乏进一步的算法设计内容,甚至连动态规划都未提及。另外,如果你觉得算法书比较枯燥的话,你可以看看这本有趣的《算法图解》。
理论加持。如果说上面这本书偏于实践和工程,而你看完后,对算法和数据结构的兴趣更浓了,那么你可以再看看另一本也是很经典的偏于理论方面的书——《算法导论》。虽然其中的一些理论知识在《算法》那本书中也有提过,但《算法导论》这本书更为专业一些,是美国计算机科学本科生的教科书。
思维改善。还有一本叫《编程珠玑》的书,写这本书的人是世界著名计算机科学家乔恩·本特利(Jon Bentley),被誉为影响算法发展的十位大师之一。你可能不认识这个人,但是你知道他的学生有多厉害吗?我例举几个,一个是 Tcl 语言设计者约翰·奥斯德奥特(John Ousterhout),另一个是 Java 语言设计者詹姆斯·高斯林(James Gosling),还有一个是《算法导论》作者之一查尔斯·雷斯尔森(Charles Leiserson),还有好多好多。这本书也是很经典的算法书,其中都是一些非常实际的问题,并以其独有的洞察力和创造力,来引导读者理解并学会解决这些问题的方法,也是一本可以改善你思维方式的书。
然后,你需要去做一些题来训练一下自己的算法能力,这里就要推荐 LeetCode 这个网站了。它是一个很不错的做算法训练的地方。现在也越做越好了。基本上来说,这里会有两类题。
基础算法题。其中有大量的算法题,解这些题都是有套路的,不是用递归(深度优先 DFS、广度优先 BFS),就是要用动态规划(Dynamic Programming),或是折半查找(Binary Search),或是回溯(Back tracing),或是分治法(Divide and Conquer),还有大量的对树、数组、链表、字符串和 hash 表的操作。通过做这些题能让你对这些最基础的算法的思路有非常扎实的了解和训练。对我而言,Dynamic Programming 是我的短板,尤其是一些比较复杂的问题,在推导递推公式上总是有思维的缺陷(数学是我的硬伤)。做了这些题后,我能感到我在动态编程的思路上受到了很大的启发。
编程题。比如:atoi、strstr、add two nums、括号匹配、字符串乘法、通配符匹配、文件路径简化、Text Justification、反转单词等,这些题的 Edge Case 和 Corner Case 有很多。这些题需要你想清楚了再干,只要你稍有疏忽,就会有几个 case 让你痛不欲生,而且一不小心就会让你的代码写得又臭又长,无法阅读。通过做这些题,可以非常好地训练你对各种情况的考虑,以及你对程序代码组织的掌控(其实就是其中的状态变量)。
我觉得每个程序员都应该花时间和精力做这些题,因为你会从这些题中得到很大的收益。我在 Leetcode 上做的一些题的代码在这——我的 GitHub 上,可以给你一些参考。
如果能够把这些算法能力都掌握了,那么你就有很大的概率可以很容易地通过这世界上最优的公司的面试,比如:Google、Amazon、Facebook 之类的公司。对你来说,如果能够进入到这些公司里工作,那么你未来的想像空间也会大很多。
最后,我们要知道这个世界上的数据结构和算法有很多,下面给出了两个网站。
List of Algorithms ,这个网站罗列了非常多的算法,完全可以当成一个算法字典,或是用来开阔眼界。
还有一个数据结构动画图的网站 Data Structure Visualizations。

其它理论基础知识

下面这些书,基本上是计算机科学系的大学教材。如果你想有科班出身的理论基础,那么这些书是必读的。当然,这些理论基础知识比较枯燥,但我觉得如果你想成为专业的程序员,那么应该要找时间读一下。
《数据结构与算法分析》,这本书曾被评为 20 世纪顶尖的 30 部计算机著作之一,作者 Mark Allen Weiss 在数据结构和算法分析方面卓有建树,他在数据结构和算法分析等方面的著作尤其畅销,并广受好评,已被世界 500 余所大学用作教材。
《数据库系统概念》,它是数据库系统方面的经典教材之一。国际上许多著名大学包括斯坦福大学、耶鲁大学、德克萨斯大学、康奈尔大学、伊利诺伊大学、印度理工学院等都采用本书作为教科书。这本书全面介绍了数据库系统的各种知识,透彻阐释数据库管理的基本概念。不仅讨论了数据库查询语言、模式设计、数据仓库、数据库应用开发、基于对象的数据库和 XML、数据存储和查询、事务管理、数据挖掘与信息检索以及数据库系统体系结构等方面的内容,而且对性能评测标准、性能调整、标准化以及空间与地理数据、事务处理监控等高级应用主题进行了广泛讨论。
《现代操作系统》,这本书是操作系统领域的经典之作,书中集中讨论了操作系统的基本原理,包括进程、线程、存储管理、文件系统、输入 / 输出、死锁等,同时还包含了有关计算机安全、多媒体操作系统、掌上计算机操作系统、微内核、多核处理机上的虚拟机以及操作系统设计等方面的内容。
《计算机网络》,这本书采用了独创的自顶向下方法,即从应用层开始沿协议栈向下讲解计算机网络的基本原理,强调应用层范例和应用编程接口,内容深入浅出,注重教学方法,理论与实践相结合。新版中还增加了无线和移动网络一章,并扩充了对等网络、BGP、MPLS、网络安全、广播选路和因特网编址及转发方面的材料。是一本不可多得的教科书。
《计算机程序的构造和解释》,这本书也很经典,是 MIT 的计算机科学系的教材。这本书中主要证实了很多程序是怎么构造出来的,以及程序的本质是什么。整本书主要是使用 Scheme/Lisp 语言,从数据抽象、过程抽象、迭代、高阶函数等编程和控制系统复杂性的思想,到数据结构和算法,到编译器 / 解释器、编程语言设计。
《编译原理》,这本书又叫 “ 龙书 “,其全面、深入地探讨了编译器设计方面的重要主题,包括词法分析、语法分析、语法制导定义和语法制导翻译、运行时刻环境、目标代码生成、代码优化技术、并行性检测以及过程间分析技术,并在相关章节中给出大量的实例。与上一版相比,本书进行了全面的修订,涵盖了编译器开发方面的最新进展。每章中都提供了大量的系统及参考文献。

小结

好了,最后我们来总结一些今天分享的内容。在这篇文章中,我建议想进入专业编程领域的人,一定要学习算法、数据结构、网络模型、计算机原理等理论知识,并推荐了相应的学习素材,给出了我的思考和建议。
我认为,虽然这些理论知识枯燥难学,而且通常学完了在工作中也并不是马上就能用上,但这些知识是必须要学好的。这些理论知识可以说是计算机科学这门学科最精华的知识了,认真学习,理解其背后的逻辑和思维方式,会让你受益匪浅。不管是未来你是要学习新技能,还是解决什么疑难问题,都能在这些知识中获得灵感或者启发。
下篇文章中,我们将分享每个程序员都需要掌握的系统知识。敬请期待。

75 | 程序员练级攻略:系统知识

2018-06-19 陈皓
《左耳听风》
课程介绍

image.png
image.pngimage.pngimage.pngimage.png

讲述:柴巍

时长11:27大小5.24M

进入专业的编程领域,学习系统知识是非常关键的一部分。
首先推荐的是翻译版图书《深入理解计算机系统》,原书名为《Computer Systems A Programmer’s Perspective》。不过,这本书叫做《程序员所需要了解的计算机知识》更为合适。
本书的最大优点是为程序员描述计算机系统的实现细节,帮助其在大脑中构造一个层次型的计算机系统。从最底层的数据在内存中的表示到流水线指令的构成,到虚拟存储器,到编译系统,到动态加载库,到最后的用户态应用。通过掌握程序是如何映射到系统上,以及程序是如何执行的,你能够更好地理解程序的行为为什么是这样的,以及效率低下是如何造成的。
再强调一下,这本书是程序员必读的一本书!
然后就是美国计算机科学家 理查德·史蒂文斯(Richard Stevens) 的三套巨经典无比的书。(理查德·史蒂文斯于 1999 年 9 月 1 日离世,终年 48 岁。死因不详,有人说是滑雪意外,有人说是攀岩意外,有人说是滑翔机意外。总之,家人没有透露。大师的 个人主页 今天还可以访问。)
《Unix 高级环境编程》。
《Unix 网络编程》 第 1 卷 套接口 API 、第 2 卷 进程间通信 。
《TCP/IP 详解 卷 I 协议》。
这几本书的地位我就不多说了,你可以自己看相关的书评。但是,这三本书可能都不容易读,一方面是比较厚,另一方面是知识的密度太大了,所以,读起来有点枯燥和乏味。但是,这没办法,你得忍住。
这里要重点说一下《TCP/IP 详解》这本书,是一本很奇怪的书。这本书迄今至少被 近五百篇学术论文引用过 。这本写给工程师看的书居然被各种学院派的论文来引用,也是很神奇的一件事了。而且,虽然理查德·史蒂文斯不是 TCP 的发明人,但是这本书中把这个协议深入浅出地讲出来,还画了几百张时序图,也是令人叹为观止了。
如果你觉得上面这几本经典书比较难啃,你可以试试下面这些通俗易懂的(当然,如果读得懂上面那三本的,下面的这些也就不需要读了)。
《Linux C 编程一站式学习》。
《TCP/IP 网络编程》。
《图解 TCP/IP》,这本书其实并不是只讲了 TCP/IP,应该是叫《计算机网络》才对,主要是给想快速入门的人看的。
《The TCP/IP Guide》,这本书在豆瓣上的评分 9.2,这里给的链接是这本书的 HTML 英文免费版的,里面的图画得很精彩。
另外,学习网络协议不单只是看书,你最好用个抓包工具看看这些网络包是什么样的。所以,这里推荐一本书《Wireshark 数据包分析实战》。在这本书中,作者结合一些简单易懂的实际网络案例,图文并茂地演示使用 Wireshark 进行数据包分析的技术方法,可以让我们更好地了解和学习网络协议。当然,也拥有了一定的黑客的技能。
看完《Unix 高级环境编程》后,你可以趁热打铁看看《Linux/Unix 系统编程手册》或是罗伯特·拉姆(Robert Love)的 Linux System Programming 英文电子版 。其中文翻译版Linux 系统编程 也值得一读,虽然和《Unix 高级环境编程》很像,不过其主要突出的是 Linux 的一些关键技术和相关的系统调用。
关于 TCP 的东西,你还可以看看下面这一系列的文章。
Let’s code a TCP/IP stack, 1: Ethernet & ARP
Let’s code a TCP/IP stack, 2: IPv4 & ICMPv4
Let’s code a TCP/IP stack, 3: TCP Basics & Handshake
Let’s code a TCP/IP stack, 4: TCP Data Flow & Socket API
Let’s code a TCP/IP stack, 5: TCP Retransmission
对于系统知识,我认为主要有以下一些学习要点。
用这些系统知识操作一下文件系统,实现一个可以拷贝目录树的小程序。
用 fork / wait / waitpid 写一个多进程的程序,用 pthread 写一个多线程带同步或互斥的程序。比如,多进程购票的程序。
用 signal / kill / raise / alarm / pause / sigprocmask 实现一个多进程间的信号量通信的程序。
学会使用 gcc 和 gdb 来编程和调试程序(参看我的《用 gdb 调试程序》一、二、三、四、五、六、七)。
学会使用 makefile 来编译程序(参看我的《跟我一起写 makefile》一、二、三、四、五、六、七、八、九、十、十一、十二、十三、十四)。
Socket 的进程间通信。用 C 语言写一个 1 对 1 的聊天小程序,或是一个简单的 HTTP 服务器。

C10K 问题

然后,当你读完《Unix 网络编程》后,千万要去读一下 “C10K Problem (中文翻译版)”。提出这个问题的人叫丹·凯格尔(Dan Kegel),目前在 Google 任职。
他从 1978 年起开始接触计算机编程,是 Winetricks 的作者,也是 Wine 1.0 的管理员,同时也是 Crosstool( 一个让 gcc/glibc 编译器更易用的工具套件)的作者。还是 Java JSR 51 规范的提交者并参与编写了 Java 平台的 NIO 和文件锁,同时参与了 RFC 5128 标准中有关 NAT 穿越(P2P 打洞)技术的描述和定义。
C10K 问题本质上是操作系统处理大并发请求的问题。对于 Web 时代的操作系统而言,对于客户端过来的大量的并发请求,需要创建相应的服务进程或线程。这些进程或线程多了,导致数据拷贝频繁(缓存 I/O、内核将数据拷贝到用户进程空间、阻塞), 进程 / 线程上下文切换消耗大,从而导致资源被耗尽而崩溃。这就是 C10K 问题的本质。
了解这个问题,并了解操作系统是如何通过多路复用的技术来解决这个问题的,有助于你了解各种 I/O 和异步模型,这对于你未来的编程和架构能力是相当重要的。
另外,现在,整个世界都在解决 C10M 问题,推荐看看 The Secret To 10 Million Concurrent Connections -The Kernel Is The Problem, Not The Solution 一文。

实践项目

我们已经学习完了编程语言、理论学科和系统知识三部分内容,下面就来做几个实践项目,小试牛刀一下。实现语言可以用 C、C++ 或 Java。
实现一个 telnet 版本的聊天服务器,主要有以下需求。
每个客户端可以用使用telnet ip:port的方式连接到服务器上。
新连接需要用用户名和密码登录,如果没有,则需要注册一个。
然后可以选择一个聊天室加入聊天。
管理员有权创建或删除聊天室,普通人员只有加入、退出、查询聊天室的权力。
聊天室需要有人数限制,每个人发出来的话,其它所有的人都要能看得到。
实现一个简单的 HTTP 服务器,主要有以下需求。
解释浏览器传来的 HTTP 协议,只需要处理 URL path。
然后把所代理的目录列出来。
在浏览器上可以浏览目录里的文件和下级目录。
如果点击文件,则把文件打开传给浏览器(浏览器能够自动显示图片、PDF,或 HTML、CSS、JavaScript 以及文本文件)。
如果点击子目录,则进入到子目录中,并把子目录中的文件列出来。
实现一个生产者 / 消费者消息队列服务,主要有以下需求。
消息队列采用一个 Ring-buffer 的数据结构。
可以有多个 topic 供生产者写入消息及消费者取出消息。
需要支持多个生产者并发写。
需要支持多个消费者消费消息(只要有一个消费者成功处理消息就可以删除消息)。
消息队列要做到不丢数据(要把消息持久化下来)。
能做到性能很高。

小结

到今天,我们已经学习完了专业编程方面最为重要的三部分内容:编程语言、理论学科和系统知识,我们针对这些内容做个小结。如果想看完我推荐的那些书和知识,并能理解和掌握,我估计怎么也得需要 4-5 年的时间。嗯,是的,就是一个计算机科学系科班出身的程序员需要学习的一些东西。这其中,最重要的是下面这几点。
编程语言。以工业级的 C、C++、Java 这三门语言为主,这三门语言才是真正算得上工业级的编程语言,因为有工业级的标准化组织在控制着这几门语言,而且也有工业级的企业应用。尤其是 Java,还衍生出了大量的企业级架构上的开源生态。你至少需要掌握 C 语言和 Java 语言,这对你以后面对各式各样的编程语言是非常重要的。
此外,还推荐学习 Go 语言,它已成为云计算领域事实上的标准语言,尤其是在 Docker、Kubernetes 等项目中。而且,Go 语言在国内外一些知名公司中有了一定的应用和实践,并且其生态圈也越来越好。
算法和数据结构。这个太重要了,尤其是最基础的算法和数据结构,这是任何一个称职的程序员都需要学习和掌握的。你必需要掌握。
计算机的相关系统。你至少要掌握三个系统的基础知识,一个是操作系统,一个是网络系统,还有一个是数据库系统。它们分别代表着计算机基础构架的三大件——计算、存储、网络。
如果你能够走到这里,把前面的那些知识都了解了(不用精通,因为精通是需要时间和实践来慢慢锤炼出来的,所以,你也不用着急),那么你已经是一个合格的程序员了,而且你的潜力和可能性是非常非常高的。
如果经历过这些比较枯燥的理论知识,而且你还能有热情和成就感,那么我要恭喜你了。因为你已经超过了绝大多数人,而且还是排在上游的比较抢手的程序员了。我相信你至少可以找到年薪 50 万以上的工作了。
但是,你还需要很多的经验或是一些实践,以及一些大系统大项目的实际动手的经验。没关系,我们后面会有教你怎么实操的方法和攻略。
但是,往后面走,你需要开始需要术业有专攻了。下面给一些建议的方向。
底层方向:操作系统、文件系统、数据库、网络……
架构方向:分布式系统架构、微服务、DevOps、Cloud Native……
数据方向:大数据、机器学习、人工智能……
前端方向:你对用户体验或是交互更感兴趣,那么你走前端的路吧。
其它方向:比如,安全开发、运维开发、嵌入式开发……
这些方向你要仔细选择,因为一旦选好,就要勇往直前地走下去,当然,你要回头转别的方向也没什么问题,因为你有前面的这些基础知识在身,所以,不用害怕。只是不同的方向上会有不同的经验积累,经验积累是看书看不来的,这个是转方向的成本。
下篇文章,我们将进入《软件设计篇》。敬请期待。

76 | 程序员练级攻略:软件设计


学习了前面文章中的入门级经验和知识后,你可能会有两种反应。
一种反应可能是,你对编程有一点的兴趣了,甚至有一点点小骄傲,可能还会四处炫耀。我想说,请保持这种感觉,但是你也要清醒一下,上面的那些东西,还不算真正的入门,你只是入门了一条腿。
另一种反应也可能是,你被吓着了,觉得太难了。感觉不是一般人能玩的,如果是这样的话,我想鼓励你一下–“无论你做什么事,你都会面对各式各样的困难,这对每个人来说都是一样的,而只有兴趣、热情和成就感才能让你不畏惧这些困难”。所以,你问问你自己,是否从中收获了成就感,如果没有的话,可能这条路并不适合你。如果有的话,哪怕一丁点儿,你也应该继续坚持下来。
这篇文章,我主要是让你成为更为专业的入门程序员。请注意,此时,你可能需要读一些比较枯燥的书,但我想说,这些是非常非常重要的。你一定要坚持住。

编程技能

在系统地学习编程技能之前,我希望你能先看一下 “ The Key To Accelerating Your Coding Skills”, 这篇文章会告诉你如何有效地快速提高自己的编程能力。
然后接下来是下面几大块内容,但还只是入门级的。
编程技巧方面 - 你可以开始看怎么把程序写好的书了,这里推荐的是《代码大全》。这本书好多年没有更新了,其中有一些内容可能有点过时,但还是一本非常好的书,有点厚,你不需要马上就看完。在你的编程路上,这本书可以陪你走很久,因为当你有更多的编程经验时,踩过更多的坑后,再把这本书拿出来看看,你会有更多的体会。好的书和不好的书最大的区别就是,好的书在你不同的阶段来读,你会有不同的收获,而且还会产生更多的深层次的思考! 《代码大全》就是这样的一本书。
编程语言方面 - 这个阶段,你可以开始了解一下 Java 语言了,我个人觉得 Java 是世界上目前为止综合排名最好的语言。你一定要学好这门语言。推荐《Java 核心技术(卷 1)》,除了让你了解 Java 的语法,它还会让你了解面向对象编程是个什么概念(如果你觉得这本书有点深,那么,你可以降低难度看更为基础的《Head First Java》)。然后,既然开始学习 Java 了,那就一定要学 Spring,推荐看看《Spring in Action》或是直接从最新的 Spring Boot 开始,推荐看看《Spring Boot 实战》。关于 Spring 的这两本书,里面可能会有很多你从来没有听说过的东西,比如,IoC 和 AOP 之类的东西,能看懂多少就看懂多少,没事儿。
操作系统 - 这里你可以看看《鸟哥的 Linux 私房菜》,这本书会让你对计算机和操作系统,以及 Linux 有一个非常全面的了解,并能够管理或是操作好一个 Linux 系统。当然,这本书有很多比较专业的知识,你可能会看不懂,没关系,就暂时略过就好了。这本书的确并不适合初学者,你能看多少就看多少吧。
网络协议 - 你需要系统地了解一下 HTTP 协议,请到 MDN 阅读一下其官方的 HTTP 的文档。你需要知道 HTTP 协议的几个关键点:1)HTTP 头,2)HTTP 的请求方法,3)HTTP 的返回码。还有,HTTP 的 Cookie、缓存、会话,以及链接管理,等等,在 MDN 的这个文档中都有了。对于 HTTP 协议,你不需要知道所有的东西,你只需要了解这个协议的最关键的那些东西就好了。
数据库设计 - 你需要系统地了解一下数据库设计中的那些东西,这里推荐慕课网的一个在线课程:数据库设计的那些事。每个小课程不过 5-6 分钟,全部不到 2 个小时,我相信你一定能跟下来。你需要搞清楚数据的那几个范式,还有 SQL 语句的一些用法。当然,你还要学习和使用一下数据库,这里推荐学习开源的 MySQL。你可以看官方文档,也可以看一下这本书《MySQL 必知必会》。
前端方面 - 前端的东西不算复杂,你需要学习几个东西。一个是和 JavaScript 相关的 jQuery,另一个是和 CSS 相关的 Bootstrap,学习这两个东西都不复杂,直接上其官网看文档就好了。最重要的是,你要学习一下如何使用 JavaScript Ajax 请求后端的 API 接口,而不是再像前面那样用后端来向前端返回 HTML 页面的形式了。这里,你需要学习一下,JavaScript 的 Promise 模式。阮一峰翻译的 ES6 的教程中有相关的内容。当然,你 Google 一下,也可以找到一堆学习资料。
字符编码方面 - 在你处理中文时有时会发现有乱码出现,此时需要了解 ASCII 和 Unicode 这样的字符编码。这里推荐一篇文章 - “关于字符编码,你所需要知道的(ASCII,Unicode,Utf-8,GB2312…)” 或是英文文章 “The history of Character Encoding” 以及 Wikipedia - Character encoding。还有 GitHub 上的这两个 Awesome 仓库:Awesome Unicode 和 Awesome Code Points。

为什么转成 Java 语言?

相信你可能会问,为什么之前学习的 Python 和 JavaScript 不接着学,而是直接切到 Java 语言上来,这样会不会切得太快了。这是一个好问题,这里需要说明一下,为什么我会切到 Java 这个语言上来,主要是有以下几方面考虑。
Java 是所有语言里面综合实力最强的,这也是为什么几乎所有大型的互联网或是分布式架构基本上都是 Java 技术栈。所以,这是一个工业级的编程语言(Python 和 JavaScript 还达不到这样的水准)。
之所以没有用 Java 来做入门语言而是用了 Python,这是因为编程是一件比较费脑子的事,一开始学习时,兴趣的培养很重要。Python 比较简单,容易上手,能够比较容易地提起兴趣,而用 Java 则可能比较难。
在你有了一些编程语言的基础后,有了一些代码的逻辑后,切到工业级的编程语言上来,更为专业地学习编程,是非常有帮助的。像 Python 和 JavaScript 这样的动态语言用着是很爽,但是,只有像 C、C++ 和 Java 这样的静态语言才可以让你真正地进阶。
对于一个合格的程序员,掌握几门语言是非常正常的事情。一方面,这会让你对不同的语言进行比较,让你有更多的思考。另一方面,这也是一种学习能力的培养。很多时候,一些程序员只在自己熟悉的技术而不是合适的技术上工作,这其实并不好,这会让你的视野受限,而视野会决定你的高度。综上所述,这就是在入门的时候我故意让你多学几门语言的原因。

编程工具

编程工具方面,你需要开始学习使用下面这些工具了。
编程的 IDE。传统一点的,你可以使用 Eclipse(教程)。当然,我推荐你使用 Intellij IDEA(教程)。这两个工具都可以开发各种语言,但是主要用在 Java。如果你想玩得更时髦一些的话,使用 Visual Studio Code 也不错,这个工具潜力十足,用其开发 Python、JavaScript、Java、Go、C 和 C++ 都能得心应手(教程)。
版本管理工具。版本管理工具是非常重要的编程工具。传统的有 P4、 SVN、CVS 等,但都会被 Git 取代,所以,你就只用学习 Git 就好了。学习 Git 的教程网上有很多,这里我推荐非常系统的 Pro Git 第二版 (如果你觉得 Pro Git 比较枯燥的话,备选猴子都能懂的 Git 入门),然后你要学会使用 GitHub。关于一些 Git 环境安装和准备以及 GitHub 使用,你可以自行 Google(比如:这篇GitHub and Git 图文教程 或是这篇Git 图文教程及详解)。
调试前端程序。你需要学会使用 Chrome 调试前端程序,Google 一下会有很多文章,你可以看看 超完整的 Chrome 浏览器客户端调试大全。
数据库设计工具。你需要学会使用 MySQL WorkBench,这个工具很容易使用。相关的手册,你可以看一下官方文档。

实践项目

这回我们需要设计一个投票系统的项目。
业务上的需求如下:
用户只有在登录后,才可以生成投票表单。
投票项可以单选,可以多选。
其它用户投票后显示当前投票结果(但是不能刷票)。
投票有相应的时间,页面上需要出现倒计时。
投票结果需要用不同颜色不同长度的横条,并显示百分比和人数。
技术上的需求如下:
这回要用 Java Spring Boot 来实现了,然后,后端不返回任何的 HTML,只返回 JSON 数据给前端。
由前端的 JQuery 来处理并操作相关的 HTML 动态生成在前端展示的页面。
前端的页面还要是响应式的,也就是可以在手机端和电脑端有不同的呈现。 这个可以用 Bootstrap 来完成。
如果你有兴趣,还可以挑战以下这些功能。
在微信中,通过微信授权后记录用户信息,以防止刷票。
可以不用刷页面,就可以动态地看到投票结果的变化。
Google 一些画图表的 JavaScript 库,然后把图表画得漂亮一些。

小结

上面那些书和知识你要看完,还要能理解并掌握,我估计你最少也要花 1-2 年左右的时间。如果你能够走到这里,把前面的那些知识都了解了,不用精通,能独立地做出上面的那些实践项目,那么,你就算是真正的入门了。
而且,你已经是一个“全栈工程师”的样子了,在这里我要给你一个大大的赞。如果这个时候,你对编程还有很大的热情,那么我要恭喜你了,你可能会是一个非常不错的程序员。加油啊!
上面的那些技术已经算是比较专业的了。如果你已经大致掌握了,我相信你可以找到至少年薪 20 万以上的工作了,而且你的知识面算是有不错的广度了。但是深度还不够,这个时候,是一个比较关键点了。
你可能已经沉醉在沾沾自喜的骄傲的情绪中,那么你也可以就此止步,加入一些公司,在那里按部就班地完成一些功能性的开发,成为一个搬砖的码农。你也可以开始选择一个方向开始深入。
我给你的建议是选择一个方向开始深入。因为你并不知道你未来会有多大的可能性,也不知道你会成为什么样的人,所以为什么不再更努力一把呢?
后面,我们就开始非常专业的程序员之路了。这也是一般程序员和高级程序员的分水岭了,能不能过去就看你的了。

79 | 程序员练级攻略:Java底层知识

2018-07-03 陈皓
《左耳听风》
课程介绍

image.png
image.pngimage.pngimage.pngimage.png

讲述:柴巍

时长07:25大小3.40M

前两篇文章分享的是系统底层方面的内容,今天我们进入高手成长篇的第二部分——Java 底层知识。

Java 字节码相关

首先,Java 最黑科技的玩法就是字节码编程,也就是动态修改或是动态生成 Java 字节码。Java 的字节码相当于汇编,其中的一些细节你可以从下面的这几个教程中学习。
Java Zone: Introduction to Java Bytecode ,这篇文章图文并茂地向你讲述了 Java 字节码的一些细节,是一篇很不错的入门文章。
IBM DeveloperWorks: Java bytecode ,虽然这篇文章很老了,但是这篇文章是一篇非常好的讲 Java 字节码的文章。
Java Bytecode and JVMTI Examples,这是一些使用 JVM Tool Interface 操作字节码的比较实用的例子。包括方法调用统计、静态字节码修改、Heap Taggin 和 Heap Walking。
当然,一般来说,我们不使用 JVMTI 操作字节码,而是用一些更好用的库。这里有三个库可以帮你比较容易地做这个事。
asmtools - 用于生产环境的 Java .class 文件开发工具。
Byte Buddy - 代码生成库:运行时创建 Class 文件而不需要编译器帮助。
Jitescript - 和 BiteScript 类似的字节码生成库。
就我而言,我更喜欢 Byte Buddy,它在 2015 年还获了 Oracle 的 “Duke’s Choice”大奖,其中说 Byte Buddy 极大地发展了 Java 的技术。
使用字节码编程可以玩出很多高级玩法,最高级的还是在 Java 程序运行时进行字节码修改和代码注入。听起来是不是一些很黑客,也很黑科技的事?是的,这个方式使用 Java 这门静态语言在运行时可以进行各种动态的代码修改,而且可以进行无侵入的编程。
比如, 我们不需要在代码中埋点做统计或监控,可以使用这种技术把我们的监控代码直接以字节码的方式注入到别人的代码中,从而实现对实际程序运行情况进行统计和监控。如果你看过我的《编程范式游记》,你就知道这种技术的威力了,其可以很魔法地把业务逻辑和代码控制分离开来。
要做到这个事,你还需要学习一个叫 Java Agent 的技术。Java Agent 使用的是 “Java Instrumentation API”,其主要方法是实现一个叫 premain() 的方法(嗯,一个比 main() 函数还要超前执行的 main 函数),然后把你的代码编译成一个 jar 文件。
在 JVM 启动时,使用这样的命令行来引入你的 jar 文件:java -javaagent:yourAwesomeAgent.jar -jar App.jar。更为详细的文章你可以参看:“Java Code Geeks: Java Agents”,你还可以看一下这个示例项目:jvm-monitoring-agent 或是 EntryPointKR/Agent.java。如果想用 ByteBuddy 来玩,你可以看看这篇文章 “通过使用 Byte Buddy,便捷地创建 Java Agent”。如果你想学习如何用 Java Agent 做监控,你可以看一下这个项目 Stage Monitor。

JVM 相关

接下来讲讲 Java 底层知识中另一个非常重要的内容——JVM。
说起 JVM,你有必要读一下 JVM 的规格说明书,我在这里放一个 Java 8 的, The Java Virtual Machine Specification Java SE 8 Edition 。对于规格说明书的阅读,我认为是系统了解 JVM 规范的最佳文档,这个文档可以让你对于搞不清楚或是诡异的问题恍然大悟。关于中文翻译,有人在 GitHub 上开了个 Repo - “java-virtual-machine-specification”。
另外,也推荐一下 JVM Anatomy Park JVM 解剖公园,这是一个系列的文章,每篇文章都不长,但是都很精彩,带你一点一点地把 JVM 中的一些技术解开。
学习 Java 底层原理还有 Java 的内存模型,官方文章是 JSR 133。还有马里兰大学的威廉·皮尤(William Pugh)教授收集的和 Java 内存模型相关的文献 - The Java Memory Model ,你可以前往浏览。
对于内存方面,道格·利(Doug Lea)有两篇文章也是很有价值的。
The JSR-133 Cookbook for Compiler Writers,解释了怎样实现 Java 内存模型,特别是在考虑到多处理器(或多核)系统的情况下,多线程和读写屏障的实现。
Using JDK 9 Memory Order Modes,讲了怎样通过 VarHandle 来使用 plain、opaque、release/acquire 和 volatile 四种共享内存的访问模式,并剖析了底层的原理。
垃圾回收机制也是需要好好学习的,在这里推荐一本书 《The Garbage Collection Handbook》,在豆瓣上的得分居然是 9.9(当然,评价人数不多)。这本书非常全面地介绍了垃圾收集的原理、设计和算法。但是这本书也是相当难啃的。中文翻译《垃圾回收算法手册》翻译得很一般,有人说翻译得很烂。所以,如果可能,还是读英文版的。如果你对从事垃圾回收相关的工作有兴趣,那么你需要好好看一下这本书。
当然,更多的人可能只需要知道怎么调优垃圾回收, 那么推荐读读 Garbage Collection Tuning Guide ,它是 Hotspot Java 虚拟机的垃圾回收调优指南,对你很有帮助。
Quick Tips for Fast Code on the JVM 也是一篇很不错的文章,里面有写出更快的 Java 代码的几个小提示,值得一读。

小结

好了,总结一下今天学到的内容。Java 最黑科技的玩法就是字节码编程,也就是动态修改或是动态生成 Java 字节码。Java 的字节码相当于汇编,学习其中的细节很有意思,为此我精心挑选了 3 篇文章,供你学习。我们一般不使用 JVMTI 操作字节码,而是用一些更好用的库,如 asmtools、Byte Buddy 和 BiteScript 等。使用字节码编程可以玩出很多高级玩法,其中最高级的玩法是在 Java 程序运行时进行字节码修改和代码注入。同时,我介绍了 Java Agent 技术,帮助你更好地实现这种高级玩法。
JVM 也是学习 Java 过程中非常重要的一部分内容。我推荐阅读一下 JVM 的规格说明书,我认为,它是系统了解 JVM 规范的最佳文档,可以让你对于搞不清楚或是诡异的问题恍然大悟。同时推荐了 JVM Anatomy Park 系列文章,也非常值得一读。
随后介绍的是 Java 的内存模型和垃圾回收机制,尤其给出了如何调优垃圾回收方面的资料。这些内容都很底层,但也都很重要。对于想成为高手的你来说,还是有必要花时间来啃一啃的。
下篇文章是数据库方面的内容,我们将探讨各种类型的数据库,非常有意思。敬请期待。

80 | 程序员练级攻略:数据库

2018-07-05 陈皓
《左耳听风》
课程介绍

image.png
image.pngimage.pngimage.pngimage.png

讲述:柴巍

时长11:09大小5.11M

对于数据库方向,重点就是两种数据库,一种是以 SQL 为代表的关系型数据库,另一种是以非 SQL 为代表的 NoSQL 数据库。关系型数据库主要有三个:Oracle、MySQL 和 Postgres。
在这里,我们只讨论越来越主流的 MySQL 数据库。首先,我们要了解数据库的一些实现原理和内存的一些细节,然后我们要知道数据的高可用和数据复制这些比较重要的话题,了解一下关系型数据库的一些实践和难点。然后,我们会进入到 NoSQL 数据库的学习。
NoSQL 数据库千奇百怪,其主要是解决了关系型数据库中的各种问题。第一个大问题就是数据的 Schema 非常多,用关系型数据库来表示不同的 Data Schema 是非常笨拙的,所以要有不同的数据库(如时序型、键值对型、搜索型、文档型、图结构型等)。另一个大问题是,关系型数据库的 ACID 是一件很讨厌的事,这极大地影响了数据库的性能和扩展性,所以 NoSQL 在这上面做了相应的妥协以解决大规模伸缩的问题。
对于一个程序员,你可能觉得数据库的事都是 DBA 的事,然而我想告诉你你错了,这些事才真正是程序员的事。因为程序是需要和数据打交道的,所以程序员或架构师不仅需要设计数据模型,还要保证整体系统的稳定性和可用性,数据是整个系统中关键中的关键。所以,作为一个架构师或程序员,你必须了解最重要的数据存储——数据库。

关系型数据库

今天,关系型数据库最主要的两个代表是闭源的 Oracle 和开源的 MySQL。当然,还有很多了,比如微软的 SQL Server,IBM 的 DB2 等,还有开源的 PostgreSQL。关系型数据库的世界中有好多好多产品。当然,还是 Oracle 和 MySQL 是比较主流的。所以,这里主要介绍更为开放和主流的 MySQL。
如果你要玩 Oracle,我这里只推荐一本书《Oracle Database 9i/10g/11g 编程艺术》,无论是开发人员还是 DBA,它都是必读的书。这本书的作者是 Oracle 公司的技术副总裁托马斯·凯特(Thomas Kyte),他也是世界顶级的 Oracle 专家。
这本书中深入分析了 Oracle 数据库体系结构,包括文件、内存结构以及构成 Oracle 数据库和实例的底层进程,利用具体示例讨论了一些重要的数据库主题,如锁定、并发控制、事务等。同时分析了数据库中的物理结构,如表、索引和数据类型,并介绍采用哪些技术能最优地使用这些物理结构。
学习 MySQL,首先一定是要看MySQL 官方手册。
然后,官方还有几个 PPT 也要学习一下。
How to Analyze and Tune MySQL Queries for Better Performance
MySQL Performance Tuning 101
MySQL Performance Schema & Sys Schema
MySQL Performance: Demystified Tuning & Best Practices
MySQL Security Best Practices
MySQL Cluster Deployment Best Practices
MySQL High Availability with InnoDB Cluster
然后推荐《高性能 MySQL》,这本书是 MySQL 领域的经典之作,拥有广泛的影响力。不但适合数据库管理员(DBA)阅读,也适合开发人员参考学习。不管是数据库新手还是专家,都能从本书中有所收获。
如果你对 MySQL 的内部原理有兴趣的话,可以看一下这本书《MySQL 技术内幕:InnoDB 存储引擎》。当然,还有官网的MySQL Internals Manual 。
数据库的索引设计和优化也是非常关键的,这里还有一本书《数据库的索引设计与优化》也是很不错的。虽然不是讲 MySQL 的,但是原理都是相通的。这也是上面推荐过的《高性能 MySQL》在其索引部分推荐的一本好书。
你千万不要觉得只有做数据库你才需要学习这种索引技术。不是的!在系统架构上,在分布式架构中,索引技术也是非常重要的。这本书对于索引性能进行了非常清楚的估算,不像其它书中只是模糊的描述,你一定会收获很多。
下面还有一些不错的和 MySQL 相关的文章。
MySQL 索引背后的数据结构及算法原理
Some study on database storage internals
Sharding Pinterest: How we scaled our MySQL fleet
Guide to MySQL High Availability
Choosing MySQL High Availability Solutions
High availability with MariaDB TX: The definitive guide
最后,还有一个 MySQL 的资源列表 Awesome MySQL,这个列表中有很多的工具和开发资源,可以帮助你做很多事。
MySQL 有两个比较有名的分支,一个是 Percona,另一个是 MariaDB,其官网上的 Resources 页面中有很多不错的资源和文档,可以经常看看。 Percona Resources、MariaDB Resources ,以及它们的开发博客中也有很多不错的文章,分别为 Percona Blog 和 MariaDB Blog。
然后是关于 MySQL 的一些相关经验型的文章。
Booking.com: Evolution of MySQL System Design ,Booking.com 的 MySQL 数据库使用的演化,其中有很多不错的经验分享,我相信也是很多公司会遇到的的问题。
Tracking the Money - Scaling Financial Reporting at Airbnb ,Airbnb 的数据库扩展的经验分享。
Why Uber Engineering Switched from Postgres to MySQL ,无意比较两个数据库谁好谁不好,推荐这篇 Uber 的长文,主要是想让你从中学习到一些经验和技术细节,这是一篇很不错的文章。
关于 MySQL 的集群复制,下面有这些文章供你学习一下,都是很不错的实践性比较强的文章。
Monitoring Delayed Replication, With A Focus On MySQL
Mitigating replication lag and reducing read load with freno
另外,Booking.com 给了一系列的文章,你可以看看:
Better Parallel Replication for MySQL
Evaluating MySQL Parallel Replication Part 2: Slave Group Commit
Evaluating MySQL Parallel Replication Part 3: Benchmarks in Production
Evaluating MySQL Parallel Replication Part 4: More Benchmarks in Production
Evaluating MySQL Parallel Replication Part 4, Annex: Under the Hood
对于 MySQL 的数据分区来说,还有下面几篇文章你可以看看。
StackOverflow: MySQL sharding approaches?
Why you don’t want to shard
How to Scale Big Data Applications
MySQL Sharding with ProxySQL
然后,再看看各个公司做 MySQL Sharding 的一些经验分享。
MailChimp: Using Shards to Accommodate Millions of Users
Uber: Code Migration in Production: Rewriting the Sharding Layer of Uber’s Schemaless Datastore
Sharding & IDs at Instagram
Airbnb: How We Partitioned Airbnb’s Main Database in Two Weeks

NoSQL 数据库

关于 NoSQL 数据库,其最初目的就是解决大数据的问题。然而,也有人把其直接用来替换掉关系型数据库。所以在学习这个技术之前,我们需要对这个技术的一些概念和初衷有一定的了解。下面是一些推荐资料。
Martin Fowler 在 YouTube 上分享的 NoSQL 介绍 Introduction To NoSQL, 以及他参与编写的 NoSQL Distilled - NoSQL 精粹,这本书才 100 多页,是本难得的关于 NoSQL 的书,很不错,非常易读。
NoSQL Databases: a Survey and Decision Guidance,这篇文章可以带你自上而下地从 CAP 原理到开始了解 NoSQL 的种种技术,是一篇非常不错的文章。
Distribution, Data, Deployment: Software Architecture Convergence in Big Data Systems,这是卡内基·梅隆大学的一篇讲分布式大数据系统的论文。其中主要讨论了在大数据时代下的软件工程中的一些关键点,也说到了 NoSQL 数据库。
No Relation: The Mixed Blessings of Non-Relational Databases,这篇论文虽然有点年代久远。但这篇论文是 HBase 的基础,你花上一点时间来读读,就可以了解到,对各种非关系型数据存储优缺点的一个很好的比较。
NoSQL Data Modeling Techniques ,NoSQL 建模技术。这篇文章我曾经翻译在了 CoolShell 上,标题为 NoSQL 数据建模技术,供你参考。
MongoDB - Data Modeling Introduction ,虽然这是 MongoDB 的数据建模介绍,但是其很多观点可以用于其它的 NoSQL 数据库。
Firebase - Structure Your Database ,Google 的 Firebase 数据库使用 JSON 建模的一些最佳实践。
因为 CAP 原理,所以当你需要选择一个 NoSQL 数据库的时候,你应该看看这篇文档 Visual Guide to NoSQL Systems。
选 SQL 还是 NoSQL,这里有两篇文章,值得你看看。
SQL vs. NoSQL Databases: What’s the Difference?
Salesforce: SQL or NoSQL

各种 NoSQL 数据库

学习使用 NoSQL 数据库其实并不是一件很难的事,只要你把官方的文档仔细地读一下,是很容易上手的,而且大多数 NoSQL 数据库都是开源的,所以,也可以通过代码自己解决问题。下面我主要给出一些典型的 NoSQL 数据库的一些经验型的文章,供你参考。
列数据库 Column Database
Cassandra 相关
沃尔玛实验室有两篇文章值得一读。
Avoid Pitfalls in Scaling Cassandra Cluster at Walmart
Storing Images in Cassandra at Walmart
Yelp: How We Scaled Our Ad Analytics with Apache Cassandra ,Yelp 的这篇博客也有一些相关的经验和教训。
Discord: How Discord Stores Billions of Messages ,Discord 公司分享的一个如何存储十亿级消息的技术文章。
Cassandra at Instagram ,Instagram 的一个 PPT,其中介绍了 Instagram 中是怎么使用 Cassandra 的。
Netflix: Benchmarking Cassandra Scalability on AWS - Over a million writes per second ,Netflix 公司在 AWS 上给 Cassandra 做的一个 Benchmark。
HBase 相关
Imgur Notification: From MySQL to HBASE
Pinterest: Improving HBase Backup Efficiency
IBM : Tuning HBase performance
HBase File Locality in HDFS
Apache Hadoop Goes Realtime at Facebook
Storage Infrastructure Behind Facebook Messages: Using HBase at Scale
GitHub: Awesome HBase
针对于 HBase 有两本书你可以考虑一下。
首先,先推荐两本书,一本是偏实践的《HBase 实战》,另一本是偏大而全的手册型的《HBase 权威指南》。
当然,你也可以看看官方的 The Apache HBase™ Reference Guide
另外两个列数据库:
ClickHouse - Open Source Distributed Column Database at Yandex
Scaling Redshift without Scaling Costs at GIPHY
文档数据库 Document Database - MongoDB, SimpleDB, CouchDB
Data Points - What the Heck Are Document Databases?
eBay: Building Mission-Critical Multi-Data Center Applications with MongoDB
The AWS and MongoDB Infrastructure of Parse: Lessons Learned
Migrating Mountains of Mongo Data
Couchbase Ecosystem at LinkedIn
SimpleDB at Zendesk
Github: Awesome MongoDB
数据结构数据库 Data structure Database - Redis
Learn Redis the hard way (in production) at Trivago
Twitter: How Twitter Uses Redis To Scale - 105TB RAM, 39MM QPS, 10,000+ Instances
Slack: Scaling Slack’s Job Queue - Robustly Handling Billions of Tasks in Milliseconds Using Kafka and Redis
GitHub: Moving persistent data out of Redis at GitHub
Instagram: Storing Hundreds of Millions of Simple Key-Value Pairs in Redis
Redis in Chat Architecture of Twitch (from 27:22)
Deliveroo: Optimizing Session Key Storage in Redis
Deliveroo: Optimizing Redis Storage
GitHub: Awesome Redis
时序数据库 Time-Series Database
What is Time-Series Data & Why We Need a Time-Series Database
Time Series Data: Why and How to Use a Relational Database instead of NoSQL
Beringei: High-performance Time Series Storage Engine @Facebook
Introducing Atlas: Netflix’s Primary Telemetry Platform @Netflix
Building a Scalable Time Series Database on PostgreSQL
Scaling Time Series Data Storage - Part I @Netflix
Design of a Cost Efficient Time Series Store for Big Data
GitHub: Awesome Time-Series Database
图数据库 - Graph Platform
首先是 IBM Devloperworks 上的两个简介性的 PPT。
Intro to graph databases, Part 1, Graph databases and the CRUD operations
Intro to graph databases, Part 2, Building a recommendation engine with a graph database
然后是一本免费的电子书《Graph Database》。
接下来是一些图数据库的介绍文章。
Handling Billions of Edges in a Graph Database
Neo4j case studies with Walmart, eBay, AirBnB, NASA, etc
FlockDB: Distributed Graph Database for Storing Adjacency Lists at Twitter
JanusGraph: Scalable Graph Database backed by Google, IBM and Hortonworks
Amazon Neptune
搜索数据库 - ElasticSearch
Elasticsearch: The Definitive Guide 这是官网方的 ElasticSearch 的学习资料,基本上来说,看这个就够了。
接下来是 4 篇和性能调优相关的工程实践。
Elasticsearch Performance Tuning Practice at eBay
Elasticsearch at Kickstarter
9 tips on ElasticSearch configuration for high performance
Elasticsearch In Production - Deployment Best Practices
最后是 GitHub 上的资源列表 GitHub: Awesome ElasticSearch 。

小结

好了,总结一下今天分享的内容。虽然有人会认为数据库与程序员无关,是 DBA 的事儿。但我坚信,数据库才真正是程序员的事儿。因为程序是需要和数据打交道的,所以程序员或架构师不仅需要设计数据模型,还要保证整体系统的稳定性和可用性,数据是整个系统中关键中的关键。
对于数据库方向,重点就是两种数据库,一种是以 SQL 为代表的关系型数据库,另一种是以非 SQL 为代表的 NoSQL 数据库。因而,在这篇文章中,我给出了 MySQL 和各种开源 NoSQL 的一些相关的有价值的文章和导读,主要是让你对这些数据库的内在有一定的了解,但又不会太深。同时给出了一些知名企业使用数据库的工程实践,这对于了解各种数据库的优劣非常有帮助,值得认真读读。
从下篇文章开始,我们将进入分布式系统架构方面的内容,里面不仅涵盖了大量的理论知识,更有丰富的入门指导和大量的工程实践。敬请期待。

81 | 程序员练级攻略:分布式架构入门

分布式理论

下面,我们来学习一下分布式方面的理论知识。
首先,你需要看一下 An introduction to distributed systems。 这只是某个教学课程的提纲,我觉得还是很不错的,几乎涵盖了分布式系统方面的所有知识点,而且辅以简洁并切中要害的说明文字,非常适合初学者提纲挈领地了解知识全貌,快速与现有知识结合,形成知识体系。这也是一个分布式系统的知识图谱,可以让你看到分布式系统的整体全貌。你可以根据这个知识图 Google 下去,然后你会学会所有的东西。

然后,你需要了解一下拜占庭将军问题(Byzantine Generals Problem)。这个问题是莱斯利·兰波特(Leslie Lamport)于 1982 年提出用来解释一致性问题的一个虚构模型(论文地址)。拜占庭是古代东罗马帝国的首都,由于地域宽广,守卫边境的多个将军(系统中的多个节点)需要通过信使来传递消息,达成某些一致的决定。但由于将军中可能存在叛徒(系统中节点出错),这些叛徒将努力向不同的将军发送不同的消息,试图会干扰一致性的达成。拜占庭问题即为在此情况下,如何让忠诚的将军们能达成行动的一致。

对于拜占庭问题来说,假如节点总数为 N,叛变将军数为 F,则当 N >= 3F + 1 时,问题才有解,即拜占庭容错(Byzantine Fault Tolerant,BFT)算法。拜占庭容错算法解决的是,网络通信可靠但节点可能故障情况下一致性该如何达成的问题。

最早由卡斯特罗(Castro)和利斯科夫(Liskov)在 1999 年提出的实用拜占庭容错(Practical Byzantine Fault Tolerant,PBFT)算法,是第一个得到广泛应用的 BFT 算法。只要系统中有 2/3 的节点是正常工作的,则可以保证一致性。PBFT 算法包括三个阶段来达成共识:预准备(Pre-Prepare)、准备(Prepare)和提交(Commit)。

拜占庭容错系统研究中有三个重要理论:CAP、FLP 和 DLS。

CAP

CAP 定理,CAP 理论相信你应该听说过不下 N 次了。CAP 定理是分布式系统设计中最基础也是最为关键的理论。CAP 定理指出,分布式数据存储不可能同时满足以下三个条件:一致性(Consistency)、可用性(Availability)和 分区容忍(Partition tolerance)。 “在网络发生阻断(partition)时,你只能选择数据的一致性(consistency)或可用性(availability),无法两者兼得”。论点比较直观:如果网络因阻断而分隔为二,在其中一边我送出一笔交易:“将我的十元给 A”;在另一半我送出另一笔交易:“将我的十元给 B”。此时系统要不是,a)无可用性,即这两笔交易至少会有一笔交易不会被接受;要不就是,b)无一致性,一半看到的是 A 多了十元而另一半则看到 B 多了十元。要注意的是,CAP 理论和扩展性(scalability)是无关的,在分片(sharded)或非分片的系统皆适用。

FLP

FLP impossibility,在异步环境中,如果节点间的网络延迟没有上限,只要有一个恶意的节点存在,就没有算法能在有限的时间内达成共识。但值得注意的是, “Las Vegas” algorithms(这个算法又叫撞大运算法,其保证结果正确,只是在运算时所用资源上进行赌博,一个简单的例子是随机快速排序,它的 pivot 是随机选的,但排序结果永远一致)在每一轮皆有一定机率达成共识,随着时间增加,机率会越趋近于 1。而这也是许多成功的共识算法会采用的解决问题的办法。

容错的上限

从DLS 论文 中我们可以得到以下结论:

  1. 在部分同步(partially synchronous)的网络环境中(即网络延迟有一定的上限,但我们无法事先知道上限是多少),协议可以容忍最多 1/3 的拜占庭故障(Byzantine fault)。
  2. 在异步(asynchronous)的网络环境中,具有确定性质的协议无法容忍任何错误,但这篇论文并没有提及 randomized algorithms,在这种情况下可以容忍最多 1/3 的拜占庭故障。
  3. 在同步(synchronous)网络环境中(即网络延迟有上限且上限是已知的),协议可以容忍 100% 的拜占庭故障,但当超过 1/2 的节点为恶意节点时,会有一些限制条件。要注意的是,我们考虑的是”具有认证特性的拜占庭模型(authenticated Byzantine)”,而不是”一般的拜占庭模型”;具有认证特性指的是将如今已经过大量研究且成本低廉的公私钥加密机制应用在我们的算法中。

    8 条荒谬的分布式假设

    当然,还有一个著名的“8 条荒谬的分布式假设(Fallacies of Distributed Computing)”。

  4. 网络是稳定的。

  5. 网络传输的延迟是零。
  6. 网络的带宽是无穷大。
  7. 网络是安全的。
  8. 网络的拓扑不会改变。
  9. 只有一个系统管理员。
  10. 传输数据的成本为零。
  11. 整个网络是同构的。

阿尔农·罗特姆 - 盖尔 - 奥兹(Arnon Rotem-Gal-Oz)写了一篇长文 Fallacies of Distributed Computing Explained 来解释为什么这些观点是错误的。另外,加勒思·威尔逊(Gareth Wilson)的文章 则用日常生活中的例子,对这些点做了通俗的解释。为什么我们深刻地认识到这 8 个错误?是因为,这要我们清楚地认识到——在分布式系统中错误是不可能避免的,我们在分布式系统中,能做的不是避免错误,而是要把错误的处理当成功能写在代码中。

下面分享几篇一致性方面的论文。当然,关于经典的 CAP 理论,也存在一些误导的地方,这个问题在 2012 年有一篇论文 CAP Twelve Years Later: How the Rules Have Changed (中译版)中做了一些讨论,主要是说,在 CAP 中最大的问题就是分区,也就是 P,在 P 发生的情况下,非常难以保证 C 和 A。然而,这是强一致性的情况。其实,在很多时候,我们并不需要强一致性的系统,所以后来,人们争论关于数据一致性和可用性时,主要是集中在强一致性的 ACID 或最终一致性的 BASE。当时,BASE 还不怎么为世人所接受,主要是大家都觉得 ACID 是最完美的模型,大家很难接受不完美的 BASE。在 CAP 理论中,大家总是觉得需要“三选二”,也就是说,P 是必选项,那“三选二”的选择题不就变成数据一致性 (consistency)、服务可用性 (availability) 间的“二选一”?
然而,现实却是,P 很少遇到,而 C 和 A 这两个事,工程实践中一致性有不同程度,可用性也有不同等级,在保证分区容错性的前提下,放宽约束后可以兼顾一致性和可用性,两者不是非此即彼。其实,在一个时间可能允许的范围内是可以取舍并交替选择的。
Harvest, Yield, and Scalable Tolerant Systems ,这篇论文是基于上面那篇“CAP 12 年后”的论文写的,它主要提出了 Harvest 和 Yield 概念,并把上面那篇论文中所讨论的东西讲得更为仔细了一些。
Base: An Acid Alternative (中译版),本文是 eBay 的架构师在 2008 年发表给 ACM 的文章,是一篇解释 BASE 原则,或者说最终一致性的经典文章。文中讨论了 BASE 与 ACID 原则的基本差异, 以及如何设计大型网站以满足不断增长的可伸缩性需求,其中有如何对业务做调整和折中,以及一些具体的折中技术的介绍。一个比较经典的话是——“在对数据库进行分区后, 为了可用性(Availability)牺牲部分一致性(Consistency)可以显著地提升系统的可伸缩性 (Scalability)”。
Eventually Consistent ,这篇文章是 AWS 的 CTO 维尔纳·沃格尔(Werner Vogels)在 2008年发布在 ACM Queue 上的一篇数据库方面的重要文章,阐述了 NoSQL 数据库的理论基石——最终一致性,对传统的关系型数据库(ACID,Transaction)做了较好的补充。

小结

好了,总结一下今天分享的内容。文章的开头,我给出了学习分布式架构需要注意的几个关键点,然后列出了入门学习的资源,基本涵盖了所有与系统架构相关的技术。随后讲述了拜占庭容错系统研究中有三个重要理论:CAP、FLP 和 DLS,以及 8 条荒谬的分布式假设,从理论和认知等角度让你更为清楚地理解分布式系统。最后分享了几篇一致性相关的论文,很实用很经典,推荐阅读。

82 | 程序员练级攻略:分布式架构经典图书和论文

经典图书

首先,我推荐几本分布式架构方面的经典图书。
Distributed Systems for fun and profit,这是一本免费的电子书。作者撰写此书的目的是希望以一种更易于理解的方式,讲述以亚马逊的 Dynamo、谷歌的 Bigtable 和 MapReduce 等为代表的分布式系统背后的核心思想。
Designing Data Intensive Applications,这本书是一本非常好的书,我们知道,在分布式的世界里,数据结点的扩展是一件非常麻烦的事。这本书深入浅出地用很多的工程案例讲解了如何让数据结点做扩展。作者马丁·科勒普曼(Martin Kleppmann)在分布式数据系统领域有着很深的功底,并在这本书中完整地梳理各类纷繁复杂设计背后的技术逻辑,不同架构之间的妥协与超越,很值得开发人员与架构设计者阅读。
这本书深入到 B-Tree、SSTables、LSM 这类数据存储结构中,并且从外部的视角来审视这些数据结构对 NoSQL 和关系型数据库的影响。这本书可以让你很清楚地了解到真正世界的大数据架构中的数据分区、数据复制的一些坑,并提供了很好的解决方案。最赞的是,作者将各种各样技术的本质非常好地关联在一起,令你触类旁通。
而且,这本书完全就是抽丝剥茧,循循善诱,从“提出问题”到“解决问题”、“解决方案”、“优化方案”和“对比不同的方案”,一点一点地把非常晦涩的技术和知识展开。本书的引用相当多,每章后面都有几百个 Reference,通过这些 Reference 你可以看到更为广阔、更为精彩的世界。
Distributed Systems: Principles and Paradigms ,本书是由计算机科学家安德鲁·斯图尔特·塔能鲍姆(Andrew S. Tanenbaum)和其同事马丁·范·斯蒂恩(Martin van Steen)合力撰写的,是分布式系统方面的经典教材。
语言简洁,内容通俗易懂,介绍了分布式系统的七大核心原理,并给出了大量的例子;系统讲述了分布式系统的概念和技术,包括通信、进程、命名、同步化、一致性和复制、容错以及安全等;讨论了分布式应用的开发方法(即范型)。但本书不是一本指导“如何做”的手册,仅适合系统性地学习基础知识,了解编写分布式系统的基本原则和逻辑。中文翻译版为《分布式系统原理与范型》(第二版)。
Scalable Web Architecture and Distributed Systems,
这是一本免费的在线小册子,其中文翻译版 可扩展的 Web 架构和分布式系统。本书主要针对面向互联网(公网)的分布式系统,但其中的原理或许也可以应用于其他分布式系统的设计中。作者的观点是,通过了解大型网站的分布式架构原理,小型网站的构建也能从中受益。本书从大型互联网系统的常见特性,如高可用、高性能、高可靠、易管理等出发,引出了一个类似于 Flickr 的典型的大型图片网站的例子。
Principles of Distributed Systems ,本书是苏黎世联邦理工学院的教材。它讲述了多种分布式系统中会用到的算法。虽然分布式系统的不同场景会用到不同算法,但并不表示这些算法都会被用到。不过,作为学生来说,掌握了算法设计的精髓也就能举一反三地设计出解决其他问题的算法,从而得到分布式系统架构设计中所需的算法。

经典论文

分布式事务

想了解分布式模型中最难的“分布式事务”,你需要看看 Google App Engine 联合创始人瑞恩·巴雷特(Ryan Barrett)在 2009 年的 Google I/O 大会上的演讲《Transaction Across DataCenter》(YouTube 视频)。
在这个演讲中,巴雷特讲述了各种经典的解决方案如何在一致性、事务、性能和错误上做平衡。而最后得到为什么分布式系统的事务只有 Paxos 算法是最好的。
下面这个图是这个算法中的结论。
左耳听风 - 图26
你也可以移步看一下我在 Coolshell 上写的这篇文章《分布式系统的事务处理》。

Paxos 一致性算法

Paxos 算法,是莱斯利·兰伯特(Lesile Lamport)于 1990 年提出来的一种基于消息传递且具有高度容错特性的一致性算法。但是这个算法太过于晦涩,所以一直以来都属于理论上的论文性质的东西。其真正进入工程圈,主要是来源于 Google 的 Chubby lock——一个分布式的锁服务,用在了 Bigtable 中。直到 Google 发布了下面这两篇论文,Paxos 才进入到工程界的视野中来。
Bigtable: A Distributed Storage System for Structured Data
The Chubby lock service for loosely-coupled distributed systems
Google 与 Bigtable 相齐名的还有另外两篇论文。
The Google File System
MapReduce: Simplified Data Processing on Large Clusters
不过,这几篇文章中并没有讲太多的 Paxos 算法上的细节,反而是在Paxos Made Live - An Engineering Perspective 这篇论文中提到了很多工程实现的细节。这篇论文详细解释了 Google 实现 Paxos 时遇到的各种问题和解决方案,讲述了从理论到实际应用二者之间巨大的鸿沟。
Paxos 算法的原版论文比较晦涩,也不易懂。这里推荐一篇比较容易读的—— Neat Algorithms - Paxos 。这篇文章中还有一些小动画帮助你读懂。还有一篇可以帮你理解的文章是 Paxos by Examples。

Raft 一致性算法

因为 Paxos 算法太过于晦涩,而且在实际的实现上有太多的坑,并不太容易写对。所以,有人搞出了另外一个一致性的算法,叫 Raft。其原始论文是 In search of an Understandable Consensus Algorithm (Extended Version) ,寻找一种易于理解的 Raft 算法。这篇论文的译文在 InfoQ 上,题为《Raft 一致性算法论文译文》,推荐你读一读。
这里推荐几个不错的 Raft 算法的动画演示。
Raft - The Secret Lives of Data
Raft Consensus Algorithm
Raft Distributed Consensus Algorithm Visualization

Gossip 一致性算法

后面,业内又搞出来一些工程上的东西,比如 Amazon 的 DynamoDB,其论文Dynamo: Amazon’s Highly Available Key Value Store 的影响力非常大。这篇论文中讲述了 Amazon 的 DynamoDB 是如何满足系统的高可用、高扩展和高可靠的。其中展示了系统架构是如何做到数据分布以及数据一致性的。GFS 采用的是查表式的数据分布,而 DynamoDB 采用的是计算式的,也是一个改进版的通过虚拟结点减少增加结点带来数据迁移的一致性哈希。
这篇文章中有几个关键的概念,一个是 Vector Clock,另一个是 Gossip 协议。
Time, Clocks and the Ordering of Events in a Distributed System ,这篇文章是莱斯利·兰伯特(Leslie Lamport)于 1978 年发表的,并在 2007 年被选入 SOSP 的名人堂,被誉为第一篇真正的“分布式系统”论文,该论文曾一度成为计算机科学史上被引用最多的文章。分布式系统中的时钟同步是一个非常难的问题,因为分布式系统中是使用消息进行通信的,若使用物理时钟来进行同步,一方面是不同的 process 的时钟有差异,另一方面是时间的计算也有一定的误差,这样若有两个时间相同的事件,则无法区分它们谁前谁后了。这篇文章主要解决分布式系统中的时钟同步问题。
马萨诸塞大学课程 Distributed Operating System 中第 10 节 Clock Synchronization,这篇讲义讲述了时钟同步的问题。
关于 Vector Clock,你可以看一下 Why Vector Clocks are Easy 和 Why Vector Clocks are Hard 这两篇文章。
用来做数据同步的 Gossip 协议的原始论文是 Efficient Reconciliation and Flow Control for Anti-Entropy Protocols。Gossip 算法也是 Cassandra 使用的数据复制协议。这个协议就像八卦和谣言传播一样,可以“一传十、十传百”传播开来。但是这个协议看似简单,细节上却非常麻烦。
Gossip 协议也是 NoSQL 数据库 Cassandra 中使用到的数据协议,你可以上 YouTube 上看一下这个视频介绍: Understanding Gossip (Cassandra Internals)。
关于 Gossip 的一些图示化的东西,你可以看一下动画 Gossip Visualization。

分布式存储和数据库

除了前面的 Google 的 BigTable 和 Google File System 那两篇论文,还有 Amazon 的 DynamoDB 的论文,下面也有几篇也是要读一下的。
一篇是 AWS Aurora 的论文 Amazon Aurora: Design Considerations for High Throughput Cloud -Native Relation Databases。
另一篇是比较有代表的论文是 Google 的 Spanner: Google’s Globally-Distributed Database。 其 2017 年的新版论文:Spanner, TrueTime & The CAP Theorem。
F1 - The Fault-Tolerant Distributed RDBMS Supporting Google’s Ad Business 。
Cassandra: A Decentralized Structured Storage System 。
CRUSH: Controlled, Scalable, Decentralized Placement of Replicated Data, 这里提到的算法被应用在了 Ceph 分布式文件系统中,其架构可以读一下 RADOS - A Scalable, Reliable Storage Service for Petabyte-scaleStorage Clusters 以及 Ceph 的架构文档。

分布式消息系统

分布式消息系统,你一定要读一下 Kafka 的这篇论文 Kafka: a Distributed Messaging System for Log Processing。
Wormhole: Reliable Pub-Sub to Support Geo-replicated Internet Services ,Wormhole 是 Facebook 内部使用的一个 Pub-Sub 系统,目前还没有开源。它和 Kafka 之类的消息中间件很类似。但是它又不像其它的 Pub-Sub 系统,Wormhole 没有自己的存储来保存消息,它也不需要数据源在原有的更新路径上去插入一个操作来发送消息,是非侵入式的。其直接部署在数据源的机器上并直接扫描数据源的 transaction logs,这样还带来一个好处,Wormhole 本身不需要做任何地域复制(geo-replication)策略,只需要依赖于数据源的 geo-replication 策略即可。
All Aboard the Databus! LinkedIn’s Scalable Consistent Change Data Capture Platform , 在 LinkedIn 投稿 SOCC 2012 的这篇论文中,指出支持对不同数据源的抽取,允许不同数据源抽取器的开发和接入,只需该抽取器遵循设计规范即可。该规范的一个重要方面就是每个数据变化都必须被一个单调递增的数字标注(SCN),用于同步。这其中的一些方法完全可以用做异地双活的系统架构中。(和这篇论文相关的几个链接如下:PDF 论文 、 PPT 分享。)

日志和数据

The Log: What every software engineer should know about real-time data’s unifying abstraction ,这篇文章好长,不过这是一篇非常好非常好的文章,这是每个工程师都应用知道的事,必看啊。你可以看中译版《日志:每个软件工程师都应该知道的有关实时数据的统一概念》。
The Log-Structured Merge-Tree (LSM-Tree) ,N 多年前,谷歌发表了 Bigtable 的论文,论文中很多很酷的方面,其一就是它所使用的文件组织方式,这个方法更一般的名字叫 Log Structured-Merge Tree。LSM 是当前被用在许多产品的文件结构策略:HBase、Cassandra、LevelDB、SQLite,甚至在 MongoDB 3.0 中也带了一个可选的 LSM 引擎(Wired Tiger 实现的)。LSM 有趣的地方是它抛弃了大多数数据库所使用的传统文件组织方法。实际上,当你第一次看它时是违反直觉的。这篇论文可以让你明白这个技术。(如果读起来有些费解的话,你可以看看中文社区里的这几篇文章:文章一、文章二。)
Immutability Changes Everything ,这篇论文是现任 Salesforce 软件架构师帕特·赫兰德(Pat Helland)在 CIDR 2015 大会上发表的(相关视频演讲)。
Tango: Distributed Data Structures over a Shared Log)。这个论文非常经典,其中说明了不可变性(immutability)架构设计的优点。随着为海量数据集存储和计算而设计的以数据为中心的新型抽象技术的出现,分布式系统比以往任何时候都更容易构建。但是,对于元数据的存储和访问不存在类似的抽象。
为了填补这一空白,Tango 为开发人员提供了一个由共享日志支持的内存复制数据结构(例如地图或树)的抽象。Tango 对象易于构建和使用,通过共享日志上简单的追加和读取操作来复制状态,而不是复杂的分布式协议。在这个过程中,它们从共享日志中获得诸如线性化、持久性和高可用性等属性。Tango 还利用共享日志支持跨不同对象的快速事务处理,允许应用程序跨机器进行状态划分,并在不牺牲一致性的情况下扩展到底层日志的上限。

分布式监控和跟踪

Google 的分布式跟踪监控论文 - Dapper, a Large-Scale Distributed Systems Tracing Infrastructure, 其开源实现有三个 Zipkin、Pinpoint 和 HTrace。我个人更喜欢 Zipkin。

数据分析

The Unified Logging Infrastructure for Data Analytics at Twitter ,Twitter 公司的一篇关于日志架构和数据分析的论文。
Scaling Big Data Mining Infrastructure: The Twitter Experience ,讲 Twitter 公司的数据分析平台在数据量越来越大,架构越来越复杂,业务需求越来越多的情况下,数据分析从头到底是怎么做的。
Dremel: Interactive Analysis of Web-Scale Datasets,Google 公司的 Dremel,是一个针对临时查询提供服务的系统,它处理的是只读的多层数据。本篇文章介绍了它的架构与实现,以及它与 MapReduce 是如何互补的。
Resident Distributed Datasets: a Fault-Tolerant Abstraction for In-Memory Cluster Computing,这篇论文提出了弹性分布式数据集(Resilient Distributed Dataset,RDD)的概念,它是一个分布式存储抽象,使得程序员可以在大型集群上以容错的方式执行内存计算;解释了其出现原因:解决之前计算框架在迭代算法和交互式数据挖掘工具两种应用场景下处理效率低下的问题,并指出将数据保存在内存中,可以将性能提高一个数量级;同时阐述了其实现原理及应用场景等多方面内容。很有趣儿,推荐阅读。

与编程相关的论文

Distributed Programming Model
PSync: a partially synchronous language for fault-tolerant distributed algorithms
Programming Models for Distributed Computing
Logic and Lattices for Distributed Programming

其它的分布式论文阅读列表

除了上面上的那些我觉得不错的论文,下面还有三个我觉得不错的分布式系统论文的阅读列表,你可以浏览一下。
Services Engineering Reading List
Readings in Distributed Systems
Google Research - Distributed Systems and Parallel Computing

小结

今天分享的内容是分布式架构方面的经典图书和论文,并给出了导读文字,几乎涵盖了分布式系统架构方面的所有关键的理论知识。这些内容非常重要,是学好分布式架构的基石,请一定要认真学习。
下篇文章中,我们将讲述分布式架构工程设计方面的内容,包括设计原则、设计模式以及工程实践等方面的内容。敬请期待。


下载APP

83 | 程序员练级攻略:分布式架构工程设计


要学好分布式架构,你首先需要学习一些架构指导性的文章和方法论,即分布式架构设计原则。下面是几篇很不错的文章,值得一读。
Designs, Lessons and Advice from Building Large Distributed Systems,Google 杰夫·迪恩(Jeff Dean)2009 年一次演讲的 PPT。2010 年,斯坦福大学请杰夫·迪恩到大学里给他们讲了一节课,你可以在 YouTube 上看一下,Building Software Systems At Google and Lessons Learned ,其回顾了 Google 发展的历史。
The Twelve-Factor App ,如今,软件通常会作为一种服务来交付,它们被称为网络应用程序,或软件即服务(SaaS)。12-Factor 为构建 SaaS 应用提供了方法论,是架构师必读的文章。(中译版)这篇文章在业内的影响力很大,必读!
Notes on Distributed Systems for Young Bloods ,给准备进入分布式系统领域的人的一些忠告。
On Designing and Deploying Internet-Scale Services(中译版),微软 Windows Live 服务平台的一些经验性的总结文章,很值得一读。
4 Things to Keep in Mind When Building a Platform for the Enterprise ,Box 平台 VP 海蒂·威廉姆斯(Heidi Williams)撰写的一篇文章,阐述了为企业构建平台时需要牢记的四件关于软件设计方面的事:1. Design Broadly, Build Narrowly; 2. Platforms Are Powerful and Flexible. Choose wisely what to expose when!;3. Build Incrementally, Get Feedback, and Iterate;4. Create a Platform-first Mentality。文章中有详细的解读,推荐看看。
Principles of Chaos Engineering ,我们知道,Netflix 公司有一个叫 Chaos Monkey 的东西,这个东西会到分布式系统里“瞎搞”,以此来测试系统的健壮和稳定性。这个视频中,Netflix 分享了一些软件架构的经验和原则,值得一看。
Building Fast & Resilient Web Applications ,伊利亚·格里高利克(Ilya Grigorik)在 Google I/O 2016 上的一次关于如何通过弹力设计来实现快速和可容错的网站架构的演讲,其中有好些经验分享。
Design for Resiliency ,这篇文章带我们全面认识“弹力(Resiliency)”,以及弹力对于系统的重要性,并详细阐述了如何设计和实现系统的弹力。
微软的 Azure 网站上有一系列的 Design Principle 的文章,你可以看看这几篇: Design for Self-healing 、Design for Scaling Out 和 Design for Evolution 。
Eventually Consistent ,AWS CTO 维尔纳·沃格尔斯(Werner Vogels)发布在自己 Blog 上的一篇关于最终一致性的好文。
Writing Code that Scales ,Rackspace 的一篇很不错的博文,告诉我们一些很不错的写出高扩展和高性能代码的工程原则。
Automate and Abstract: Lessons from Facebook on Engineering for Scale ,软件自动化和软件抽象,这是软件工程中最重要的两件事了。通过这篇文章,我们可以看到 Facebook 的关于这方面的一些经验教训。

设计模式

有了方法论后,你还需要学习一些比较细节的落地的技术。最好的方式就是学习被前人总结出来的设计模式,虽然设计模式也要分场景,但是设计模式可以让你知道一些套路,这些套路对于我们设计的分布式系统有非常大的帮助,不但可以让我们少走一些弯路,而且还能让我们更为系统和健壮地设计我们的架构。
下面是一些分布式架构设计模式的网站。
首先,需要重点推荐的是微软云平台 Azure 上的设计模式。 Cloud Design Patterns ,这个网站上罗列了分布式设计的各种设计模式,可以说是非常全面和完整。对于每一个模式都有详细的说明,并有对其优缺点的讨论,以及适用场景和不适用场景的说明,实在是一个非常不错的学习分布式设计模式的地方。其中有如下分类。
设计模式:可用性;
设计模式:数据管理;
设计模式:设计和实现;
设计模式:消息;
设计模式:管理和监控;
设计模式:性能和扩展;
设计模式:系统弹力;
设计模式:安全。
除此之外,还有其它的一些关于分布式系统设计模式的网站和相关资料。
AWS Cloud Pattern ,这里收集了 AWS 云平台的一些设计模式。
Design patterns for container-based distributed systems ,这是 Google 给的一篇论文,其中描述了容器化下的分布式架构的设计模式。
Patterns for distributed systems ,这是一个 PPT,其中讲了一些分布式系统的架构模式,你可以顺着到 Google 里去搜索。
我个人觉得微服务也好,SOA 也好,都是分布式系统的一部分,这里有两个网站罗列了各种各样的服务架构模式。
A Pattern Language for Micro-Services ;
SOA Patterns。
当然,还有我在极客时间上写的那些分布式的设计模式的总结。
弹力设计篇,内容包括:认识故障和弹力设计、隔离设计、异步通讯设计、幂等性设计、服务的状态、补偿事务、重试设计、熔断设计、限流设计、降级设计、弹力设计总结。
管理设计篇,内容包括:分布式锁、配置中心、边车模式、服务网格、网关模式、部署升级策略等。
性能设计篇,内容包括:缓存、异步处理、数据库扩展、秒杀、边缘计算等。

设计与工程实践

分布式系统的故障测试

FIT: Failure Injection Testing ,Netflix 公司的一篇关于做故障注入测试的文章。
Automated Failure Testing ,同样来自 Netflix 公司的自动化故障测试的一篇博文。
Automating Failure Testing Research at Internet Scale ,Netflix 公司伙同圣克鲁斯加利福尼亚大学和 Gremlin 游戏公司一同撰写的一篇论文。

弹性伸缩

4 Architecture Issues When Scaling Web Applications: Bottlenecks, Database, CPU, IO ,本文讲解了后端程序的主要性能指标,即响应时间和可伸缩性这两者如何能提高的解决方案,讨论了包括纵向和横向扩展,可伸缩架构、负载均衡、数据库的伸缩、CPU 密集型和 I/O 密集型程序的考量等。
Scaling Stateful Objects ,这是一本叫《Development&Deployment of Multiplayer Online Games》书中一章内容的节选,讨论了有状态和无状态的节点如何伸缩的问题。虽然还没有写完,但是可以给你一些很不错的基本概念和想法。
Scale Up vs Scale Out: Hidden Costs ,Coding Horror 上的一篇有趣的文章,详细分析了可伸缩性架构的不同扩展方案(横向扩展或纵向扩展)所带来的成本差异,帮助你更好地选择合理的扩展方案,可以看看。
Best Practices for Scaling Out ,OpenShift 的一篇讨论 Scale out 最佳实践的文章。
Scalability Worst Practices ,这篇文章讨论了一些最差实践,你需要小心避免。
Reddit: Lessons Learned From Mistakes Made Scaling To 1 Billion Pageviews A Month ,Reddit 分享的一些关于系统扩展的经验教训。
下面是几篇关于自动化弹性伸缩的文章。
Autoscaling Pinterest;
Square: Autoscaling Based on Request Queuing;
PayPal: Autoscaling Applications;
Trivago: Your Definite Guide For Autoscaling Jenkins;
Scryer: Netflix’s Predictive Auto Scaling Engine。

一致性哈希

Consistent Hashing ,这是一个一致性哈希的简单教程,其中还有代码示例。
Consistent Hashing: Algorithmic Tradeoffs ,这篇文章讲述了一致性哈希的一些缺陷和坑,以及各种哈希算法的性能比较,最后还给了一组代码仓库,其中有各种哈希算法的实现。
Distributing Content to Open Connect ,Netflix 的一个对一致性哈希的实践,提出了 Uniform Consistent Hashing,是挺有意思的一篇文章。
Consistent Hashing in Cassandra ,这是 Cassandra 中使用到的一致性哈希的相关设计。

数据库分布式

Life Beyond Distributed Transactions ,该文是 Salesforce 的软件架构师帕特·赫兰德(Pat Helland)于 2016 年 12 月发表的针对其在 2007 年 CIDR(创新数据库研究会议)上首次发表的同名文章的更新和缩写版本。业界谈到分布式事务通常指两段提交 2PC 事务(Spring/JEE 中 JTA 等) 或者 Paxos 与 Raft,这些事务都有明显缺点和局限性。
而赫兰德在本文讨论的是另外一种基于本地事务情况下的事务机制,它是基于实体和活动(Activity)的概念,其实类似 DDD 聚合根和领域事件的概念,这种工作流类型事务虽然需要程序员介入,依靠消息系统实现,但可以实现接近无限扩展的大型系统。赫兰德文中提出了重要的观点:“如果你不能使用分布式事务,那么你就只能使用工作流。”
How Sharding Works ,这是一篇很不错的探讨数据 Sharding 的文章。基本上来说,数据 Sharding 可能的问题都在这篇文章里谈到了。
Why you don’t want to shard ,这是 Percona 的一篇文章,其中表达了,不到万不得已不要做数据库分片。是的,最好还是先按业务来拆分,先把做成微服务的架构,然后把数据集变简单,然后再做 Sharding 会更好。
How to Scale Big Data Applications ,这也是 Percona 给出的一篇关于怎样给大数据应用做架构扩展的文章。值得一读。
MySQL Sharding with ProxySQL ,用 ProxySQL 来支撑 MySQL 数据分片的一篇实践文章。

缓存

缓存更新的套路,这是我在 CoolShell 上写的缓存更新的几个设计模式,包括 Cache Aside、Read/Write Through、Write Behind Caching。
Design Of A Modern Cache ,设计一个现代化的缓存系统需要注意到的东西。
Netflix: Caching for a Global Netflix ,Netflix 公司的全局缓存架构实践。
Facebook: An analysis of Facebook photo caching ,Facebook 公司的图片缓存使用分析,这篇文章挺有意思的,用数据来调优不同的缓存大小和算法。
How trivago Reduced Memcached Memory Usage by 50% ,Trivago 公司一篇分享自己是如何把 Memcached 的内存使用率降了一半的实践性文章。很有意思,可以让你学到很多东西。
Caching Internal Service Calls at Yelp ,Yelp 公司的缓存系统架构。

消息队列

Understanding When to use RabbitMQ or Apache Kafka ,什么时候使用 RabbitMQ,什么时候使用 Kafka,通过这篇文章可以让你明白如何做技术决策。
Trello: Why We Chose Kafka For The Trello Socket Architecture ,Trello 的 Kafka 架构分享。
LinkedIn: Running Kafka At Scale ,LinkedIn 公司的 Kafka 架构扩展实践。
Should You Put Several Event Types in the Same Kafka Topic? ,这个问题可能经常困扰你,这篇文章可以为你找到答案。
Billions of Messages a Day - Yelp’s Real-time Data Pipeline ,Yelp 公司每天十亿级实时消息的架构。
Uber: Building Reliable Reprocessing and Dead Letter Queues with Kafka ,Uber 公司的 Kafka 应用。
Uber: Introducing Chaperone: How Uber Engineering Audits Kafka End-to-End ,Uber 公司对 Kafka 消息的端到端审计。
Publishing with Apache Kafka at The New York Times ,纽约时报的 Kafka 工程实践。
Kafka Streams on Heroku ,Heroku 公司的 Kafka Streams 实践。
Salesforce: How Apache Kafka Inspired Our Platform Events Architecture ,Salesforce 的 Kafka 工程实践。
Exactly-once Semantics are Possible: Here’s How Kafka Does it ,怎样用 Kafka 让只发送一次的语义变为可能。这是业界中一个很难的工程问题。
Delivering billions of messages exactly once 同上,这也是一篇挑战消息只发送一次这个技术难题的文章。
Benchmarking Streaming Computation Engines at Yahoo!。Yahoo! 的 Storm 团队在为他们的流式计算做技术选型时,发现市面上缺乏针对不同计算平台的性能基准测试。于是,他们研究并设计了一种方案来做基准测试,测试了 Apache Flink、Apache Storm 和 Apache Spark 这三种平台。文中给出了结论和具体的测试方案。(如果原文链接不可用,请尝试搜索引擎对该网页的快照。)

关于日志方面

Using Logs to Build a Solid Data Infrastructure - Martin Kleppmann ,设计基于 log 结构应用架构的一篇不错的文章。
Building DistributedLog: High-performance replicated log service ,Distributed 是 Twitter 2016 年 5 月份开源的一个分布式日志系统。在 Twitter 内部已经使用 2 年多。其主页在 distributedlog.io。这篇文章讲述了这个高性能日志系统的一些技术细节。另外,其技术负责人是个中国人,其在微信公众号中也分享过这个系统 Twitter 高性能分布式日志系统架构解析。
LogDevice: a distributed data store for logs ,Facebook 分布式日志系统方面的一些工程分享。

关于性能方面

Understand Latency ,这篇文章收集并整理了一些和系统响应时间相关的文章,可以让你全面了解和 Latency 有关的系统架构和设计经验方面的知识。
Common Bottlenecks ,文中讲述了 20 个常见的系统瓶颈。
Performance is a Feature ,Coding Horror 上的一篇让你关注性能的文章。
Make Performance Part of Your Workflow ,这篇文章是图书《Designing for Performance》中的节选(国内没有卖的),其中给出来了一些和性能有关的设计上的平衡和美学。
CloudFlare: How we built rate limiting capable of scaling to millions of domains,讲述了 CloudFlare 公司是怎样实现他们的限流功能的。从最简单的每客户 IP 限流开始分析,进一步讲到 anycast,在这种情况下 PoP 的分布式限流是怎样实现的,并详细解释了具体的算法。

关于搜索方面

Instagram: Search Architecture
eBay: The Architecture of eBay Search
eBay: Improving Search Engine Efficiency by over 25%
LinkedIn: Introducing LinkedIn’s new search architecture
LinkedIn: Search Federation Architecture at LinkedIn
Slack: Search at Slack
DoorDash: Search and Recommendations at DoorDash
Twitter: Search Service at Twitter (2014)
Pinterest: Manas: High Performing Customized Search System
Sherlock: Near Real Time Search Indexing at Flipkart
Airbnb: Nebula: Storage Platform to Build Search Backends

各公司的架构实践

High Scalability ,这个网站会定期分享一些大规模系统架构是怎样构建的,下面是迄今为止各个公司的架构说明。
YouTube Architecture
Scaling Pinterest
Google Architecture
Scaling Twitter
The WhatsApp Architecture
Flickr Architecture
Amazon Architecture
Stack Overflow Architecture
Pinterest Architecture
Tumblr Architecture
Instagram Architecture
TripAdvisor Architecture
Scaling Mailbox
Salesforce Architecture
ESPN Architecture
Uber Architecture
Dropbox Design
Splunk Architecture

小结

今天我们分享的内容是高手成长篇分布式架构部分的最后一篇——分布式架构工程设计,讲述了设计原则、设计模式等方面的内容,尤其整理和推荐了国内外知名企业的设计思路和工程实践,十分具有借鉴意义。
下篇文章中,我们将分享微服务架构方面的内容。敬请期待

90 | 程序员练级攻略:技术资源集散地

个人技术博客

首先,我先推荐一些不错的个人技术博客。
Coding Horror ,这是杰夫·阿特伍德(Jeff Atwood)于 2004 年创办的博客,记录其在软件开发经历中的所思所想、点点滴滴。时至今日,该博客每天都有近 10 万人次的访问量,读者纷纷参与评论,各种观点与智慧在这里不断地激情碰撞。其博文选集在中国被翻译成《高效能程序员的修练》,在豆瓣上有 8.3 的高分。2008 年,他和 Joel Spolsky 联合创办了 StackOverflow 问答网站,为程序员在开发软件时节省了非常多的时间,并开启了“StackOverflow Copy + Paste 式编程”。
Joel on Software ,Joel Spolsky 的这个博客在全世界都有很多的读者和粉丝,其博文选集在中国被翻译成《软件随想录》在豆瓣上有 8.7 的高分。这是一本关于软件技术、人才、创业和企业管理的随想文集,作者以诙谐幽默的笔触将自己在软件行业的亲身感悟娓娓道来,观点新颖独特,简洁实用。
Clean Coder Blog ,这是编程大师“Bob 大叔”的博客,其真名叫 Robert C. Martin,世界级软件开发大师,设计模式和敏捷开发先驱,敏捷联盟首任主席,C++ Report 前主编,被后辈程序员尊称为“Bob 大叔”。其博文选集在中国被翻译成《程序员的职业素养》,在豆瓣上有 8.8 的高分。
Martin Fowler ,这是另外一个程序员大师,Martin 主要专注于面向对象分析与设计、统一建模语言、领域建模,以及敏捷软件开发方法,包括极限编程。他的《重构》、《分析模式》、《企业应用架构模式》、《领域特定语言》和《NoSQL 精粹》都是非常不错的书。在他的博客上有很多很多的编程和架构模式方法可以学习。
Paul Graham Essays ,美国著名程序员、风险投资家、博客和技术作家。《黑客与画家》是他的著作之一。2005 年他与人共同创建了科技创业孵化器 Y Combinator,孵化了 Airbnb、Dropbox、Stripe 等知名互联网公司。他有几篇创业方面的文章都很经典,如果你想创业,可以读一读这几篇:《How to Get Startup Ideas》、《Do Things that Don’t Scale》、《Startup = Growth》。Paul Graham 的文章以清新自然,思想深刻见长。不仅可以跟 Paul Graham 学创业,学思考,学技术,更可以学习写作。
Steve Yegge ,Steve Yegge 这个人算是一个知名的程序员了,在 Amazon 呆过,现在在 Google,他的文章都是长篇大论,最知名的文章就是对 Amazon 和 Google 平台的吐槽,这篇文章引发了大家的讨论和议论。
Bruce Eckel’s Programming Blog ,《Thinking in Java》作者的博客,他之前的博客在 artima - Computing Thoughts 。
Herb Sutter ,C++ 大拿,C++ 标准委员会专家,微软软件架构师。《Exceptional C++ 》、《More Exceptional C++》、《Exceptional C++ Style》作者。
Eli Bendersky’s website ,这位老哥从 2003 年就一直写博客到今天,其中的文章都非常不错,原理型的,主要是 C、C++ 和 Python 相关的。里面有很多干货。
Peter Krumins’ blog ,这位老哥从 2007 年开始写博客,他博客里好玩的东西太多了。
Brendan D. Gregg ,Brendan 是 Netflix 的工程师,他的博客里有大量的非常不错的文章,基本上都是和 Linux 性能分析相关的,这是一个如果你要玩底层性能分析一定不能错过的博客。
Evan Klitzke ,主要讨论 Linux 和 C++ 相关的内容。
Julia Evans ,主要讨论 Linux debug 工具和网络相关的内容。
null program ,和 C/C++ 相关的一个博客。其中关于 Linux 系统调用、GPU、无锁编程、JIT 编译的一些文章非常不错。
Fluent {C++} ,博主是 Murex 的首席工程师,主要玩 C++,在这个博客里有很多很不错的 C++ 相关的文章。
Preshing on Programming ,这也是一个和 C/C++ 相关的博客,其中有很多的干货。
Programming is Terrible ,这个博客有很多强观点的文章,主要是软件开发中的一些教训。
Accidentally Quadratic ,姑且翻译成事故二次方,这里有好些非常有趣的文章。
Hacker Noon ,这是一个一堆人在写的博客,里面有很多质量很高的文章。
其实还有很多不错的博客,不过,现在国外不错的博客都在一个叫 Medium 的网站,我也发现我 Google 很多东西时都会到这个网站上。这个网站上的内容不只有技术的,还有很多很多其他方面的内容,比如文化、艺术、科学等等。这个网站就是一个博客发布系统,其是由 Twitter 联合创始人埃文·克拉克·威廉姆斯(Evan Clark Williams)和克里斯多福·艾萨克·比兹·斯通(Christopher Isaac Biz Stone)创办的,这两个人觉得 Twitter 上全是垃圾没有营养的信息。所以,创办了 Medium,这个平台上有专业和非专业的贡献者,亦有受雇的编者。
我已经感觉到,未来高质量的文章都会在 Medium 这个平台上出现,因为有一些公司的技术博客也在这个平台上发布了,比如 Netflix 的。所以,你有必要上到这个平台上 follow 一些作者、专栏和主题。

YouTube 技术频道

下面是我订阅的一些我认为还不错的和编程相关的频道,推荐给你。
Devoxx ,Devoxx 的频道,其中有各种很不错的技术分享。
Coding Tech ,也是个非常不错的编程频道,涵盖各种技术。
Amazon Web Services
Facebook Developers
Google Developer ,Google 公司的官方频道,其中包括 Google I/O 大会、教程、新闻、最佳实践、技巧分享……
Spring Developer ,Spring 的官方频道。
Microsoft Research
MIT 公开课
Stanford Online
Prof. Dr. Jens Dittrich ,一个德国教授开的一个关于数据库相关的频道,里面有很不错的数据库内在原理的内容。
Red Hat Summit ,RedHat 峰会频道,其中有很多和 Linux 相关的技术新闻和分享。
Open Networking Summit ,这是一个网络相关的频道。
Dan Van Boxel ,这是一个机器学习工程师折腾各种事的视频,挺有意思的。
The New Boston ,这个频道应该是前端开发工程师必去的地方,可能也是我所知道的最好的关于前端技术的 YouTube 频道。
Derek Banas 是一个教程型的频道,其中包括编程语言、游戏开发、Web 开发……我个人觉得是一个可以用来练英文听力的频道。
Java ,Java 相关的各种分享。
CppCon ,C++ 大会的一些视频,可以让你了解很多 C++ 最新功能和相关的动态。
Computerphile ,这个频道是布雷迪·哈伦(Brady Haran)运作的几个频道中的一个,在这个频道里你可以看到很多很有趣的技术方面的科普教程、资讯、见闻等,说得都非常地简单易懂,所以有大量的订阅用户。布雷迪是个对任何技术都很有热情的人,这个频道是关于计算机技术的。除此之外,他还运作 Numberphile(数学)、Periodic Videos(化学)、Sixty Symbols(物理)、Deep Sky Videos(天文)等有众多阅人数的频道。如果你喜欢,你都可以一一订阅,感觉就是一个个人版的 Discovery。
关于安全,有如下四个频道你可以订阅一下:
DEFCONConference ,defcon.org 的官方频道。
CCCen ,Chaos Computer Club。
RSA Conference ,RSA Conference。
Black Hat - Black Hat Conference。

各大公司技术博客

细心的你一定会发现这份攻略中的很多推荐文章都来自于各个公司的技术团队的博客。是的,跟随这些公司的博客,你不但可以看到这些公司的工程技术,还能掌握到一些技术方向和趋势。
下面是 Airbnb、AWS、Cloudera、Dropbox、Facebook、Google 等各个公司的技术博客列表。
Airbnb Engineering
AWS 相关
All Things Distributed
AWS Architecture Blog
On Efficiency, Reliability, Scaling - James Hamilton, VP at AWS
Bandcamp Tech
BankSimple Simple Blog
Bitly Engineering Blog
Cloudera Developer Blog
Dropbox Tech Blog
Etsy Code as Craft
Facebook Engineering
Flickr Code
Foursquare Engineering Blog
Google Research Blog
Groupn Engineering Blog
High Scalability
Instagram Engineering
LinkedIn Engineering
Oyster Tech Blog
Pinterest Engineering Blog
Quora Engineering
Songkick Technology Blog
SoundCloud Backstage Blog
Square The Corner
The Reddit Blog
The GitHub Blog
The Netflix Tech Blog
Twilio Engineering Blog
Twitter Engineering
WebEngage Engineering Blog
Yammer Engineering
Yelp Engineering Blog
Smarkets Blog

论文

要想将技术研究得精深,论文是必不可少的。那要如何读论文呢?

如何读论文

下面有几篇文章,教你一些读论文的方法,非常不错。
How to read an academic article
Advice on reading academic papers
How to read and understand a scientific paper
Should I Read Papers?
The Refreshingly Rewarding Realm of Research Papers

论文集散地

要成长为一个高手,论文是你一定要读的。下面是一些非常不错的计算机方面的论文集散地。
2 Minute Papers ,这是一个 YouTube 的频道,其会给出一些非常不错的和计算机相关的论文介绍,让你了解目前最有意思的一些科学突破,每次两分钟左右。
Best Paper Awards in Computer Science ,从 1996 年以来,获奖的计算机科学方面的论文收集。
Google Scholar ,Google 学术搜索(英语:Google Scholar)是一个可以免费搜索学术文章的网络搜索引擎,由计算机专家阿努拉格·阿查里雅(Anurag Acharya)开发。2004 年 11 月,Google 第一次发布了 Google 学术搜索的试用版。该项索引包括了世界上绝大部分出版的学术期刊。
Facebook ,Facebook 公司的论文。
Research at Google ,Google 发布一些论文。
Microsoft Research ,微软发布的论文。
MIT’s Artificial Intelligence Lab Publications ,MIT 和人工智能相关的论文。
MIT’s Distributed System’s Reading Group ,MIT 和分布式系统相关的论文。
arXiv Paper Repository ,arXiv 是一个收集物理学、数学、计算机科学与生物学的论文预印本的网站,始于 1991 年 8 月 14 日。截至 2008 年 10 月,arXiv.org 已收集超过 50 万篇预印本。至 2014 年底,藏量达到 1 百万篇。
在 2014 年时,约以每月 8000 篇的速度增加。arXiv 的存在是造就科学出版业中所谓开放获取运动的因素之一。现今的一些数学家及科学家习惯先将其论文上传至 arXiv.org,再提交予专业的学术期刊。这个趋势对传统学术期刊的经营模式造成了可观的冲击。
SciRate ,arXiv 上的论文太多,所以,SciRate 索引了 arXiv 上的一些好评的论文,并供大家评论和打分。(开源代码。)
cat-v.org ,这个网站,不只有论文,还有技术手册或是一些有意思的文章,包括一些历史资料什么的。
Usenix: Best Papers ,Usenix 上推荐的最佳论文。
The Morning Paper ,该博客会每天推送一篇论文,特别棒。
Lobste.rs tagged as PDF ,Lobsters 是一个聚焦于技术的社区,主要是链接聚合和对话题进行讨论。其中的 PDF 分类可以认为也是一个论文的集散地。
Papers We Love ,GitHub 上的一个近 3 万颗星的计算机科学方面的论文社区。

小结

总结一下今天的内容。这篇文章我主要跟你分享了一些好的学习资源,帮你开拓眼界,为后续学习夯实基础。
首先,我推荐了 Coding Horror、Joel on Software、Clean Coder Blog、Martin Fowler、Paul Graham Essays 等多个知名的个人技术博客。然后分享了一些我认为还不错的和编程相关的 YouTube 频道,比如 Coding Tech、Amazon Web Services、Facebook Developers、Google Developer 等。
随后是 Airbnb、AWS、Cloudera、Dropbox、Facebook、Google 等各个公司的技术博客,跟随这些公司的博客,你不但可以看到这些公司的工程技术,还能掌握到一些技术方向和趋势。最后,想成长为一个高手,论文是一定要读的。所以,我给出了一个非常不错的计算机方面的论文集散地,并推荐了一些学习资源来教你如何读这些论文。
我一直认为,学习需要自我驱动,要学会自己“找食物”,而不是“等着喂”。程序员练级攻略 2018 版到今天就全部更新完成了,但我认为,这其实只是技术练级的起点,还有很多知识和技术,需要我们不断地去探索和发现。加油,我能做到的,你一定也可以做到。

91 | 程序员练级攻略的正确打开方式

image.pngimage.pngimage.pngimage.png
到这里,我估计《程序员练级攻略》系列文章你都已经了解个大概了,不知道此时此刻你有什么样的感受?这份攻略其实是给了一个进阶的地图,也罗列了很多书籍和文档。但我可以确定地说,只是看这些列表,你肯定会抱怨说头都要大了,而且,你可能还会觉得纸上谈兵,不知道怎么把这些知识转变成自己的能力,尤其是你的工作中没有这些场景,你都可能不知道怎么实操。
所以,在这里,我把我个人相关的实践都写一下,这样会让你更好地掌握这份攻略。如果大家有更好的方法,也欢迎留言。
对于本攻略来说,你并不需要按顺序学习,你可以从自己喜欢的切入点,按自己喜欢的路线学习,通常来说,有如下的一些注意事项。
《入门篇》和《专业基础篇》中的那些书和文章,你肯定是得认真精读的,这是基础。但是也没有必要揪住细节不放,重要的是知道这个技术的“解题思路”,抓住其中的重点,一个技术的关键点就那么几个。
《高手成长篇》的相关书籍、文章和论文,你不一定全读,可以挑感兴趣的内容研究。
《修养篇》和《设计篇》里的内容,你可能要经常拿出来读,因为这些都是经验,随着你的成长,以及阅历的增加,你每次读都会收获更多新东西,正所谓常看常新。另外,你还可以顺着这些东西找到更多的“修养”和“设计”。
但是读这些资料,很多人都是记忆式的学习方式。但,你也知道,记忆学习是简单粗暴的,所以也很容易忘,如果你不实操一下,就不会有具体、真实的感觉。所以,一定要动手实践。
下面是一些配合程序员练级攻略中技术成长的相关的建议。
首先,你需要建一个自己的实验室。咱们讲了很多内容,看完之后,你要动起来,徒手把环境搭出来,写一些实验性的程序验证或感受一下相关的技术点,出了问题也要自己进行调试和修复。因为只有这样,你才可以获得一些感性认识。
《入门篇》和《专业基础篇》都有很多的编程语言要学,你并不需要一下全部都学,但是为了你可以一个人 solo,你需要至少学一个后端和一个前端语言,我给你的建议是 Java 和 JavaScript。
在《入门篇》和《专业基础篇》我都给了一些实践项目,如果你没有太多的工作经验,这些实践项目会对你的学习非常有帮助。因为在实现代码的时候,你会遇到很多细节问题,这些细节问题会倒逼你去看文档,去 Google,去提问,这相当于是把你扔到具体的问题场景里锻炼你、打磨你。
对于《数据结构》,其实都是在围绕增删改查的相关性能,在平衡时间和空间。对于《算法》则要么这些数据结构的操作,要么就是数学逻辑的推导,比如动态规划。这些东西可能在你的生活当中用不到,但是你可以把它作为一个脑筋体操来不断训练自己的数学思维。
对于《高手成长篇》中的很多东西,也是需要你自己先搭个环境,自己写一些 Hello World 式的程序先体会一下那些知识。比如内存分配、异步 I/O 模型、locker-free、JVM 和字节码操作,还有浏览器原理等等这些东西,写几个小程序就可以体会到了。而还有一些中间件的知识,你也是可以搭个环境自己玩玩,并且最好能够搭出一些比较高级的用法。
其次,把你的实验室升级成一个工作室。工作室和实验室不一样的地方是,实验室只是在做一些验证型的实验,以跑通一个小技术功能为主。而工作室则是要以完成一个比较完整的软件功能为主,也就是说,可以让别人 / 用户来用的东西(哪怕很丑很难用,但是可以让别人来用)。这个阶段,我给你如下的几个建议。
你得选用一个主流的开发框架,并且在写这个软件的时候,你需要有一定的修养,比如有不错的编程风格,追求代码的可读性,有一定的测试案例,等等这些我们在《修养篇》和《软件设计篇》里提到的东西。这个时候,你需要大量学习一些优秀项目的代码,因为你可以在开源软件中找到一些不错的代码实现(你可以做一些源码分析的事,但不是去整理其中的编程逻辑,而是要去学习代码组织的方法)。然后你需要照葫芦画瓢似的练习,无论你完成得好不好其实都没有关系,这就像画画一样,一开始总是画的很不好的,但是只要你坚持,并且多思考别人为什么要写成那样,那么,我相信你提高得也会很快。
你需要完成一个能用的项目,对于选择什么样的项目,这里,我也有几个建议。第一,从自己的痛点出发,写一个能解决自己问题的东西。第二,临摹别人的作品,复刻一个其它的成功产品。有人说,学好一门语言或是一个开源软件最好的方式,就是用想学 / 喜欢的编程语言翻译下这个开源软件,比如,你用 Go 语言翻译一下某个 Java 的组件。第三,深度参与一些你喜欢的开源项目。第四,在工作中找到风险可控的项目和需求。
你最好跟别人一起组队升级打怪。这里需要注意的是,一定要找好队友,要那种有热情,爱专研,能相互打气的队友,千万别找那些为自己的不努力找各种各样借口的人。
在这个工作室中,你还可以尝试使用各种前沿的或是你没有玩过的技术和中间件。这里,你需要注意的是你一定要使用一些高级技术,比如一些高级算法,或是分布式技术等。
当你的东西做好后,一定要做压力测试或 Benchmark,这样你才知道自己产品与其他软件的差距,然后还会逼着你对自己的系统或软件进行调优。
最后,把你的工作室升级成工厂。工作室与工厂最大的差别就是,工作室是比较自我比较随意的,而工厂是有相关的工业标准的,是有一整套的规范和标准的。对此,有如下的一些建议:
当有了“工作室”的能力后,一般来说,你就可以去头部的互联网公司或是一些技术公司了。但是你一定要在一些核心的项目或产品工作,也就是说,你要在那些有技术挑战的地方工作,并在那里收割更多的经验和技能。
你需要读各种各样的 RFC、论文、Specificaiton、标准化文档,还要使用工业级的工程能力要求自己,比如,CI/CD 这样的软件流程。你得不断告诉自己,把代码提高到可维护、可扩展,甚至可重用的级别。
你必须对技术有更深入的了解,对软件开发的套路和各种 trade-off 还有各种解决方案的优缺点都非常熟悉。这就需要你了解软件内部的设计和原理,并知道优缺点和使用场景。
你需要开始追求软件运行的 SLA,也就是能在什么样的性能下做到多少个 9。还要关注系统的可运维性,也就是你需要为你的软件做很多的配套设施。就像为了汽车,建加油站,建 4S 店,建公路,建交通管理部门……
你需要找那些有工业素养的工程师一起讨论或工作。这类的工程师有丰富的工作和项目经验,也见过大世面。他们通常来说会对外有输出(不是那些写微信公众号的人,或是在知乎上输出的人,而是那些在软件开发工作上有丰富工程经验的人)
这个时候,对于你要做的软件,你不仅仅只是为了完成,你追求的是一种技术高度,追求那种严谨和科学的态度。你已经把这个软件当成了自己作品,变成了自己的名片,你在等待接受别人的学习和膜拜。
好了,基本就是上面这些,你还要记住我的学习能力一文中的那个学习金字塔,在上面的过程中不断地输出你的认识和体会。
最后,我用下面的几个观点来结束这篇文章,希望对你有所帮助:
带着一些具体的问题来学习,能够让你更有感觉,也容易获得正反馈和成就感。
开拓视野,尽可能只读英文社区的一手文章,这样你会得到更有营养的知识。
多问为什么,为什么要设计成这样,为什么要有这个技术,到底解决了什么样的问题?这会让你对技术有更深的认识。
学会归纳总结,在不同的技术中找到相似或是相同的东西,更容易让你触及技术的本质。
把自己的理解用自己的语言表达出来,对外输出,这是最好的学习方式。
“动手”和“坚持”,这是一个动手能力很强的学科,不动手,你什么都不可能学精、学深。这是一个需要你不断坚持的事,在这条路上,你有很多很多的理由可以让你放弃,只有坚持才有可能有突破。


下载APP

92 | 程序员面试攻略:面试前的准备


学习了《程序员练级攻略》以后,我觉得你应该来学习一下“如何面试”了。在我的职业生涯中,我应聘过很多公司,小公司、中型公司、大公司、国内的公司、国外的公司都有。我有成功获得 offer 的经历,也有过不少失败的经历。
我从 2007 年做管理以来,面试过至少 1000 多人次的工程师。这十多年来,我发现有一些事情没什么变化,我们一代又一代的年轻人在应聘时的表现和我 20 年前没什么两样,连简历都没什么改进,更不要说程序员在表达能力方面的长进了。如果只看面试表现的话,感觉世界停止了 20 年似的。
我一直在想,为什么应聘、与人沟通、赚钱等这些重要的软技能,学校里不教呢?这么重要的技能居然要你自己去学,不得不说是教育上的一种失败。另外,关于如何应聘的事,估计你也看过一些文章了,我这里只分享一些我的实实在在的经验和相关的技巧。一定你和看过的不太一样。相信一定能帮得到你!
应聘是需要准备的,下面这些点你需要好好地准备一下。如果你没有准备的话,那么被 pass 掉的概率会非常大。

怎样写简历

首先你要准备的是简历。简历很重要,这是别人了解你的第一个地方,所以简历要好好写。当然,我们知道真正的好简历是要用自己的经历去写的,比如,有人的简历就是一句话:我发明了 Unix。
当然,并不是所有的人都有这样的经历,但这依然告诉我们,自己的经历才是简历最大的亮点。所以,你要去那些能让你的简历有更多含金量的公司工作,要做那些能让你的简历更闪亮的工作。这是写简历的最佳实践——用自己的经历聊,而不是用文字写。
但从另一方面来说,简历这个文本也是要好好写的,况且,我们不是每个人都会有很耀眼的经历,所以,还是要好好写简历。基本上来说,简历上的信息不要写太多,信息太多相当于没有信息,不要单纯地罗列,要突出自己的长处和技能。一般来说,简历需要包括以下几项内容。
自我简介。这个自我简介是用最简单的话来说明自己的情况,不超过 200 字。比如:10+ 年的软件开发经验(说明你的主业),4+ 年的团队 leader 经验(说明你的领导力),擅长高可用高性能的分布式架构(说明你的专业和专攻),多年互联网和金融行业背景(说明你的行业背景),任职于 XXX 公司的 XX 职位(说明你的职业),负责 XXX 平台或系统(说明你的业务场景)……
个人信息。这里有几点需要注意。
基本信息。电子邮箱建议用 Gmail,千万不要用 QQ 邮箱,要让人感觉职业化一些。
个人网站。如果你有个人主页、博客、GitHub 或是 Stack Overflow,请一定附上,这是加分项。如果个人主页或博客有独立域名,那更好,这会给人一种你爱动手做事的感觉。页面也要干净有美感,这样会让人感觉你有品味。
网站内容。一般来说这些项都会被面试官点看浏览,所以,里面的内容你需要小心组织和呈现,千万不要造假。另外,除了技术上的一些知识总结(不要太初级,要有深度的、原理型的、刨根问底型的文章),你也可以秀一秀自己的技术价值观(比如,对代码整洁的追求,对一些技术热点事件的看法),这会让你更容易获得面试官的好感。面试官的好感很重要。
作品展。如果你有一些作品展现,会更好。当然,对于前端程序员来说,这是比较容易的。而对于后端程序员来说,这会比较难一些,只能展示一下自己的 GitHub 了。如果你有一些比较不错的证书或奖项(如微软的认证、Oracle 的认证),也可以展示一下。
个人技能。个人信息下面你应该罗列几条个人的技能。这些内容要能很明显地让对方了解你掌握的技术和熟悉的领域。
技术技能栈。其中包括你擅长和会用的编程语言(如 Java、Go、Python 等),编程框架或一些重要的库(如 Spring Boot、Netty、React.js、gRPC 等),熟悉的一些技术软件(如 Redis、Kafka、Docker 等),设计或架构(如面向对象设计、分布式系统架构、异步编程、高性能调优等)。
技术领域。前端、算法、机器学习、分布式、底层、数据库等。
业务领域。一方面是行业领域,如金融、电商、电信等,另一方面是业务领域,如 CRM、支付、物流、商品等。
经验和软技能。带过多少人的团队、有多少年的项目管理经验、学习能力如何、执行力怎么样、设计过什么样的系统。(不要太多,几句话就好)
其实和用人单位发布的招聘信息中的职位技能需求很相似。有时候我都在想,明明用人单位的职位需求里写成那样,为什么应聘人还不依葫芦画瓢呢?所以,对应于你的简历,如果能和职位需求看齐有相类似的描述,这样可以快速地让人觉得你和要应聘的职位很匹配
工作经历和教育经历
列一下你的工作经历。每份工作完成的主要项目(不要列一大堆项目,挑重要的),主要突出项目的难度、规模、挑战、职责,以及获得的认可和荣誉。
工作经历和教育经历,主要是对上述的个人技能的印证。不要东拉西扯,要紧紧地围绕着你的技能、特长和亮点来展开。
一般来说,你简历中的内容最好控制在两页 A4 纸以内,最好有中英文版,简历不要是 Word 版的,最好是 PDF 版,然后简历的格式和风格请参考 LinkedIn 上的(在 微软的 Office 模板网站 上也能找到一些不错的简历模板)。简历的内容不要太多,内容太多,重点就不明显了。写简历的目的是呈现自己的特长、亮点和特点。只要你能呈现出 2-3 个亮点和特长,就可以吸引到人了。
简历只是一块敲门砖。一些热门的公司和项目能够吸引到很多很多人的简历,所以,你要在众多的简历中脱颖而出。除了自己的经历和能力有亮点外,你还需要有吸引用人单位的方法。
有很多公司都是 HR 先来筛一遍简历,HR 其实并不懂技术,她们只会看你的过往经历、能力是否和职位描述上的匹配。如果简历上的经历和技术亮点不足的话,那么你可以在简历的版式和形式的制作上花些心思,以及在简历的自我描述中加上一些“虚”的东西。
比如“工作态度积极,不分份内和份外的事,只要对公司和个人有利,都会努力做好;勤奋踏实,热爱学习,喜欢做一个全栈工程师;善于发现问题,并解决问题……”表示我虽然现在的经历和技能不足以打动你,但是我的态度端正,潜力巨大,你不能错过……

技术知识准备

一般来说,你的简历上写什么,面试官就会问什么,所以,不要打自己的脸,精通就是精通,熟悉就是熟悉,了解就是了解。然后对于你列出来的这些技术,你一定要把其最基本的技术细节给掌握了。面试官一般也会逐步加大问题的难度和深度,看看你到底在哪个层次上。所以,你还是需要系统地看看书,才能应对面试官的问题。比如:
你写上了 Java,那么 Java 的基本语法都要了解,并发编程、NIO、JVM 等,你多少要有点儿了解,Spring、Netty 这些框架也要了解。
你写上了 Go,那么至少得把官网上的 Effective Go 给看了。
你写上了 Redis,那么除了 Redis 的数据结构,Redis 的性能优化、高可用配置、分布式锁什么的,你多少也要把官网上的那几篇文章读一读。
你写上了面向对象,那么怎么着也得把《设计模式》中的 23 个模式了解一下。
你写上了分布式架构,那么 CAP 理论、微服务架构、弹力设计、Spring Cloud、Cloud Native 这些架构就要做到心里有数。
你写上网络编程,那么 TCP/IP 的三次握手,四次挥手,两端的状态变化你得知道吧,Socket 编程的那几个系统调用,还有 select、poll、epoll 这些异步 IO 多路复用的东西,你得知道。
总之,无论你在简历里写什么技术,这些技术的基础知识你都得学一下。本质上来说,这跟考试一样啊。你想想你是怎样准备期末考试的,是不是得把教科书上所有章节中的关键知识点都过一下?你不见得要记住所有的知识点,但是 80% 以上的关键知识点,你多少得知道吧。

算法题准备

国外的公司一般还会面算法题,他们用算法题来过滤掉那些非计算机专业出身的人。国内的一些公司也一样,尤其是一些校招面试,也有很多算法题。所以,算法是很重要的,是你需要努力学习和准备的。
LeetCode 是一个不错的地方。如果你能完成其中 50% 的题,那么你基本上可以想面哪里就面哪里了。这里,你要知道,一些面试官也是新手,他们也是从网上找一些算法题来考你。所以,你不用太害怕算法题,都是有套路的。比如:
如果是数据排序方面的题,那基本上是和二分查找有关系的。
如果是在一个无序数组上的搜索或者统计,基本上来说需要动用 O(1) 时间复杂度的 hash 数据结构。
在一堆无序的数据中找 top n 的算法,基本上来说,就是使用最大堆或是最小堆的数据结构。
如果是穷举答案相关的题(如八皇后、二叉树等),基本上来说,需要使用深度优先、广度优先或是回溯等递归的思路。
动态规划要重点准备一下,这样的题很多,如最大和子数组、买卖股票、背包问题、爬楼梯、改字符……这里有一个 Top 20 的动态规划题的列表 。
一些经典的数据结构算法也要看一下,比如,二叉树、链表和数组上的经典算法,LRU 算法,Trie 树,字符串子串匹配,回文等,这些常见的题都是经常会被考到的。
基本上来说,算法题主要是考察应聘者是否是计算机专业出身的,对于基本的数据结构和算法有没有相应的认识。你做得多了,就是能感觉得到其中的套路和方法的。所以,本质来说,还是要多练多做。

工作项目准备

无论什么公司的面试,都会让你说一个你做过的项目,或是你过去解决过的一个难题。但我很好奇怪,这种必问的题,为什么很多应聘者都没有好好准备一下。
一般来说,会有下面这样的几个经典的面试问题。
说一个你做过的最自豪的项目,或是最近做过的一个项目。
说一个你解决过的最难的技术问题,或是最有技术含量的问题。
说一个你最痛苦的项目,或最艰难的项目。
说一个犯过的最大的技术错误,或是引发的技术故障。
对于上面这四个问题:第一个问题,主要是想看看你过去工作中做过的最高级的事是什么,还有你的兴趣点和兴奋点是什么;第二和第三个问题,主要是想看看你解决难题的能力,以及面对压力和困难时的心态;第四个问题,主要是想了解一下你面对错误时的态度,还要了解你是否会对错误有所总结和改进。
这些问题都会伴随着对各种细节的不停追问,因为这样的问题太容易造假了。所以,面试官会不停地追问细节,就像审问一样。因为一个谎言需要用更多的谎言来掩盖,如果没有经过高强度和专业的训练的话,最好不要撒谎。因此对于业余的不是做特工或是间谍的人来说,谎言是经不起追问的。
怎样准备这样的题,我这里有几个提示。
要有框架。讲故事要学会使用 STAR 。Situation - 在什么样的环境和背景下,Task - 你要干什么样的事,Action - 你采取了什么样的行动和努力,Result - 最终得到了什么样的效果。这是整个语言组织的框架,不要冗长啰嗦。
要有细节。没有细节的故事听起来就很假,所以,其中要有很多细节。因为是技术方面的,所以,一定要有很多技术细节。
要有感情。讲这些故事一定要带感情。要让面试官感受到你的热情、骄傲、坚韧和顽强。一定要是真实的,只有真实的事才会有真实的感情。
要有思考。只有细节和故事还不够,还要有自己的思考和得失总结,以及后续的改进。
要做到上述,是不容易的。一般来说,你也是需要训练的。首先,你要形成及时总结的习惯,对自己的日常工作和经历做总结,否则难免会有“书到用时方恨少”的感觉。另外,你还需要训练自己的语言组织能力。最后,你还要有对这些事件的思考,这需要和其他人进行讨论和总结。
对此,如果你想有一个比较好的面试回答效果,这不是你能临时准备出来的,工夫都是花在平时的。而训练这方面能力的最好方式就是在工作中写文档 ,在工作之余写博客。只有写得多了,写得好了,你这样的能力才能训练出来。

小结

总结一下今天的内容。面试前的准备该怎样做,对面试成功与否至关重要。在这篇文章中,我分享了自己总结一些经验和相关技巧。首先是怎样写简历,我认为,简历上的信息不要写太多,信息太多相当于没有信息,不要单纯地罗列,要突出自己的长处和技能。
然后是技术知识的准备,我强调,无论你在简历里写什么技术,这些技术的基础知识你都得学一下。即便不能记住所有的知识点,但是 80% 以上的关键知识点,你多少得知道吧。随后是算法题的准备,我推荐了 LeetCode,并给出了好几种经典算法题的解题套路。
最后是工作项目的准备,给出了几种经典的面试问题及应答思路,并分享了该如何做准备。我认为,想有一个比较好的面试回答效果,是临时准备不出来的,要将工夫花在平时。
下篇文章中,介绍的是面试中的技巧,比如,答不出来时该怎么办、如何回答尖锐问题、如何抓住最后提问的机会等,很有实践指导意义。敬请期待。96 | 高效学习:端正学习态度

在开始这一系列文章之前,我想说,如果你想从我这里得到一些速成的方法,那么你就不用往下看了,学习是不可能速成的。这里只有一些方法和技巧,是我这么多年来行之有效的,分享出来也许对你有帮助。一方面,可能会让你学得更多和更累,另一方面,可能会让你学得更系统、更全面。总之,学习是一件“逆人性”的事,就像锻炼身体一样,需要人持续付出,会让人感到痛苦,并随时想找理由放弃

大部分人都认为自己爱学习,但是:
他们都是只有意识没有行动,
他们是动力不足的人。
他们都不知道自己该学什么,
他们缺乏方向和目标。
他们都不具备自主学习的能力,没有正确的方法和技能。
更要命的是,他们缺乏实践和坚持

如果你去研究一下古今中外的成功人士,就会发现,他们基本上都是非常自律的,也都是非常热爱学习的。他们可以沉得下心来不断地学习,在学习中不断地思考、探索和实践。
所以,如果你不能克服自己 DNA 中的弱点,不能端正自己的态度,不能自律,不能坚持,不能举一反三,不能不断追问等,那么,无论有多好的方法,你都不可能学好。所以,有正确的态度很重要。

然后,我会在后面给你一些方法和相关的技能,让你可以真正实际操作起来。
主动学习和被动学习
1946 年,美国学者埃德加·戴尔(Edgar Dale)提出了「学习金字塔」(Cone of Learning)的理论。之后,美国缅因州国家训练实验室也做了相同的实验,并发布了「学习金字塔」报告。

image.png
人的学习分为「被动学习」和「主动学习」两个层次。

  • 被动学习:如听讲、阅读、视听、演示,学习内容的平均留存率为 5%、10%、20% 和 30%。
  • 主动学习:如通过讨论、实践、教授给他人,会将原来被动学习的内容留存率从 5% 提升到 50%、75% 和 90%。

这个模型很好地展示了不同学习深度和层次之间的对比。
我们可以看到,你听别人讲,或是自己看书,或是让别人演示给你,这些都不能让你真正获得学习能力,因为你是在被别人灌输,在听别人说。

只有你开始自己思考,开始自己总结和归纳,开始找人交流讨论,开始践行,并开始对外输出,你才会掌握到真正的学习能力。

举个大家都懂的例子,那就是学习英文,我们从小就是在开始学习英文了,很多人英文成绩可以考得很好,语法也可以不错。然而,哪天真正要和外国人交流的时候,却发现自己的英文能力渣得不要不要的,只会回答:Fine. Thank you, and you? 这就是浅度学习的结果

我的英文能力也是一样的,直到有一天进到外企,外企请了个外教每周来公司三次和我们练英文,我的英文能力才有一点点进步,然而,还是不够。后来有一天,公司的客户抱怨我们的一线客服处理问题太慢,问我们在后台做开发的人有谁去一线支持客户,我举手了。于是我接了半年来自日本、新加坡、德国、法国、英国等多个国家的客户电话和邮件。

在这期间,我的英文能力直线上升,速度快得不得了。一方面是我要把自己知道的讲给客户听,另一方面要跟客户有交流,所以我学得更努力,也更有效果。主要是日本人和德国人给了我足够的信心,这两个国家的人可能是这世界上最严谨的人,他们非常喜欢打破沙锅问到底,而且他们的英文也不怎么好,但是他们都用很慢的语速来和我交流,一方面是怕他们自己说不好,另一方面是也希望我用慢速的话和他们说。于是,大家都在一种慢速的环境下说英文,把每个单词的音都发准了,这使我提高了英文能力。
后面再跟一些口音很奇葩的老外(比如印度人和法国人)说英文的时候,我就会让他们说慢点,以便我适应他们的口音。几年后,我到了另外一家外国公司工作,需要跟一些口音非常重的印度人和非洲人说英文,我都能听懂,着实把我身边的同事们都震住了。这就是深度学习的最好的例子,要践行

所以,学习不是努力读更多的书,盲目追求阅读的速度和数量,这会让人产生低层次的勤奋和成长的感觉,这只是在使蛮力。要思辨,要践行,要总结和归纳,否则,你只是在机械地重复某件事,而不会有质的成长的。

浅度学习和深度学习

老实说,对于当前这个社会:

  • 大多数人的信息渠道都被微信朋友圈、微博、知乎、今日头条、抖音占据着。这些信息渠道中有营养的信息少之又少。
  • 大多数公司都是实行类似于 996 这样的加班文化,在透支和消耗着下一代年轻人,让他们成长不起来。
  • 因为国内互联网访问不通畅,加上英文水平受限,所以,大多数人根本没法获取到国外的第一手信息。
  • 快餐文化盛行,绝大多数人都急于速成,心态比较浮燥,对事物不求甚解。

所以,你看,在这种环境下,你根本不需要努力的。你只需要踏实一点,像以前那样看书,看英文资料,你只需要正常学习,根本不用努力,就可以超过你身边的绝大多数人。

我们整个世界进入了前所未有的信息爆炸时代,人们担忧的不再是无知识可学,而是有学不完的知识。而且时代的节奏变得越来越快,你可能再也不像 20 年前,可以沉着优雅平和地泡上一杯茶,坐在一个远离喧嚣的环境下,认认真真地看本书。这个时代,你再也不会有大块大块的时间,你的时间都被打成碎片了,不知不觉你也成为了快餐文化的拥趸……

在这样一个时代下,种种迹象表明,快速、简单、轻松的方式给人带来的快感更强烈,而高层次的思考、思辨和逻辑则被这些频度高的快餐信息感所弱化。于是,商家们看到了其中的商机,看到了如何在这样的时代里怎么治愈这些人在学习上的焦虑,他们在想方设法地用一些手段推出各种代读、领读和听读类产品,让人们可以在短时间内体会到轻松获取知识的快感,并产生勤奋好学和成长的幻觉(老实说,像我这种付费专栏或是得到等知识付费产品基本上就是类似的产物)。

这些所谓的“快餐文化”可以让你有短暂的满足感,但是无法让你有更深层次的思考和把知识转换成自己的技能的有效路径,因为那些都是需要大量时间和精力的付出,不符合现代人的生活节奏。人们开始在朋友圈、公众号、得到等这样的地方进行学习,导致他们越学越焦虑,越学越浮燥,越学越不会思考。于是,他们成了“什么都懂,但依然过不好这一生”的状态。

只要你注意观察,就会发现,少数的精英人士,他们在训练自己获取知识的能力,他们到源头查看第一手的资料,然后,深度钻研,并通过自己的思考后,生产更好的内容。而绝大部分受众享受轻度学习,消费内容。

你有没有发现,在知识的领域也有阶层之分,那些长期在底层知识阶层的人,需要等着高层的人来喂养,他们长期陷于各种谣言和不准确的信息环境中,于是就导致错误或幼稚的认知,并习惯于那些不费劲儿的轻度学习方式,从而一点点地丧失了深度学习的独立思考能力,从而再也没有能力打破知识阶层的限制,被困在认知底层翻不了身。

可见深度学习十分重要,但应该怎样进行深度学习呢?下面几点是关键。

  1. 高质量的信息源和第一手的知识。
  2. 把知识连成地图,将自己的理解反述出来。
  3. 不断地反思和思辨,与不同年龄段的人讨论。
  4. 举一反三,并践行之,把知识转换成技能。

换言之,学习有三个步骤。

  • 知识采集。信息源是非常重要的,获取信息源头、破解表面信息的内在本质、多方数据印证,是这个步骤的关键。
  • 知识缝合。所谓缝合就是把信息组织起来成为结构体的知识。这里,连接记忆,逻辑推理,知识梳理是很重要的三部分。
  • 技能转换。通过举一反三、实践和练习,以及传授教导,把知识转化成自己的技能。这种技能可以让你进入更高的阶层。

我觉得这是任何人都是可以做到的,就是看你想不想做了。
此外,在正式开始讲如何学习之前,让我先说一些关于学习的观点,这是在为后面的那些学习方法和技巧做提纲挈领的铺垫。

学习是为了找到方法

学习不仅仅是为了找到答案,而更是为了找到方法。很多时候,尤其是中国的学生,他们在整个学生时代都喜欢死记硬背,因为他们只有一个 KPI,那就是在考试中取得好成绩,所以,死记硬背或题海战术成了他们的学习习惯。然而,在知识的海洋中,答案太多了,你是记不住那么多答案的。
只有掌握解题的思路和方法,你才算得上拥有解决问题的能力。所有的练习,所有的答案,其实都是在引导你去寻找一种“以不变应万变”的方法或能力。在这种能力下,你不需要知道答案,因为你可以用这种方法很快找到答案,找到解,甚至可以通过这样的方式找到最优解或最优雅的答案。
这就好像,你要去登一座山,一种方法是通过别人修好的路爬上去,一种是通过自己的技能找到路(或是自己修一条路)爬上去。也就是说,需要有路才爬得上山的人,和没有路能造路的人相比,后者的能力就会比前者大得多得多。所以,学习是为了找到通往答案的路径和方法,是为了拥有无师自通的能力。

学习是为了找到原理

学习不仅仅是为了知道,而更是为了思考和理解。在学习的过程中,我们不是为了知道某个事的表面是什么,而是要通过表象去探索其内在的本质和原理。真正的学习,从来都不是很轻松的,而是那种你知道得越多,你的问题就会越多,你的问题越多,你就会思考得越多,你思考得越多,你就会越觉得自己知道得越少,于是你就会想要了解更多。如此循环,是这么一种螺旋上升上下求索的状态。

但是,这种循环,会在你理解了某个关键知识点后一下子把所有的知识全部融会贯通,让你赫然开朗,此时的那种感觉是非常美妙而难以言语的。在学习的过程中,我们要不断地问自己,这个技术出现的初衷是什么?是要解决什么样的问题?为什么那个问题要用这种方法解?为什么不能用别的方法解?为什么不能简单一些?……

这些问题都会驱使你像一个侦探一样去探索背后的事实和真相,并在不断的思考中一点一点地理解整个事情的内在本质、逻辑和原理。一旦理解和掌握了这些本质的东西,你就会发现,整个复杂多变的世界在变得越来越简单。你就好像找到了所有问题的最终答案似的,一通百通了。

学习是为了了解自己

学习不仅仅是为了开拓眼界,而更是为了找到自己的未知,为了了解自己。英文中有句话叫:You do not know what you do not know,可以翻译为:你不知道你不知道的东西。也就是说,你永远不会去学习你不知道其存在的东西。就好像你永远 Google 不出来你不知道的事,因为对于你不知道的事,你不知道用什么样的关键词,你不知道关键词,你就找不到你想要的知识。
这个世界上有很多东西是你不知道的,所以,学习可以让你知道自己不知道的东西。只有当我们知道有自己不知道的东西,我们才会知道我们要学什么。所以,我们要多走出去,与不同的人交流,与比自己聪明的人共事,你才会知道自己的短板和缺失,才会反过来审视和分析自己,从而明白如何提升自己。
山外有山,楼外有楼,人活着最怕的就是坐井观天,自以为是。因为这样一来,你的大脑会封闭起来,你会开始不接受新的东西,你的发展也就到了天花板。开拓眼界的目的就是发现自己的不足和上升空间,从而才能让自己成长。

学习是为了改变自己

学习不仅仅是为了成长,而更是为了改变自己。很多时候,我们觉得学习是为了自己的成长,但是其实,学习是为了改变自己,然后才能获得成长。为什么这么说呢?我们知道,人都是有直觉的,但如果人的直觉真的靠谱,那么我们就不需要学习了。而学习就是为了告诉我们,我们的很多直觉或是思维方式是不对的,不好的,不科学的。

只有做出了改变后,我们才能够获得更好的成长。你可以回顾一下自己的成长经历,哪一次你有质的成长时,不是因为你突然间开窍了,开始用一种更有效率、更科学、更系统的方式做事,然后让你达到了更高的地方。不是吗?当你学习了乘法以后,在很多场景下,就不需要用加法来统计了,你可以使用乘法来数数,效率提升百倍。

当你有一天知道了逻辑中的充要条件或是因果关系后,你会发现使用这样的方式来思考问题时,你比以往更接近问题的真相。学习是为了改变自己的思考方式,改变自己的思维方式,改变自己与生俱来的那些垃圾和低效的算法。总之,学习让我们改变自己,行动和践行,反思和改善,从而获得成长

小结

总结一下今天的内容。首先,学习是一件“逆人性”的事,就像锻炼身体一样,需要人持续付出,但会让人痛苦,并随时可能找理由放弃。如果你不能克服自己 DNA 中的弱点,不能端正自己的态度,不能自律,不能坚持,不能举一反三,不能不断追问等,那 么,无论有多好的方法,你都不可能学好。因此,有正确的态度很重要。
此外,还要拥有正确的学习观念:学习不仅仅是为了找到答案,而更是为了找到方法;学习不仅仅是为了知道,而更是为了思考和理解;学习不仅仅是为了开拓眼界,而更是为了找到自己的未知,为了了解自己;学习不仅仅是为了成长,而更是为了改变自己,改变自己的思考方式,改变自己的思维方式,改变自己与生俱来的那些垃圾和低效的算法。

端正的学习态度和正确的学习观念,是高效学习的第一步,拥有这两者一定可以让你事半功倍。然后就是要总结和掌握高效学习的方法,这是我们下篇文章中将要分享的内容。敬请期待。

93 | 程序员面试攻略:面试中的技巧


前面一篇文章讲的是面试前的准备,我从简历、技术知识、算法题和工作项目四个方面一一分享了该如何做准备,以及其中的经验和技巧。今天我们就来聊聊面试中的技巧。

形象和谈吐

面试过程很短,对一个人的认识和了解也是很有限的。如果你的技能一般的话,那么就需要加强你的形象和谈吐了。总之,你不能内在和外在都不要吧,最好是内在和外在都很好。
形象方面,最好还是穿工作便装,休闲的也没事,但是要让人感到干净、整洁。不要有异味,不要邋遢——头不梳、胡子不刮、衣服也皱巴巴的,还是要修修边幅的。因为有 HR 的人会来面你的,HR 一般都是女孩子,所以不要吓到她们。
另外,保持微笑,表现得热情、开朗和幽默是非常重要的。每个人都喜欢和开朗风趣积极向上的人相处。经常微笑,表现出自己的热情,适当开开玩笑,自嘲一下,会让人觉得你很容易亲近。交谈时千万不要像挤牙膏一样,别人问你一句,你答一句,要把完整的前因后果讲完。别人问你个事,你就多分享一些这个事中的酸甜苦辣,把故事讲得生动有趣点儿,能逗笑 HR 妹子最好(但不要撩)。
说话的时候,要看着对方,一方面这是对对方的尊重和礼貌,另一方面,这也是一种自信。就算没有面好,也不要低着头,又不是做错了什么事。有什么事说不清楚的,不要犹豫,该画图画图。对于比较复杂的面试官听不懂的问题,要变换不同的方式来描述。
面试官问的问题,你要给出充足的细节,千万不要让面试官不断地追问,那样就被动了。你问我解决过的最难的问题是什么,我就把这个问题的来龙去脉和其中的各种细节给你滔滔不绝地讲个遍。当然,也要讲得清楚干净有条理,不要东拉西扯的,也不要云山雾罩的。这些表达和谈吐还是要多练!
最好的训练就写作,你写得多了,能把复杂的问题描述清楚了,自然也会体现在语言组织能力上了。

答不出来

面试中有一些问题很难,但是不要放弃,要不断尝试。很多时候,面试官并不期待你能在很短的时候内解出一道难题,他只是想看一下你遇到难题时的态度和思维方式。如果你能证明给面试官看,你解决问题的方向和方法是正确的,就算是没有找到答案,也是很不错的。因为只要方向走对了,剩下的就是时间问题了。
如果实在解不出来,或是被问了不懂的知识性问题,那么就直接说不懂就好了。记下来,回去多看多练,下次记住了就好。
另外,对于没有答上来的问题,有的人会在面试后请教一下面试官。但是我觉得更好的方式是,问面试官要个他的邮箱或微信,回去后,努力搞懂,举一反三,然后写个东西再发回去。这样做是有可能让你起死回生的。多少可以暗示对方:“你看,我有不懂的,但是我能下工夫很快就搞懂了,你看我的学习能力还不错哦。你就不再考虑一下了吗?”

尖锐问题

应聘的时候,你有可能会被问到几个尖锐的问题,这时你要小心做答。一般来说,你会遇到这几个常见的比较尖锐的问题。
你为什么要离开现在的公司?这种问题一般都是来问你的离职动机的,招聘方有理由相信,你是怎样离开前东家的,就会怎样离开我。另外,从这个问题上,招聘方想了解你真实的动机,对工作的想法和个人的喜好。一般来说,永远不要说之前公司的坏话,最标准的外交词令是:“我离开现有公司的原因是我太喜欢你们公司了”。
这样的回答,对于招聘方来说毫无破绽可言,而如果你开始抱怨你现在的公司了,很可能会引出很多问题把你问到最后都抬不起头来。当然,你也可以说前公司的问题,比如:自己心爱的项目被公司废弃了、公司转型了、公司业绩下滑了、在现有的公司没有成长空间了…… 这些都还是可以说的。
说一下你的缺点?并给出几个例子。这个问题也是很难很难回答的。但是,我想说,人无完人,是个人总是会有缺点的,但是有的缺点也有点不好意思说。所以,这个问题是比较难的。这个问题不能说套话,说套话会显得特别假。这个问题还是要说实话,也不能说一些不痛不痒的小毛病,这样会让他觉得你避重就轻。
只要你认识到任何性格的人都有问题,那么这个问题你就好回答了。比如,对我来说,我个是比较着急的人,急性子,而且是个做事的人。所以,我最大的问题就是在推进一些事的时候,会忽略别人的感受。当压力变大的时候,我甚至会说出一些别人难以接受的话(俗话说的情商为零)。这个没什么不好意思承认的,我这么多年来也在改进自己。
总之,我想说的是,我们每个人都应审视一下自己,思考一下自己光明面的后面。而回答这个问题的最佳方法,就是想想附着在正面事件上的阴暗面,那就是你的答案。比如,我对事情的要求太高了,跟我在一起工作人的压力太大。我太内向了,所以别人和我沟通起来有点费劲。我太过关心团队了,所以,有时候会忽略了项目成本和时间进度……
最后还要补一句,我知道我的缺点,我也在努力改正,我正在通过什么样的方式改正。这非常关键,因为这基本上是面试官最喜欢看到的答案了,就是你不仅能正视自己的缺点,而且还能不断地改正
另外,与这个问题相对应的是,说一下你的优点。这个问题是比较坑的,你的优点是需要用证据来说明的。比如,我通常的回答是,我的优点就是学习能力强,因为我掌握的技术面很广,而且,我什么样的技术都学,比如最新的 Cloud Native 技术。作为后端人员我还学前端方面的技术如 React.js 和 Vue.js,这一切都来源于我扎实的基础知识……
回答这个问题的时候,一般都会反衬出你的价值观,HR 就是想了解你的价值观。比如,我比较踏实,我想把技术一直做到老。再比如,我有韧性,我受过哪些挫折、失败、不公、无奈和无助,我没有当逃兵……
你为什么换工作换得这么勤?很多公司的 HR 都会对应聘者频繁换工作持比较负面的评价。频繁换工作在职业生涯中真不是一件好事,因为用人方会觉得要么是你太不踏实了,要么是你太不行了。所以,工作不要换得太频繁。但是如果换得太频繁了,我给你一个建议,在简历里面写上离职原因。
另外,在面试时被问到这个问题时,你需要给出合理的解释,以消除用人方的疑惑。怎么给出合理的解释呢?一方面,你还是需要诚恳一点儿,另一方面,你在解释时需要承认频繁换工作也不是自己想的,自己何尝不想在一份工作上干得时间长一点儿。
无奈,要么是公司有变化,要么就是自己没选好。一方面表达自己也厌倦了频繁换工作这种事,另一方面,你要把这个话题引到另外一个方向上——什么样的工作自己可以干很久?自己所期望的工作内容和工作环境是什么样的?这样就转而去谈你所向往的工作内容和环境了,并再表达一下在这样的工作环境下,是可以很长时间做下去的,并愿意和公司一起发展。
但是,先不要说得太理想了,不然,用人方也会觉得自己是做不到的。正确的说法是,自己并不担心公司有各种各样的问题,只要有一起扛事的队友一起拼搏,这才是最关键的。
你在一家公司呆了接近 10 年为什么没有做到管理层?你又是怎么保持竞争力的?一般来说,不想做管理的程序员也挺多的,在技术的方向上勤勤恳恳深耕细作,会是一个非常难得的优秀工程师。专注于技术,不分心,不断地在技术上的深度和广度上钻研,这就是保持竞争力最好的方式。所以,其实这个问题挺好回答的。
但另一个更难的问题是:你工作满 5 年了,为什么还不是一个高级程序员?对于国外的顶尖公司来说,如果你有 5 年的工作经验,但还不能胜任高级程序员(Amazon 的 SDE2)的职位,那么你这个人就基本会被 pass 掉了,包括在职的员工也是一样的。于是,对于工作年限超过 5 年的程序员,如果你还不能证明你可以独当一面,你的能力能够驾驭复杂难题,那么国外的顶尖公司都不会问你这个问题的。
国内的公司可能会问你这个问题,对此,我个人认为比较好的回答是要分几方面来谈。一方面,过去因为什么原因耽误了些时间(环境因素、客观条件因素),另一方面,要表示同样也有主观因素,不然显得有点找借口的感觉,不诚恳。
接下来,要表明自己心里面也比较慌(表明自己不用别人提醒可以自己意识到自己的问题),所以,近一年来一直在学习,罗列一下学过哪些东西,最好还有学习目标和学习计划(表明自己除了有意识外,还有行动)。当然,厉害的面试官会不断地追问你一些细节,以此来确定你没有说假话,对此,你要有充足的准备。
你为什么换了一个方向?你觉得你有什么优势? 这个问题其实并不难回答,实话实说就好了。但是不要让招聘方感受到你浮燥的内心,或是朝三暮四的性格,更不要让人感觉到你像“小猫钓鱼”那样一边不行又来搞另一边。
我觉得回答这个问题有两种方式:一种是非常自信的回答——“我从来没有改变我的方向,因为种种原因,我没能得到我想要的方向,虽然现在很残酷,但是我一直都没有放弃我的方向,我一直都在努力学习……”如果你要这么回答了,你就要真的是这样的,在新的方向有所研究和建树,不然会被识破的。
另一种回答则常规一点,首先说明一下,自己的兴趣爱好,为什么这个方向要比之前的那个方向更适合自己。可以用几个例子来说明,但其中要有一些细节,比如,自己试过这个新方向 ,发现干得比原来那边更好,更容易出成绩,自己的兴奋点更大,所以觉得新方向更适合自己。然后,承认换一个方向短期内并没有优势。但是,因为自己的某某特质,比如,学习能力强、勤奋、聪明等特质,未来一定是可以胜任的。
但是,你要用证据证明你的学习能力强,你比一般人勤奋,比一般人聪明。不然如果对方追问下去,会让你破绽百出的。总之,回答这样的问题,需要一定的证据作为补充,而且还要伴随着以降职降薪为代价。所以,一般来说,选定方向最好不要再变了,如果一定要变的话,你也要有必胜的信心和先下后上的心态,而且这些信心和心态要让招聘方看到。
对于技术的热情或初心体现在你生活和工作中的哪里?这个问题其实是想了解一下你的性格,以及对生活和工作的态度。这个问题会伴随着很多细节上的追问。所以,你要小心回答,而且是要带感情的,但一定要是真实的。
一般来说,热情和初心不是停留在嘴上的,而是要表现在行动上的,你需要给出几个曾经发生过的示例。这些示例可以是:你死磕某个事解决某个难题不认输的精神;你坚持做某件事,无论风吹雨打,无论有没有激励;你在某个逆境中依然没有放弃依然努力的态度;在面对压力时,你勇于承担责任的精神;你严谨细心、精益求精的做事风格;面对诱惑能沉得住气,不浮躁……
总结一下,对技术的热情或初心,需要表现在这么几个特质上:执着、坚持、坚韧、不服输、担当、不妥协、不浮燥……我说一句,我相信每个人或多或少都会有这些特质,这是你的亮点,要小心呵护。不然,你跟一条咸鱼就没什么两样了。
你觉得你比男性程序员有什么优势?这种问题一看就带有性别歧视。我的建议是,首先从更高的维度教育一下对方,放出观点,性别不能算优势,人与人的不同和差距是体现在工作技能和态度上的。然后,把回答转向到自己的工作技能和工作态度上来,随后从诸如想象力、品味、沟通能力、严谨细心、承受压力等方面说明自己的长处。
当然,能问得出这样问题的公司一定不是好公司,千万不要去了。所以,可以放心地怼回去。需要注意的是,职场中的怼人是要用数据和事实打脸的。
比如:世界上第一个程序员就是女的叫 Ada,她不仅预言了通用计算机的可能,还发明了世界上第一个计算机程序。世界上第一台通用计算机 ENIAC 的编译和部署工作是由 6 位女程序员组成的团队完成的。把阿波罗送到月球的程序员也是女的,叫 Margaret Hamilton。微软 Halo 游戏引擎的主程也是女的,还是中国香港人,叫余国荔……另外,在中国的运动比赛上,女性运动员比男性运动员的成绩要好……
在各个公司,我看到更多的男性除了在使蛮力和搬砖上比女性要强,也没什么其他长项。如果认为写程序是劳动密集型的工种,当然是男性比女性好用。对了,你们这里是劳动密集型的公司吗?最后,我认为,就对女性尊重方面还是国外公司做得好。所以,建议女程序员还是要去国外公司工作。
最后,我想说一下,回答尖锐问题你会有两种方法,一般是比较官方的,像外交或是政治词令,另一种是比较诚恳的、真实的。虽然两者都可以,但是我觉得后者更好一些。因为那是能打动人的。对于一些不礼貌的问题,我觉得你要站在更高的维度教育他们,这样才会显得他们的 low。

结尾问题

一般来说,面试结束的时候,都会问你有没有什么问题。不要放弃这个机会。
如果你面得比较好,这个时候可以问几个尖锐的问题,这样有利于后面谈 offer 和岗位(抓住机会反转被动为主动)。比如,我就问过国外某一线公司的面试官下面两组问题:
你们公司有多少一线开发经理还在写代码?你们的一线经理都没有时间来写代码了,不知道细节怎么做好管理?另外是不是说明你们公司有大量的内耗?
任何公司都有好的有不好的,你能不能分享一下你最喜欢这个公司的地方和最不喜欢的地方?
基本上来说,面试官都会被我问住,然后开始语塞。能让说英语母语的老外在我这个英文一般的人面前说不清话,我还是很满足的。哈哈哈。当然,也不一定是非要像我这么尖锐地问问题,你也可以设计几个柔和一点儿的问题。总之,问这样问题的目的是,暗示一下对方,我来不来还不一定呢,也别想压低我的 offer,你们公司也不是什么都好,要想让我来,得再加点……(嘿嘿嘿)
如果你面得一般,这个时候你也可以问些加分的问题。比如:目前贵公司或是贵团队最需要解决什么样的问题?我能帮贵公司做些什么?能不能给我一些资料我先了解一下,这样我后面如果能进来,就能上手更快一些了。因为你面得一般的话,面试官会比较犹豫和纠结,此时你需要让面试官不要犹豫,所以,你可以表现得更加热情和主动一点。你看,竟然一副通过面试明天就要上班的“无耻嘴脸”也会为你加点分的……(哈哈哈)
如果你面得很不行,基本挂掉了。这个时候,也要问问题。但最好问一下面试官对你的评价,并且让他指出你的不足和需要改进的地方。面试本来就是一次经历和一次学习,你也可以把其当作是一种受教育的过程。所以,不要放过自己可以成长的机会。通过面试官给你的评价,你日后就知道自己需要努力的地方和方向了。这是多好的一件事儿啊。

小结

总结一下今天的内容。我认为,形象和谈吐对于面试成功与否非常重要。着装方面一定要大方得体,干净整洁;谈吐方面一定要自信从容,能够清楚准确地表达自己的观点和想法。随后是如何面对一些答不上来的问题,如何回答尖锐问题,以及在面试结束之后,如何提问,为自己争取福利或者机会。
下一篇文章,我们将谈谈国内外公司的面试风格,知己知彼,更好地做面试准备。敬请期待。

97 | 高效学习:源头、原理和知识地图


有了上一篇文章中分享的那些观点,我们来看看应该怎么做。下面是我觉得比较不错的一些学习的方法,或者说对我来说最有效的学习方法。我相信,只要你和我一样,做到的话,你的学习效率一定能够提升很快。

挑选知识和信息源

还是我在《程序员练级攻略》中说的那样,英文对于我们来说至关重要,尤其是对于计算机知识来说。如果你觉得用百度搜中文关键词就可以找到自己想要的知识,那么你一定远远落后于这个时代了。如果你用 Google 英文关键词可以找到自己想要的知识,那么你算是能跟得上这个时代。如果你能在社区里跟社区里的大牛交流得到答案,那么你算是领先于这个时代了。

但我想通过这些简单链接的方式,为我的读者打开一个全新的世界,他们可以在这个世界中自己找食吃,而不需要依赖我,这才是我想给大家带来的东西。我不知道,我的那些推荐文章,有没有让你看到了一个很广阔的世界,在那里,每天都在产生很多最新、最酷、最有营养的一手信息,而不是被我或他人消化过的二手信息。

注重基础和原理

我在很多的场合都提到过,基础知识和原理性的东西是无比重要的。这些基础知识就好像地基一样,只要足够扎实,就要可以盖出很高很高的楼。正所谓“勿在浮沙筑高台”。我说过,很多人并不是学得不够快,而他们的基础真的不行。基础不行,会影响你对事物的理解,甚至会让你不能理解为什么是这样。当你对事物的出现有不理解的东西时,通常来说,是因为你的基础知识没有跟上。
最最关键的是,这些基础知识和原理性的东西和技术,都是经历过长时间的考验的,所以,这些基础技术也有很多人类历史上的智慧结晶,会给你很多启示和帮助。比如:TCP 协议的状态机,可以让你明白,如果你要设计一个异步通信协议,状态机是一件多么重要的事,还有 TCP 拥塞控制中的方式,让你知道,设计一个以响应时间来限流的中件间是什么样的。

使用知识图

从知识树的主干开始做广度或是深度遍历,于是我就得到了一整棵的知识树。这种“顺藤摸瓜”的记忆方式让我记住了很多知识。最重要的是,当出现一些我不知道的知识点时,我就会往这棵知识树上挂,而这样一来,也使得我的学习更为系统和全面。

这种画知识图的方式可以让你从一个技术最重要最主干的地方出发开始遍历所有的技术细节,也就是画地图的方式。如果你不想在知识的海洋中迷路,你需要有一份地图,所以,学习并不是为了要记忆那些知识点,而是为了要找到一个知识的地图,你在这个地图上能通过关键路径找到你想要的答案

98 | 高效学习:深度,归纳和坚持实践


系统学习

在学习某个技术的时候,我除了会用到上篇文章中提到的知识图,还会问自己很多个为什么。于是,我形成了一个更高层的知识脑图。下面我把这这个方法分享出来。当然学习一门技术时,Go 语言也好,Docker 也好,我都有一个学习模板。只有把这个学习模板中的内容都填实了,我才罢休。这个模板如下:
1 这个技术出现的背景、初衷和要达到什么样的目标或是要解决什么样的问题。这个问题非常关键,也就是说,你在学习一个技术的时候,需要知道这个技术的成因和目标,也就是这个技术的灵魂。如果不知道这些的话,那么你会看不懂这个技术的一些设计理念。
2 这个技术的优势和劣势分别是什么,或者说,这个技术的 trade-off 是什么。任何技术都有其好坏,在解决一个问题的时候,也会带来新的问题。另外,一般来说,任何设计都有 trade-off(要什么和不要什么),所以,你要清楚这个技术的优势和劣势,以及带来的挑战。
3 这个技术适用的场景。任何技术都有其适用的场景,离开了这个场景,这个技术可能会有很多槽点,所以学习技术不但要知道这个技术是什么,还要知道其适用的场景。没有任何一个技术是普适的。注意,所谓场景一般分别两个,一个是业务场景,一个是技术场景。
4 技术的组成部分和关键点。这是技术的核心思想和核心组件了,也是这个技术的灵魂所在了。学习技术的核心部分是快速掌握的关键。
5 技术的底层原理和关键实现。任何一个技术都有其底层的关键基础技术,这些关键技术很有可能也是其它技术的关键基础技术。所以,学习这些关键的基础底层技术,可以让你未来很快地掌握其它技术。可以参看我在 CoolShell 上写的 Docker 底层技术那一系列文章。
6 已有的实现和它之间的对比。一般来说,任何一个技术都会有不同的实现,不同的实现都会有不同的侧重。学习不同的实现,可以让你得到不同的想法和思路,对于开阔思维,深入细节是非常重要的。
基本上来说,如果你按照我上面所提的这 6 大点来学习一门技术,你一定会学习到技术的精髓,而且学习的高度在一开始就超过很多人了。如果你能这样坚持 2-3 年,我相信你一定会在某个领域成为炙手可热的佼佼者。

举一反三

举一反三的道理人人都知道,所以,在这里我并不想讨论为什么要举一反三,而是想讨论如何才能有举一反三的能力。我认为,人与人最大的差别就是举一反三的能力。那些聪明的或者是有经验的人举一反三起来真是太令人惊叹。
我觉得一个人的举一反三能力,可以分解成如下三种基本能力。

1联想能力。
这种能力的锻炼需要你平时就在不停地思考同一个事物的不同的用法,或是联想与之有关的其他事物。对于软件开发和技术学习也一样。
2抽象能力。
抽象能力是举一反三的基本技能。平时你解决问题的时候,如果你能对这个问题进行抽象,你就可以获得更多的表现形式。抽象能力需要找到解决问题的通用模型,比如数学就是对现实世界的一种抽象。只要我们能把现实世界的各种问题建立成数据模型(如,建立各种维度的向量),我们就可以用数学来求解,这也是机器学习的本质。
3 自省能力。
所谓自省能力就是自己找自己的难看。当你得到一个解的时候,要站在自己的对立面来找这个解的漏洞。有点像左右手互博。这种自己和自己辩论的能力又叫思辨能力。将自己分裂成正反方,左右方,甚至多方,站在不同的立场上来和自己辩论,从而做到不漏过一个 case,从而获得完整全面的问题分析能力。

在这方面,我对自己的训练如下。

  1. 对于一个场景,制造出各种不同的问题或难题。
  2. 对于一个问题,努力寻找尽可能多的解,并比较这些解的优劣。
  3. 对于一个解,努力寻找各种不同的测试案例,以图让其健壮。

总结和归纳

对自己的知识进行总结和归纳是提高学习能力的一个非常重要的手段。这是把一个复杂问题用简单的语言来描述的能力。就像我小时候上学时,老师让我们写文章的中心思想一样。这种总结和归纳能力会让你更好地掌握和使用知识。
也就是说,我们把学到的东西用自己的语言和理解重新组织并表达出来,本质上是对信息进行消化和再加工的过程,这个过程可能会有信息损失,但也可能会有新信息加入,本质上是信息重构的过程。

我们积累的知识越多,在知识间进行联系和区辨的能力就越强,对知识进行总结和归纳也就越轻松。而想要提高总结归纳的能力,首先要多阅读,多积累素材,扩大自己的知识面,多和别人讨论,多思辨,从而见多识广。

不过,我们需要注意的是,如果只学了部分知识或者还没有学透,就开始对知识进行总结归纳,那么总结归纳出来的知识结构也只能是混乱和幼稚的。因此,学习的开始阶段,可以不急于总结归纳,不急于下判断,做结论,而应该保留部分知识的不确定性,保持对知识的开放状态。当对整个知识的理解更深入,自己站的位置更高以后,总结和归纳才会更有条理。总结归纳更多是在复习中对知识的回顾和重组,而不是一边学习一边就总结归纳。

我们来总结一下做总结归纳的方法:把你看到和学习到的信息,归整好,排列好,关联好,总之把信息碎片给结构化掉,然后在结构化的信息中,找到规律,找到相通之处,找到共同之处,进行简化、归纳和总结,最终形成一种套路,一种模式,一种通用方法。

实践出真知

实践是很累很痛苦的事,但只有痛苦才会让人反思,而反思则是学习和改变自己的动力。Grow up through the pain, 是非常有道理的。

坚持不懈

坚持是一件反人性的事,所以,它才难能可贵,也更有价值。也更有价值。我从 2003 年写 blog 到今天 15 年了,看书学习写代码,我都会一点一点的坚持。人不怕笨,怕的是懒,怕的是找到各种理由放弃。
坚持也不是要苦苦地坚持,有循环有成就感的坚持才是真正可以持续的。所以,一方面你要把你的坚持形成成果晒出来,让别人来给你点赞,另一方面,你还要把坚持变成一种习惯,就像吃饭喝水一样,你感觉不到太多的成本付出。只有做到这两点,你才能够真正坚持。

小结

总结一下今天的内容。我分享了系统学习、举一反三、总结归纳、实践出真知和坚持不懈等几个方面的内容。
在系统学习中,我给出了我学习时用的学习模板,它不但有助于你学习到技术的精髓,更能帮你提升你的学习高度。坚持几年,你一定能在某个领域成为炙手可热的佼佼者。
在举一反三中,我分享了如何获得这种能力的方法。
在总结和归纳中,我指出,积累的知识越多,在知识间进行联系和区辨的能力越强,总结归纳的能力越强,进而逐渐形成在更高维度上思考问题的能力。
在实践出真知中,我阐明了实践的重要性,并认为,只有实践过,才能对学到的东西有更深的体会。

最后,我强调,虽然学习方法很重要,但坚持不懈更为重要,并给出了怎样做才能让自己对学习这件反人类的事儿坚持不懈。

100 | 高效学习:面对枯燥和量大的知识

如何面对枯燥的知识

首先,我们要知道,为什么会有枯燥的知识?一般来说,枯燥的东西通常是你不感兴趣的东西,而你不感兴趣的东西,可能是你并不知道有什么用的东西。这样的知识通常是比较底层或是抽象度比较高的知识,比如:线性代数,或者一些操作系统内部的原理……越理论的东西就越让人觉得枯燥。
我列举我的这个学习过程,就是想说,如果你发现有些知识太过于枯燥,那么可以通过下面的方法解决。

  1. 这个知识对于你来说来太高级了,你可能不知道能用在什么地方。
  2. 人的认知是从感性认识向理性认识转化的,所以,你可能要先去找一下应用场景,学点更实用的,再回来学理论。
  3. 学习需要有反馈,有成就感,带着相关问题去学习会更好。
  4. 当然,找到牛人来给你讲解,也是一个很不错的手段。

    如何面对大量的知识

    看过《程序员练级攻略》的朋友们,一定会有这样的疑问,东西太多了,怎么学。我给你的建议是,一点一点学,一口一口吃。你可以使用我前面说过的那些方法,注重基础,画知识图,多问为什么,多动手,然后坚持住,哪怕你每周就学一个知识点,你一年也可以学到 50 个知识点。只要你在进步,总有一天可以把这些知识学到手的。
    当然,你的目的不是学完这些知识,因为学无止境,你永远也学不完,所以你在学习时,一定不要学在表面上,一定要学到本质,学到原理上,那些东西是不容易变的,也是经得住时间考验的。把学习当成投资,这是这个世界上回报最好的投资。
    带着问题去学习,带着要解决的东西去学习,带着挑战去学习,于是每当你解决了一个问题,做了一个功能,完成了一个挑战,你就会感到兴奋和有成就感。这样,你也就找到了源源不断的学习驱动力。
    把你学习的心得、过程、笔记、代码分享出来,找到和你一同学习的人,因为一个人长跑很辛苦,有人同行就会好很多,就算没有人同行,你的读者,你的观众也会为你鼓掌加油,这些也是让你持续前行的动力。
    人的一生是要永远学习的。加油!

其它几个实用的技巧

用不同的方式来学习同一个东西。比如:通过看书,听课,创建脑图,写博客,讲课,解决实际问题,等等。

  1. 不要被打断。被打断简直就是学习的天敌,所以,你在学习的时候,最好把手机设置成勿扰模式放在一边,然后把电脑上的所有通知也关掉,最好到一个别人找不到你的地方。
  2. 总结压缩信息。当你获得太多的信息时,你需要有一个“压缩算法”。我常用的压缩算法是只关心关键点,所以,你需要使用表格、图示、笔记或者脑图来帮助你压缩信息。
  3. 把未知关联到已知。把你新学的知识点关联到已知的事物上来。比如,你在学习 Go 语言,你就把一些知识关联到自己已经学过的语言上比如 C 和 Java。通过类比,你会学得更扎实,也会思考得更多。
  4. 用教的方式来学习。你想想,如果你过几天要在公开场合对很多人讲一个技术,那么这个压力会让你学得更好。因为要教给别人,所以,这么高的标准需要你不但要把自己已掌握的东西学好,还要把周边的也一并学了,才可能做到百问不倒。你才敢去教别人,不是么?(试试教 6 岁的孩子编程,如果你掌握了这种技能,那么你一定是把知识吃得非常透彻了。)
  5. 学以致用。把学到的东西用起来,没有什么比用起来能让你的知识更巩固的了。在实践中,你才会有更为真实的体会,你才会遇到非常细节和非常具体的问题,这些都会让你重新思考,或深化学习。
  6. 不要记忆。聪明的人不会记忆知识的,他们会找方法,那些可以推导出知识或答案的方法。这也是为什么外国人特别喜欢方法论。
  7. 多犯错误。犯错会让你学得到更多,通过错误总结教训,你会比没有犯过错的人体会得更深。但是千万不要犯低级错误,也不要同一个错误犯两次。

    结束语 | 业精于勤,行成于思


    不过,好在现在的人都被微博、微信、知乎、今日头条、抖音等这些 App 消费着(注意:我说的不是人在消费 App,而是人被 App 消费),然后英文还不行,科学上网也不行。所以,你真的不需要努力,只需要正常,你就可以超过绝大多数人。

你真的千万不要以为你订几个专栏,买几本书,听高手讲几次课,你就可以变成高手了。这就好像你以为你买了一个高级的机械键盘,27 吋的 4K 屏、高性能的电脑,高级的人体工程学的桌椅,你就可以写出好的代码来一样。我们要成为一个好的羽毛球高手,不是买几副好的运动装备,到正规的体育场去打球,而是要付出常人不能付出的汗水甚至伤痛。任何行业都是这样的。
这里,我还要把我《高效学习》中那个学习金字塔再帖出来。
image.png

再次强调一下,这个世界上的学习只有两种,一种是被动学习,一种是主动学习。听课,看书,看视频,看别人的演讲,这些统统都是被动学习,知识的留存度最多只有 30%,不信你问问自己,今天我的专栏中,你记住了多少?而与别人讨论,实践和传授给别人,是主动学习,其可以让你掌握知识的 50% 到 90% 以上。

我觉得大家应该要去自己读最源头的东西,源头的文章都有很多的链接,你也会有第一手的感受,这样你可以顺着找到更好的知识源,并组织出适合你自己的学习路径和地图。

这个世界不存在知识不够的情况,真的还没有到知识被少数精英的攥在手里面不给大家的情况,这个世界上的知识就像阳光和空气一样,根本不需要你付费,你就可以获得的。问题是,大多数人都失去了获取知识的能力,你就算把知识放在他们面前,他们也不会去学习,他们需要你喂,甚至需要你帮他们嚼碎了,帮他们消化过了,他们才能吃得到,消化得了。这才是最大的问题。不好意思,我又说实话了,难听但是对你有用。

另外,有很多知识我把其称作为“硬核知识”,这类的知识就像硬核桃一样,相当难啃。就像那些数学公式、计算机底层原理、复杂的网络协议和操作系统的调度等等,这些知识,你除了死磕之外,没有其它的办法。

我有微信交流群,我们的读友会群约定,你需要承诺,你可以每周完成一个 ARTS:
每周至少

  1. 做一个 leetcode 的算法题、
  2. 阅读并点评至少一篇英文技术文章、
  3. 学习至少一个技术技巧、
  4. 分享一篇有观点和思考的技术文章。

(也就是 Algorithm、Review、Tip、Share 简称 ARTS)你需要坚持至少一年。

加餐 | 谈谈我的“三观”


许是人到了四十多了,才敢写这么大的命题。不过,我还是想把我的想法记录下来,算是对我思考的一个“快照”(snapshot),给未来的我看看。我想这篇文章要么被未来的我打脸,要么打未来我的脸。但不管怎么样,我觉得对自己来说都很有意义。

我在标题中提到的“三观”指的是世界观、人生观和价值观:

  1. 世界观代表你是怎么看这个世界的,是左还是右,是激进还是保守,是理想还是现实,是乐观还是悲观……
  2. 人生观代表你想成为什么样的人,是成为有钱人,还是成为人生的体验者,是成为老师,还是成为行业专家,是成为有思想的人,还是成为有创造力的人……
  3. 价值观则代表你觉得什么对你来说更重要,是名是利,是过程还是结果,是付出还是索取,是国家还是自己,是家庭还是职业……人的三观其实是会变的,回顾一下我的过去,我感觉我的三观至少在这几个

人的三观其实是会变的,回顾一下我的过去,我感觉我的三观至少在这几个阶段有比较明显的变化:学生时代、刚走上社会的年轻时代、三十岁后、还有现在。估计其他人也都差不多吧。

学生时代的三观更多是学校给的,用各种标准答案给的。刚走上社会后发现完全不是这么一回事,但学生时代的三观已经在思想中根深蒂固,以至于三观开始分裂,内心开始挣扎。三十岁后,不如意的事越来越多,对社会越来越了解,有些人屈从现实,有些人不服输继续奋斗,有些人展露才能开始影响社会。此时我们分裂的三观开始收敛,而我属于还在继续奋斗的人。四十岁时,经历过的事太多,发现留给自己的时间不多了,世界太复杂,还有好多事没做,发现自己变得与世无争,也变得更加自我了。

面对世界

我深深感觉到,要有一个好的世界观,你需要亲身去经历和体会这个世界,而不是光听别人怎么说。

所以,到现在,我也不是很理解为什么国与国之间硬要比个你高我低,硬要分个高下,争个输赢。世界都已经发展到全球化的阶段了,很多产品早就是你中有我,我中有你的情况了。举个例子,一部手机中的元件,可能来自全世界数十个国家,我们已经说不清楚一部手机究竟是哪个国家生产的了。既然整个世界都在以一种合作共赢的姿态运作,我们就认准自己的位置,拥抱世界,持续向先进国家学习,互惠互利,不好吗?

我对国与国之间关系的态度是,有礼有节,不卑不亢,对待外国人,有礼貌但也要有节气,既不卑躬屈膝,也不趾高气昂。整体而言,我并不觉得我们比国外有多差,也不觉得我们比国外有多好。我们还在成长,还需要帮助与协作,俗话说“四海之内皆兄弟”,无论在哪个国家,在老百姓的世界里,哪有那么多矛盾。有机会多出去走走,多结交几个其它民族的朋友,你会觉得,在友善和包容的环境下,你的心情和生活可以更好。

你可能会说,不是我们不想这样,是别的国家不容许我们发展。老实说,大的层面我也感受不到,但就我所在的互联网计算机行业而言,我觉得世界的开放性越来越好,开源项目空前的繁荣,互联网文化也空前的开放。在计算机和互联网行业,我们享受了太多开源和开放的红利,别人不开放,我们可能在很多领域还落后数十年

随着自己经历越来越多,也发现这个世界越来越复杂,自己越来越渺小,这个世界有它自己的运作规律和方法,还有很多事情超出了我能理解的范围,更超出了我能控制的范围。

面对社会

在网上与别人争论观点或事情,我觉得越来越无聊,以前被怼了,一定要怼回去,可现在不会了,视而不见。不是怕了,是因为在我看来,网络上的争论大多数都没有章法且逻辑混乱。

  1. 很多讨论不是针对事,而是直接骂人,随意给人扣帽子。
  2. 非黑即白,你说这个不是黑的,他们就会把你划到白的那边。
  3. 漂移观点,复杂化问题,东拉西扯,牵强附会,还扯出其它不相关的事来混淆。
  4. 杠精很多,不关心你的整体观点,抓住一个小辫子就大作文章。

很明显,与其花时间教育这些人,不如花时间提升自己,让自己变得更优秀,这样就有更高的可能性去接触更聪明、更成功、更高层次的人。因为,一方面,你改变不了他们,另一方面,改变他们对你自己也没什么意义,改变自己,提升自己,让自己成长才有意义。时间是宝贵的,而那些人根本不值得你浪费时间,你应该花时间去结交更聪明、更有素质的人,做更有价值的事。 美国总统富兰克林·罗斯福的妻子埃莉诺·罗斯福(Eleanor Roosevelt)说过:
Great minds discuss ideas(伟人谈论想法)
Average minds discuss events(普通人谈论事件)
Small minds discuss people(庸人谈论他人)
把时间多放在一些想法上,对自己、对社会都是有意义的,而把时间用来八卦别人,说长道短,你既不可能改善自己的生活,也不会让你有所成长,更不会提升你的影响力。记住,你的影响力不是你对别人说长道短的能力,而是体现在有多少人信赖你并希望得到你的帮助。因此,多交一些有想法的朋友,多把自己的想法付诸实践,哪怕没有成功,你的人生也会比别人过得有意义。

如果你看过我以前的博客,你会发现一些吐槽性质的文章,但后面就再也没有了,我也不再针对具体的某个人做出评价。因为人太复杂了,经历越多,你就会发现你很难评价人,与其花时间在评论人和事上,不如花时间做一些力所能及的事来改善自己或身边的环境。所以,我建议大家少一些对人的指责和批评,多通过一件事来引发你的思考,想一想有什么可以改善的地方,有什么方法可以做得更好,有哪些是自己可以添砖加瓦的?你会发现,只要你坚持这么做,你个人的提升以及对社会的价值会越来越大,你的影响力也会越来越大。

面对人生

《教父》里有这样的人生观:
第一步要努力实现自我价值
第二步要全力照顾好家人
第三步要尽可能帮助善良的人
第四步为族群发声
第五步为国家争荣誉。
事实上作为男人,前两步成功,人生已算得上圆满,做到第三步堪称伟大,而随意颠倒次序的那些人,一般不值得信任。这也是古人的“修身齐家治国平天下”!所以,在你我准备开始“平天下”的时候,也得先想想,自己的生活有没有过好,家人照顾好了么,身边有哪些事是自己力所能及可以去改善的。

穷则独善其身,达则兼济天下。提升自己,照顾好自己的家人,尽己所能帮助身边的人,这已经很不错了!

什么样的人干什么样的事,什么样的阶段做什么样的选择。有人说,选择比努力更重要,我深以为然,而且,我觉得选择和决定,比努力更难。努力是认准了一件事后不停地发力,而决定要认准哪件事作为自己坚持和努力的方向,则是令人彷徨和焦虑的(半途而废的人也很多)。面对人生,你每天都在做一个又一个的决定,在做一个又一个的选择,有的决定大,有的决定小,你的人生轨迹就是沿着这一个一个的决定和选择走出来的。

我在 24 岁放弃房子,离开银行到小公司上班的时候,就知道人生的选择是一个翘翘板,你选择这一头就不能坐上另一头,选择是有代价的,而不选择的代价更大;
选择是要冒险的,你不敢冒险时风险可能更大;
选择是需要放弃的,鱼和熊掌不可兼得。想想等你老了回头看时,好多事情在年轻的时候不敢做,可你再也没有机会了,你就知道不敢选择、不敢冒险的代价有多大了。选择就是一种权衡( trade off),这世上根本不会有什么完美,只要你想做事,有雄心壮志,你的人生就是一个坑接着一个坑,你所能做的就是找到你喜欢的方向跳坑。

因此,你要想清楚自己要什么,不要什么,而且还不能要得太多,这样你才好做选择。否则,影响决定的因子太多,决定就不好做,也做不好。
正如本文开头说的那样,你是激进派还是保守派,你是喜欢领导还是喜欢跟从,你是注重长期还是注重短期,你是注重过程还是注重结果……你对这些东西的坚持和守护,成为了你的“三观”,而你的三观影响着你的选择,你的选择影响着你的人生。

价值取向

下面是一些大家经常在说,可能也是大多数人关心的问题,就这些问题,我也谈谈我的价值取向。

1. 挣钱。

挣钱是一件大家都想做的事,但你得解决一个很核心的问题,那就是为什么别人愿意给你钱?对于挣钱这件事的看法,我从大学毕业到现在都没怎么变过,那就是我更多关注怎么提高自己的能力,让自己值那个价钱,让别人愿意付钱。另外,我发现越是有能力的人,就越不计较一些短期得失,越计较短期得失的人往往都是很平庸的人。

有能力的人不会关心自己的年终奖得拿多少,会不会晋升,他们更关心自己的实力有没有超过更多人,更关注自己长远的成长,而不是一时的利益。聪明的人从不关心眼前的得失,不关心表面上的东西,他们更关心的是长期利益,关心长期利益的人一定不是投机者,而是投资者,投资者会把时间、精力、金钱投资在能让自己成长与提升的地方,能让自己施展本领与抱负的地方,他们培养自己的领导力和影响力。而投机者则是在职场溜须拍马、讨好领导,在学习上追求速成,在投资上使用跟随策略,在创业上甚至会不择手段。当风险来临时,投机者是几乎没有任何抗风险能力的,他们所谓的能力只不过是因为形势好。

2. 技术。

对于计算机技术来说,要学的东西实在是太多,我并不害怕要学的东西很多,因为学习能力是一个好的工程师必需具备的能力,所以我不惧怕困难和挑战。我觉得争论语言和技术谁好谁坏是一种幼稚的表现, 没有完美的技术,工程(Engineering )玩的是权衡( trade off)。所以,我对没有完美的技术并不担心,我担心的是,当我们进入一家公司后,这家公司会有一些技术上的沉淀,也就是针对公司自己的专用技术,比如一些中间件,一些编程框架,lib 库什么的。

老实说,我比较害怕公司的专用技术,因为一旦失业,我建立在这些专用技术上的技能也会随之瓦解,有时候,我甚至害怕把我的技术建立在某一个平台上,小众的不用说了,大众的我也比较担扰,比如 Windows 或 Unix/Linux,因为一旦这个平台不流行或是被取代,那我也会随之被淘汰(过去的这 20 年已经发生过太多这样的事了)。为了应对这样的焦虑,我更愿意花时间在技术的原理和技术的本质上,这导致我需要了解各种各样的技术的设计方法以及内在原理。所以,在国内绝大多数程序员们更多关注架构性能的今天,我则花更多的时间去了解编程范式,代码重构,软件设计,计算机系统原理,领域设计,工程方法……只有原理、本质和设计思想才可能让我不会被绑在某个专用技术或平台上,除非我们人类的这条计算机之路没走对。

3. 职业。

在过去 20 多年的职业生涯中,我从基层工程师做到管理,很多做技术的人都会转管理,但我还是扎根技术,就算是在今天,还是会抠很多技术细节,包括写代码。一方面,我觉得不写代码的人一定是做不好技术管理的,技术管理要做技术决定,而从不上手技术的人是做不好技术决定的,另一方面,我觉得管理是支持性工作,不是产出性工作,大多数管理者无非是因为组织大了,需要管人管事,所以要花大量的时间和精力处理各种问题,甚至办公室政治。然而,如果有一天失业了,大环境变得不好了,一个管理者和一个程序员要出去找工作,程序员会比管理者更能自食其力。因此,我并不觉得管理者这个职业有意思,我还是觉得程序员这个有创造性的职业更有趣。通常来说,管理者的技能需要到公司和组织中才能展现,而有创造性技能的人则可以让自己更加独立。相比之下,我觉得程序员的技能可以让我更稳定更自由地活着。所以,我更喜欢“电影工作组”那样的团队和组织形式。

4. 打工。

对于打工,也就是加入一家公司工作,无论是在小公司还是大公司工作,都会有利有弊,任何公司都有其不完美的地方,这个需要承认。首先我必须完成公司交给我的任务(但我也不会是傻傻地完成工作,对于一些有问题的任务我也会提出我的看法)。然后,我会尽我所能找到工作中可以提高效率的地方,并改善它。在推动公司 / 部门 / 团队在技术与工程方面进步并不是一件很容易的事,因为进步是需要成本的。有时候,这种成本并不一定是公司和团队愿意接受的。

另外,从客观规律上来说,某件事的进步一定会和现状有一些摩擦。有的人害怕摩擦而选择忍耐,我则不是,我觉得与别人的摩擦并不可怕,因为大家的目标都是基本一致的,只是做事的标准和方式不一样,这是可以沟通和相互理解的。反而,如果没有去推动这件事,我觉得对于公司或对于我个人来说,都是一种对人生的浪费。敬业也好,激情也好,其就是体现在你是否愿意冒险去推动一件于公于私都有利的事,而不是成为一个“听话”、“随大流”、“懒政”的人,这样即耽误了公司也耽误了自己。所以,我更信仰的是《做正确的事情,等着被开除》,这些东西,可参看《我看绩效考核》,以及我在GitChat 上的一些问答。

5. 创业。

前两天,有个小伙跟我说,他要离开 BAT 去创业公司了,他觉得在那里更自由一些,没有大公司的种种问题。我毫不犹豫地教育了他。我说,你选择这个创业公司的动机不对啊,你无非就是在逃避一些东西罢了,你把创业公司当做一个避风港,这是不对的,因为创业公司的问题可能会更多。去创业公司更好的心态是,这个创业公司在干的事业是不是你的事业?说白了,如果你是为了你的事业,为了解决个什么问题,为了改进个什么东西,那么,创业是适合你的,也只有在做自己事业的时候,你才能不惧困难,勇敢地面对一切。那种想找一个安稳的避风港的心态不会让你平静,你要知道世界本来就是不平静的,找到自己的归宿和目标才可能让你真正平静。

正因如此,在我现在的创业团队,我不要求大家加班,我也不灌洗脑鸡汤,对于想要加入的人,我会跟他讲我现在遇到的各种问题以及各种机遇,并让他自己思考,我们在做的事情是不是他自己的事业诉求?还可不可以更好?每个人都应该为自己的事业、为自己的理想去活一次,追逐自己的事业和理想并不容易,需要有很大付出,也只有你内心的那个理想才值得这么大的付出……

6. 客户。

基于上述的价值观,我现在创业面对客户时,并不会完全迁就客户,我的一些银行客户和互联网客户应该体会到我的做事方式了。虽然用户要什么我就给什么,用户想听什么我就说什么,这样更圆滑,可以省很多精力,但这都不是我喜欢的。我更愿意鲜明地表达我的观点,并拉着用户跟我一起成长,因为我并不觉得完成客户的项目有成就感,我的成就感来自于客户的成长。所以,面对客户做得不对的、有问题有隐患的地方,我基本上都是直言不讳地说出来。因为我觉得把真实的想法说出来是对客户、对自己最基本的尊重,不管客户最终的选择是什么,我都要把利弊跟客户讲清楚。我并不是在这里装,因为,我也想做一些更高级、更有技术含量的事。所以,对于一些还未达到我预期的客户,如果我不把他们拉上来,我也对不起自己。

最后,对于我“不惑之年”形成的这些价值观体系,也许未来还会变,也许还不成熟,总之,我不愿跟大多数人一样,因为大多数人都是随遇而安或随大流的,他们觉得这样做风险最小,而我想走一条属于自己的路,做真正的自己。就像我 24 岁从银行里出来时想的那样,我选择了一个正确的专业(计算机科学),待在了一个正确的年代(信息化革命),这样的“狗屎运”几百年不遇,如果我还患得患失,那我岂不辜负了活在这样一个刺激的时代?!我只需要在这个时代中做有价值的事就好了!