平凡程序员的生存之道

在HackerNews上看到这篇好文,于是自己进行了翻译,供广大与我一样平凡的程序员一同感受一下
原标题:I am a mediocre developer
原贴地址:https://dev.to/sobolevn/i-am-a-mediocre-developer--30hn

前言

我个人认识一些非常有才华的程序员,他们可以十分顺利地开发出近乎完美的软件。正是由于这些天才程序员的存在,人们对我们程序员抱有很高的期望。但可悲的事实是:并非每个人都是学识渊博、代码风骚、效率恐怖的天才程序员。

而我正是这样的一个人:一个平凡的程序员。如果你不是天才,本文将指导你在行业中生存下去。

面向搜索引擎编程

我无法记住太多东西──比如标准库中的函数和方法、参数位置、包名称、样板代码等等。

所以,我必须在谷歌上搜索这些,我每天都这样做。我也重复使用旧项目的代码。有时我甚至可以从StackOverflow或Github复制粘贴答案。是的,他们本质上是相同的:StackOverflow驱动开发

不止是我,许多程序员也是这样做的。关于这个,有一个很火的Twitter讨论,是由Ruby on Rails的作者发起的。

为什么不提倡这样做?

搬运代码有以下几个缺点:

  1. 你可能因此复制了糟糕的设计,或者是别人写的的不安全的代码
  2. 容易形成不良的心态:如果我们不能搜索到解决方案,就会不经思考地询问他人
  3. 一旦脱离了互联网,我们就没法工作

但是,我认为这不是一个大问题。它甚至可以作为你的秘密武器。我有一些建议可以减少这些负面影响。

生存之道:

  1. 使用IDE的代码提示、代码补全功能,这样你就不必搜索编程语言的基础内容
  2. 记住你解决某个问题的地方(而不是如何解决的),这样你可以随时在那里找到解决方案
  3. 所有粘贴到项目中的代码都应该进行分析,重构和审查,这样我们就不会破坏现有项目,又能够快速实现功能

代码保持简洁

机器总是按照程序员所写的代码去执行,即使代码有问题机器也依然服从指令。所以,软件开发中的主要问题不是机器,而是开发人员的思维能力。而人的思维空间是非常有限的。所以,我们──平凡的程序员──不能浪费有限的脑力来构建复杂的抽象、模糊的算法或不可读的长代码块。我们只有一个宗旨:保持简单。

但是,我们怎么评价这个代码是简单还是复杂?我们需要使用WTFs/Minute这个量化指标来衡量代码质量。

WTFs/Minute

这个原则很容易理解。然而每当你在现有项目中发现一些你很难理解的代码时,你能做什么?

  1. 重写,使得设计更加简洁
  2. 提供文档
  3. 在难以理解的部分添加注释,但请记住,这些注释应该与代码的设计相符

重头构建一个项目时,如何在一开始就保持代码简洁:

  1. 为变量、函数和类使用适当的命名
  2. 确保程序的每个部分只做一件事
  3. 纯函数优于普通函数
  4. 普通函数优于类
  5. 仅在强烈需求的情况下使用类

不要相信自己

一些开发人员证明自己可以提供高质量的代码。像下图这位女士──阿波罗计划的首席软件工程师Margaret Hamilton。照片中,她手扶着的是她为登月任务所编写的代码:

Margaret Hamilton

但是,每当我自己编写代码时,我都不能信任自己。即使是项目最简单的部分,也有可能被我搞得一团糟。我可能会犯下这些错误:

  1. 语法错误
  2. 逻辑错误
  3. 设计错误
  4. 样式错误
  5. 安全错误
  6. WTF错误(我最为喜欢的!)

关于“学习如何编写无错代码”的魔法书并不存在。所有软件都有bug(除了这个框架),我们能做的就是处理bug。

问题是:任何人都不应该被允许编写有明显错误的代码。至少,我们应该尽量去避免bug。但是我们怎样才能写出更健壮的代码?有多种方式可以做到这一点。

生存之道:

  1. 编写测试。写很多测试,从集成测试开始到单元测试。在每次pull请求前在CI中运行测试。这样可以避免一些逻辑错误
  2. 使用静态类型或可选的静态类型。例如,我们在python中使用mypy,在javascript中使用flow。积极的影响:更简洁的设计和“编译时”检查
  3. 使用自动样式检查。每种语言都有很多风格检查器
  4. 使用质量检查。有些工具在你的代码库上运行一些复杂的启发式算法来检测不同的问题,比如这行内部有太多的逻辑,这个类是不需要的,这个函数太复杂了,等等
  5. 审查你的代码。在合并到master分支前以及合并后的某个时间对其进行检查。
  6. 付费让其他人对您的代码进行审查。这项技术具有巨大的积极影响!因为当开发人员首次查看您的代码时,他们更容易发现不一致和糟糕的设计决策

程序不应该只能在你的电脑上运行

大约十年前,当我们团队开发了我们的第一个大型软件项目时,我们将它作为java源文件发布。在交付给客户前的几个小时,我们发现它竟然无法在目标服务器上编译。这是一个很大的失误!最后我们用尽办法终于能够启动并运行了,但不可否认这真的是一次刻骨铭心的体验。

发生这种情况是因为构建流水线中有很多配置和复杂性,而且我们无法妥善管理这个系统的复杂性。从那一天起,为了减少这种复杂性,我尝试在隔离的环境中打包我的程序,并且在实际部署之前在这个环境中测试它们。

在近几年,随着容器技术的崛起,这一切变得简单了。docker允许您在相同的隔离环境中进行开发、测试和生产。所以,你永远不会错过任何重要的事情。

那么你会怎么做?说说我自己,我总是在创建服务器、初始配置或集成时忘记了一些事情。因为有很多事情要需要耗费脑力记住!但现在这些都可以实现自动化。有许多的工具都可以自动化部署过程,如:terraformansiblepacker。了解这些工具,找出符合你需求的一个来帮你完成工作。

我也尝试尽快配置好CI/CD。这样如果我的构建在测试或部署中失败,我就会马上收到报告。

生存之道:

  1. 所有部署的工作都实现自动化
  2. 使用docker进行应用程序的开发、测试和部署
  3. 使用部署工具

程序部署后仍然不能松懈

终于,我们的程序部署到了生产环境中,并且可以工作。我终于可以休息了,应该不会出什么问题了。等等,不!一切都崩溃了。是的,我说的就是:一切。

实际上,有一些工具可以更容易地查找和解决现有问题。

  1. Sentry。当您的任何用户遇到错误时,你将收到通知。这个服务现在已经支持几乎所有的编程语言
  2. 使用不同的服务工具将多个进程和服务器的日志收集到一个地方
  3. 服务器监控。在这你可以监控CPU、磁盘、网络和内存,这样你可以在你的服务崩溃之前尽早发现。

简而言之,我们需要监控我们在生产环境中的应用。我们有时使用所有这些工具,有时只使用最需要的部分。

学无止境

哇!有这么多东西需要我们去学习。但这些东西确实很有用。如果我们想编写好的程序,我们需要不断学习,没有捷径。我们只需保持每天都前进一小步。

总之,我们需要理解两件基本的事情:

  1. 每个人都遇到问题。唯一重要的是我们为这些问题做好了准备
  2. 我们可以将问题保持在我们可控的范围内

这与你的心智能力或心态无关。