DevOps 方法论漫谈(六):有品位的开发做 DevOps——不只管“能不能跑”,还管“好不好看”

系列写到最后一篇,想聊一个略带个人色彩的话题:有品位的开发做 DevOps,和传统运维做 DevOps,有什么本质不同?

当然这里没有贬低运维的意思。运维出身的高手大有人在,对稳定性和故障处理的理解深度,是很多开发出身的人比不了的。但我观察到的一个事实是:一个有良好开发素养的人转型做 DevOps,会带着一些“开发者的好习惯”进来,而这些习惯恰好是 DevOps 实践中很容易被忽视、却又至关重要的部分。

一、“能跑就行” vs “写得好看”

如果说运维出身的 DevOps 工程师有一个最常见的习惯,那就是“能跑就行”

脚本写完了,功能实现了,服务起来了——OK。代码长什么样不重要,命名规不规范无所谓,有没有注释看心情,重复代码复制粘贴不在乎。反正又不是给人看的,能跑就行。

但一个长期做开发的工程师,他的神经已经被代码审查训练得高度敏感。他看到不规范的命名会不舒服,看到重复代码会想抽方法,看到没有注释的关键逻辑会想补上。这不是装,是肌肉记忆

这种“写得好看”的习惯,放到 DevOps 场景里,翻译过来就是:

  • 脚本可读性:Shell 脚本不是写了就完了,要考虑后来人能不能看懂。变量命名要有意义,复杂逻辑要有注释。
  • 配置即代码:Jenkins Pipeline、Dockerfile、K8s YAML——这些本质上都是代码。既然是代码,就应该遵守代码规范:格式化一致、结构清晰、关键参数有说明。
  • DRY 原则:多个流水线里都有的公共逻辑,要抽成共享库或模板,而不是复制粘贴六份。

这些事情,短期看不出差别。但一年之后,十个服务、二十条流水线交织在一起的时候,“能跑就行”的债就开始还了——改一个配置要找六个地方,排查一个问题要翻半天脚本。

二、CleanCode 意识:代码是写给人看的

CleanCode 是开发领域的经典理念,但 DevOps 领域的脚本和配置,本质上也是代码。既然是代码,CleanCode 的原则就同样适用。

举几个实际场景:

场景一:Shell 脚本里的魔法数字。

# 糟糕的写法
if [ $retry_count -gt 3 ]; then
  exit 1
fi

# 好的写法
MAX_RETRY_COUNT=3
if [ $retry_count -gt ${MAX_RETRY_COUNT} ]; then
  exit 1
fi

一个常量提取出来,含义就立刻清楚了。

场景二:Dockerfile 的分层策略。

没有 CleanCode 意识的 Dockerfile 往往是一个 RUN 一把梭,所有操作挤在一起。但你稍微有点“结构意识”,就会想到:把变化频率不同的操作分开,充分利用 Docker 的层缓存。

场景三:流水线配置的单一职责。

一条 Pipeline 干了编译、测试、部署、发通知四件事,每个阶段都写死在同一个文件里。有结构意识的人会想:能不能把每个 stage 拆成可复用的模块?能不能用 shared library 来管理?

这些都是看起来“不紧急不重要”,但实际上决定了你将来走多远的事情。

三、架构思维:不被眼前需求牵着走

有开发经验的人做 DevOps,另一个隐藏优势是架构思维

架构思维是什么?说白了就是分模块、定边界、理依赖

放在 DevOps 场景里:

  • 不是所有服务应该用同一条流水线——不同技术栈、不同风险等级的服务,要设计不同的流程模板,但共享公共组件。
  • CI 和 CD 不是一个东西——不要把 Jenkins 脚本写得 CI 和 CD 搅在一起。CI 关注的是“代码合不合格”,CD 关注的是“能不能上线”。关注点要分离。
  • 环境的抽象要合理——开发、测试、预发布、生产四套环境,哪些配置是环境相关的、哪些是服务本身的,要分清楚。不要每个环境拷一份配置。

如果没有这种架构思维,DevOps 实践会演变成什么样子呢?——加一个服务就拷一条流水线,加一个环境就拷一套配置。 初期很快,但很快就会陷入维护地狱。

架构思维让你在面对复杂系统时,本能地去做抽象和分层。这种本能在开发工作中是常态,但在传统运维的思维里并不常见。

四、MR/CODEOWNERS:协作规范的力量

一个有品位的开发,通常经历过严格的代码审查流程。他知道 MR(Merge Request)应该怎么写——标题清晰、描述清楚改了什么和为什么改、关联需求单号、附上测试结果。

他也知道 CODEOWNERS 机制的价值——重要的模块,合入必须经过特定的人审批。

这些习惯放到 DevOps 场景里,意味着什么?

  • 流水线配置的变更也应该走 MR 流程。“只是改个配置而已,直接合吧”——这种想法在开发思维里是不可接受的。任何对生产环境有影响的变更,都应该经过审查。
  • 基础设施即代码(IaC)的仓库也应该有 CODEOWNERS。 比如网络配置、安全策略的变更,必须有相关的运维或安全人员审批。
  • 运维脚本也应该有版本控制和审查。 那些放在服务器角落里、不知道谁写的、不敢改的脚本,本质上就是技术债。

你可能觉得这些事情太“理想化”了。但你想一想:开发那边对代码审查的要求,是因为不审查就会出 Bug。那 DevOps 这边的配置变更,出了事就没事儿吗?逻辑完全是一样的。只是大家的意识还没跟上来而已。

五、产品思维:自建小项目带来的全局视角

最后想聊一个容易被忽视的点:产品思维

很多优秀的开发都有自己从零搭建小项目的经验——不管是个人博客、小工具,还是一个 side project。这个经历看似和 DevOps 无关,但它给了你一个特别宝贵的视角:从用户需求到最终交付的完整链路

你做一个小工具,你得自己思考需求是什么、功能怎么设计、代码怎么写、要不要加测试、怎么部署给别人用、出问题了怎么排查。这不就是一个迷你版的 DevOps 回环吗?

有这个经历的人,做 DevOps 的时候会自然地想到:

  • “这个流水线最终是谁在用?他们真正的痛点是什么?”
  • “这个流程设计完之后,使用者的体验是什么?会不会门槛太高?”
  • “这个工具不只是搭起来了,还要持续维护——文档、培训、问题反馈通道怎么建?”

这就是产品思维。你不是在“搭一个 Jenkins”,而是在“为团队提供一个持续交付的服务”。从产品视角来看 DevOps,你的关注点自然会从“我怎么配”转向“他们怎么用”。

六、开发出身和运维出身的本质区别

写到这儿,可以做个总结了。

运维出身的 DevOps 工程师,强在稳定性和故障处理。他们知道生产环境出事有多可怕,所以他们把稳定放在第一位。但他们的思维惯性容易让 DevOps 变成“运维自动化”——关注点集中在回环的后半段(部署 → 监控)。

开发出身的 DevOps 工程师,强在全流程视角和工程素养。他们理解代码是怎么写出来的,理解审查和测试的意义,带着 CleanCode 的习惯去做自动化和配置管理。他们的思维惯性是关注回环的前半段(需求 → 代码 → 测试),而把自动化和稳定性看作服务于交付质量的手段。

哪一种更好?不做价值判断。 但如果你问我:“我应该补齐哪些能力?” 我的回答是:

  • 如果你是运维出身,去写一段时间业务代码。不是写 Hello World,是真的参与一个服务从需求到上线的全过程。感受一下研发的痛,你才能理解 DevOps 回环的前半段为什么重要。
  • 如果你是开发出身,去管一个生产环境。不是搭完就跑,是真的接告警、排故障、做容量规划。感受一下稳定性的压力,你才能理解运维为什么那么“保守”。

两边都碰过,你才是真正意义上的 DevOps 工程师。

七、写在系列最后

六篇文章写下来,从文化谈到回环,从专业背景谈到工具链,从能力模型谈到开发品位。如果让我用一句话总结这个系列想表达的核心观点,那就是:

DevOps 不是一个职位,也不是一套工具,而是一种思维方式——用端到端的视角看待软件交付,用工程化的手段推动流程改进,用协作的文化替代对立的壁垒。

不管你什么背景、做什么工具链,只要你在往这个方向走,你就在做 DevOps。

每天前进一小步,就是一个新的高度!