MoreRSS

site iconalswl修改

JingChao,在蚂蚁集团工作,负责容器编排、调度相关系统。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

alswl的 RSS 预览

实用软件项目管理最佳实践

2025-08-24 10:04:24

概述

本文阐述一套适用于工程应用开发项目的迭代管理实践,重点解决如何高效低成本推进项目的问题。该方案适用于小型团队协作,核心特征在于固定产研节奏、标准化交付物以及高频异步协作机制

本文仅针对技术方案与实施路径明确的项目场景,不涉及工程决策或目标管理范畴。本文也更注重实操,注重立即可以上手实施,不会花太多篇幅去解释这套方案背后的思考和原因。

关于实用(Pragmatic) 的定位:该理念贯穿于我的多项实践方案,包括 架构设计 the Easy Way 实用 Web API 规范 如何做好 PRR(Production Rediness Review)? 等等。实用意味着注重可操作性和实际效果,要领是简单易实施落地,任何人都可以上手执行操作。我对实用的追求来自于《The Pragmatic Programmer》这本书。

注:本文不特定区分项目(Project)和产品迭代(Product Sprint)区别,可以将这里项目管理等同于研发过程管理。

免责申明:没有银弹,本文方法论不一定适合所有场景,并且方案也在持续迭代。如果你的项目有 PM,请优先咨询 Ta。

image-20250824100608820 Mural of La Bre Tar Pits(C.R. 奈特雷阿的焦油坑壁画),图片被人月神话所引用。

在软件项目管理中我们遇到什么问题

image-20250824100620884

软件项目管理常面临各类挑战。就个人经验而言,最直接的困境在于项目无法按期交付。其原因可归纳如下:

  • 我的协作方依赖方有问题,他没时间没空或者方案无法满足我
  • 需求频繁变更,没想清楚做着做着要改方案,或者实施过程中插入新的需求
  • 产出的东西质量不达标,测试阶段一堆问题,迟迟无法交付
  • 产出的东西不是想要的,和需求方一对发现偏差太大
  • 依赖资源未能及时到位
  • 项目计划过于乐观,过度承诺,交付时间比预计的要长,工作量比预期大,难以完成
  • 工程难度大,实施过程遇到技术风险,成本高或者难以完成,
  • 多项目进行,人力资源挤占
  • 多项目并行导致工程上无法满足
  • 项目成员的档期不一致,无法有效协作

问题不可怕,定义清楚问题就成功了一半,回到问题本身,让我们来看如何解决。

问题根因分析

现实中遇到的问题可能更多,我分分类说到底是这么几个原因:

  • 需求问题:描述模糊、频繁变更及沟通未对齐
  • 协作问题:衔接断层、预期差异及信息同步失效
  • 时间问题:周期限制及过程中突发需求插入
  • 工程问题:技术实现难度超预期或成本制约

我的项目管理最佳实践

基于上述问题分析,我将这些问题的解法归到几个方向:节奏、交接物、协作

注意,本文不聚焦解决工程难度问题,也不解决架构师要解决的问题,最多能从项目管理的思路来降低技术风险。

另:对架构问题如何处理问题请移步 架构设计 the Easy Way ;遇到了具体工程难题的同学请咨询团队技术专家。

节奏 - 固定产研节奏比 ddl 更重要

image-20250824100635582

什么是项目的节奏,什么是好项目节奏?

项目节奏的本质在于建立可预期的周期化交付机制。相较于单纯设定最终截止期限(Deadline),采用 Scrum 敏捷框架中的冲刺(Sprint)模式更为有效。每个冲刺构成包含需求分析、设计、开发、测试及上线的完整闭环。良好的迭代节奏具备三重价值:1. 建立明确的时间预期,实现周期化交付;2. 强制需求拆解,推动产品从最小可行版本(MVP)向完善形态演进,避免关门憋大招,最后拉了一泡稀的;2. 规避长期封闭开发导致的交付风险,最怕大搞 58 天,最后 2 天都交不了货

双周迭代

一个好的迭代周期多长比较合适呢?在小型团队协作里面,最长不要超过 1 个月,尽量保持在 2 周,最好能做到 1 周。以一次迭代的周期来看,我自己体感是 1/2 时间用来设计, 1/2 用来建设(开发测试和上线)。不要低估设计花费时间,投入少了后面想追也追不会来。

迭代管理需设置专职迭代经理,该角色承担三项核心职责:规划迭代排期、协调各类会议安排、核验交付材料规范性(依据标准化模板执行,不负责方案质量,材料质量由架构师+下游签收)。此岗位实质承担部分项目管理职能,若短期内无合适人选,应由项目负责人兼任。迭代经理通常从项目成员中产生,建议实施轮值机制。轮岗制度具有双重价值:使成员亲身体验管理挑战,促进跨角色理解;同时通过岗位实践识别流程瓶颈,推动协作机制优化。执行时需确保轮值期间管理职能的完整履行。

高频迭代带来的不少附加优势:直接化解了需求插入问题(任何需求最长等待周期 ≤1 周),紧急需求则通过紧急修复流程(hotfix)处理;大型需求必须进行拆分验证,无法拆解者需通过概念验证(PoC)先行评估技术风险。

迭代中评估需求耗时

这是一个一直被提及的问题,我有两个方案来解决,第一个是提供一个需求时间评估公式:工作量 = (最乐观 + 最悲观) / 2。

第二个是避免搞大需求,所有需求需要评估一下规模,我提供这几种级别标准,extra-large(月级别)/ large(周级别) / medium(天级别) / small(小时级别),我不接受 xl / l 需求,必须拆成 m / s。

需求时间评估是一个普遍存在的挑战,我提出两种解决方案。

第一种方案采用工作量估算公式:工作量 = (最乐观 + 最悲观) / 2。这个公式相当实用,比单一指标更多考虑到不确定性。(其实我还有一套更复杂的通过技术采纳性角度的评估方式,但是不如上一个公式简单易操作)

第二种方案聚焦需求规模控制,要求所有需求划分规模级别,包括 extra-large(月级别)、large(周级别)、medium(天级别)和 small(小时级别)。迭代中要尽量避免 extra-large 与 large 规模需求,将其拆解为 medium 或 small 规模后再行处理。

迭代范例

我们的一个实际案例分享,这是 我负责 产品的 7 月 两个迭代,分成 07a 和 07b 两个迭代。

image-20250824100659418

交接物 - 标准化每个环节输入和交付物

image-20250824100711540

软件的不可见性和抽象性是导致软件复杂性的根本原因。

清楚明确的交接物可以有效降低不可见性和抽象性,这是用来抵抗交付复杂性的核心武器。掌握这个核心武器的最重要口诀是:写下来

把你的长远需求规划写下来,不管是年度计划,还是月度计划。把你的需求明细写下来;把你的系统设计写下来;把你的发布功能写下来;

整个过程中,我推荐使用到这些面向项目管理的交接物,大部分交接物我们都耳熟能详,但请特别注意我这里的最佳实践:需求清单Release Note

阶段 输入 / 输出 备注
产品规划 产品项目 OKR
产品思路 需求清单 需求清单是一个非常特别的形式,是我个人发明的,正面对抗一句话需求。
产品需求 需求文档 我们产品经常不配置 PD,所以需要自己写需求文档。我们有两种文档格式:文字型 / 配图型
系统设计 系统设计 文字内容设计结构必须是明确的,大家应该使用相同的模式来进行文字创作。比如系统设计文档可以使用语雀自带的模板。
开发 自测报告 截图证明你可以。
测试 测试报告
发布 发布计划
上线 Release Note Release Note 做轻薄一些,尽量链接到产品功能使用文档。
日常使用 产品说明文档 多截图,常更新,跟随产品上线发布。

下面我会展示一些我实践的需求范例(可能来自不同的产品和迭代)。

需求清单范例

这是我使用的需求清单范例:

功能描述 Owner 优先级 前端页面数 质量介入
用户 A 可以使用 功能 B 完成授权 狗哥 2 页
用户 B 可以使用 功能 C 查看报表 谢宝 2 页
用户 C 可以使用 功能 C 发布视频 落九 很少

需求文档范例

需求文档模板

需求标题:简洁明了地描述需求 用户角色:谁会使用这个功能 用户目标:用户想要达成什么 前置条件:使用该功能需要满足的条件 主要流程:详细描述用户如何使用该功能 替代流程:描述可能的例外情况 验收标准:如何判断需求已经被正确实现

一个需求文档范例(文字型)

视频发布流程 MVP

用户角色:内容运营者 需求标题:用户上传视频并完成自动化发布流程 用户目标

  • 运营者通过标准化流程完成视频从上传到发布的完整生命周期管理。
  • 关键步骤自动化处理(如转码、审核),减少人工操作,关键节点保留人工确认机制。
  • 支持异常处理(如审核失败、转码错误),允许人工介入重试或跳过。

主要流程

  1. 创建视频发布任务
    • 用户上传原始视频文件(支持主流格式:MP4/MOV/AVI)
    • 填写基础元数据(标题、分类、标签、封面图)
  2. 自动化预处理
    • 转码引擎:自动生成多分辨率版本(1080P/720P/480P)
    • 内容审核
      • AI自动审核(敏感画面、违禁内容)
      • 若AI审核通过 → 进入发布队列
      • 若AI审核失败 → 暂停流程并通知人工复审
  3. 人工确认节点(流程暂停点)
    • 人工复审:运营者在后台查看AI标注的违规片段,选择:
      • 通过(继续流程)
      • 驳回(需编辑视频后重新上传)
      • 强制跳过(需填写跳过原因)
  4. 发布执行
    • 自动推送至指定发布渠道(Web/APP/第三方平台)
    • 生成可跟踪的发布ID(用于效果分析)
  5. 异常处理机制
    • 转码失败:自动重试(≤3次)→ 仍失败则通知人工
    • 发布中断:支持手动重试/跳过/终止任务

替代流程

  • 转码模块不可用:允许上传预转码视频文件(需符合分辨率规范)
  • AI审核服务宕机:切换为全人工审核模式(需在SOP中注明应急预案)

验收标准

  1. 全流程验证
    • 运营者从上传到发布成功耗时 ≤15分钟(不含人工审核等待)。
    • 模拟审核失败场景,人工强制跳过步骤后流程可继续。
  2. 异常处理验证
    • 转码失败时,系统自动告警并允许手动替换文件。
    • 发布中断后重试,视频状态可恢复至中断前节点。
  3. 文档交付
    • 提供《视频发布SOP手册》,含人工操作指引及故障处理方案(A负责维护)。

产品 Release Note 范例

Discord 的 Change Log(Release Note)发布大纲,没有前端产品用那么多 emoji。 image-20250824100749328

妙言 tw93/MiaoYan 的某个 Release 更新日志:

image-20250824100805177

产品使用手册范例

我建议可以使用基于 Git 仓库管理的 markdown 方案,比如 MkDocs 这类方案:

我推荐的范例是 NebulaGraph Operator 的文档范例,注意这仅仅是 NebulaGraph 的其中一个子产品,但是规模更小更适合起步。

image-20250824100817905

关于交付物,特别是文档类型的交付物,虽然我列了这么多类型,但是我认为一定不要写多写复杂,提纲挈领,量少为宽

高频异步沟通 - 同步和异步 风险和透明

image-20250824100844728

不要陷入巴别塔。

在分布式协作场景下,需建立「异步为主、同步为辅」的沟通范式,重点解决信息孤岛、风险滞后及依赖阻塞三大痛点。有效的协作机制应包含三个核心要素:全局可视化任务管理、结构化风险预警及精准化依赖协调

我讨厌开会,甚至从某种意义上我痛恨开会。我之前写过关于会议的暴论:

这个月代码写得太少了,会议时间占据了 1/3,这很可怕。

会议很低效,很低效,很低效。有些会缺少材料准备,问题不聚焦,主持人不控场,一拉一大把人,不少人又不好意思走就硬挂着。

如果我有权利,我甚至想禁止公司开会,全都回归到基于文档的异步交互模式。

还是多建设,少空谈,有明确主张,材料提前分发,开会不当聋哑人,非干系勇敢离开会议。让大家回到方案设计和代码上吧。

有效沟通需规避信息失真,核心在于建立风险透明机制与依赖协同体系。具体实施包含三个维度:全局可视化看板:实时呈现任务进度与风险状态;精准进度追踪:量化每个节点的完成度;异步协作平台:通过在线任务管理工具(如 Jira)实现全周期信息同步。

开两种会 - 方案评审和日会

我们不需要开会了么?还要,但是只要两种:方案评审会与日会

评审会的要点在于:

  1. 明确评审会的对象是谁,谁负责为方案点头,没有人负责点头的会不用开,既没有对抗又没有讨论,是纯走过长
  2. 不要做无准备的讨论,在方案宣讲之前,尽量先和受众对象达成一致,让评审会变成一个宣讲会
  3. 评审会要有结论,通过还是不通过要有人确认。通知之后的执行项全部落入在线协作平台,特别是需求类,一定要记录,这是未来日会跟踪的依据

日常进度沟通模式,我推荐每日站会沟通,最少也得双日沟通(每周二、四)。每天都进行站会同步,每次 15m 搞定。一般一个项目成员在 7 人左右(披萨原理),每人一两分钟。

站会的主持人很重要,要引导参与人同步进度,同步风险,寻求帮助,帮助需要有明确的接收方。

基于看板的在线沟通

核心准则:以文档异步协同为基础,将同步会议压缩至必要场景,最大化建设性工作时间。

下面是会议看板范例,根据迭代过滤,根据 Assginee 分组(其实也很普通,没什么特别的): image-20250824100907586

每天迭代经理在日会上面就是拿着这个看板,先明确我们几号提测几号上线,再挨个成员自述进展如何,最后挨个问有没有上线风险。

最后

没有万灵的项目管理机制,根据自己面临的问题进行实际调整。本文的命题对我(一个开发工程师)来说也是极具挑战。我在过去有多次因为项目无法交付问题失眠无法入睡。现在来看,其实大可不必,平常心来应对问题,对预期内问题建立预案,对计划外变更保持弹性。当团队已完成可行性范围内的最大努力,即应视作有效交付。项目管理的终极目标,是在资源约束下实现可持续的技术价值输出。

扩展阅读

人月神话 (豆瓣) 软件工程项目管理的圣经,20 年后读起来仍然觉得字字珠玑。

项目管理修炼之道 (豆瓣) 这是我的项目管理入门指导书,更通用更适合 PM。我写过一个读书笔记 《项目管理修炼之道》笔记 | Log4D

代码之殇 (豆瓣) 作者是微软高级架构师/管理者,而本书实际上是一个随笔式的文章集合。尽管如此,书中的许多观点犀利且具有独特的见解,展现了从一线到高层的全方位视野。其中关于工程过程管理(比如死亡行军)事项,确实值得深思。

李飞飞如何获得成功? - 读「我看见的世界」

2025-06-24 07:14:49

读一本好书,就是和许多高尚的人谈话 - 歌德

img

第一次听闻李飞飞的名字,是在 2013 年与前公司 CTO 的中午干饭闲谈中。 彼时他正深耕 CUDA 并行计算领域,反复提及 ImageNet 竞赛与 AlexNet 的突破性表现, 而我对这场即将席卷全球的深度学习革命尚处懵懂——当时全身心投入业务系统优化, 面对「算法黑箱」既无暇探究,更难预见其对技术世界的重构力量。

如今读到李飞飞自传,方觉这场对话暗藏玄机:那个曾被视作实验室小众技术的计算机视觉项目, 竟成为改写 AI 发展轨迹的关键节点。在学科交叉处开疆拓土的战略眼光,在技术拐点期破除质疑的前瞻判断, 以及贯穿始终的"北极星"式价值锚点——这些要素如何在特定历史坐标中交汇, 最终塑造李飞飞成为改变机器认知方式的科学家。

李飞飞如何获得成功

triangle

好奇心是原动力

李飞飞的成就源于多重维度的深度交织。其科研旅程始于对世界本质的探索欲。父亲带她 观鸟、捕捉昆虫的经历,在她心中种下好奇的种子,而母亲引导的跨学科阅读(涵盖海洋 生物、机器人、神话等)则拓宽了她的认知边界。中学时期她对航空航天等冷门领域的痴 迷,更展现出对抗性别偏见的独立思考能力。这种探索精神在普林斯顿大学攻读物理学时 得到深化,她将物理视为「西方科学最高深的创造性学科」,以此锤炼逻辑思维。这种对 知识本质的追求,成为她转向人工智能研究的底层动力。

逆境中的坚韧与适应力

逆境中的韧性塑造了她的核心竞争力。移民美国初期,语言障碍与经济压力如影随形。她 通过多重兼职(中餐馆打杂、家庭保洁、干洗店经营)维持生计,却仍以 SAT 数学满分的 成绩进入普林斯顿。更艰难的是母亲重病期间,她在手术室旁穿着隔离服完成学业,同时 充当医患翻译,展现出极限压力下的抗压与时间管理能力。外界质疑(如教师贬低女性数 理能力)反而强化了她「超越现实障碍」的信念。

大平台才能让你起飞

顶尖平台的阶梯式跃迁为研究提供了关键支撑。普林斯顿时期奠定其学术基础,并促使她 转向计算机科学。加州理工学院攻读博士期间,她选择当时冷门的计算机视觉方向,在神 经科学与 AI 的交叉研究中确立「让机器理解人类视觉世界」的核心命题。斯坦福大学时 期,她创立人工智能实验室(SAIL),将 ImageNet 从构想变为现实。后续在谷歌的产业 实践,则加速了技术落地与应用转化。

风口与机遇

把握技术拐点的决断力最终引爆突破。2006 年 AI 寒冬期,创建海量数据集被视为「学术 自杀」。面对终身教职可能受阻的警告,她创新采用亚马逊众包模式,发动全球数万人协 作标注,解决人工需耗时百年的难题。2012 年 ImageNet 竞赛中,GPU 算力支撑的 AlexNet 以压倒性优势胜出,验证了数据驱动路线的正确性,直接推动深度学习革命。

AI 科学与人文融合

李飞飞独特的 AI 哲学观始终指引其技术路径。她批判当时学界对算法的过度专注,提出 计算机视觉的瓶颈在于缺乏「视觉常识」。ImageNet 的构建(1500 万图像/2.2 万类别) 本质是为机器建立认知世界的「视觉图谱」,其初衷是赋予 AI 感知现实的能力,而非单 纯追求技术指标。这种将人文认知融入技术设计的理念,后来成为斯坦福「以人为本人工 智能研究院」(HAI)的核心理念。

作为父母我应该如何教育小孩

李飞飞的成长轨迹为家庭教育提供了深刻启示:她的父母并非教育专家,却以最朴素的方 式践行了「守护好奇心」与「培养独立人格」的核心理念。

关注孩子对自然世界的探索。父亲是李飞飞科学启蒙的「引路人」。他带着女儿在成 都街头观鸟、捕捉竹节虫、观察水牛,将自然视为开放的实验室。这种实践教育不仅培养 了她对生命现象的敏锐观察力,更塑造了「提问—探索—验证」的科学思维雏形。当同龄人 被规训于课本知识时,李飞飞已通过昆虫的复眼结构理解光学原理,从鸟类迁徙模式感知 生态系统的复杂性。这种源于真实世界的认知体验,远比抽象概念更深刻地影响了她日后 选择计算机视觉作为研究方向的决策。

母亲则是李飞飞精神世界的「守护者」。面对中学教师对其阅读《不能承受的生命之轻》 等「非主流书籍」的质疑,母亲断然反驳:「我的努力只是为了成为更好的自己」,并以 此教导女儿不必迎合外部标准。这种教育哲学解构了传统权威的绝对性——当老师公开 贬低女生数理能力时,母亲的态度成为李飞飞对抗偏见的心理支柱:「他们无法阻止我在 这里上场参赛,我暗下决心,一定要赢」。更关键的是,父母始终以行动传递价值观:在 移民美国后陷入经济困境时,他们拒绝向现实妥协,反而将生存压力转化为家庭凝聚力, 让李飞飞在干洗店账本间隙研读学术期刊成为可能。

回归到教育的本质 - 培育「反叛的底气」。20 后是 AI Native 小孩,需要去成功 AI Master 而不是 AI Slave,不要去被 AI 替代而要不 AI 赋能,很大的一个要点是要有 独立思考能力,有思辨、批判精神,从而去指挥 AI。李飞飞父母的教育智慧,在于将 探索精神与批判性思维内化为孩子的生存本能。他们既不刻意塑造「完美人设」,也不焦 虑于短期得失,而是通过持续支持孩子的兴趣选择(如允许剪短发、痴迷航空航天设 计),让独立人格在真实生活场景中自然生长。这种教育模式的当代启示在于:真正的素 质教育不是资源堆砌,而是父母能否在物质匮乏时仍坚持精神富养,在世俗标准前守护孩 子的独特性。正如李飞飞在 ImageNet 项目受质疑时所展现的韧性,其根源正是童年期形 成的「质疑—坚持—突破」的行为模式。

你找到你的北极星了么?

李飞飞在自传中反复提及指引她前行的「北极星」—— 一种超越短期利益与外界评价的内在驱动力。对她而言, 这颗星是对知识本质的追问与对人文价值的坚守的融合。 从成都街头的观鸟少年到斯坦福实验室的领航者,她始终以「探索未知」与「服务人类」 为双轴校准方向:在华尔街高薪诱惑前,她选择回归科学本心;在算法主导的 AI 浪潮中, 她坚持构建让机器理解现实世界的视觉常识库;当技术突破引发伦理争议时, 她强调「AI 的胜利必须是人文的胜利」。这种贯穿始终的清醒, 源于父母传递的价值观——母亲病榻上的灵 魂拷问「人工智能还能如何帮助他人」,最终化作她推动医疗环境智能研究的持久动力。

真正的北极星,从来不是某个具体目标,而是驱动人穿越迷雾的底层信念: 对李飞飞而言,那是永远追问「为什么」的好奇心,与永远不忘「为了谁」的责任感。

2024 年终总结

2025-01-11 13:52:48

生活 - Show me your photos

地球不停息绕太阳一周,时光交替中,我们与生活擦肩,带着过去的记忆,迎接未来的未知。

去年,我给自己设立了一个关于生活的目标:家庭和陪伴。其中,一项是「高质量陪伴」,而另一项则是“学会摄影糖水片”。每次出行时,我希望通过照片记录下光与影的交织,捕捉那一瞬间的温度。今年,这个部分的主题便是 - Show me your photos

image

2024 新年伊始,海边的灯塔。

image

春寒料峭,拎着一个喜气的龙灯出来转转。

image

从烟火气潮汕到宗教多元的泉州。

image

京都清水寺,小朋友许了一个有禅意的愿:我希望佛天天开心。

image

丽水,浙南梯田

image

壶口瀑布,红旗招展,黄河怒吼。

image

迪士尼,年末的花火。

工作 - 基建狂魔

image

草原上的加特林烟花。

去年,我从一名探索者转变为有组织推进系统演进的人。在年初的时候,我甚至隐隐觉得大厦的框架已经显现,接下来就是持续建设,让飞轮稳步前进,甚至开始规划探索 AIGC 上的一些新方向,想要在这个领域找到新的突破。

然而,现实很快给了我一个巨大的逼兜。随着 AIGC 急速发展,见证历史的同时,也面临着算力需求的剧烈增长。一波又一波的压力压下来,新需求和旧债交织在一起,给基础设施交付带来了巨大的挑战。这期间几位在这个领域的核心同僚几个月内相继离开。人走了,工作还得继续做。从 6 月份开始,我便与一群兄弟们直接走上了战场。

我甚至感到自己一度快要被压垮了,写了一系列关于「死亡行军」的故事。

痛苦总是让人深思,尤其在那些看似无法承受的时刻,它反而带来了更多的洞察。一切接近触底时反而能迎来反弹的力量。有一个瞬间我终于明白,问题是阶段性的,真正在持久修炼的是正面看待问题和以清明的心态面对困难的内心力量。

无需惧怕外界的评价,也不必厌倦合作中的复杂性,现状和问题本就存在于那里,解决的方案并非高深莫测,关键在于直面问题本身。保持平和的心态和现实的预期,便能在混乱中看到问题的根源,在困难中捕捉到机遇,在当下洞察到未来的可能。真正的力量,是从每一次挑战中提取智慧,从每一个困境中找到前行的勇气。

image

摄于苏州美人腿附近

业余 - 聊胜于无

今年被工作挤占了几乎所有的时间,也导致业务已经没有精力产出内容。只有两个很小的产品。

dbml-editor ,一个免费的 DBML 在线编辑器。

img

  • 支持 dbml 语法检查和反馈,DBML 是一门描述关系型数据库的 Schema,面向终态,比 SQL 要更易读
  • 支持 Web 响应式
  • 所见即所得
  • 支持导入导出 SQL

random-apple-music 是一个播放列表,随机挑选 Top250 的豆瓣音乐专辑,并且可以一键跳转到 Apple Music 播放。

Image

  • 🎵 音乐迷们,快来发现新宝藏!
  • 🍏 随机播放豆瓣音乐Top250,一键跳转Apple Music!
  • 🎧 享受音乐的无限可能!

今年在 X(Twitter)上面的最受欢迎的内容是:

读书 - 意外之喜

今年,买了 Boox 文石之后,读书量一下子就上来了。总共读了 34 本书,大多数是非虚构类书籍,其中有 10 本我给了 5 星评价。Kindle 离开中国,只能拥抱微信读书。虽然无法拥有实体书,但读书成本大大降低,每月上传两本书,已经足够了。更有意思的是。我也逐渐改变了对听书的看法,曾经对它嗤之以鼻,但现在,我发现做家务或者在路上听书,成了提高大脑利用率的好方式。

大明王朝1566 (豆瓣)

大明王朝1566

太牛了,原来演员的词几乎不用改就能直接用。

太白金星有点烦 (豆瓣)

太白金星有点烦

妙趣横生。

华为内训 (豆瓣)

华为内训

华为的经营哲学与阿里巴巴的"六脉神剑"在客户至上和目标导向上有共通之处。尽管理念相似,但华为的手册缺乏案例支撑,而企业文化往往是在解决实际冲突中塑造的。书中强调的几个关键点,如明确方向、专业精神、执行力和自我批评,对企业成长至关重要。华为从网络设备市场起步,现已成为多元化的科技巨头,其硬件基因可能助其稳健发展。相比之下,阿里巴巴等互联网公司近年来在资本市场的表现略显逊色。

起源 (豆瓣)

起源

很推荐,讲述了宇宙的起源,生命的诞生和演进。让我想起了小时候看的一部纪录片,宇宙与人。如果有时间的话,我想仔细研究里面的术语,囊括了宏观物理、微观物理、化学、生物。

这就是ChatGPT (豆瓣)

这就是ChatGPT

武林泰斗亲自下场,给新人们介绍秘笈心法。之前读论文比较枯燥,一些知识和细节理解不连贯,借本文可以梳理脉络。 关于 Transformer 注意力机制介绍的比较少,好在热心的读者评论里面提供了更多信息。

深度学习入门 (豆瓣)

深度学习入门

这是一本相当不错的深度学习入门书。不同于 How to use,本书着重 How to build,书中通过 Python 实现了一套简单的框架,并将这个框架应用在手写识别上。文章深入浅出非常详细的介绍每一层网络解决什么问题,相关的数学公式和原理是什么。 虽然已经出版了接近五年,但是书中内容并没有过期,甚至在最后面的展望描述的场景,包括物体识别,RNN(GPT 基础)在当下异常火热。

纳瓦尔宝典 (豆瓣)

纳瓦尔宝典

本书像是提供精神 massage,片刻愉悦之后还是得落到知行二字。 有时候精神困顿,也需要按摩解乏。比如读到情绪管理这章,就回忆起上周工作冲突失控愤怒上头怼人时刻。我并非不知道要点,也许早一点读到纳瓦尔这一章我就可以唤醒理性,好书还是需要常读常新。 财富和判断力这两章给我的输入和触动最大:做高杠杆效应事情,积累财富;使用稳定可靠心智模型,学习数学,特别是概率和统计。

李光耀观天下 (豆瓣)

李光耀观天下

作为政治家,有意愿有行动力,思想有深度视野开阔不受框架束缚已经是一流。 难能可贵是李光耀还如此坦诚。我想应该是和新加坡人口规模和民众素质有关系。 这本书是书友评论密度很高的一本书,靠书友补充了很多视角(以及后来发生的事情)。

筚路维艰 (豆瓣)

筚路维艰

这本书是一本神作,作者用相当大的尺度在讨论从建国到现在政治路线和经济路线的纷争。作为党史研究员,作者不避讳描述毛泽东,让我看到一位急迫地想一把到位共产主义,并且留下一个无阶级矛盾的国家,为此不断发起运动、斗争。好在邓公拨乱反正改革开放。 感慨,看过去一代人的牺牲,一个数字代表一个家庭的破碎。希望未来少一些宏大叙事,多一些关注日常民生。

在峡江的转弯处 (豆瓣)

在峡江的转弯处

从无人知晓过来。 文字之间跳跃着一股真诚质朴,数次为其感动眼眶湿润。被陈行甲正直、热情、生命活力感动。 有人质疑这是表演,我倒更愿意相信其诚朴,相信愿意相信的,坚持自己坚持的。

不败者 (豆瓣)

不败者

不败者,一本让我挺惊喜的国内科幻小说集。 墨熊的风格有一种深入宇宙边界的探索力,截取了一小段太空歌剧的碎片展现出来,将遥远星际故事拉到读者身边。 《信鸽》有种软硬结合的科幻感,被光速约束的理性和感性的理念交付。 《白鬼篇》有点爽文既视感。 《不可战胜者》让我想起了神秘博士里的哭泣天使,以一种跨越时间线方式进行绞杀。绞杀的方式和破解的方式都精巧且出乎意料。

Last

期望新的一年可以热烈又恬静,深刻又朴素。

2023 年终总结

2024-01-08 23:38:59

flower

时间已做了选择,太多感受,绝非三言两语能形容

生活 - 陪伴和成长

boy

这是第 35 个年头,我熟悉地扮演着多个角色,父亲、丈夫、儿子,每一刻都在陪伴和成长中交织。 生活的步伐似乎匆匆,但我努力让自己拥有一颗年轻的心,渴望保持对世界的好奇和激情。

时光大多被生活所占据,只有地铁上和饭桌上我能成为时间主宰。 好在我并未感到疲惫或沉闷,反而逐渐适应了这个身份的变化。 或许,正是在这些琐碎的日常中,我找到了一种生活的节奏,一种平和而温馨的状态。

今年我们走过了北京、汉中、西安、淳安、长沙、张家界、台州。 新年即将到来,准备给孩子办理一下护照,走出去看看。

tower

在陪伴孩子的过程中,参与各种自然知识课程,参观各种展览,我发现在陪伴的同时,我们也在不知不觉中共同成长。 生活中的另一个领域,我从母亲那里薅了两只相机,终于决心好好学习摄像, 我把 Canon 6D 出售,保留了 SONY a6500 这支轻便的 APS-C 相机。 期望摄影成为我表达内心、记录生活的一种方式,每一张照片都是时光的凝固,是岁月的见证。

five

游戏的世界中,我似乎进入了一段电子阳痿期。购买的游戏几乎只能玩上一个小时就变得索然无味, 也许现实生活才是最引人入胜的游戏吧。

或许,人生就是一场不断变化的冒险。在时间的舞台上,我们扮演着各色角色, 演绎着属于自己的故事。

工作 - 精进

balloon

工作上一直压力和张力巨大,我开始进一步成为探索者。 这两年,我在工作中不断推动项目的上线,部门推出的新产品中的一半是我负责的,我很喜欢这个领域,也确实想把事情做好。

但有时候,我感觉自己有点像是公司招进来的清理工,身处于一个「散多垂」的状态, 面对复杂的环境,解决问题绝非易事。在整理垃圾的过程中还在自动产生垃圾,而清理的工作永远不会终结。 现实往往是,大家注意力持续被新事物(比如 AIGC)吸引走,对现存的问题更容易选择性忽视。

企业的大环境在不断变化,一些老朋友选择离开,大部门也经历了一些变革。 从面向风险的团队 re-org 到面向算力的基础设施团队。我认为这是一个好的信号, AI Infra将继续裹挟着整个 Infra 领域前进,算力管理将成为一个新的命题。

业余 - 更多连接

在 Github 数据的细碎图形中,映射出一年的自娱自乐,可惜的是,未给开源社区更多的贡献。

contributions

今年,我在开源领域主要的贡献是 alswl/excalidraw-collaboration。 这个 self-host 的 Excalidraw 版本集协作和中文化字体于一身。这个项目以及相关项目吸引了近300个 star,成为我个人最有影响力的开源项目之一,尽管它是一个前端产品。

excalidraw-collboration

在暑假期间,趁着家中小神兽不在,我开发了一个关于起名的小程序。虽然这款产品目前有点烂尾, 亏损严重,但我依然希望花更多时间进行开发和改进。一个美好的名字可以给家庭带来无限愉悦, 希望这个项目可以养活服务器资源~

另外,今年我重新活跃在 Twitter 上,分享一些技巧和心得。我的 Follower 从几百人增长到近 4000 人, 虽然离有影响力的推友还有差距,但与许多有趣的朋友交流本身就是一种有趣的事情。

今年一年最受欢迎的内容是:

  • 167k 转载:对抗软件复杂度的战争 X
  • 160k 英语学习经验介绍 X
  • 127k 介绍 Lightboard X
  • 120k Web 框架讨论 - Kratos X
  • 90k 介绍 dumi X

今年最具价值的文章是介绍「许世伟的架构课」X,赚了几个月 Twitter 的订阅费。

今年我还重新开始听播客,聆听了一大半「内核恐慌」的存档,虽然未能赶上他们活跃的时期。 幸运的是,在外滩大会上我有机会参与了他们的聚会,与 Rio 和吴涛面对面交流。搞笑的是,虽然现场还有一位同事, 但我们却没有互相认出来,令人感叹在庞大的公司中,有时即便共事也未必能够相识(我们一起担任 Go 语言评委)。

panic

除了内核恐慌,我还一直在听「硬地骇客」,一集都没拉,最近还开始听「有知有行」的播客。

在博客输出方面,我分享了两篇关于工程实践心得的文章,希望能够对读者有所帮助。

我最想分享的是 Obsidian Tasks 插件,详细信息可以在我的博客文章中找到, 从 Toodledo 到 Obsidian Tasks - 我的 GTD 最佳实践。我也很高兴成为 Obsidian Tasks 的 Sponser。

回顾一年的时间,我意识到自己在业余时光中的每周时间仅有10小时左右,非常宝贵。 期许着未来能够实现财务自由,以获得更多的自由时间,投入更多的兴趣爱好。

读书

cup

读书仍然大部分都是非虚构类书籍。

牛棚杂忆 (豆瓣)

士可杀亦可辱;过去带来惆怅,现在带来迷惘,未来带来希望。

素书 (豆瓣)

讲述做人做事的道理,古人的智慧。常读常新,尤其烦躁时候可以翻出来静一下。

翻译乃大道 (豆瓣)

就是为了看 中文的常态与变态。

沙丘 (豆瓣)

老男爵举家迁新球,贵公子初入沙漠星。 老皇帝密授哈克南,雷托族全体遭判断。 小保罗掌权弗雷曼,杰西卡诞下遗腹子。 穆阿迪布反攻沙丘,娶伊勒朗再封帝位。

跌荡一百年 (豆瓣)

国、企、民、央、地。 悲观。

被讨厌的勇气 (豆瓣)

好希望自己能在 20 岁时候读到这本书。(现在的我已经不需要啦)。教读者如何和自己、周边、世界相处,如何和自己对话以及改变自己。和遇见未知的自己属于同一个路数。

旧制度与大革命 (豆瓣)

治乱循环在反复。群体的无意识;民主和精英政治是否是解药?评估稳定性一个指标是贫富差距。极权下也孕育变革风险。

门后的秘密 (豆瓣)

管理入门快速操作手册

为什么 (豆瓣)

这本书我给不出星级,超出了我的评价范围。 它可能是一个新学科(因果推断)理论,也可能是统计学中的一个星火闪烁。 作者 Pearl 是统计学大拿,也是人工智能领域权威专家,他确在晚年提出了反对自己过去一系列方法路线。 今天为我们所熟知的大部分机器学习技术,都是基于概率上相关性,从啤酒和尿布,到今天 GPT 大杀四方,AIGC 智能涌现。Peral 认为真正有意义的是提出「为什么」,即解释因果关系。因果关系的论述需要智能能够想象不存在的事物,而这正是当前人工智能无法理解的(Maybe?) 本书成于 2019 年,作者今年已经 87 高龄,不知道他对当前 AIGC 风起云涌是怎么看待的。

为什么中国人勤劳而不富有 (豆瓣)

作者说的正确但是不全面。

Flag

高质量陪伴家人,放下手机,走向户外

执行了周三、周五家庭日给小朋友陪伴;每天早上送小朋友上学;周末一定有一天陪出行。

陪伴小孩这块我做的不如我老婆好,感谢老婆对家庭的贡献。

每月输出文章,特别是 Kubernetes / 研发设计领域可以写一些心得

今年输出 6 篇文章,达标率 50%。其中两篇 实用 Web API 规范架构设计 the Easy Way 我都是很满意的。

经历了新冠,今年计划安排个私教教我健身房运动

没有完成。

投资收益率能做到 10%,今年新手阶段投资以股票型基金为主,投资收益 3.9%,跑赢了大盘和余额宝

今年投资收益率 -1.35%,刚出新手村就被暴击,我还是缺乏对市场和商业的理解。

新的一年 Flag:

  • 高质量陪伴家人,走向户外,一起参与
  • 持续高质量输出文章,特别是 Kuberntes / PaaS 领域
  • 更多运动
  • 学习投资的基本框架,建立常识和投资逻辑

Last

每段经历,每次重逢,每本书籍,都是独特的命运线。新的一年已经来临, 期待着与家人、朋友一同继续探寻生活的真谛,去体验伟大与渺小。

往年总结:

如何免费用云服务搭建博客评论系统

2023-11-25 17:23:35

问题

博客自 2012 年从 WordPress 迁移到静态站点后,就选择了 Disqus 作为评论系统。 但最近 Disqus 硬广告过于频繁,迫切寻找新的评论系统

Disqus 官方 明确说明,要去掉广告就付费。

What if I want to remove Ads? If you’d like to remove Disqus Ads from your integration, you may purchase and ads-free subscription from your Subscription and Billing page. More information on Disqus ads-free subscriptions may be found here.

OK,那再见吧 Disqus,我会找到可靠、免费、易用的评论系统。 最后既然是寻找新的评论系统,现在 2023 年了, 我希望这个新系统充分使用云服务的便利,要做到 免费、可靠、易运维

no-disqus-twitter

选型原则

在进入探索之前,我先梳理一下自己的原则和选型要求:

  • 数据自有是核心要求
    • 确保评论数据完全归属于博主,不会因为使用第三方服务而失去对数据的控制。
  • 服务部署和存储是难点
    • 考虑到服务的稳定性和成本,选择一个易于部署且存储成本较低的方案。
  • 访问速度是考虑项
    • 评论系统的访问速度直接关系到用户体验, 因此需要选择一个能够提供较快访问速度的系统。

从功能上面分析需要的能力:

  • 邮件通知
  • Markdown
  • 内容安全:No Injection
  • 评论审核和删除
  • 授权登录(Optional)

非功能需求:

  • 低成本:控制在 12 元 / 年
  • 系统稳定

通过明晰这些原则和要求,可以更有针对性地选择合适的评论系统,确保满足核心功能和非功能需求。接下来,将根据这些原则,继续探讨如何选择和搭建评论系统。

初步方案探索

现在我们初步试验一些方案并进行一些探索,以方便我们熟悉一下当前常见系统的特性和水准

utterances

utterances

  • 经常见到的一个评论系统,流行于程序员群体,基于 Github Issues 系统因此免费,需要使用 Github 账号登录
  • 7.8k star
  • 托管在 Github Issues

Twikoo

twikoo

  • 国产方案,基于云服务展开,需要寻找云函数部署环境(大部分收费)
  • 880 star

Cusdis

cusdis

  • 国产方案,提供免费的 Cloud 服务(但是额度比较受限)
  • 2.4k star
  • 支持迁移
  • 手工通过评论
  • 活跃度不高

我同时还看了一些外部的一些方案评测报告:

根据初步方案探索,我可以明确部署形态基本如下:

comment-system-deploy-diagram

横向对比

这是一个横向对比表格,列举我一些关心的特性以及候选者在这些特性方面的表现。除了上述提到几款常见软件, 我还额外调研了海外常用的评论 SaaS 服务

Name self-host Official SaaS SaaS Free Star Import Disqus export data Comments
Utterances x v v 7.8k v Github account required
Cusdis v v v? 2.3k v v? import from Disqus failed
Cactus Comments v v 100 Matrix Protocol, blocked
Commento x v $10/month v v
Graph Comment v Free to $7
Hyvor Talk x v $12/month
IntenseDebate v ? x too old
Isso v x 4.8k v sqlite storage
Mutt v $16/month
Remark42 v x 4.3k v v full featured, one file storage
ReplyBox v $5/month
Staticman v 2.3k v using github as storage
Talkyard v €4.5/ month
Waline v 1.5k v v Multi Storage / Service Provider supported
Twikoo v x 1.1k v v FaaS / MongoDB

根据横向对比我们可以得出几个结论:

  • 海外传统评论系统数据透明度低,风格也是是古早型系统
  • 官方提供 SaaS 服务普遍需要收费
  • self-host 的几个产品需要自己搭建服务,没有一键使用免费的 Cloud Provider 路径

小结

符合我需求的几款产品是:Utterances、Cusdis、Waline。

PoC 和实施

我最后选择了 utterances 和 Waline 进行 PoC, 其中我的英文博客使用了 utterances, 中文博客使用了 Waline。

为什么不选择 Cusdis 和 Twikoo?因为 Cusdis 使用 PostgreSQL, 而 Twikoo 存储使用腾讯云函数(免费额度有限)或者 MongoDB, 存储上 Waline 选择更多。 另外,作为同类型方案,Waline 是三者贡献者数量最多的,Commit 数量也最多, 社区更有保障。

Waline 实施

一个搞笑的点,如果这里使用 h3 标题叫做「Waline」,会直接在这里插入一个当前博客的评论框

  • 优点
    • 多平台部署
    • 多数据库支持(MongoDB、sqlite、PostgreSQL、MySQL)
    • 评论功能强大
    • 导入工具
    • 活跃度尚可
  • 缺点
    • 功能太多,不够克制(好在可以自定义配置)
    • 国产产品
  • 接入流程:
    • 找个 Storage 供应商(我选择 LeanCloud
    • 找个 Server 供应商部署(我选择 Vercel
    • 找个邮件发送供应商(我选择了 Brevo(原来叫 SendinBlue))
    • 前端部署(Hugo 内集成一下)

部署图:

waline

具体操作,跟随官方文档即可:

实施 PR(仅包含前端,因为后端代码包含了密钥,不便于分享): feat: comments on waline · alswl/blog.alswl.com@e34e348

Utterances 实施

utterances 的部署则更为简单,一个 PR 就可以启用。 feat: comment using utteranc · alswl/en.blog.alswl.com@29028f6 (github.com)

也没有什么特色,主打简单省事,考虑我英文博客访问量极低,就简单方案。

小结

最后我选择了 Waline / utterances 作为我的评论系统,两者的部署成本都是 0。

妥协牺牲了一些访问速度、安全性,但进一步增强了数据可控性,完成了 self-host。 从稳定性上面来看,尽管这个系统链路变复杂了,单机上也存在可用性风险, 但依托 Vercel / LeanCloud / Brevo 三家 SaaS 服务商,整体风险可控。

毕竟只是一个小小评论系统,0 成本 + 正常工作就行了。

欢迎在下面评测测试一下哦~

GitOps 和版本管理

2023-09-23 18:22:27

car

image via shipvehicles

使用 GitOps 管理交付内容是一个常见的 DevOps 使用模式。 我们会使用 Git 进行版本管理, 并通过 Git Tag 来跟踪部署软件的版本。 虽然这看上去可以工作,但在云原生技术的推动下,版本的概念远非如此简单。

版本问题

在引入 GitOps 到 DevOps 流程后,我们可以借助 GitOps 的能力进行持续集成和持续交付。 GitOps 解决了三个核心问题:内容版本协作。然而,我们经常将注意力集中在内容上,却经常忽略了版本管理问题。

在 GitOps 过程中,有哪些版本管理问题需要解决呢?

一套完整的 GitOps 解决方案包括内容描述(Manifest)、构建方案(Builder)和生效方案(Applier)。其中,内容描述衍生出多种描述语言,从最传统的 Ansible / Chef,到云计算和云原生流行起来的 TerraformHelmKustomize 等。引入了这么多内容描述方式之后,当我们想要明确一个应用的版本时,变得非常复杂。

当提到版本时,我们是指应用源代码的版本?还是指镜像的版本?或者是指某个基础设施即代码(IaC)仓库的版本?进一步地,如果我们要发布一组相互关联的应用,例如前端和后端,或者由多个后端应用组成的系统,如何清晰地描述它们之间的版本依赖关系

一旦版本描述不准确,就会引入一系列问题,例如错误的上线版本、混乱的应用依赖关系、无法回滚等。

大多数团队对于这个问题的解决方案比较模糊:发布最新的版本,先发布后端再发布前端。然而,在一个复杂的业务团队或需要同时保留多个稳定版本的团队中,这种粗暴的方案是无法接受的。

版本管理不仅解决了版本定位的问题,还可以用于管理应用之间的依赖关系。因此,GitOps 版本管理需要解决以下问题:

  • 如何构建交付给客户的制品,如何定义这些制品的版本以及如何展示所有版本的制品。
  • 如果有一组软件存在版本依赖关系,如何解决这些依赖问题。
  • 如果一组软件形成了一个系统,如何描述这个系统。

在所有的交付产品中,版本管理都是一个重要问题。我们将逐步拆分版本管理这个命题,并从原始问题过渡到 GitOps 的版本管理最佳实践。

GitOps 简介

在开始正文之前,我将简要介绍 GitOps,以避免对关键概念的理解出现分歧。

GitOps 最核心的技术是基础设施即代码(IaC),即使用声明式描述来取代命令式描述。 通常,IaC 的内容基于某种范式,用于描述特定目标的期望状态。这个范式可以是 Terraform、Kubernetes YAML、Pulumi,甚至是 Ansible。而特定目标可以是云服务、Kubernetes,甚至是物理机。 直观的说,通过使用 YAML 取代过去的 Bash 命令,我们可以大大提高变更的准确性和可控性。

对于 GitOps 来说,是否使用 Git 并不是最重要的,我们也可以使用 SVN 来实现 GitOps。只是 Git 具有更广泛的适用范围,并可以充分发挥 Git 仓库在团队协作和持续集成/持续部署中的能力。

引入 Git 仓库后,我们还同时拥有了基于 Git Revision / Tag / Branch 的版本管理能力,这体现在业务上就是版本记录、多版本并行管理等方面。

简单地基于 Git Revision 进行描述还不足以满足我们的实际需求。

问题的源头 - 二进制文件和启动配置文件版本

在探索版本的源头时,我们会发现最原始的版本是代码的版本。

代码的版本是什么?是代码仓库的版本还是代码编译出来应用的版本。 这个版本并不是代码所在的版本管理系统(如 Git / Mercurial / SVN 等)的版本。尽管这两者经常相关,但事实上,一份代码本身只是一组代码文件,只要构建成功,就会有一个版本。如果没有定义,版本就是未知的,此时与仓库管理没有关联。

注意:下文我们不再区分 Git / Mercurial / SVN 多种版本管理方案,统一使用 Git 进行描述

还需要注意的是,中文中有两个概念(库 Libray 和仓库 Repository)。 无论是哪种定义,都没有表示一个库一定是一个版本化(Git / SVN)仓库, 这意味着我们并没有假设代码库一定是被版本化管理的。当我们将代码文件打包成一个 zip 文件时(GitHub 的 zip 下载就是这种形式),即使这个 zip 文件失去了所有的 Git 历史,它仍然是一个代码库。

代码的版本实质上是应用的版本,这是作者的意图表达。这个版本往往是 vx.y.z 这种形式,而不是 Git commit hash, 最常见的管理方案是基于语义化版本

我推荐的版本存储方式是使用一个 VERSION 文件将版本存储在代码目录中。例如,Git 的 Version 文件可以清楚地看到当前 Git 的版本是:

GVF=GIT-VERSION-FILE
DEF_VER=v2.42.GIT

其中的 .GIT 也明确说明了这个代码是一个开发模式下的版本。如果我们切换到一个发布版本的代码,例如 v2.39.3 版本,我们可以看到 DEF_VER=v2.39.3,这是一个遵循标准的制品(Artifacts)格式。这里还有两个最佳实践:

  • 使用文件来保存源代码的版本。
  • 源代码中的版本文件始终处于 dev 模式,只有在进行标记封版之后才会成为正式版本号。

源代码的最终产物不仅包括二进制文件、可执行文件和动态库(.dll / .so / .dylib),还包括相应的启动配置文件。这些启动配置文件通常与对应的版本一起进行管理。例如,Nginx 的启动文件 nginx.conf 和 Redis 的启动文件 redis.conf,这些启动配置文件也应该纳入版本管理。

从源代码仓库构建出来的内容就是制品(Artifacts)。制品已经具有两个版本:

  • 源代码版本,即使用 VERSION 文件中定义的版本。
  • 源代码仓库版本,即 Git Revision

制品版本管理

引入制品版本管理后,问题变得更加复杂,因为制品带来了更多的问题:

  • 制品是什么,由什么构成?(上文已经回答)
  • 制品如何进行安装,安装程序(Installer)是什么,运行时(Runtime)是什么?
  • 制品信息如何进行集中管理,数据如何管理?
  • 制品之间是否存在依赖关系,如何处理依赖关系,版本如何约束?

制品的概念非常重要,其中最核心的一个理念是:制品可以通过打包器形成新的制品

由于制品具有版本,而新的制品将形成新的版本,我们将进入多层嵌套。为了避免最原始的版本信息丢失,我们将 Version 的概念扩展为 Upstream Version,这是软件作者人为指定的版本,是所有版本的源头。

为什么制品可以形成新的制品呢?我举一个 Kubernetes 容器环境下的例子。 容器是一种交付形式,它将可执行文件和启动配置文件写入镜像文件中,并可以在容器环境中运行。形成的镜像文件存在于镜像仓库中,本身也是一种制品。

另外,Helm / Kustomize 也是一种交付形式(打包工具链)。 每个构建层解决其特定问题,并且可以在特定环境(例如容器、Kubernetes、云基础设施)中运行。

每个制品都需要构建,过程中会有自己的额外描述信息(Packaging Info),这些额外的描述信息本身也会发生变化,因此会增加一个版本。在实践中,我们希望制品的版本与其上游版本绑定。每种打包机制可能会包含自己的一些定义配置,但仍然遵循上游的版本。例如,Kubernetes 的 Workload 包含一个镜像,Workload 的描述是附加信息,而镜像仍然受到上游控制。

Artifact + Packaging Info = New Artifact,制品经过打包可以形成新的制品。直到最后的 Installer 放置到相应的环境中生效。

如果这些制品可以通过文件(IaC)进行描述,就形成了各种 IaC 仓库,这些仓库成为了 GitOps 的核心对象。

概念梳理

让我们来理清一下这些略有晦涩的概念:

中文 英文 解释
源代码 Source Code 程序、应用的源文件集合
代码仓库 Source Code Repo 源代码放到版本管理系统中的管理单元
版本 Version 源代码对应的应用版本,人为定义,语义化,有些场景会说 Upstream Version
可执行文件 Executable File 源代码构建出来的结果,一般是 ELF 可执行文件,也可以是 Lib 文件
启动配置文件 Configuration File 配套 ELF / Lib 的启动配置文件,区别于广泛意义上的配置文件(比如 Kubernetes YAML)
制品 Artifact 包含可执行文件和启动配置文件的集合,可以运行在运行时下面,一般是文件形态。制品可以嵌套制品。
安装器 Installer 将制品安装到运行时的工具
运行时 Runtime 制品的运行环境,比如特定操作系统,Kubernetes,Docker Engine。
打包器 Packer 将制品打包成特定格式(新的制品)的工具
打包附属信息 Packaging Info 制品打包时候需要的额外信息,比如容器的操作系统,进程的运行容量,默认环境变量等

这些概念共同构成了制品版本管理的核心要素,帮助我们管理和跟踪制品的不同版本,以及它们之间的关联和依赖关系。

打包器 Packer

打包器是一种工具,通过打包操作(Packaging)将制品组织成特定的格式,形成全新的制品。 打包的过程涉及编译、链接、合并和存档等常见概念。

它通常以上游(Upstream)作为输入,上游可以是源码,也可以是其他系统生成的制品(Artifacts)。

例如,在打包 Docker Compose 时,输入是镜像(Image),而对于 Helm,输入则包括镜像、启动配置文件和 Helm 模板,而输出则是 YAML 文件。

制品 Artifacts

制品是一种数据集合,可以在特定环境中运行。 它由可执行文件和启动配置文件等组成,通常以文件形式存在,并且可以在运行时环境下运行。制品具有嵌套的能力,可以包含其他制品。

最常见的形态是二进制文件(ELF),也可以是适用于特定环境的运行物,如容器镜像。

制品通常以文件形式进行传输。

安装器 Installer

安装器是一种工具,用于将制品安装到运行时环境中。 它负责将制品部署到目标环境并确保其正常运行。 例如,dpkg、Pacman 是常见的安装器工具,而在 Windows 平台上,我们常见自引导的安装器。

对于特定的环境如 Kubernetes,我们可以使用 kubectl 命令进行安装,而 Helm 则使用helm命令来进行安装。

Linux 社区实践

当我们理解了这些概念后,我们或许会惊讶地发现,这些概念与 Linux 社区多年来的实践是如此相似。抛开云原生等新概念,Linux 社区早就拥有了完整的解决方案。

每一层制品都会引入新的配置(Config)/ 扩展(Extension)/ 值(Values)/ 环境变量(Env)等等,无论如何称呼, 我们统一称之为配置。 这些新加入的 Packaging Info 的描述在大规模集群管理下也带来了新的问题。

自豪地使用 ArchLinux。

Arch Linux 社区的实践

Arch Linux 使用 Pacman 作为包安装器,并且拥有一套完整的构建方案

在 Arch Linux 中,PKGBUILD link用于描述包的构建方式,它本身是 Bash 的子集,是描述包的核心文件。

版本管理方面,Arch Linux 提供了清晰明确的方案,并且设计了完整的制品嵌套解决方案。 在 PKGBUILD 中,pkgver 表示上游版本,并经过适当的修正,使用 _ 替代 -,并调整了时间戳的格式。而 pkgrel 则表示发布号,而不是构建号,每次发布都会增加该号码,用于管理 Arch Linux 的发布动作。当大部分 PKGBUILD 发生变化时,发布号都会发生变化。

此外,epoch 是一个强制构建版本的机制,默认为 0 并且隐藏起来。使用 epoch 是一种兜底的解决方案,通过破坏版本对比来强制进行新版本的升级。

另外,在 PKGBUILD 中,使用了版本依赖的方式来优雅地解决模块的问题。 例如,base-devel 包是对 26 个基础软件的依赖,而该包本身没有具体的内容。这种方案非常优雅,避免了引入一个新的模型(比如叫做 Group / 产品)。

基于 GitOps 的版本管理解决方案

最后让我们回归到 GitOps 版本管理本身,让我们重新面对文中的几个问题,通过以上的分析和调研,是否已经解决了这些问题呢?

  • 交付给客户的制品如何构成,如何定义这个制品的版本,以及如何呈现所有版本的制品?
    • 使用 VERSION 文件来确定软件版本,也就是上游版本(Upstream Version)
    • 不同形式的制品有独立的版本号,这些版本号需要与上游版本关联。例如,可以使用 v1.2.3-afe12c 的形式来追踪 Git 仓库中的版本,使用 v1.2.3-afe12c-b1 来追踪镜像构建物的版本。
  • 如果存在一组软件,如何解决这组软件之间的版本依赖问题?
    • 这个问题可以交给具体的安装器处理,一般这些元信息会在对应的打包信息(Packaging Info)中定义,并由 Installer 识别和处理。
  • 如果一组软件形成了一套体系,如何表达这个体系?
    • 创建一个没有上游版本的新制品,其中交付的内容可能为空,但包含相应的打包信息和依赖信息。
    • (或者)也可以真正抽象出一个新的概念来进行管理,这取决于打包器和安装器之间的协作。

总结

版本管理的智慧,其实已经体现在当年的 RPM / DEB / PKGBUILD 中。 我们通过明确版本定义权交给应用作者,提出制品嵌套的概念,允许版本的概念进行多层嵌套。

我们希望,最后运行的制品版本仍然是原始应用版本(Upstream Version)的衍生。毕竟, 让每个运行的程序都知道自己来自何处、自己是谁,在大规模集群管理下已经变得相当重要。