目录

大学四年,如何成为还算不错的程序员?

1、问题

经常有些读者问我一些指导性的问题,让我冷不丁去回答,给出建议都是碎片化的,无法形成有效可落地的建议。

举个例子
  1. 我学习什么能进入优秀的互联网公司工作?
  2. 我现在大X,我想做软件研发我应该学习什么?

众所周知,这问题就像你问学霸说你这么厉害一样让人难以回答。我作为一个资质和背景平凡的软工本科学生,经过大学自己摸索和不断试错,毕业开始在百度从事研发工作。其实,我当时也有很多类似的疑惑,在这里给大家讲讲我的踩坑历程。

记忆中,我当年逛知乎、求助高人、甚至我的导师,都很难给出一个可执行落地的建议。除此之外,在我那种普通的双非学校,知名企业都不会去咱学校校招,进大厂是件不容易的事情,需要花很多时间去探索和学习技术。

作为探路者,求助知乎和论坛,给出的结论几乎都是好好学习数据结构/算法、现在大数据很火你应该学学Hadoop/Spark、你要是会微服务、docker、k8s一定会很加分。

让我想起了我当年问学霸考试题目如何解?学霸说:这个题目是来源于第X章第X例题,你这样解,答案就出来了,很容易的。至于为什么他能想到,鬼也不知道。

当时,我真的是花里胡哨的啥都学,啥都去倒腾,不知道是不是梁静茹给我的勇气。前端、后端技术栈、Hadoop/Spark、docker/k8s这些几乎都实操过,只是很多只是入门并没有深入研究,效果自然也十分有限。

这些概念,对于小白或者在校生来说,这仿佛在对说你不用学了,除非你天生技术欲望特别强烈。这对于大多数普通人来说,明显是劝退的节奏,可操行十分有限,几乎没有参考价值,不知道从何下手。

其实,道理是没有错的,多研究底层和热门技术栈是有益的。但是,脱离实际情况谈技术就是扯犊子,就像让中国男足拿世界杯冠军显然不符合实际,更应该是根据实际情况,做产出最大的事情,否则会信心全无。

接下来,我系统性拆分问题,在不同阶段应该「学什么」、「如何学」、「学到什么程度」,重点讲我当时遇到的问题,还有我是如何去思考的,最终如何解决的,思路比结论重要。

2、思路

首先,说说在大厂工作都是些什么样的人,他们当年都是背着什么光环混进去的?经过我的调研和分析,主要有如下五点指标。

举个例子
  1. 学历/专业、扎实专业基本功
  2. 有成果的科研经历
  3. 省/国家级软件设计大赛
  4. 丰富互联网公司实习经历
  5. 小有名气的开源项目经历

大概思路就是,要么你证明你令人信服的天赋如逻辑系统思维、聪明,让人觉得你可以被快速培养;要么你有丰富的工程实战经验,证明你具备优秀工程师的潜质。

当然,你可能会说这么多要求,恐怕神仙也做不到啊,简直太苛刻了。在这里,我想说的是并不是上述所有指标全部满足,只是满足其中2-3项能证明你的实力即可,毕竟面试时间十分有限必须有点让人信服的东西啊。

举个例子
  1. 假设你是上海交大、华中科大大学毕业的学生,你可能重点复习数据结构算法/计算机基础等专业知识,辅之把学校的科研经历着重阐述一下。可能进入什么腾讯阿里华为百度难度也不是很大,专业知识对于你们来说自己不再话下,毕竟这些都是你们的专长。
  2. 假如你是双非大学毕业的学生,那么你必须用国家级大赛、开源项目、互联网公司实习经历证明自己。总之,多做项目,专注于技术本身,让自己更早具备职业软件工程师的实战技能。

简而言之,你没有光环,那就比别人多努力点,提前做好职业规划,把时间投入技术本身不要投机取巧。

3、落地

鉴于上述分析,我们知道了需求是什么?对我们来说,应把精力重点投入到技术本身、精益求精。这时候,我们将遇到一系列问题。

  • 我应该做什么方向?(方向)
  • 我应该学习什么内容?(规划)
  • 我如何学这些内容?(方法/策略)
  • 我应该学到什么程度?(量化)
  • 如何把理论用到实际项目/产品中?(产出)

3.1、方向&规划

不同方向,意味着不同领域不同,学习的知识和实战项目有共性也有差异。在这里,我主要讲一下通用的思路。重点拿我擅长方向举例,其他方向可按照同样思路举一反三。

根据我的经验,可将内容分为原理、应用、擅长方向三个纬度。原理和应用纬度必须学习,方向纬度根据自己擅长方向深入学习。

https://cdn.jsdelivr.net/gh/piqiu96/aqiucdn/imgs/codelife/university/plan.png

原理:计算机网络、操作系统、数据结构/算法,这些东西都是专业课好好学即可,数据结构/算法日常多刷刷题,大不可必研究特么深入,待校招前留出时间来重点突击和复习即可。

应用:它是最基础的内容,不管你从事什么领域都将离不开它们。这也是小白入门重点花费时间的地方,你将在这里不断与程序斗争如调试、验证、异常、解决。

方向:不同方向本质上就是在基础应用上扩充,发挥它们擅长领域和特性去解决特定问题。

举个例子
  • 后端开发方向:数据库、缓存、消息队列、rpc、微服务
  • 大数据开发方向:Hadoop、Spark、Storm、Flink
  • 自动化运维方向:elk、ansible、zabbix、docker、k8s

3.2、方法&量化

基于上述分析,主要讲了整体思路,大家可能会觉得有点不太好理解。接下来,拿我当时遭遇的处境进行举例阐述,这样让不同水平或时期的同学有不一样的体会。

假设回到大学时代,我会先战略性放弃计算机组成原理、操作系统原理、计算机网络等原理课,只需上课硬着头皮听个大概脑子留个印象即可,毕竟我这种全是高大上的原理,每次上课就想睡觉。当然,数据结构/算法我还能好好听听,毕竟我数学功底还行让我不排斥。事实上,我当时就是这么做的。

为什么不先深入研究计算机基础原理?

假设你学骑自行车,你是直接上去就蹬?还是先把轮子拆下来研究清楚原理再去学习怎么蹬?根据我的经历,在新手阶段不管是接触新的语言,还是新的方向。最快的方式就是先把自行车蹬起来,等你蹬熟练了再去研究轮子是怎么造出来的。

根据上述策略,刨除我踩的一些坑,我把学习征途划分四个阶段,最终实现学习效率的最优解。

3.2.1、第一阶段:新手入门

在我入门的时候,我遇到的最大困难是代码不会写,DEBUG不会做,程序报错不会看毫无头绪,甚至大家常说的百度一下的关键字我也不知道搜。

这时候,最大的目标就是根据百度/查文档/看视频,把程序调试出预期结果,甚至你抄代码都行,很多时候抄代码你都不一定能DEBUG出预期结果。这就是现实,主要就是要把对编程的排斥消磨殆尽。

这个阶段,不需要太关注底层实现原理,最重要的工作就是把应用层面的技术,不断练习直到熟练掌握上面提到的应用纬度「 编程语言、Linux、数据库、HTTP网络协议 」。

  • 目标:会调试、会查文档、会用搜索引擎
  • 内容:JAVA基础语法、MYSQL数据库、Linux操作系统、HTTP通信协议
  • 方法:只关注如何使用技术,难以理解的背下来,不关注底层原理。
  • 成果:实现常见的管理系统模块,能部署在服务器上,供他人访问。

对于现已从事计算机行业的同学,其实这部分内容非常简单,可能按照正常水平少则几天,多则不超过一周就能开发出简单模块。简单说,它顶多是毕设设计水准,主要是让新手在感官上体验软件产品。本质上,在计算机世界里,抽象来看就是数据的计算、传输、存储。随着你的经验增多,你会发现很多技术都是诞生或优化性能都是在解决计算、存储、传输的问题。 在这里,主要让大家在系统的角度感受最简单、最初级的技术模型。

http://cdn.jsdelivr.net/gh/piqiu96/aqiucdn/imgs/codelife/university/simple2.png

  1. Linux操作系统:承载应用程序、数据库的运行,提供CPU供应用程序计算。
  2. 应用程序(Java/Python/Php):JAVA主要采用Servlet、JDBC承载网络的传输、数据库连接管理。
  3. 数据库(MySQL):主要理解关系类数据库的存储,对数据进行操作。
  4. HTTP/TCP:熟悉重点网络协议,它分为包头/包体进行传输,包体格式可能分为form、json、pb、二进制。

3.2.2、第二阶段:项目练习

通过第一个阶段学习,你对编程从一无所知到有所斩获,对计算机世界充满了好奇,甚至有所开心。这时候,你最应该做的就是去满足你装逼的梦想。

  • 假设你是爬虫方向,你应该去爬表情包、爬知乎数据、自动抢票,去满足你无数个装逼梦想。
  • 假设你是算法方向,你可以去研究推荐算法、图像识别模型,去做个商品推荐、人脸识秀一秀。
  • 假设你是后端方向,你可以去研究下网络编程/网站开发开发个仿微信聊天应用,体验下lowB版微信。

作为大学生,实验室、软件设计比赛、开源社区都是你发挥现象力的天堂,这些倒腾的经历将是你毕业时最宝贵的经历。

3.2.3、第三阶段:强化理论

经过前两个阶段实践,这时候你的软件开发水平已达到计算机毕设水平。同时,专业课如数据结构/操作系统/计算机网络也学的差不多了,对概念多多少少有初步了解。

这时候,你会发现很多原理你不懂,将很难更上一层楼。

  • 你不知道使用ArrayList还是LinkedList?
  • 你不知道为什么要使用线程池?
  • MySQL底层原理是什么样的?

你一直停留在写代码一时爽,一直写一直爽,从不考虑性能或规范,遇到难题就束手无策、程序直接土崩瓦解。所以,你不得不去学习理论知识让你走得更远。

问题:为什么在这个阶段强化理论知识?
在新手阶段去强化理论知识,会让你兴趣骤减且产生学了有何用的错觉。同时,这是最好的时机,学校专业课学完你有基础概念,你有实际软件应用场景,这些东西让你深挖理论的时候会快速给你构建起基础图谱,让你兴趣激增不断体验学会的东西,将戳痛你最痛的神经,瞬间把你以前遇到的问题有新的认知,这就是答案。简单说,面向问题,解决问题,让你实实在在感受到成长,这就是成就感的力量。

问题:如何高效的学习理论?

其实,编程语言和计算机基础都是相通的,只要你学透一门编程语言剩下的就大同小异。当然,计算机基础毕竟是枯燥无味的,学习毕竟是有方法的。站在编程语言角度,不管你用的是什么编程语言,你会发现不管什么编程语言,变来变去都是换了个花样在谈以下内容。

  • 程序结构(数据类型、控制语句、面对对象、异常处理)
  • 集合(list、set、map)
  • 网络编程(IO、BIO、NIO)
  • 并发编程(线程池)
  • 内存管理(jvm)

不管在面试还是技术探讨,重点考察的都是集合、网络通信、线程/线程池。源自于它跟计算机基础有紧密结合,你要优化它们你必须具备扎实基本功。基于我的研究经验,我建议大家在学习计算机基础的时候,不要因为理论而理论。你应该去通过编程语言源码去学习计算机基础,只学你当前认为最重要的。

举个例子:

  • 当我去学习数据结构/算法的时候,我会一边学习源码一边思考数据结构,这样就让我有实际应用场景不会因为理论而理论。我学习list、set源码的时候,我就学会链表、栈。我学习map的时候,我就学会了红黑树、散列表。
  • 当我去学习计算机网络的时候,我会一边学习socket的用法,学习Linux网络通信模型epoll,这样就重点把网络协议学会了。同时,很多应用场景极少的理论知识,我就粗略记忆或者跳过,这样就节约了很多时间。
  • 当我去学习线程/线程池的时候,我会学习锁机制、生产者/消费者模型这些操作系统原理的重要知识,跟编程语言中关联不大的我就粗略记忆。

3.2.4、第四阶段:深究专长

经过前面三个阶段的学习,你已经具备扎实基本功和项目实战经验。接下来,你需要做的就是更加的专业化,研究一些有生产意义的东西。如果你一直写学生管理系统,这些没有价值没有意义的东西,那么毫无意义。

这时候,你应该去互联网公司验证你学习的技能。除此之外,你可以去学习额外的成熟先进技术栈。这样,你就有实际业务经验,就有技术的宽度,同时又有深度,这就是你核心优势,毕竟算法/数据结构这些东西在竞争的时候大家都会。

画外音:去实习,最好去大厂实习,接受互联网软件开发的挑战。要是不能,那么去研究实际企业技术栈的应用与底层研究。

举个例子:

假设你是后端开发,你就可以去学习微服务的技术栈,springboot、dubbo、docker、hadoop都可以去学习。除此之外,设计模式,redis原理都可以去学习研究,只有这样当你去面试的时候,你有很多话题和故事讲给别人听,你的专长研究既可以让你说业务场景,你又可以讲底层原理,对答如流。

4、成果

经过上面的训练,已经具备了解决问题、快速学习、编写代码能力,也就是具备软件工程师的职业素养和扎实基本功。

这时候,进入互联网公司开启职业道路,你将会很快有产出,不会陷入徘徊自闭的状态。更何况,你的职业素养已经能够让你遇到问题,能快速的学习克服困难。但是,要是让你去参加面试可不一定能独善其身,毕竟工作拧螺丝,面试造火箭可不能疏忽大意。

接下来,重点讲一下如何应对面试?

面试也就是把自己卖出去,让别人觉得你值。简历是至关重要的环节,所有的知识和技能全都是围绕它展开,否则毫无意义。因为在面试中,面试官关心你有什么,也就是面试完全围绕着你会的东西展开提问,所以你就把你的优势发挥到极致就行。

4.1、准备简历

简历一定要认真对待,一定要简介精炼,尽可能把内容压缩到一页,毕竟简历筛选就30秒不到。这时候,简历排版、简历字体、简历模板都有讲究,细节决定成败。

在写简历的时候,主要分为个人资料、实习经历、项目经历、专业技能。其实,没什么技巧,参考STAR原则,重点体现你在项目中的价值和思考。

  1. 要体现做了什么事情?
  2. 遇到什么困难?
  3. 怎么解决的?
  4. 产出是什么?

4.2、梳理知识体系

以前,学习知识是零散的,学习策略更多是面向解决问题,以至于知识不系统,表达逻辑层次有限。面试官逻辑思维强,所以你必须做好充足准备才能脱颖而出。

最好的策略就是梳理知识体系和准备面经,我们都知道要是你面试官问的问题是你刚好熟悉的问题,你岂不是轻松闯关成功?所以,准备考纲、梳理知识体系、疯狂刷题这就是最好的策略。

4.3、技术面试

按照互联网面试流程大多数分为三轮面。

一轮面试:主要是考察计算机基础知识和擅长语言基础知识,重点考察数据结构/算法、网络编程、擅长语言基础。但是,绝对不是死记硬背的东西,一定是深度和广度紧密结合,环环相扣直到把你肚子里的东西全部挖出来。

举个例子
  1. 获取链表倒数第N个节点的值,只许遍历一次。
  2. 有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M,返回频数最高的100个词。
  3. 谈谈HashMap,说下它们的数据结构?
  4. Key在HashCode取余以后,它可能全部堆积在某几个Key对应的链表上,这样就会造成该数据结构存储或者查询低效,那怎么解决呢?
  5. 为什么会链表要变成红黑树,什么时候从链表变成红黑树,什么时候从红黑树变回链表?
  6. 假设多个线程并发访问,那可能造成容器更新或者操作出现问题?
  7. 除了使用synchronized加同步锁,还有没有其他办法解决呢?
  8. 为什么采用CAS,能说一下ConcurrentHashMap的具体实现吗?

你会发现每个问题都是环环相扣,从简单到难,目的就是挖掘出你的极限。大多数情况都是,从数据结构/算法入手,扩展到编程语言特性,再扩展到并发/网络编程不断进行深挖。当直接问实际用法应试者答不出来的时候,就会再次引入到计算机基础知识,这样不断反复调度试探应试者的是深度和广度。

二轮面试:这轮考察实习/项目经历,重点考察你的面试储备。众所周知,大部分应届生项目经验十分有限,大多数是图书馆管理系统、电商系统这样。重点说一下应对策略,可以去网上找你做的项目可能遇到的领域难题,去找解决办法,最终扩展补充到你的项目中。

三轮面试:这轮面试更多是经理考察应试者的基础能力。也就是逻辑思维、抗压、时间管理等基础能力,看下是否能融入团队,毕竟适合团队的才是最好的。

总之,作为普通学校的同学,你只有花更加多的时间在项目实战中,实习/打比赛/逛开源社区,这些时间让你更快接近成为职业软件工程师。当机会来临的时候,你抓住机会就踏入大厂的大门了,幸运永远不会无缘无故眷顾你。