前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >我苦难的转行计算机开发的经历

我苦难的转行计算机开发的经历

作者头像
范蠡
发布2021-10-18 17:37:15
9680
发布2021-10-18 17:37:15
举报

星标公众号,优质内容第一时间阅读

无意中在知乎看到一个提问:

给非计算机专业学生提供一份较为全面的书单以自学计算机专业知识,你有哪些好书值得推荐? 如题。希望知友能尽可能全面的给出答案。

这个问题太适合我了

我就是那个非计算机专业一心想转计算机专业,但是最终没转成,但是通过自学走上开发之路的,当年也是到处求书单。

目前人在某大厂做资深开发,发几张目前的工作环境照吧:

转眼毕业七年多了,这是 2014 年毕业的时候,在纪念日,和女朋友(现在已经是老婆了)一起拍的照片:

这是去年结婚 5 周年在新家拍的照片:

好啦,如果你觉得挺好的。那我就继续和你讲一讲我的故事和你要的书单。

我大学学的是地理科学专业,没错,这是一个师范专业,培养的目标是高中地理老师。

隔壁计算机专业的课程一般是这样的:

而我的专业课是这样的:

隔壁计算机专业的同学找实习是这样子的:

图片中的故事点这里

而我找实习的时候是这样的:

那我是如何从地理专业变成一名纯正的开发呢?这从我毕业的时候,给自己写的自传中可以一瞥端倪:

性耿直,直言罪人。闲静少言,不慕荣利,心无城府,胸有点墨。怀济世之志。好读书,求甚解。尚文学,喜编程,涉猎网海四载有余,阅经典之作而获益。自编软件、涂鸦设计而自乐。喜交友,恶人不诚不正。叹光阴荏苒,形单影只。愿得一人心,白首不分离。

无他,就是多读经典的计算机书籍,光读不行,而且要实践。

以下是我的书单和一些读书建议:

我知道很多非计算机专业的同学想转行计算机,而且想进大厂,这里我建议从两个方面来行动。

一、思想层面

首先,要解决思想层面上的问题。

不要给自己的人生设置上限。很多同学因为这样或者那样的原因,高考没考好,最近进入了一个不太如意的大学,或者想选计算机专业,但是因为这样那样的问题,没被计算机专业录取。

但是请不要自怨自艾,高考虽然是人生很关键的机会,但绝对不是唯一的机会。所以,学校不好,只要你能迎头赶上,专业不对口,最后通过自己的努力也未尝实现不了目标。

所以不要觉得自己考的学校不行,就处处不如人。即使你是非科班,只要努力加上正确的方法,最终一定能成功的。

其次,要用行动。这种行动不是做给别人看的。接下来学习、看书。不在乎你看多少本书,学习多长时间,而是你每次理解、学会了多少,每天甚至每周有点进步,时间久了,也可以取得长足的进步。

最怕的就是还没看一本书,朋友圈到处打卡;还没行动,人尽皆知。面试过一些同学,简历上写上看了一堆经典书籍,最后一问啥都说不清楚。记住,行动是一步一个脚印。这期间可以允许你稍微偷点懒,但是一定是这段时间比上一段时间有提高,自我安慰式的努力和自我安慰式的提高,只注重形式不注重结果的行动是没任何意义的。

这也是为什么我先建议你解决思想上的困难。天道酬勤,功不唐捐。

二、学习方法

解决了思想上的问题,下面是行动上的问题了。

1. 第一阶段

无论你是科班还是非科班,建议你一定要学好 C 语言,它应该作为你必须掌握好的语言。

你要熟悉 C 语言的基本语法,包括但不限于:

  • 顺序、条件、循环三大控制语句
  • C 中几大基元数据类型的用法
  • 熟悉掌握数组的用法
  • 熟练掌握指针的用法
  • 熟练掌握结构体、枚举、联合等数据类型的用法
  • 熟练使用常用 C 库函数,如控制台输入输出流、字符串操作、文件操作、时间函数等等

以上阶段算是启蒙阶段,在这个阶段,是基础编程语法的学习,当然,你不仅仅要掌握这些基本语法,你还要反复练习。

2. 第二阶段

如果你想毕业后进大厂,从这时开始学习算法和数据结构。学习算法和数据一定不能急功近利,算法和数据结构的知识一定要作为一个长期的学习目标。

对于非科班的同学,由于没有像科班同学那样接受到系统的学习,一定要找一两本经典书籍系统地学习下常见的算法理论、思想和常用的数据结构知识。 等熟悉了这块的知识,再适当地刷一些算法题目或者做一些算法练习。

3. 第三阶段

大学四年(研究生三年)说长不长,说短也不短。接下来就挨个补相应的基础知识了。如果你是非科班,也建议自己找点经典的书籍系统地学习一下。下面挨个说一下这几大方面的基础知识。

3.1 编程语言方面

你可以根据你的兴趣自由选择 C++ 或者 Java,这里以 C++为例:

需要强调的是,既然是学习,请抛弃各种总结经验技巧的面经,逐个掌握 C++ 语言的各个语法知识,包括但不局限于:

  • 指针和引用的概念
  • 指针与内存关系
  • 程序编译过程,静态链接库和动态链接库
  • static、const、#define的用法和区别
  • C和C++区别
  • 内存中的栈和堆分配
  • 面向对象理解
  • 访问限定符 public/protected/private
  • 构造函数/析构函数/拷贝构造
  • 多态
  • 虚函数与纯虚函数、虚函数实现机制、虚函数表 继承原理、虚继承、菱形继承
  • new/delete和malloc/free
  • 重载、重写和覆盖
  • 类型转换方式
  • RAII 与 pimpl 惯用法
  • 内存溢出和内存泄漏
  • STL标准模板库
  • 迭代器、空间配置器理解
  • 常用容器特点、用法以及底层实现vector、list、deque、set、map、unorderedmap

C++11/14/17 新标准也慢慢成为主流,这块也要熟悉,要熟悉新标准常用的语法与新功能,包括:另外,时至今日,你一定要熟悉 C++11/14/17 常用的语言特性和类库,这里简单地列一下:

  • 左值/右值/std::move/std::forward
  • 统一的类成员初始化语法与 std::initializer_list
  • 注解标签(attributes)
  • final/override/=default/=delete 语法
  • auto 关键字
  • Range-based 循环语法
  • 结构化绑定
  • stl 容器新增的实用方法
  • std::thread
  • 线程局部存储 thread_local
  • 线程同步原语 std::mutex、std::condition_variable 等
  • 原子操作类
  • 智能指针类
  • std::bind/std::function

C++11/14 网上的资料已经很多了,C++17 的资料不多,重点掌握的还是 C++11 引入的各种实用特性,这就给读者推荐一些我读过的书:

  • 《深入理解 C++11:C++11 新特性解析与应用》
  • 《深入应用 C++11:代码优化与工程级应用》
  • 《C++17 完全指南》
  • 《Cpp 17 in Detail》

3.2 熟悉编程语言相关的开发工具链

熟悉该语言的相关的 IDE 开发环境,Windows上我推荐 Visual Studio,Mac 上可以使用Subline 或者 VSCode,如果你最终的程序需要在 Linux 跑,你需要熟悉 cmake/make/gcc/g++/gdb 工具链,vim 的基本操作也要熟悉,但绝对不要直接在 vim 中写代码,纯属浪费时间,实际企业级开发也没人会这么做。这里强调一下,如果可能,至少要熟悉 Visual Studio 和 gdb 调试,调试需要掌握哪些内容呢?

建议掌握:

  • 如何启动和结束调试
  • 如何添加/删除/启用/禁用断点(包括普通断点、条件断点和数据断点)
  • 如何查看当天断点下的调用对战
  • 如何查看程序运行过程中的线程信息(这块可以放到下文再学)
  • 如何查看某个变量的内存值

掌握了一门编程语言加其开发的工具链,你的想法就可以通过动手变为现实了。熟悉了 C/C++ 语言和其相关的开发工具链,接下来你可以根据你的兴趣学习相关的开发知识了。

3.3 熟悉相关的操作系统的 API 接口

很多人说,操作系统的 API 接口不用刻意学习,根据我个人的经验,我反对这一观点,操作系统的很多 API 涉及到很多操作系统原理和使用技巧,绝非是想用的时候去查一查就可以了。就和开卷考试一样,如果不熟悉,且不说不知道如何查、在哪查,就算查到了,是否可以用好又是另外一回事了。

Linux 系统推荐学习《Linux 系统编程》,Windows 系统推荐《Windows 程序设计(第五版)》和 《Windows 核心编程》。

举个例子,有读者问了我这样两个问题:

  1. 请教个问题哈,我需要刚打开应用程序时,在View的OnDraw内创建一个线程,每次当我点击菜单按钮产生对话框后,终止View类中OnDraw内的这个线程,对话框退出,又创建这个线程,是不是得弄个线程池。。或者是使用SuspendThread和ResumeThread来控制吗?
  2. 单个 epoll + 线程池与每个线程一个 epoll 这两种架构哪个更适合大量短连接的场景?

这两个问题都反映出提问的读者对基础的原理含糊不清,我贴出这两个问题,就是想告诉你,学习操作系统的接口不仅是学习相关操作系统 API,同时也是在培养自己的动手和实践能力。常用的操作系统 API 并不多,以多线程相关的为例,Windows 系统提供的线程同步原语常用的有临界区、Event、互斥体、信号量等,Linux 常用的有互斥体、读写锁、信号量和条件变量,掌握这些并不困难,你只要花一周时间挨个地学习联系一下,很快就能掌握。

熟悉了常用操作系统的 API 之后,你就可以自由地写出自己想要的程序了,这个时候处于初级的通透状态,例如,你可以随手写出这样一个功能的程序:

主线程创建一个新的工作线程,等待工作线程获取系统时间后写入文件;主线程从文件中读取时间内容显示出来。

这个例子中,我们用到了创建线程的 API、线程等待与通知 API、获取系统时间的 API、显示到控制台的 API 在 Windows 上,我们用到:

  • CreateThread
  • WaitForSingelObject
  • GetSystemTime
  • CreateEvent/SetEvent
  • std::cout

在 Linux 上,我们可以使用:

  • pthread_create
  • pthread_mutex_init/pthread_cond_init/pthread_cond_destroy/pthread_cond_wait time
  • std::cout

这么一分析是不是觉得一下子清晰起来,因为 C/C++ 这么编程语言不是功能完备性的,如果 C/C++ 的 C 库或者 stl 本身没有提供这些功能,你不得不使用操作系统的 API。

如果你掌握到这个阶段,恭喜你,你已经可以去胜任中小企业的 C/C++ 开发了。所以,我推荐的这条路线,如果你认真学习,保底能让你找到一份小公司的 C++ 开发工作的。

3.4 熟悉多线程编程

这块与上文有一点重叠,我们再次说一下。多线程知识,你需要掌握理解线程与进程的关系、熟练使用常用的线程同步技术。推荐的一种学习方式,就是找一个开源项目,使用调试器跑起来,然后看看这个进程有多少线程,每个线程在何时被创建,每个线程的作用是什么,线程之间如何通信的。这也是上文建议你熟练掌握调试器的原因。

多线程编程目前网上我没有见过系统地、详尽的教材,于是我自己写了一个,我把它放在我的图书《C++ 服务器开发精髓》的第三章中去了,可以给大家贴下目录:

第3章 多线程编程与资源同步.. 159

3.1 线程的基本概念及常见问题... 159

3.1.1 主线程退出,支线程也将退出吗... 159

3.1.2 某个线程崩溃,会导致进程退出吗... 160

3.2 线程的基本操作... 160

3.3 惯用法:将C++类对象实例指针作为线程函数的参数... 178

3.4 整型变量的原子操作... 184

3.4.1 为什么给整型变量赋值不是原子操作... 185

3.4.2 Windows平台上对整型变量的原子操作... 186

3.4.3 C++ 11对整型变量原子操作的支持... 187

3.5 Linux线程同步对象... 190

3.5.1 Linux互斥体... 190

3.5.2 Linux信号量... 198

3.5.3 Linux条件变量... 202

3.5.4 Linux读写锁... 208

3.6 Windows线程同步对象... 217

3.6.1 WaitForSingleObject与WaitForMultipleObjects函数... 217

3.6.2 Windows临界区对象... 219

3.6.3 Windows Event对象... 224

3.6.4 Windows Mutex对象... 229

3.6.5 Windows Semaphore对象... 231

3.6.6 Windows读写锁... 235

3.6.7 Windows条件变量... 238

3.6.8 在多进程之间共享线程同步对象... 243

3.7 C++ 11/14/17线程同步对象... 244

3.7.1 std::mutex系列... 244

3.7.2 std::shared_mutex. 248

3.7.3 std::condition_variable. 253

3.8 如何确保创建的线程一定能运行... 256

3.9 多线程使用锁经验总结... 258

3.10 线程局部存储... 262

3.10.1 Windows的线程局部存储... 262

3.10.2 Linux的线程局部存储... 264

3.10.3 C++ 11 的 thread_local 关键字... 267

3.11 C库的非线程安全函数... 268

3.12 线程池与队列系统的设计... 270

3.12.1 线程池的设计原理... 270

3.12.2 环形队列... 275

3.12.3 消息中间件... 275

3.13 纤程(Fiber)与协程(Routine)... 277

3.5 熟悉操作系统原理

操作系统原理无论是面试还是自我提高的五大基础之一,我的建议学习操作系统知识时,不一定要看完所有操作系统书籍,但一定将一些基础概念(如进程、线程、内存模式等)看懂、理清。Tanenbaum.A.S《现代操作系统》是一本讲解操作系统理论不错的书,作者 Tanenbaum.A.S 是 Linux 内核创始人 Linus Torvalds 的老师。

你如果还有时间强烈推荐看看俞甲子的《程序员的自我修养:链接、装载与库》。这本书同时涉及到了 Windows 和 Linux 两个操作系统平台,用各种辅助工具剖析了程序从源码到二进制文件再到装载到进程地址空间里面的各个细节,甚至连进程地址空间中的堆结构、栈结构也分析得清清楚楚,同时也分析了 C Runtime(CRT)、glibc 这样的操作系统接口库的原理和执行逻辑,是一本实实在在帮你实战操作系统原理的好书。

当然,学有余力的同学,可以进一步了解一些关于操作系统的模式(如实模式、保护模式)、系统的启动与初始化、虚拟内存与物理内存、内存分表分页机制、进程与线程的调度算法等知识。

3.6 计算机网络

学习计算机网络要从以下三个方面学习:

3.6.1 计算机网络理论知识

计算机网络编程你需要掌握基础的如三次握手和四次挥手的过程以及各个状态值,我建议使用 tcpdump 命令实际抓下包就一目了然了,然后就是网络分层,各层的用途,重点熟悉下 TCP/IP 层相关的知识,还有就是 TCP/UDP 的区别,TCP 的滑动窗口机制、拥塞控制算法、TCP 的保序、重传、确认机制。

学习这些知识的时候,一定不要死记硬背,注重理解。我近来面试了一部分学历学校非常好的同学,然而,在问到这块的知识时却大失所望。例如,有的同学只是单纯把三次握手背下来了,我稍微变通一下他就不知道怎么回答了:

  1. 如果连接一个目标主机不存在的 IP 地址握手过程是怎样的?连接一个目标 IP 存在但是端口号不存在的主机又是怎样的握手过程呢?
  2. A 机器上的进程与 B 机器上的进程进行网络通信,分别经历了哪些网络层。
3.6.2 Socket 编程

Socket 编程你需要先掌握常用的 Socket API,包括但不局限于:

常用 Berkeley Sockets API 一览表

学习这些 Socket API 的时候,不是让你单纯地记忆这些函数的参数,而是掌握每一个函数的重难点。

例如:

  • 如何将一个 socket 设置成非阻塞模式
  • 阻塞模式下,send 和 recv 函数行为是什么样子的?* 非阻塞模式下 send/recv 的返回值分别是什么?
  • 客户端发起连接时,如何主动指定通过本地某个端口号 去连接?
  • bind 函数如果端口号设置为 0 是什么行为?
  • listen 函数的 backlog 参数用途是什么?
  • 如何实现异步的 connect 函数?
  • accept 函数调用时,三次握手是否已经完成?
  • 如何实现半关闭状态?
  • nagle 算法的用途是什么?
  • select 函数的第一个参数怎么设置?select 函数的超时参数如果设置为 NULL 是什么行为?

接着要重点学习下常用的网络模型:

Windows 上常用的网络模型有 select、WSAEventSelect、WSAAsyncSelect、完成端口模型;Linux 上常用的网络模型 select、poll、epoll,epoll 需要重点关注的是水平模式和边缘模式。

当然,也建议一定要理解,不要死记硬背。C++ 的同学来面试的时候,我会给他们准备如下面试题:

epoll 边缘模式下,某次读取了某个 socket 上的部分数据,下次是否会出发读事件?如果此时又来了一个字节的新数据,是否会触发读事件? epoll 边缘模式建议尽量一次把数据读完,怎样判断当前数据已经读完? epoll 边缘模式下,对于写事件应该如何处理?

接着还要熟悉 TCP 协议的流式特性,如何解决粘包问题;还要掌握常见的网络协议格式,像 HTTP、FTP、POP3/SMTP/WebSocket 协议的格式都建议熟练掌握。

以 HTTP 协议为例,HTTP 协议包的格式是什么样的,包头和包体如何分界的,GET 与 POST 请求的数据分别放在 HTTP 包的什么位置,如果放在包体中,如何知道包体的数据有多长。

3.6.3 常用网络命令

学习了常用的网络命令,可以用来排查网络故障与定位问题,反过来,也可以加深对网络理论知识的理解,建议掌握以下命令:ifconfig、ping、telnet、netstat、lsof、nc、curl、tcpdump。

掌握了这些命令要做到学以致用,例如现在某个服务器连接不上,如何使用这些命令判断是自己网络的问题还是目标主机的问题;开发了一个服务器程序,手头上没有可用的客户端,如何使用 nc 命令模拟一个;或者反过来,开发了一个客户端程序,如果用 nc 模拟一个服务器端用于测试。

3.7 数据库

数据库需要掌握的基础知识有:

  • 熟悉基本 SQL 操作

包括增删改查(insert、delete、update、select语句),排序 order,条件查询(where 子语句),限制查询结果数量(LIMIT语句)等

  • 稍微高级一点的 SQL 操作(如 Group by,in,join,left join,多表联合查询,别名的使用,select 子语句等)
  • 索引的概念、索引的原理、索引的创建技巧
  • 数据库本身的操作,建库建表,数据的导入导出
  • 数据库用户权限控制(权限机制)
  • MySQL 的两种数据库引擎的区别
  • SQL 优化技巧

以上属于对开发的基本的数据库知识要求,你可以找一本相关入门级的数据库图书,我推荐一下《《MySQL技术内幕(第5版)》。

高级开发除了以上要求还要熟悉高可用 MySQL、主从同步、读写分离、分表分库等技术,这些技术的细节一定要清楚,它们是你成为技术专家或者高级架构的必备知识。我们在实际面试时,在讨论高可用服务服务方案时,很多面试者也会和我们讨论到这些技术,但是不少面试者只知道这些技术的大致思想,细节往往说不清楚,细节不会就意味着你的高可用方案无法落地,企业需要可以落地的方案。

这些技术我首推《高性能 MySQL》这本书,这本书高级开发者一定要通读的,另外还有 2 本非常好的图书也推荐一下:一本是《MySQL 排错指南》,读完这本书以后,你会对整个“数据库世界”充满了清晰的认识;另外一本是《数据库索引设计与优化》,这本书读起来非常舒服,尤其是对于喜欢算法和数据结构的同学来说。

3.8 汇编

如果你熟练掌握汇编,你就比其他人多很多优势,你会能透彻地知道你写的每一行 C/C++ 代码背后的机器指令的效率。无论是做安全工程还是自己技术提升上都是非常不错的。这里推荐一本王爽老师的《汇编语言(第 3 版)》,这本书不厚,语言通俗易懂,你也不用刻意去记忆,基本上当小说书看一下就能很快看完了。

汇编实战类图书还有另外一本《老码识途:从机器码到框架的系统观逆向修炼之路》。我个人是非常喜欢这本书的。当年读这本书的时候,真的有一种“笑看妻子愁何在?漫卷诗书喜欲狂”的感觉。

3.9 代码规范与风格优化

在你学习的过程中,请一定要认真对待自己每一个变量名、函数名,养成良好的代码习惯。我学生时代花了大量时间去学习一些教人写出优美风格的代码书籍、资料、源码,在你还是个小白的时候,要认真精读一些优秀代码,不仅要学习它们的整体设计思路,还要学习它们的代码风格和细节。这里推荐《程序设计实践》《代码整洁之道》这两本书,特别是《程序设计实践》,强烈建议学生朋友看一下,能大幅度地提高你实际编码的技巧和编码风格。

注意,上文中除了 C/C++ 语言本身的一些知识,像计算机网络、多线程、数据库等等都是任何编程语言(如 Java/Go/Python 等都应该需要掌握的),这些计算机基础知识决定着你将来能走多高多远。这也是很多非科班出身的同学与科班同学之间的差距,科班同学一般都在这些方面受过系统的教育,而非科班同学就没有学习这些东西了,那么在后期一定要及时补上。

三、是否还需要掌握其他一些技术?

有同学会问那像分布式、消息中间件等要不要掌握?据说很多大厂都有这样的要求?

这个我可以明确地告诉大家,这些对于应届生来说,都不是必要的条件。

应届生主要看基础,大厂对算法和数据结构考察是重中之重;小厂要求你能上手干活,会很在乎你实际的编码调试能力,和多线程、网络编程、数据库等方面的能力。

因为我在大小厂都工作过,所以如果你按我这个路线,还是比较稳的,至少可以保底入行成功。

最后秀一下我现在的书架:

四、写在最后的话

作为一名非科班出身并且转行成功的老学长,我想说的是,转行过程中每一步都不容易,努力坚持下来,尽管过程可能有曲折,但,最后一定会美梦成真的。

最后,用媳妇画在我家墙上的话来结束本文吧:

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-10-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 高性能服务器开发 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、思想层面
  • 二、学习方法
    • 1. 第一阶段
      • 2. 第二阶段
        • 3. 第三阶段
          • 3.1 编程语言方面
          • 3.2 熟悉编程语言相关的开发工具链
          • 3.3 熟悉相关的操作系统的 API 接口
          • 3.4 熟悉多线程编程
          • 3.5 熟悉操作系统原理
          • 3.6 计算机网络
          • 3.7 数据库
          • 3.8 汇编
          • 3.9 代码规范与风格优化
      • 三、是否还需要掌握其他一些技术?
      • 四、写在最后的话
      相关产品与服务
      数据库
      云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档