最近有很多学弟学妹问:大学学 Java 和 C++ 哪一个好找工做,学前端好仍是后端好,该学 Vue 仍是 React。。。前端
仿佛看到了本身当年的模样,单纯以一个计算机应届毕业生的身份聊聊,我认为大学四年,计算机科班学生应该学些什么,哪些才是重点。程序员
一样大学四年,为何有些同窗毕业就能成为大厂 Offer 收割机,各类 SP、SSP 拿到手软,有的同窗明明在学校写了好多网站,项目经历满满,经历春秋招,却找到一份工做都很难。正则表达式
不能说后者没认真学习,或许是用力的方向不对。算法
人类的知识边界一直在不断的扩张,俗话说学无止境,这放在计算机领域也一样适用,计算机自己是一我的造科学,不属于天然科学。sql
每一年,甚至每月都不断有新的编程框架推出,学到头秃你也学不完,也没有必要去挨个学。数据库
而且你会发现,不少一二线大厂内部用的东西基本都是本身搞一套的,好比服务发现、RPC、KV、DB、消息队列、日志、监控等等。编程
因此通常这些大厂招聘的时候基本不会因没学过某种框架而挂你,反正不少东西都是要进来从新学的。windows
他们会更加关注你的基础知识、解决问题的经验以及聪明度这种更加通用的能力上。后端
反而是一些小公司,可能会要求你必须会 Spring、Vue、Redis... 这些框架或者组件。浏览器
上面分别是腾讯、阿里、某外包公司的招聘 JD,显然,腾讯阿里看中的是扎实的编程基本功和快速学习能力,这意味着有培养潜力。
而外包公司就要求你会 xx 数据库、Spring 之类。不去评价哪一个好,可是若是你想去 BAT,那么是否是至少对照着它们的 JD 来提升本身的能力,不失为一种捷径。
在这里,我粗浅的把计算机编程领域的知识分为三个部分:
● 基础知识
● 特定领域知识
● 框架和开发技能
基础知识是指无论从事任何方向的软件工程师都应该掌握的,好比数据结构、算法、操做系统。
特定领域知识就是你从事某个细分方向时须要掌握的知识,好比作游戏引擎的须要掌握图形学;作前端的须要掌握浏览器渲染原理、前端三大件;算法工程师须要更多的数学知识。
毕竟计算机各类门类挺多的,须要选个细分方向专研下去,什么都学只会什么都不精(大佬除外啦。
如今大环境比较浮躁,不多有人愿意花心思在基础上,喜欢直接学 Python 搞机器学习、写秒杀、作商城。
找工做的时候都是想看面经、总结速成。
可是做为优秀的计算机系学生的你怎么能流于各类编程框架(造框架除外)?
把时间花在算法、基础学科上他不香吗?功利一点讲,回报反而会更大。
何况在计算机领域,不少基础的理论并不十分高深,咱们努努力就能够掌握其中的核心知识。
首先说明,这里把数学也列出来不是为了显得高端,而是本身吃过数学的亏。
若是你是自学转行当程序员,我固然不会推荐数学。
可是这篇文章主要面向的是还在大学的科班学生,这部分同窗之后也许会去作算法(CV、NLP之类)、游戏引擎、信息安全编码等
这些方向对数学要求就会偏高,在计算机领域线代、几率论、统计学这些数学分支相对比较重要,计算机本质上仍是离散的。
好比在机器学习或数据挖掘中经常用线性代数来下降数据维度,不少问题最终都能化为求解线性方程组。
因此为了不之后想走这些方向却被数学卡住,在大1、大二上数学课的时候就好好的学一下。
书到用时方恨少,不要如今觉得没用处就很差好学,等你须要的时候,就知道后悔了。(默默流下了不学无术的眼泪┭┮﹏┭┮
什么?你说之后肯定走开发方向?
那的确能够把数学优先级放后面一点,用得确实很少,不过上数学课的时候总该认真听下吧,拿个高绩点也是百利无一害嘛。说不许哪天你又想加入算法内卷大军呢?
你也许会很疑惑,这里明明说基础知识,为何要把一门编程语言单独列出来呢?
由于在我看来,没有比C语言更适合用来理解计算机系统了。
咱们后面将会提到的操做系统、体系结构 这些东西很是适合用 C 语言去理解或者去实践。
而且 C 语言自己的语言特性很是少,可是想学好又是不容易,不少人都以为C语言难,难在哪里呢?回想了一下我大一时的感觉:
✿ 简陋的标准库,几乎没有可用的数据结构;
✿ 指针很难理解和使用;
✿ 须要了解汇编、连接、装载、内存等才能把 C 语言用好。
不巧的是,这些东西正是计算机系统知识的一部分,因此用 C 语言做为学习计算机系统知识是最有效率的方式。
真的很难想象用 Java 或是 Python 去给别人讲解内存,由于这些语言抽象程度都比 C 语言高,意味着离计算机系统也就越远。
在 TIOBE 编程语言排行榜上,C语言几乎永远占据前三位,其地位天然毋庸置疑。
并且几乎你开发中用到的不少东西都是用C语言编写的,Linux、Nginx、Redis、MySQL、Git......或许你会想要探究下原理,阅读点这些开源软件的源码,那么 C 语言也是你必备的瑞士军刀。
深刻学习 C 语言,可以了解计算机底层的执行原理,是理解程序运行机制的绝佳语言,无出其右。
在这里,不得不引用对C语言最经典的总结:
任何比C语言更低级的语言,都不足以完整地抽象一个计算机系统; 任何比C高级的语言,均可以用C来实现。
这真是极高而中肯的评价!
因此对于计算机科班来讲,无论你是作前端仍是后端,算法仍是开发,C 语言都建议你好好学习。这是无关方向的一门语言,就是基础!
咱们编程的 IDE、写出来的程序所有都须要运行在操做系统上,说操做系统是计算机软件的基石也不为过。
程序运行起来就须要建立进程,这涉及到操做系统的进程管理;写程序须要定义变量、存储数据吧,这又涉及到内存,对应内存管理;有时候咱们还须要读写文件,这又离不开和文件系统打交道;你须要学习使用锁、条件变量、临界区来控制程序并发执行时不会错乱。
而读写文件、分配内存这些又离不开系统调用(System call)。
而且真正作起工程就会发现,不少问题是和操做系统紧密相关的,不理解操做系统,你连问题的缘由都分析不出来。
好比前段时间咱们出现的在基于协程(libco)的框架下,使用多线程的锁去作同步互斥偶发死锁,后来分析才发现缘由:
协程是应用层实现的,一个线程内多个协程对于操做系统是感知不到的:
那么当一个协称 A 上锁后发起网络 IO 请求,这个时候会被切换到另一个协程B,而协程 B 又去请求这个锁。
那么这个时候操做系统会认为这个锁已经被上了,会将协程 B 对应的线程挂起到等待队列,这样的话就致使协称 A 永远没法运行,也就没法释放锁,致使死锁。
解决的方法也很简单,就是将锁设置为可重入锁,可重入意味着同一个线程屡次去请求同一个锁不会致使挂起。这样当协程 B 再去请求锁的时候,操做系统就会认为协程 B 所在的线程已经持有这个锁了,直接返回,继续执行。
总之,咱们写程序每时每刻都在和操做系统交互,没有理由不学好。
编译原理多是咱们平时接触得最少的了,你们也许会以为本身又不用去造新的编程语言,学编译原理干啥。
学好编译原理有啥用?
你会站在更高的角度去审视这些编程语言,看到的再也不是表面的语法,更会想到语法背后的实现。
这种感受很透彻,就像搞懂了操做系统、体系结构你会明白一个程序从双击鼠标开始,究竟是如何被运行起来的,这种掌握一切细节,透彻的感受,真的很奇妙,不信你去试试。
说人话!
那学了编译原理你能干啥?
当你学完有限状态机之后,你会发现之前以为很牛的正则表达式彷佛本身也能用 DFA、NFA 实现一下了。状态机的思想在编程中不少地方都用得上。
好比解析 HTTP 协议,若是没学过状态机思想,你可能会一行行的 if/else 去作解析,这里最麻烦的地方在于,if/else 须要提早将 HTTP 头部字段都接收到再来判断,而咱们知道 HTTP 基于 TCP,而 TCP 是流式传输,因此你颇有多是几个字符一组组接收到的,这个时候用 if/else 写出来就很难看了。
而用状态机编写起来代码就会很是优雅。状态的转移是由规则驱动的,接收到一个字符就判断一个,很是的方便。
继续学完语法分析,你会掌握递归降低分析这样很是重要的思想,你可使用递归降低快速的实现四则运算计算器。
若是不用递归降低你可能须要先中缀表达式转后缀,而后求值,这是咱们大一数据结构课写的,当时用栈写的,有点麻烦。后来学完编译原理,又用递归降低重写了一遍,区区几十行代码遍搞定。
还有一类场景在实际开发中的用的不少,好比淘宝、京东这样的电商,它们的营销规则有不少,好比满减、直减、跨店等等,这样的规则是不可能写死在代码里的。
那是怎么作的呢?
通常会实现一个配置系统,并设计一个DSL(领域特定语言)来表达这些规则,将规则直接配置到系统中,这样能够很是方便的修改,那么如何在代码里去解析 DSL 定义的规则呢?这就须要为 DSL 写一个语法解析器,这里就会用到语法分析的方法。
DSL(Domain Specific Language),它是一种用于某个特定领域的程序设计语言。这种特定于某个领域是相对于 C、C++、Python 这种通用语言而言的,通用语言能够在各个领域使用,咱们熟悉的大多数程序设计语言都是通用语言,它们都是图灵完备的。
像咱们日常常用的 JSON、SQL、HTML 这些都算是一种 DSL,你甚至能够尝试用递归降低去写一个 JSON、XML 解析器,这比写电商网站更有价值的。
继续往下学你会了解到抽象语法树 AST 如何生成、如何转化为中间代码、如何对中间代码优化、最终又是怎么生成机器指令的。
你会看到贪心算法在寄存器分配中的应用,也会看到图论中的可达性分析又是如何实现死代码消除。
IDE上面那个绿色的编译按钮对你再也不是黑魔法。
为啥点一下就能生成可执行的程序?
你写的英文字母又是如何变成一个个二进制指令的?
学完编译原理,这些统统不是问题~
固然完成一个像 Gcc、Clang 这样的编译器难度过高过高,咱们学习编译原理的目的也不是去造这样的轮子,而是为了更好的理解和运用编程语言。
上面说的都是软件层面,体系结构则是关于计算机是如何工做的,你会了解到典型的存储程序计算机是怎样运转的。
“咱们不是学习使用计算机的,而是学习如何造计算机”,造计算机有点夸张,可是至少咱们得了解计算机的实现原理,了解计算机的各个部分是如何协调工做的。
咱们说计算机中一切都是0、1,0、1又是经过高低电平来表达的,经过与、或、非等逻辑门电路来表达二进制的数值运算,再将这些简单的电路集成在一块儿,就造成了ALU等具备运算能力的处理器。
你会了解到一条指令是如何被 CPU 执行的,CPU 从内存或 Cache 中取出指令,放入指令寄存器,并对指令译码。译码就是按照指令的编码规则,将指令拆分红一系列的微操做和操做数。而后发出各类设备控制指令,执行微操做。这样就完成一条指令的执行。
咱们说学完编译原理,你可以明白咱们写的英文代码是如何被变成二进制指令的,学完操做系统你能搞懂,二进制程序是如何被连接在一块儿,又是如何被操做系统加载、执行的。而组成原理则会告诉你二进制指令是如何控制电脑的,咱们的操做系统本质上也是一个二进制的程序。
你理解了计算机存储层次结构,理解了多级 Cache,你就会经过优化数据访问方式来编写出速度更快的程序。
你会学到底层体系结构对 C 等语言的栈帧和参数传递的支持,参数是如何被传递给另一个函数的?函数的返回值又是如何拿到。
这是学习组成原理对于写代码的意义。
为何说这些是基础?
由于你会完整的看到写的代码如何变成二进制指令,又是如何去控制各类门电路,最后变成屏幕上花花绿绿的程序的(固然这里可能还须要学习显示器的原理),这就是咱们常说的“基础”和“原理”。
计算机对你再也不是黑盒,这将成为你之后的核心竞争力,不然做为科班毕业生若是只会使用 Redis、Mysql、Spring 来写各类网站,那么大学四年的学习如何体现呢?
若是读者里有半路转行或者从培训班出来的,我也但愿大家可以抽出空余时间去补补这些基础课,这会让你在编程这条路上走的更远和更稳。
为何把算法放到最后来说,是不重要吗?相反,它过重要了,因此才让它来压轴。
若是要问我大学什么最后悔?那确定是没有从大一就开始好好学算法,去打 ACM。
如今还在大1、大二的同窗还不抓紧机会,别给本身留下遗憾。固然,不打 ACM,咱们也是可以学好数据结构和算法的。
数据结构和算法你能在任何计算机领域里看到,好比在编译原理中寄存器的分配会用到贪心,死代码检测与消除会用到图论里不可达的知识;操做系统进程、线程调度会用到多级队列和调度算法;组成原理中 Cache 的替换会用到 LRU、FIFO 等算法;开发必备的数据库也离不开B+树、LSM 等数据结构和查找算法。
不少时候咱们须要的算法都被封装到编程语言的基础库里了,以致于不少同窗会以为算法离咱们太远,其实不是的。
若是不学习算法,连何时用 Map(红黑树实现)、何时用 HashMap 都分不清。
因此学习算法有助于咱们根据应用场景选择最合适的数据结构。
平常开发中也必定离不开算法,好比小北最近工做中涉及的某种嵌套 TLV(Tag-Length-Value)结构编码的解析,就须要用到递归、多叉树等知识。若是不学习算法,那么程序中只能见到大量的 if/else、while/for。。。
能够说不学算法的工程师必定不是一个优秀的工程师。
不少人喜欢把计算机网络、数据库原理这些也归为计算机基础来,我固然也认同,由于一个知识结构完整的计算机科班学生,应该了解这些知识。
可是我我的是以为计算机网络、数据库是创建在操做系统、编译原理、组成原理之上的应用层软件。
什么是数据库?没有数据库以前你会用文件去存储数据,可是不方便查找、修改等,数据库只是提升了这个过程的效率。
网络干什么的?网络就是让不在同一台电脑上的程序互相通讯,本质上就是进程间通讯的手段。
若是你只是开发单机工业软件,甚至真的能够不学网络,只是因为如今大多数程序员都是在互联网公司工做,因此无论先后端,都离不开和HTTP等网络协议打交道。
再次重申:不是计网、数据库不重要,只是我认为它们属于构建在操做系统之上的软件,不划在基础之列。
这个我不敢说太多,由于各个领域我也不太懂。只简单提一点,抛砖引玉罢了。
若是你想去腾讯、网易作游戏引擎开发,那么图形学必定是你绕不开的知识,此外你还得学习渲染管线、着色器、物理、光照等等。
若是你想去 PingCap 这样的公司作分布式存储,那么分布式理论知识必定是你绕不开的关口,包括 CAP 定理、Paxos 算法、Raft 算法、ZAB 协议等等。
若是你想写一个数据库,那么你须要去了解磁盘、索引实现、SQL 解析(编译原理)、事务、如何用 MVCC 解决读写冲突等等一大堆的东西,还得了解一大堆编程语言层面的东西,好比锁、信号量、并发编程技巧,不得不说造数据库是一个脏活也是一个累活。
更进一步你想去作分布式数据库,那可能还得去学习数据分片的知识,查询任务如何作,是集中作,仍是将逻辑下推给各个节点,如何实现分布式事务等等。
你说你只想去大厂 CRUD?没毛病,老铁!
那你得熟悉一门编译型语言(C/C++、Java、Go),理解语言部分底层原理,好比 C++ 你得看看 STL、看看对象模型吧,你不懂什么虚函数表、智能指针还想去腾讯写 C++? Java 的你得背背 JVM,什么垃圾回收算法吧,你不看看ConcurrentHashMap 好意思说你是作Java的?
咱CRUD的对象是数据库吧?那不得学学怎么才能把数据库用好。用户经过 HTTP 访问咱们得服务,总得了解 HTTP吧?顺带着不看下 TCP 三次握手、四次挥手你好意思说是学计算机的?
用户把钱、信息放我们这,总得保证用户数据安全吧?那 XSS、SQL 注入、CSRF 这些常见的 Web 攻击手段你总得了解吧?HTTPS、RSA、签名、数字证书这些安全手段总得知道吧。
双十一流量太大,老板还让你必须顶住,那你总得了解下缓存、异步、消息队列、NoSQL 这些千万 QPS 必备的大杀器吧?
看看!要想作好CRUD也不是那么容易滴。
(上面这段只是换一种方式把作后端的同窗要学的知识写出来,不是吐槽更不是调侃,纯属娱乐。)
这就不少了,包括 VS、Jetbrains 全家桶这些 IDE,文档编写 Markdown、Git 等版本管理工具。
SSH 远程登陆、端口转发,Ngrok 内网穿透等等这些提升你开发效率的工具,都算是技能,这个没啥好说的,平时用到多学习多积累就行了。
我只提一点,尽早使用 Linux、类 Unix(Mac)做为主力开发电脑。
固然了,我也不是狂热的 Linux 爱好者,只是单纯以为作开发的话,离不开各类环境安装、命令行的使用,这点上面类 Unix 系统带有自然的优点,谁用谁知道!
写完才发现,这篇文章连篇幅都是「基础 : 领域知识 : 技能」 接近 7 : 2 : 1。
这也是我推荐你在大学期间分配学习时间的比例,至少学习基础知识的时间很多于 50%,固然,这些东西你都学完了那能够去找找感兴趣的方向专研一下。
不要大1、大二一上来就扎进 Java Web、Python 爬虫这种东西,这些能够学,但不是重点。
最后我想送给你一句我挺喜欢的话:
万丈高楼平地起,勿在浮沙筑高台。
无论你是转行也好,初学也罢,进阶也可~
——【值得关注】个人编程学习进阶俱乐部 ——
涉及到:C语言、C++、windows编程、网络编程、QT界面开发、Linux编程、游戏编程、黑客等等......