2011年大学毕业以后,我就一直在传统工程行业工作。2016年抓住机会转行做了程序员,到现在已经有4年多了。

每个人自学的起点都不一样。有些人还是在校学生,只是专业不一样。有些人转行之前或许已经有一些编程经历了。所以我只能结合我的情况来讲。

明确为什么要做程序员

这个问题比较关键。你的动机决定了你将来的位置。

打比方,有人就是喜欢游戏才转行,那他大概率要进游戏行业。如果只是为了入行,那可能就要考虑进Web和移动开发方向。这些方向当前招聘规模是最大的,入行门槛也相对较低。

想清楚了方向,后面才好发力。

学什么语言

编程语言的选择可能是下定决心转行之后,面临的第一大问题。

抖个机灵,那就是英语。因为这一行思想的传递主要是依靠英语,最多的学习资料都是英语写的。汉语资料都是尚有余力的同学好心翻译的。很多资料其实没有翻译。因为英语不好而没能学习到,实际上跟同行比是吃了亏得。另外如果英语足够好,可以进到没有996的外企,也是另一种收获。

言归正传。

其实首先看自己想去得方向,学那一行的主流语言。不要学习被知乎一众鼎力推荐的那些新兴语言。因为一家公司想要尝试新兴语言的前提,是能够熟练用行业成熟语言。直接去学新语言,很容易在求职的时候栽跟头。我在当初自学的时候,就恰逢互联网风口正盛,被知乎帖子忽悠去学了Python。结果出来根本找不到网站开发岗位,去做了运维脚本开发,后来恰好有机会才转得Java开发。

如果你的选项中包含了Java,请优先选择这个。不仅仅因为Java的招聘需求很高,还因为这个语言的语法严谨或者死板,能够养成还不错的编程习惯。

比方说在C++里常见的类继承,稍有不慎就会出现多重继承的问题。绝大多数情况下,这个都是因为对业务场景的抽象有了偏差,换了思路就能解决问题。在C++里,你可能就会开始调试多重集成了。但在Java的死板语法下,你就不得不考虑调整抽象的思路。假如,你写多了Java,那回过头来写C++的时候,就很少会遇到多重继承。因为写代码得时候已经建立好了正确的抽象思路。君不见,就连Google的C++编码规范里也是建议按照Java的一类多接口的方式实现继承。

再比如说Python,作为一个灵活的动态语言,允许返回值出现多种类型。某些条件满足时返回布尔类型,某些条件返回double类型。这样子的代码写的时候当然很爽,要什么有什么。但是在后期维护的时候,尤其是代码重构时,会造成很大的困扰。因为类型不统一,如果调用的逻辑出了错又不能在上线前发现。只能解释器执行到那一步的时候,才会报错。通常来讲,一个方法能够返回多种类型,要么是构思数据类型的时候考虑不严谨,要么是这个函数里面的功能太多需要拆解。而Java只能返回一种类型,在语法层面就可以约束你认真思考统一类型。

有些人可能会说C++能更好的与计算机基础知识衔接,应该从这里入手。我的想法是,作为一个转行的开发,先降低学习的门槛。C++的语法要点太多,在自学的时候会占去大量的精力,反而学习业务知识的时间就少了。把更多的时间花在对网站后端或者大数据等领域知识的学习,会更好一些。

学习领域知识

转行要大致有一个方向,准备做Web前端、网站后端、iOS/Android移动开发又或者是大数据开发。

先选好方向,就要开始学习对应的领域知识了。我是做网站后端开发的,就拿这个举例。

我一开始选了Python做网站后端,很快照着网上的例子就搭好了一个小博客网站,Nginx + Bottle + Jinja2 + Postgres。

但那是这样就好了吗?

不是的。这里面每一个环节,都可以研究很深。

  1. 什么是HTTP协议,为什么要用这个?

  2. GET POST方法都是怎么用的?什么是Restful API?有什么好处和不足?

  3. Python服务是怎么处理请求的,为什么性能那么差?

  4. GIL是什么?对我的服务有什么影响?

  5. 怎么样提高服务的性能?

  6. Python Thread 和 CPU 硬件线程是什么关系?

  7. 在做HTTP服务器框架选型的时候,为什么选Tornado,不选CherryPy? Java也是类似的,Tomcat和Jetty对比过吗?谁的性能好一点,为什么好?

  8. epoll比select好在哪里?

  9. Nginx是做什么用的?为啥那么不直接请求Python服务?

  10. 什么是前后端分离?什么时候用?

  11. 为啥那么要用数据库?什么是SQL?怎么调优?

  12. 为什么用Postgres?MySQL是什么?两者有啥联系和区别?

进了一行,就一定要对每一个环节都要有所了解,对大部分环节有所研究,对某些感兴趣的环节要有深入研究。

学习计算机基础知识

学习领域知识可以让你成为码农,但并不能向前走的更多。

软件工程的专业课很多,但是实际大部分工作中用到的只有一小部分。

数据结构和算法基础应该是每个人都要学的,因为得了解自己代码的时间和空间的效率。如果要优化,得有思路。

操作系统和计算机体系架构也是要学习的。因为需要理解自己代码运行是怎么个原理。CPU几个核在执行代码?内存为什么不能占用太多?跨进程为什么不能共享内存?

编译原理倒是工作中用的少。大部分人工作中没有时间去调试编译器、解释器。但是工作中有时会出现解析DSL的需求,编译原理的前端知识会很有帮助。不是不用学,是不属于高优先级的学习项目。

其余的就看工作方向了。比如,做前端、移动端可能再需要看一看计算机图形学。做Web后端离不开数据库,需要看一看数据库原理。后端里分布式系统是个趋势,也需要了解一些。

保持好奇心,持续学习

不要抱着一劳永逸的想法进入这一行。我的看法是,编程这一行还处于早期,发展飞快。只守着公司技术涉及到的一亩三分地,几年以后就会淘汰。正确的做法是,保持不断学习的习惯。

不是说做了后端就在也不用关注其他方向,学了一门语言就不用再学其他语言。实际上很多东西都是相通的,可以相互借鉴。眼界越宽,思路越广。

eventloop模型在Chrome V8引擎大放异彩,Android同样在用这个思路解决用户界面卡顿的问题。到了Java后端,RxJava、Reactor等一众Reactive框架也同样在高并发场景下得到应用。

传统的多线程编程喜欢用共享内存模型,但是总归绕不开一个伪共享问题。如果所有变量都padding处理,内存会浪费很多。如果使用Actor、CSP这种消息传递模型就可以避免前述问题,但是你需要去了解Erlang、Scala或者Golang才能发现这些在Java传统编程中看不到的东东。

写Java、C++出身的,大多代码范式都是指令式的。举一个常见的坏习惯,就是喜欢返回空指针NULL。声明时返回对象(或者结构体),实现时却返回空指针。在编译层面是合法的,但在运行时中往往因为代码考虑不周,产生bug。而Scala、Haskell这些函数式语言会告诉什么是类型安全。学习函数式编程语言很难让你用这个找到工作,但会打开你的眼界。往后你在去写Java、C++代码的时候,尽管不会使用范畴论那一套东东,也会开始考虑自己的代码类型是否安全、实现的函数是否够纯。结果就是Bug率直线下降,别人996调试bug,你996看博客电子书。

当然最好的情况是没有996。

关于工作

什么时候就可以找工作了。

我的建议是至少在学习完数据结构和算法基础、操作系统和计算机体系架构之后再去找工作。因为工作开始以后,很难再有时间去学习这个。之后就看自己的情况了,但要避免闭门造车太长时间。因为没有意义,简历上的条件就那样,多学半年并不能帮助你找到更好的工作。

转行求职,很容易遭遇不信任。所以看自身情况而放低对第一份工作的期待。尽力争取最好的,但不要因此而损失了一个尚还不错的机会。

比如我第一份工作去了外包,虽然工作不怎么样,但是坚持学习,平时会坚持看看很多博客,并结合工作实际去思考。

我为什么又写了个bug,怎么样避免?

PM又改需求,我的代码好难改,怎么样抽象才能好改呢?

我的分支管理全乱了,有没有好的实践?

打个jar包ssh上传到测试环境测试好慢呀,一来一去十分钟就没了。有没有更快的手段来验证我的修改呢?

在公司写代码,就是搞工程。工程实践也需要好好思考。