服务端开发一月记

5 月份休完陪产假,再回到公司,发现原本的小组已经整体重组,只有我一人还在工位上了。后来跟 TL 聊了一下,最后反正就是几个选项,要么跟着原来的同事一起去新的部门继续写前端,要么就做点别的事情。

当时我还是挺头疼的,主要是那会事情太多了,一是小满还在月子里,二是新房子还在装修,三是那段时间身体状态有一点波动(其实主要可能还是因为这个)。继续搞前端肯定是最稳的,但是我自己其实已经有点厌倦了,属于是看到前端代码就已经有点不耐烦的程度。但是对前端以外的东西又还是很感兴趣,偶尔自己写点非前端的玩意都会感到很愉快。犹豫再三,也是跟朋友家人都聊了一下,最后选择了转成服务端开发。(其实当时还有一个可能是 C++ 客户端的方向,但是因为太过陌生,加上前面说的那些现实情况,实在是有点绷不住)

其实我在刚毕业那会做过一段时间(半年左右?)的 Java 开发,但是那段时间基本上来说还是处于比较懵的状态,也没学到什么东西,加上后来很快就转型(基本上)全职前端,Java 服务端就荒废了。现在也算是一个从头来过。

到现在 7 月份,大概算下来时间过去一个多月了,也简单说下转型后的感想。

技术栈

小组主要使用的语言大概是 Go 和 Python。Web 服务来说是 Go 居多,但是由于是在一个跟 AI 业务相关的小组,所以 Python 服务也不少。这一个多月下来 Go 的工作量大概占八成,python 二成的样子。

至于别的目前暂时就还没有接触太多,也只是粗略了解了一下业务项目的整个开发发布流程以及链条上的各种工具,还没有来得及深入学习。

学习方式

我大概在两年前的时候找同事借过一门视频课,学过一次 go 语言(算是入门)。但是到了要用的时候,年久失修,感觉大部分都已经还给老师了。周围同事朋友问了一圈,有个同事推荐了一个网站的课程,看了下各种知识的覆盖面还算可以,也没想太多,就花了四位数充了个年会(这大概是我毕业后对自己最大的一笔投资)。

充值后我就马不停蹄地开始学 Tony Bai 老师的《Go 语言第一课》,说实话这门课确实写得很好,绝对的物超所值。学习的过程中新的需求也很快就安排到了我这里来,我基本是在边学边做的情况下学完了这门课。Go 语言这门课一个星期差不多就肝完了。学完了 Go 语言后,我就打算根据工作需要,按部就班地把所有基本知识都过一遍,包括数据库、消息队列、缓存,等等。由于工作并不空闲,下班后也经常要带娃或者游戏肝日常,每天如果能学个一两章、两三章,我觉得也是不错的。

当然我毕竟因为花了四位数的钱,我必须对得起这笔开销。于是在学完这门课程后,就用刚学的 Go 语言写了一个命令行工具,它可以帮我把一门课程完整地下载到本地(包括文字里的图片!)并保存为 Markdown 格式,这样我就可以不用受年费会员的时间限制,提前下载好所有感兴趣的课程,无限期地学习了。项目地址在这里(当然,这不是一个盗版工具,要使用它的前提是使用者有年会帐号)。

开发体验

以下内容为练习时间一个半月的菜鸟程序员的一家之言。先说结论:Go 语言的开发体验明显优于 JavaScript,但服务端开发的心智模型远比前端复杂,并不是一句 CRUD 可以概括的。

为什么说体验明显优于 JavaScript 呢,首先毫无疑问 JS 是一门历史包袱很重的语言,即使发展到今天已经做了很多优化,但依然属于是带着脚镣跳舞,没有办法随心所欲。但 Go 不一样,它比较新。另外 Go 语言的哲学是“简单”,这种哲学内涵也体现在它语言设计的方方面面。举几个例子:

  1. 首先 Go 是强类型,你可能会说 TypeScript 也是强类型,但 TS 的类型体操太复杂了,Go 语言的强类型跟它相比属于是非常简单的那种,首先这一点就能够给开发体验带来质的飞跃
  2. 包含了很多 JavaScript 的优点,比如闭包、第一公民函数、值类型&引用类型
  3. 也包含了一些 TypeScript 的优点,比如类型自动推断,类型后置
  4. 文件夹即包,同包内不需要写 import,跨包不需要写 export,大写属性即默认 export
  5. 没有 class,没有继承,只有 ducktype
  6. ……

至于为什么说心智模型复杂呢,主要还是在多线程处理这件事情上。

前端这个领域(包括 Node.js 等一系列 JS runtime),再复杂的模块也是单个线程,代码都是线性执行的,不存在资源抢占。浏览器就不用说了,即使是 Node.js 中也没有“锁”的概念(主要是指线程锁)。Node.js 最多就是开个 Cluster 模式,多启动几个线程占满 CPU,但是每个线程之间都是独立的,完全没有交集。所以写 JS 代码的时候完全不用考虑资源抢占,一路莽到底。

(不过话说回来我也是现在才意识到 Node.js 到底有多牛:这家伙居然能用一条线程实现那么高的吞吐量!)

但是 Go 不一样:包括 Go 在内的众多服务端技术,它们有多线程(在 Go 中则是线程更轻量级的“协程 goroutine”)。任何一个变量,哪怕是一个 int,一个 bool,只要涉及到多线程读写,就会有问题。要么传统方案“加锁”,要么使用 Go 独有的 channel 方式。总之就是绕不开这个话题。

另外说到 channel,相比“锁”,这确实是一种很有意思的设计,也给 Go 语言增加了一些趣味。将本来复杂且易错的“锁”替换成了另一种更为直观的心智模型。这也算是一种强大的体验优化。

至于 Python 的体验,感觉跟写 Node.js 大差不差,以及大家永远都在吐槽的性能问题,这个就没什么好说的。

我的工作

由于我所在的小组不是重业务组,属于是 AI 研究团队,工作更多是各类配合 AI 同学的基础设施建设和维护,当然也会有一部分 AI 相关的业务。所以到现在为止我甚至还没写过正经的 CRUD。

目前接手过的工作,比如说从零开始开发某个微服务项目(Go 或 Python)并部署上线,配置网关和 K8S,开发一些实用脚本,给某个 Web 服务添加一些功能,维护某个内部使用的数据工具,以及开发它的 Go 语言版 sdk等。比较杂。有时候新的工作来了,当我没有理解它要怎么做的时候也会比较焦虑(毕竟转行)。但是在这些过程中,我还是比较快乐的,包括编码的过程都很快乐。我有很强的动力去重构我写的或者前人写的代码,可能会在不断的删代码写代码、删代码写代码循环中度过好几天,并在这过程中从各个方面反复地体验一门新语言的设计艺术,试图寻找一件事情最最优雅的解决方案。这跟两个月前写前端的时候完全不一样。感觉我又回到了大三大四那段学习前端技术的时间的充满热情、废寝忘食的状态。

总的来说,我还是喜欢编码这件事情的。在一个方向上呆久了可能会有点腻,但对于编码本身的兴趣目前来说依然没有任何变化。很高兴我有勇气做出了这个转行的决定,希望两年后可以成长为一个不那么菜的后端工程师,顺便多赚点钱。