分享 Java、.NET、Javascript、效率、软件工程、编程语言等技术知识。
本文 GitHub TechShare 已收录,没有广告,Just For Fun。
零、前言
关于该文档
在不同的阶段要使用不同的学习方法,这里将学习分为两个阶段:从 0 到 1 的阶段、从 1 到 100 的阶段,本文主要讲这两个阶段的学习方式和相关资料。
另外这份文档侧重的是在长期如何学好,而非短期,短期要迅速上手使用某一技术,那可以采用其他的学习形式。
一、从 0 到 1
金字塔模型
在从 0 到 1 的阶段,需要采用金字塔模型的学习方法,即先深入学习基础原理,再向上学习应用层技术。举个栗子,比如一个初学者在java基础不扎实的情况下去学习 spring 框架,当看到 bean 的生命周期时,他是否能够很好地进行理解?这背后的思考可以引出一连串的问题,比如为何需要 IoC,为何默认是单例,DI 和单元测试之间有什么关系?对于初学者来说这些必然是很难理解透彻的,所以需要先打好基础。
时间成本
也可以从时间成本的角度去考虑这个问题,当在学习较为基础的知识的时候,不容易碰到难点,这个时候能够尽快吸收,每分钟的阅读效率更高。这是一个很朴素的道理,只是由于许多现实原因导致许多开发者没有很好的学习基础知识:计算机科学概论、编程语言入门、离散数学、数据结构与算法等等。
易学难精
在应用层的基础知识其实并不难,尤其是编程语言方面,也有一些同学很重视基础学习,但就是学的不够好,这里就涉及到学习编程的一个难点,即易学难精,对于面向对象语言而言,需要掌握的东西相对来讲是很少的,归根结底就是条件控制、循环、封装、继承、多态、多线程、语法等诸如此类,现在有许多的少儿编程培训班也可以佐证编程语言是易于学习的,难于精通在于这些基础知识本身就具有相当高的抽象层级,最早的计算机就是一个巨型的计算器,要使用计算器是简单的,但是一个问题为何要如此计算却可以是无比复杂的。
第一性原理
学习编程可以类比学习数学,那么如何才能学的更好,除了先学习基础知识外,在学习其上的内容的时候,还要时刻思考基础知识,这有点像马斯克提出的第一性原理,时刻剥开事物的表象,看到里面的本质,然后再从本质一层层往上走,数学学的好的人并不是靠死记硬背记公式,而是自己有能力推导出公式,同样编程学的好的人也并不是靠背 sdk,他们自己就可以设计出 sdk,那么当我们在学习 sdk、框架、技术工具的时候都可以进行逆向思考,jdk、spring 框架为何如此设计,它们是如何运用面向对象的三大特性?为何这三大特性可以演化出如此多的设计模式?看完一本基础理论书籍后不应该将其束之高阁,而是应当反复咀嚼,时刻保持思考,直至豁然开朗、融会贯通。
像产品迭代一样更新学习方法
学习的时候同时要不断更新「学习的方法」,使自己的学习方式得到迭代升级、提升效率,关于学习的书也有很多,比如《如何阅读一本书》、《学会提问》、《像加勒比海盗一样学习》、《思维导图》、《快速阅读》、《把时间当作朋友》等等,这些书让我们掌握更多学习方法论的同时也扩展了知识网络,正所谓磨刀不误砍柴工、万变不离其宗,多从不同的角度思考学习编程这件事情,提升学习能力并非一蹴而就,而是一件需要沉淀和积累的事情。
学习方向
有了金字塔这一基础的学习模型后,相对来讲不太容易走弯路,但技术道路千千万,还是要有一定的方向,否则容易在技术的道路上迷失。学习的方向跟个人兴趣关系也很大,因此这里仅列举一个大致的方向,仅供参考。
首先是基础知识。
计算机科学概论
- 计算机科学这门学科的总览,从深度和广度上展现这门学科的基本框架。
编程语言
- 《Java 编程思想》、《Java 核心技术》
- 入门时最需要的是一本由浅入深的书籍。
数据结构与算法
- 《数据结构与算法分析》、《算法导论》、《离散数学及其应用》
- 代码写的好与坏,数据结构和算法是根本。
计算机网络
- 《计算机网络:自顶向下方法》、《TCP/IP 详情》
- 在服务端开发领域,计算机网络的重要性不言而喻。
基础知识领域是非常广阔的,这里面也有纷繁复杂的问题,当碰到难懂的知识点时需要去补充更多的基础知识以便进行下一步学习,就像玩游戏一样,当你的等级还打不赢一个 boss 的时候就不要硬打,先去打打小怪补充点经验。
以上内容不需要全部学完才开始下一阶段,有了一定的基础之后可以开始学习应用层的知识,具体什么时候开始,这个就看基础知识的掌握程度,多从时间成本的角度思考,当学习效率不足的时候考虑去补充更多的基础理论知识。
应用层:
Web 开发
- 《Java Web 高级编程》
Spring 框架
- 《Spring 实战》、《Spring Boot 实战》
编程语言
- 《Java 并发编程实战》
再次说明,以上仅是简单的列举了一些学习点,关键还是围绕着自底向上这一思想进行学习,但并非把所有的底都铺好再往上学习,而是根据不同的领域,打不同区块的地基,在不同区块上垒高墙。
阅读经典
学习方向并非三言两语可以讲清楚的,因为这个方向本身在学习的过程中很容易产生变化,阅读的书籍会改变人的思维,其重要性不言而喻,市面上的书多如牛毛,伏尔泰说过图书馆是真理和谬误的宝库,如果读错了书,那不仅没有提升,还可能令自己退步,如何甄选好书其实不难,优先选择经典一般不会有错。现在是一个知识付费的时代,拥有知识比以往更容易变现,这衍生出一个问题,就是知识市场上存在质量参差不齐的「产品」,也存在大量的同质化,这些内容一般追求尽快见效,是不适合从 0 到 1 这个阶段的,经典则经过时间的考验,是最优质的知识来源。
学习方式
很多人不读经典,一部分原因是一些经典的书比较难以阅读,还有一些是因为通过其他方式学习更加轻松,比如看教学视频,看视频学习的节奏比较慢,头脑可以处在一个比较轻松的状态下去接收知识,不光要接收知识,还需要接收很多无用的信息,比如讲课老师的长时间停顿、演示等等,这些无形中消耗了时间成本。看视频学习需要视情况而定,即在学习艰深难懂的知识时才需要通过他人来讲解,我们最开始都是通过老师讲课来学习知识的,在读大学的时候应该已经能够形成较强的自学能力,在许多知识领域的学习上都不再需要他人教授。
根据所学知识的困难程度,选择适合自己的学习方式,优先读经典书籍,不要因为惰性而选择低效的学习方式。
学习质量
采用适当的学习方式是为了提升学习效率,但不要陷入一味追求速度的误区,在从 0 到 1 的阶段许多书都需要通读而非挑读,对书中的细节也不能忽略,经典的基础理论书籍需要慢慢阅读,而非快速阅读,在阅读的时候要辅以练习提升学习质量。
编程实战
在编程方面,遇见较难学习的知识点的时候,一个解决办法是去补充更多的基础知识,另一个方法是进行编程练习,可以找一些自己感兴趣的小项目进行实践,比如学到面向对象的时候,可以写一个简单的小游戏,定义游戏里面人物、怪物的对象模型,揣摩为何会由过程式编程转变为面向对象编程,这些自我实践在早期是非常重要的,可以加深学习理解,令自己不需要死记硬背。
兴趣是最好的老师
找自己感兴趣的项目也可以提升个人的编程兴趣,兴趣是最好的老师,当你兴趣越来越浓之时,苦学编程就变成了一种享受,当你写出一个网站、写出一个小游戏的时候,成就感会促使你继续学习,甚至激发你的潜能。
二、从 1 到 100
当已经入门编程这个领域之后,你应该能够感受到编程的魅力,也对其有了一个较为全面的认识,满足这两点后就进入接下来从 1 到 100 的过程,若不满足,则这个上升过程可能是会比较痛苦或者懈怠的,这时更需要时刻去巩固基础知识,更多的去发现编程有趣的地方,更全面的去认识编程。
在这个阶段差不多开始需要面对工作的问题,那首先从实用性的角度出发学习必备的知识技能,如数据库、设计模式等,再不断扩充知识广度,同时又时刻运用第一性原理去理清知识脉络。
挑选书籍
在第一个阶段,看的书不在多而在精,基础理论的经典书籍也更多,比如大家熟知的「Java 四大名著」,在 0 到 1 阶段的书比较容易挑选,而在这个阶段需要看的书则会更多,所以如何在学习之前做好准备工作,挑好书籍也是非常重要,有效地利用豆瓣、github,仔细翻阅书的目录,相同领域的书多加对比,直到挑选出适合自己的书后再开始阅读。
提升技术视野
学习多种编程语言可以提升编程能力,毕竟不同的编程语言的特性和设计还是有不少差别,可以从中吸纳别的编程语言的优点,除了学习同类范式的编程语言,还可学习不同范式的编程语言,比如函数式编程语言,除了这些常见的,还有逻辑编程语言、领域特定语言等。尽量学习一些差异跟 Java 较大的语言,比如 python、ruby,Python 之禅中提到「做一件事情有且只有一种方法」,而 ruby 则提倡做一件事情可以有多种方法,这些设计哲学背后可以引发一系列的思考。
Java 编程语言由于用户过多,所以在语法和版本上的更新是相对落后的,如果视野仅停留在这个领域,实际上是对自身存在一个比较大的限制。将其与 C# 对比也非常有意思,Java 中许多新的语言特性都是在跟随 C# 的脚步,有一些 C# 里面优秀的东西,在 Java 中很难找到替代品,比如 linq,Java 中有开源的 QueryDSL 项目,但跟这种语言级别的特性比起来确实逊色不少。
好奇心、探索欲和顺藤摸瓜
多学几门编程语言是提升技术视野的一个小的方面,要提升这种视野扩展的能力,具备好奇心和探索欲是必不可少的,当我们看到一本优秀的书籍的时候,里面一般会引用其他书籍,顺藤摸瓜地进行学习可以形成更好的知识脉络。
平衡的艺术
将新学习的语言与 Java 进行对比,出现设计上的差异必然是各有优缺点,在思考的过程中找到其中的平衡点是非常关键的,因为编程在许多情况下都需要权衡多种方案,阅读他人写的代码比较难的一个原因之一就是实现一个功能的方式有太多种了,而当能够得心应手地进行权衡的时候,脑海里会浮现出更优秀的方案,这时可选择性已经不多了,那整体的代码可读性也变高了,这便是 Python 之禅「做一件事情有且只有一种方法」的立意。这个设计跟 ruby 各有优缺点,但这一点显然是降低了开发时的认知负担和选择成本。
做减法,减少心智负担
学习了一定的知识后,容易出现一个现象,即拿着锤子看什么都像钉子,想挥一挥刚掌握的这把锤子,实际上在应用的时候是不可一股脑把会的技术都用上,必须学会做减法。举个例子,当我们学习了 ORM 框架之后,在简单的 CRUD 场景下不再需要写 SQL 语句,这便是一种减负,那由于 ORM 框架在处理复杂的聚合查询时是不那么透明的,需要很深入的学习才能写好一个高性能的复杂查询,那我们在运用 ORM 编写复杂查询的时候会增加很大的心智负担,不由地会思考一个问题,这个时候为什么不直接写 SQL 呢?这其实也是不断权衡的过程,当问题的复杂程度达到一个级别后,写 SQL 变成了一个更好的选择。学习是为了帮助我们减负,储备更多的知识则会有更明朗的选择。
注重工程实践
学习技术知识的同时,很多时候要将其与工程实践相结合,比如:接口优先原则能够使团队协作更加顺利,通过 git 提交代码要考虑代码审查和持续集成,单元测试为何要按运行快慢进行分类,这些都是技术需要与工程相结合的案例,结合思考才能更加全面,才能使软件开发更加敏捷。
用力思考/Think Harder
粗浅的编码工作是容易的,只需要浅显的思考就可完成,但对于艰深的问题,却需要我们 Think Harder,用力思考,想的更深入些,思考更多的可能性,自己提出问题,寻找答案,重复这一过程,直到想不出其他问题,编程需要的是非常缜密的思考,当用你的程序的用户越来越多的时候,可能性也越来越多,必须思考的足够周全。事务消息是一个深入思考的典型案例,即提出一个又一个的问题,最后便会出现浅显思考下不会出现的解决方案。还有像单元测试中为何需要 mock 框架,为什么 NoSQL 采用列式存储,都不是浅显思考所能想明白的,用力思考才会得到答案。
编程思想
要形成深厚的功力,需要我们用力思考、多元化投资知识资产,不是一朝一夕可以获得的,但我们可以透过现象去看本质寻求一个高效的提升方法。认知决定思想,那我们可以多看一些关于技术认知方面的书籍,比如《设计模式》、《代码大全》、《程序员修炼之道》、《Unix 编程艺术》这类的书籍。
建立技术分支
当编程已经成为你的职业之后,不能光按照个人兴趣来进行学习,需要考虑工作需要,有的人很重视主干技术的发展,当工作中需要用到其他技术时不去系统学习,将就着用,这在短期对自己影响不大,长期却造成了巨大的时间浪费,比如在部分公司 Java 后端开发偶尔需要做一些前端工作,那需要自己去衡量该如何学习以及学到何种程度,从投资回报率的角度去考虑这个问题,当由于没有系统学习导致自己在处理小问题时都花费大量时间时,那就应该去系统学习下,最终花费的时间更少,并且还建立了技术分支,在学习其他技术的时候,技术视野以及技术思维也能够提升。
像做投资一样管理知识资产
建立技术分支时可以从投资回报率的角度思考,那在知识资产的其他方面同样也适用。
严肃的投资者定期投资;多元化是长期成功的关键;聪明的投资者在保守的投资和高风险高回报的投资之间平衡他们的资产;周期性地重新评估和平衡资产。
谦虚是一把钥匙
笛卡尔说过,学的越多,越能发现自己的无知,萧伯纳也说,看的好书越多,越能发现自己的无知。这里再次提到好书的重要性,另外一个重点就是学习使人变强,但千万不能越学越傲慢,经常看好书的人比较少出现这种现象,反而是学习不到位的人容易出现,这里面隐含的一个逻辑就是我们毛主席说过的「谦虚使人进步」,在学习的道路上,谦虚是一把钥匙,谦虚的人往往看到的是他人的优点,汲取他人所长为我所用。文人相轻的现象切勿出现在技术领域,对于他人分享的一些知识、工具,多去了解,切莫先入为主,好的东西及时转化为自己的知识资产。
批判性思维
谦虚是一把钥匙,但也不能谦虚过头,我们搞代码的思考问题就是得如此审慎,谦虚促使我们向他人学习,但不能什么都接收,当然还是要取其精华去其糟粕。批判性思维运用得当在学习上也是大有脾益,现在互联网上各种知识分享、博客,那些全是对的吗?其中提出的一个观点是否经过验证,若有采取测试,那测试方法是否得当?必要的时候使用批判性思维。什么又是批判性思维呢,如何锻炼批判性思维呢?带着这些问题又可以迭代升级我们的学习方法了。
三、学习资料
大道至简,以上两部分内容是内功,可以使用上面的「学习大法」来运用下面给出的一些学习资料。
Java 相关学习资料
- Java 四大名著:《Java 编程语言》、《Java 编程思想》、《Java 核心技术》、《Effective Java》
- 《Head First Java》
- 《Java 并发编程实战》
- 《Java Web 高级编程》
- 《Java 8 实战》
- 《Spring 实战》、《Spring Boot 实战》
- 《Java 性能优化权威指南》
- 《深入理解 Java 虚拟机》
- 《Netty 实战》
- 《RxJava 响应式编程》
- 《单元测试的艺术》
- https://github.com/Snailclimb/JavaGuide
- https://github.com/lcomplete/SpringCloudLearning
- https://github.com/lcomplete/advanced-java
- https://github.com/lcomplete/technology-talk
- https://github.com/hollischuang/toBeTopJavaer
- https://github.com/xkcoding/spring-boot-demo
基础知识
- 《计算机科学概论》
- 《数据结构与算法分析》
- 《离散数学及其应用》
- 《计算机网络:自顶向下方法》、《TCP/IP 详解》
- 《现代操作系统》
- 《汇编语言》
- 《C 语言程序设计》
- https://github.com/lcomplete/CS-Notes
- https://github.com/wolverinn/Waking-Up
算法
- 《编程珠玑》
- 《编程之美》
- 《算法导论》
- https://github.com/azl397985856/leetcode
- https://github.com/MisterBooo/LeetCodeAnimation
- https://github.com/labuladong/fucking-algorithm
- https://github.com/greyireland/algorithm-pattern
编程思想
- 《设计模式》、《Head First 设计模式》、《反模式》
- 《代码整洁之道》
- 《编写整洁代码的艺术》
- 《重构》
- 《领域驱动开发》
- 《Unix 编程艺术》
- 《七周七语言》
数据库
- 《SQL 必知必会》
- 《高性能 MySQL》
- 《SQL 语言艺术》
- 《MySQL 技术内幕》
- 《Microsoft SQL Server 2008 技术内幕:T-SQL 查询》
- 《Microsoft SQL Server 2008 技术内幕:T-SQL 程序设计》
- 《SQL 反模式》
- https://github.com/lcomplete/Database-Series
- https://github.com/lcomplete/BigData-Notes
架构
- 《架构整洁之道》
- 《企业架构模式》
- 《微服务架构设计模式》
- 《Kubernetes in Action 中文版》
- https://github.com/lcomplete/architect-awesome
- https://github.com/rootsongjc/kubernetes-handbook
工程实践
- 《敏捷软件开发:原则、模式与实践》
- 《代码大全》
- 《人月神话》
- 《人件》
- 《持续交付2.0》
个人修炼
- 《程序员修炼之道》
- 《程序员的职业素养》
- 《高效程序员的 45 个习惯》
linux
- 《鸟哥的 linux 私房菜》
- 《Linux命令行与 shell 脚本编程大全》
技术相关
- 《黑客与画家》
- 《软件随想录》
- 《松本行弘的程序世界》
- 《编程人生》
- 《浪潮之巅》
学习之道
- 《如何阅读一本书》
- 《思维导图使用手册》
- 《学会提问》
- 《像加勒比海盗一样学习》
- 《把时间当作朋友》
- 《快速阅读》
- 《学习之道》
其他优秀资源
- 《精通正则表达式》
- https://github.com/lcomplete/free-programming-books-zh_CN
- https://github.com/Nepxion/DiscoveryGuide
- https://github.com/wuyouzhuguli/SpringAll
- https://github.com/julycoding/The-Art-Of-Programming-By-July
- https://github.com/wx-chevalier/Developer-Zero-To-Mastery
既然已经看到这里,不防点个赞, star 一下,github,没有广告,交个朋友 。