
为什么你在教程里学的一到生产环境就“哑火”了好多程序员所采用的学习途径, 基本上是如出一辙的: 盯着视频教程观看, 翻阅各类博客文章, 依照教程视频之中的播放清单去开展若干看上去貌似酷炫至极的小型项目作业。于这些模拟出来的环境里, 代码运行得极为顺畅, 各项测试皆顺利通过, 逻辑呈现得清晰且美观所有状况看上去均臻于至善至美之境。直到你把第一套系统推向真实的生产环境。身处生产环境里, 问题已不再处于静默状态, 而是变得响亮起来, 变得混乱不堪, 变得毫不留情。程序或许不会马上就崩掉, 然而一切都正朝着崩溃的方向缓缓行进: 日志被填得满满当当, 未曾设想过的边缘情况成群结队地出现, 原本正常运行的函数在高并发情形下开始频繁超时。在这个时候, 你才会发觉, 一个令人不快的事实出现, 那便是: 教程向你传授运行的方式, 然而生产环境却告诉你软件是怎样走向失败的。1. “代码能跑”只是及格线中的最低要求位于学习时期, 我们针对成功的界定相当简易, 即脚本得以运行, 输出是正确的, 且未出现报错。然而在真切的生产环境当中, 此标准将会快速瓦解。仅限于“能工作”的代码, 这肯定是远远不足够的。处于生产环境里的代码, 它必须要拥有四个强硬性质, 分别是: 压力存在时易于阅读、负载状况下能够预测、出现错误之际具备安全性、维护起来会让人觉得枯燥无味。我曾经编写过好多被认为“完美运行”的代码, 然而半年之后, 当其他人甚至包括我自己需要对其进行修改时, 那些自以为是的简写, 那些模糊不清的命名, 以及那些缺失的边界判定, 统统都变成了带着高额利息的技术债。生产环境给我的第一个教训是记着, 要是有个函数, 非得去写注释, 才可以让人弄明白, 那它说不定承担了过多的功能。2. 别让“聪明”的代码成为半夜加班的诱因在刚开始的阶段, 不少开发者着迷于一种简洁的美感啦 打个比方, 在进行生成器操作时, 把列表推导式放进里面嵌套着, 到处书写那样的表达式呀, 又或者执着于去追寻那种看上去显得特别高级的一行代码便是One-呢 尽管相关教程会对这种风格予以激励, 源于这样看上去颇具水准的。但在生产环境里这种做法会让你付出代价。在系统于凌晨两点出现崩溃状况之际, 没有任何人会有意愿去破解那些含义隐晦、难以理解的推导式, 像下方这般进行编写的程序代码就是示例:result [x for x in data if x.is_valid() and process(x) not in cache]虽其酷矣, 然于排查问题之际, 众人更愿见此写法此写法乃至稍显“土气”者:valid_items [] for item in data: if not item.is_valid(): continue processed process(item) if processed in cache: continue valid_items.append(item)写起来慢, 且占地方。不过, 其理解速度快得惊人。它的核心优势并非是让你少敲几次键盘, 其核心优势在于它无与伦比的清晰度。3. 错误不是失败而是系统给你的“信号”教程常常将错误视作敌人, 教给你怎样避开它们, 或者干脆运用try把程序代码包起来, 直至程序不再发出抱怨为止。但在生产环境中心态必须转变。错误是信号它们在告诉你于生产开发期间, 最为危险的行为当中的一种, 便是毫无任何上下文情境地去捕获异常。要是你惯于书写那样的代码, 即冒号与空格加上 pass, 那么 Bug 极有可能会在你的系统之内潜藏数月之久, 却不被发觉。生产代码需要有“目的性”的错误处理一个崩溃, 它带着详细堆栈信息, 往往情况下, 比那种吞掉错误从而导致数据污染的静默失败, 要好出许多。4. 日志是你在黑暗中的唯一眼睛于教程当中, 书写日志视之仿若无关紧要。然而在生产环境氛围之下, 日志系你之生命线, 为你可见性来源所在之根基。在问题出现之际, 挽救你性命的往往并非仪表盘, 而是日志。生产环境令我领悟, 务必要于以下这些关键节点记载日志:尤为关键的是, 得于出事之前予以记录, 并非在出事之后进行记录。良好的日志应当能够叙说一个完整的故事, 即: 系统打算做什么? 接收到了何种数据? 做出了怎样的决定? 缘何选择走这条路径? 倘若日志无法达成这些, 则其仅仅是占用磁盘空间的噪声罢了。5. 性能瓶颈通常不在算法而在系统消耗教程会教给你算法复杂度方面的内容, 会教给你Big - O符号相关的知识, 会教给你怎样去避免那嵌套循环的情况。然而在生产环境当中性能问题常常伪装得相当巧妙。我见过的那些最慢的 系统原因往往不是算法烂而是因为哪怕你已将算法优化至极致, 然而那在循环里调用千百次数据库的操作, 仍能够刹那间令你的努力化为乌有, 在生产环境当中, 我们实则更应当去追问, 我们于何处等待, 我们在重复着什么, 什么是能够缓存的, 什么是能够进行批量处理的。性能通常不关乎 本身慢不慢而关乎系统设计是否草率。6. 并不是所有的测试都能救命把教程弄得来写测试仿佛呈现而出的样子是特别直观的: 去撰写若干个单元测试对着输出进行一番断言, 只要覆盖率达到标准了便宣告一切都没问题了。然而呢, 摆在生产环境跟前的时候, 类似这样的一种幻觉马上就会一下子破碎掉。拥有百分之九十测试覆盖率的有些系统, 在上线几分钟之内竟会崩溃, 原因简单, 这些测试验证的是行为而非现实。生产级测试更看重假如存在这样一种测试, 当代码实现发生了改变, 然而功能表现却没有变化的时候, 它居然也会报错, 那么这种测试就不是在对你起到帮助的作用, 反而是在对你进行束缚了。7. 每一个依赖包都是一份长期合同教程老是极为简略地让你“径直安装这个包, 它可解决全部问题”, 然而在生产环境里, 每一个新增加的依赖, 都代表着一份长期的合同。它们会带来安全性更新需求, 会带来破坏性的版本更新, 会带来潜在的版本冲突, 还会带来长期的维护风险。现在我对待依赖就像对待员工一样谨慎系统依赖越少在出问题时你的掌控力就越强。8. 生产环境没有绝对的“纯净”教程有着这样一种倾向, 那就是将“最佳实践”看成是绝对真理, 可是生产环境却会运用“上下文”去替代这些持绝对观点的论断。有时候为了系统的稳定我们不得不做一些折中那并非教条主义者的那种优秀生产环境工程师, 是务实主义者。我们旨在的并非写出堪称完美样子代码, 我们要做的是于时间、风险以及业务压力之间去做出合乎情理的权衡。结语从“写代码”到“工程化”的跨越在某个时刻你与 的关系会发生微妙的变化。你不再执着于“这段代码是否足够优雅? ”, 而是转而不断反复确认“在实际真实情形里这段代码能够不出现问题正常运行吗? ”, 这意味着你已然从“学习”的阶段成功跨越到了“专业运用”的阶段。教程属于必要的起始点, 然而绝对不是最终点。生产环境能够教会你纪律, 教会你谦逊, 教会你克制, 会使你明白软件并非仅仅是代码, 它涉及到人, 涉及到系统, 还涉及到真实世界的后果。当你处在学习的时期, 务必要持续地奋发努力, 要是你已然深陷生产环境, 忙得不可开交满心焦虑, 那可要恭喜你了, 那些令你产生痛苦之感的经验教训, 恰恰是促使你成为一名货真价实工程师的必定要经历的道路。