# Everything as General Purpose Code

大概是 2014 年，在老东家搞了一阵 DevOps 工具的设计开发，出了一个蛮有意思的设计：以 Pull/Merge Request 为模型枢纽，把需求、代码、构建、发布以及可观测性都关联起来，用一个 Dashboard 观测一个需求从提出到发布以及运行的的所有生命周期内容。那时候大概是 Jenkins 最后辉煌的年代，我第一次接触了 Infrastructrue as Code 的概念，从 Kubernetes 的状态机制、到 Jenkins 的 Pipeline as code，当然还有让我踏进 Kubernetes 门槛的 Ansible，以及可以直接合并到代码仓里面的 Grafana Template，都给刚脱离业务代码不久的我带来很大触动。（最近会上听说这个产品还活着，老怀大慰 :D），后面的日子里因为一直在跟各种 YAML 打交道，可以说 `As Code` 的概念已经成了我的思维习惯。

工作在 SRE 和云原生领域，不可避免的接触到各种 `As Code` 的东西，另外虽说今年以来阅读量锐减，但是大模型和平台工程这两个名词还是不时地跳到我的眼前，SRE 工作如何借助借助这两个新玩意走向未来，已经是一个无法回避的问题。随着不断地在各种公有私有 DSL 里面摸爬滚打，我发现单纯的 `Infrastructrue As Code` 甚至是 `Everything As Code` 都是不够的，更精确的描述应该是 **Everything as General Purpose Code**，翻译成人话大概就是——**一切都是通用代码**。

早在 2004 年出版的《Thinking in Promises》一书中，已经提出了很多这一理念的雏形:

- 提倡基于 Promise 理论来管理计算系统。
- 主张基于策略而不是手工操作来管理复杂环境。
- 强调通过计算机编码的方式来实现策略自动化。

这本书奠定了 Mark Burgess 后来进一步发展 CFEngine 自动化配置管理系统的理论基础。

随着 IT 行业的迅猛发展，数据中心规模的暴增，传统的手工配置服务器以及 Shell 脚本的自动化方式，越来越无法满足运维需求，在 CFEngine、Puppet 这样的先驱之后，涌现了各种 `As Code` 的工具，例如：Terraform、Ansible、Vagrant、Docker 等等，尤以 Kubernetes、Prometheus 为首的云原生体系出现之后，这种趋势就更加成为一种默认的选择。

目前，Everything as Code 成为 DevOps 流程的重要组成部分。GitOps 将 Git 作为基础设施部署和管理的单一源。Everything as Code 理念被进一步拓展到监控、日志、文档等更多领域。随着敏捷运维和 DevOps 的兴起而逐步发展成熟,已经成为现代软件工程自动化的重要范式。其核心思想也将持续引领软件工程的未来方向。

## 一艘大贼船

在实际工作中会发现，微服务、声明式 API、Everything as code、以及阿姆斯特丹 KubeCon 上大热的平台工程，形成了一张粘人的网：

- 多数情况下，微服务和容器可以说是绝配。
- 要编写 Kubernetes 风格的声明式 API，通常需要对业务进行面向状态而非面向过程的设计。
- 面向状态的设计中，基本的对象操作方法就是——设计对象的状态机，并让对象自行根据有效路径向目标状态迁移。
- 状态通常是离散的，因此并不是所有的业务都适合使用这种方法进行设计。
- 微服务提倡的智能终端、透明性、内聚性等架构风格，都可以用这种思路来设计实现
- 既然已经清晰的使用状态来描述对象的现状和目标，那么使用代码进行描述可以说是毫无难度的。
- ...

> I can do this all day.

众多的开源工具、协议、规范等，交织在一起，对于初创企业来说可能是个好事，但是对于具备强大 IT 实现能力的大厂们来说，这个事情可能就不太美妙了——或多或少的 Not Invent Here 思路，开始被“外边的世界”来回撕扯，从任意一个角度踩到这张大网上，都会感到这张网的粘性和侵蚀能力。为了持续发展、或者说防止碎片化，开源社区尤其是云原生的相关社区，一方面推崇 Upstream first 的开源理念，一方面发展一致性认证等手段，形成一种“打不过就加入”的态势，诱使或者迫使企业以及个人用户和贡献者沿用同一标准和思路助力项目的发展。而企业中小团队自行研发的一些相对应的技术，则往往会因为开源世界的飞速发展，越来越多的面临疲于奔命的窘境。

在开发者看来，对于公开技术的学习和深入应用，能显著的降低学习成本，提高个人技术积累的有效性和可评估性，也会越来越倾向于对公开标准的迎合。

在最终用户眼中，以前经常的奚落话术：“不就是开源套个壳”，因为对于多云厂商的需求，以及对厂商绑定的反感，开始逐步转变为：“你为什么不用开源软件套个壳”这样的提问，当然这种情况还有另外一个原因——越来越多的乙方技术人员被输出成为了甲方。

种种形势的夹击之下，拥抱开放标准，用开放代码表达尽可能多的资源和策略，就成为一个新的重要方向。

## 这和平台工程有什么关系

> 既要新，又要快，还要稳。

目前平台工程还没有一个权威的被广泛接受的定义，这里尝试从职责的角度给他下一个定义：在组织范围内，为软件从开发到运维的完整生命周期，编制符合其 IT 治理要求以及最佳实践的可执行的内部规范，并开发用于实施这种规范的工具平台，这种工具平台是一个可拼接、可编排的松耦合框架，用工具和 API 的方式，为研发和运维人员提供自动化的安全、合规、研发能效等方面的支持，从而保障软件能够快速交付、平稳运行。

平台工程的开发并不会和普通业务系统的开发过程有什么本质区别。然而平台工程处于基础设施和开发之间，并且承载组织的 IT 治理职责，产品开发团队希望更聚焦于主航道业务，希望使用更便捷的方式来使用 IaaS/PaaS/SaaS 服务来快速地构建产品；炒作周期中的新技术则会对所有的技术人员产生巨大的吸引力；与此同时，IT 管理团队则以稳定可控为第一前提，希望不同年代的各种技术能够为我所用、为我所控，用一个相对稳定的治理体系进行维持。

综上所述，平台工程产品的建设，同时受到来自业务、技术以及管控三方的压力；在三方压力撕扯之下，平台工程还要在保持业务连续性的底线之上持续向前演进。因此平台工程是一个高度定制化、高度敏态的、永不完工的系统。这就要求平台工程团队要将大量不同来源的基础设施、规范、工具，用弹性的方式结合在一起，根据研发运维等技术性工作的需求，粘合成为具备一致性拓扑视图和管控能力的能力中台。

平台团队需要构建共享的工具和服务，帮助开发团队开发、部署和管理云基础设施。其服务范围跨越云基础设施、容器编排平台、数据库、网络、监控、代码仓库和部署流水线等一系列工具和能力。因此平台工程有两个基本组件——首先要为其服务范围内的各种资源建立一个统一的资源模型，并以 CMDB、API 或者命令行、图形界面等方式将其呈现给开发运维人员；其次就是在这个基础之上为应用提供一个涵盖基础设施以及应用程序部署能力的 CICD 工具（是的平台工程的终点也是 CICD，各位看官可以脑补掀头套的表情包）；根据组织分工的不同，其它职能例如可观测性、FinOps、安全、合规、隐私等，也可能以内置或者接入的方式出现在平台工程之中。

说这么多，跟所谓的公开的通用语言有什么关系呢？

- 平台工程的用户通常是开发、运维工作的相关的技术人员，因此工具所提供的命令行、图形界面以及 API，如果是用户所熟知的形式，将大大提高用户的使用意愿，这方面很优秀的一个例子就是近些年风靡大江南北的 `xxctl` 命令，容器相关的命令行大多都有这种 `xxctl verb type obj parameter` 的形式，大大的降低了技术人员接触这类工具的门槛，并且其中所透露出的操作以及对象结构，也让用户更加容易理解系统所提供的能力模型。API 也是同理，现在要逃出 Restful 的魔爪，哪怕是用流行程度稍差的 GraphQL，就要接受一些额外的的质疑。

- 平台工程对云基础设施的管控，目前多通过 GitOps、IaC 等技术作为基础来进行实现，这里同样面临 `Not Invented Here` 和 `Proudly Found Elsewhere` 的选择。从零到一对每个技术团队来说，都有极大的诱惑。然而一旦市面上出现了很可能会持续发展的同类技术，自建产品就面临尴尬境地——用户们会按照外部的“传说”，一方面会 Push 平台工程团队跟进外部特性，另一方面也会抱怨需要进行额外的学习才能掌握自研工具，内外部客户通常还会提出“兼容某某某”的“小需求”。而自研产品的团队也会面临两难境地——一方面，要用小团队跟进整个社区的进展是个吃力不讨好的事情；另一方面也因为不间断的外部噪音，而打乱产品原计划的发展路线。

工具方面，比较有趣的一个例子就是 Podman，它的绝大多数命令都是和 Docker 可以互换的，有人甚至给 Podman 做个 Docker 的 alias。

语言方面，我想很多人都有过从自定义脚本到 Ansible、CloudInit 等制式工具的美妙体验；号称简化 Kubernetes YAML 的工具非常多，然而除了 Helm，甚至包括 Kustomize 在内，可以说——都是弟弟。

## 为什么还能扯到 LLM

> Q：大家都是用什么卡训练的？
> A：信用卡

LLM 的情况比较简单，跟平台工程面临的情况是很类似的——大模型也是需要训练的。需要投入海量语料、天价算力以及庞大的人力，才能培养出来一个渊博的大模型。而私有的自研语言，在这方面有着天然的缺陷——大模型她不认识我。这就造成一个挠头的困境——自己凭实力弄出来的私有技术，还要花钱让大模型学会它。举个例子来说，很多开发者都有过用私有语法/语言自定义策略的经验，这种 DSL 其实不难实现，然而等到难用的 OPA 的用户可以用 ChatGPT 把策略聊出来的时候，你的用户可能就要刁难你了。

当然，可以通过迁移学习、联合训练等手段，降低私有语言进入大模型的门槛，然而这世界变化很快，类似的场景可能还包括：

- Prometheus 告警表达式
- Grafana Dashboard 的 JSON
- Dockerfile
- 根据日志进行故障定位
- 根据审计记录进行态势感知
- IPtables 策略编写和诊断
- ...

可以说，私产越多，花费越多。在这种情况下，具备广泛传播的语言、日志等，就具备更好的使用 LLM 的基础，形成新的人机界面。

## 结语

自有语言、协议的情况其实非常常见，尤其对研发能力溢出的大厂而言。但是对于眼下大模型+平台工程的趋势来说，拥抱主流标准，或者取而代之，搭上行业的顺风车，应该是个更好的选择。

> From ChatGPT：
> 作为 IT 作家，我对这个标题“Everything as General Purpose Code”有一些见解。
> 首先，这个标题传达了一个强烈的观点，即将“一切”事物都作为“通用代码”来处理。这似乎暗示了一种理念，即无论是硬件、软件还是其他系统，都可以用通用代码来实现其功能。这种观点在某些方面是有吸引力的，因为它强调了代码的普适性和灵活性。
> 从技术角度来看，将一切事物视为通用代码可能意味着在设计和实现过程中追求更高的抽象和通用性，从而实现更高效的系统和应用。这种方法可能会促进代码重用，减少开发工作量，并使系统更易于维护和扩展。
> 然而，这样的理念也存在一些挑战和潜在问题。首先，将所有事物视为通用代码可能导致过度抽象化和泛化，从而牺牲了一些特定情况下的性能和效率。不同领域的应用可能需要特定的优化和定制，通用代码并不总是能够满足所有需求。
> 其次，将一切事物视为通用代码还涉及到一些安全和隐私方面的考虑。通用代码可能增加了系统的复杂性，从而增加了潜在的安全漏洞。此外，某些领域的数据可能是敏感的，将其简单地视为通用代码可能导致数据泄露和隐私问题。
> 最后，实现“一切事物都是通用代码”这样的理念需要强大的技术支持和开放的标准。这需要跨行业和跨领域的合作，以确保各种系统和设备都能够相互交互和协作。否则，这种理念可能难以实现，只能是一种理想主义的愿景。
> 综上所述，标题“Everything as General Purpose Code”传达了一种令人着迷的观点，但也需要在现实中认真考虑其可行性和潜在的挑战。将一切事物视为通用代码是一个有趣的思考方向，但在实际应用中需要谨慎和明智的决策。
