聊聊初创公司的后端语言选型 (小众语言)

在创业公司初创伊始,如何选择合适的语言决定了产品后续的技术栈和如何进行合理的业务支撑方向。如果你在读这篇文章之前,更倾向于选择 Java/C#/PHP 常见语言技术栈,我觉得对于你而言,这篇文章帮助不大。因为对你而言,这些技术栈意味着更加方便招人,更方便的故障处理资料等等。但是如果一个初创公司想要选择合理的小众语言技术栈,我想这篇文章对你也许有一些帮助。

在文章开始之前,我觉得有必要描述一下所谓的小众语言,这里我在最初进行技术选型时,考察了包括:

  • Python: 你可能在接触爬虫、大数据分析等等方面听过 Python 的大名,大家都知道 Pythonista 都习惯说的一句话就是:人生苦短,我用 Python。
  • Ruby: 你如果做过 Web 框架,你遇到最多的是很多人都会提到 RoR 框架。用过之后只有一个惊叹了。
  • JavaScript(Nodejs): 有没有听过 JavaScript 全栈工程师?有没有听过 JavaScript 全栈工程师?有没有听过 JavaScript 全栈工程师?
  • Golang: 简单粗暴的语言,也许你见过很多人跟你吹嘘,Golang 是下一代的云计算开发语言。

其他语言太过于小众,考虑语言的应用很多需要得到更多的社区支持,目前不在考虑的范畴内。

小众语言的劣势

正所谓知己知彼百战不殆,在了解一个技术选型之前,最好是研究这些语言的缺点。因为你最后感觉这个技术选型不适合你的时候,根本的原因是这些劣势影响了你。

在上面提到的几个语言中,Python、Ruby、JavaScript 是属于动态语言。关于动态语言的争议最大的地方是:动态语言到底是否合适进行大型项目。事实上,在某些阶段,多人合作,并且大家水平语言不同时,这个时候通常会有这样的问题:团队需要花更多的时间在确保动态语言的准确性上。对于一个项目有高可用、低错误率的要求时,由于语言的动态特性,就需要对程序开发时的单元测试和后期集成测试的要求更高。因为变量在运行时才会赋予类型含义,所以很难在静态检测过程中发现足够多的问题。这样对测试人员的压力也会更大,当你没有合适的测试人员时,这个时候通常会变成,你只覆盖测试了理想情况下的成功失败情况,而对特别异常情况缺少评估。

Python、Ruby 语法对程序员而言最大的成本在于需要重新学习一门新的语言。这个学习成本、时间成本通常对初创公司而言通常是支付不起的,哪怕像这些比较容易学习的动态语言而言。另外一个值得一提的是,无论是 Python 还是 Ruby,从长远看,如果你后续有较大的用户增长又需要保证用户体验时,Python、Ruby 的执行效率和吞吐量会有较大的影响。

Python 和程序员入门的语言差距较大:用 4 个空格表述程序缩进。这意味着,程序员直接从网上寻找解决方案(拷贝代码)时成本更高,因为很有可能他需要手工进行代码格式化,这样有可能造成程序逻辑的改变。另外一个不得不提的是一些 Python 库看似好用,实际上或多或少有有一些坑,这对新手而言,往往是致命的。对应的,Ruby 语言本身时不存在这些问题的。然而 Ruby 作为开发主语言时最大的问题是,如果选择 RoR 框架作为初始的 Web 框架时,如果没有一个熟悉 RoR 框架的人,那么学习修改 RoR 框架的成本是特别高的:对于一个通用型框架而言,你可能需要更多的特殊场景定制,这可能需要做大量的猴子补丁,如果不对框架有一个清晰了解时,这样的成本会更高。

JavaScript(后面统一用 Nodejs 代称)则借助 Nodejs 实现了高性能和较大吞吐量。而且从语言层面上,JavaScript 对很多程序员并不陌生。然而,在过去的很长时间,真正熟练掌握 JavaScript 的都是前端工程师,这是一个非常尴尬的问题。对后端工程师而言,Nodejs 需要与前端不同的技术栈,而且大概没有公司希望一个完全没有任何后端经验的前端工程师去接手后端项目的开发的。Nodejs 是一个年轻的语言,年轻必然会伴随一些问题,比如,库比较少(当然现在也是井喷期)。一些必要的库需要慢慢寻找。事实上,我也不得不吐槽,可能是开发者水平问题,导致很多 npm 提供的包,往往或多或少存在一些比较恼人的 BUG,这些 BUG 可能会在你开发过程中,正常运行中出现,而你却不得不干掉它。对于这种 BUG,很多时候更快的处理方式是你自己动手进行快速修复。然而当你的程序员不具备这种能力的时候,就需要提一个 issue 到开发者,由开发者进行修复,并且需要等待版本更新到 npm 源中。很多时候这个过程都是比较尴尬的,尤其是你选择了一个开发者并不是特别活跃的包。

Golang 是一个编译型语言,语法简单,似乎一切看起来都是那么的美好。事实上 Golang 本身还是处于在 Google 开发维护的阶段,本质上虽然语言完全开源了,但是却不是一个完全社区维护的语言。换句话说,Google 会决定 Golang 未来的走向。不过好在第三方包都是由社区来驱动的,这样还是提供了更多的可定制性。另外一个比较烦恼的是 Golang 本身的包管理机制,事实上,这是完全是一个伪命题。别告诉我你觉得 go get 完全足够了,那只是因为你还没有遇到依赖导致 break 的问题而已(Godep 也可以解决一部分问题,然而第三方包 API 的变更你是没办法控制的)。不过从现在看起码 Google 意识到自己的问题,也正在努力改变吧。Golang 同时也是一个年轻的语言,库比较少的问题也会出现。虽然你可以利用 cgo 去桥接一些现有的 C/C++ 库到 Golang 程序中,但是这部分的代码维护,涉及到 GC 的优化处理等各个方面,对开发者的要求不低。另外一个大家都会抓住讲的就是 GC 问题,在高并发环境下 GC 的影响从 1.5 开始下降了很多,但是 GC 并不像 Java 一样更加可控,很多时候 GC 还是需要进行代码层面进行控制。

上面所有的小众语言还面临一个共同的问题,招人。没错,找到一个适合的小众语言工程师是一个痛苦的事情。虽然你可以通过语言的高开发效率去节省人力,但是当你面临人手紧缺的困境时,去找一个合适的替补人就变成了一件非常昂贵的事情。通常你需要从现有的人员中培养则更加靠谱。(庆幸的是,经过培养后,哪怕我们的移动开发工程师也可以 hold 住我们现在的后端部分需求。当然,这只是感兴趣的前提下。)

如何选择合适的技术栈

这是一个复杂的问题。选择合适的技术栈,你需要覆盖上面我提到的所有的劣势问题。比如说,你选择了 Nodejs,你就要考虑,你可以 hold 住所有的难点,你可以修正开源包的问题,甚至你可以解决现在没有包的难题,OK,那么你选择这个语言本身是没有任何问题的。

而我在综合考虑之后,选择的技术栈比较简单:Python 和 Golang。其实选择的原因很简单,这两种语言我更熟悉。没错,这个是第一个理由。为什么会有 2 个技术栈,这个其实与我们现有的业务状态和未来发展的思考有关,这个会在后面进行一下介绍。厚脸皮的说一下,Python 和 Golang 语言中的绝大部分问题目前都可以自己解决,这也是另外一个理由。

接下来,人员培养方面,上面提到的小众语言大多培训容易,以现在产品发展节奏和产品演进速度,我们的人员培养成本目前是可以承受的

使用 Python 的原因,是开发更快,从而可以快速试错。利用现有的 Web 框架,搭配合适的数据库,我们可以在 1-2 周内实现一个完整产品的上线,进行快速试错。我们针对 Python 制订了一系列的标准,用于规范代码的格式,保证代码的强壮度。这个可以参考下我之前关于 代码风格要求的文章

使用 Golang 的原因,在于需要制作大型长期稳定运行项目的考量。事实上,我在前面也提到了,在目前的开发过程中,Python 在多人协作过程中个人编码风格、工程性上要更弱、长期运行无法控制的内存泄漏等等问题,如果需要长期稳定运行,我更倾向于选择可以进行编译的编译型语言,通过静态检查+动态测试方式,更好的保证程序的强壮型

结语

上面啰里八嗦说了那么多,只是想告诫大家,对小众语言而言,选择的机会成本是特别高的。如果你只是验证试错,或者你只是想卷一笔钱就跑,小众语言的高开发效率是绝对可以满足你的。但是从一个大型工程的角度,你需要通盘考虑小众语言的劣势,选择一个合适的语言作为你的技术栈是十分必要的。

另,杭州云柚科技长期招聘有潜力的 Python/Golang 开发者,有兴趣的请发送简历至 kevin |at| yeeuu |dot| com