先叠个甲,下面的内容不针对任何具体对象,我自己也是个刚加入不久的菜鸡。就是感觉最近论坛新面孔变多了是好事,但社区的“空气”也逐渐有了变化,所以随便唠两句。 借用日语里“阅读空气”的概念,希望大伙发帖前建议先感受下社区的氛围和“潜规则”。最近有些帖子在标题上我就能猜到马上会有老哥开怼,而且结果基本也都是这样。 这并不是说谁做错了什么,但我还是希望发帖和讨论最好还是把焦点放在“话题和问题本身”,而且从始至终都应该朝这个方向引导。 举个例子,对论坛发展有想法很正常,大可以把 始皇 抽象成一个“社区决策者”的角色,从成本、合规或者生态这些维度去理性探讨。但如果跳过中间的客观逻辑抽象,直接变成“听我的,直接XXX”的话,这就挺没劲的,点进去压根没什么信息,稍微直接一点的佬友可能就开始攻击了。 所以,多聊聊事情(话题)本身,大伙讨论的“空气”才能更健康。 阅读空气,从标题开始,贯穿于你发的每句话。 1 个帖子 - 1 位参与者 阅读完整话题
主流的"测试" vs 我的"6 阶段" 很多团队的测试流程是 3 段式: UT → 集成 → 上线 每阶段都做"测试"——只是测试对象不同。 我的判断不一样: ▌ 测试不是"测一遍"—— ▌ 是按 6 个阶段性质拆分, ▌ 每阶段有"该阶段独有、其他阶段无法替代"的验证内容。 不是 6 次相同动作 —— 是 6 类不同性质的验证 。 6 阶段是什么 ┌──────────────────────────────────────────────────────────┐ │ │ │ ① 单元测试 ── 验证"函数内部" │ │ ↓ │ │ ② 集成测试 ── 验证"跨网络" │ │ ↓ ← 比对工具进场 │ │ ③ Code Review ─ 验证"设计 + 性能" │ │ ↓ │ │ ④ 他测 ────── 验证"用户视角" │ │ ↓ ← 比对工具回访 │ │ ⑤ 灰度 ────── 验证"生产数据兼容" │ │ ↓ ← 比对工具在线 │ │ ⑥ 上线观察 ── 验证"业务大盘波动" │ │ │ └──────────────────────────────────────────────────────────┘ 每阶段独有验证内容: 阶段 性质 独有验证 ① 单元 函数内部 UT 覆盖率 + 冒烟 + 功能埋点 ② 集成 跨网络 跨服务冒烟 + DML 比对 ③ Review 设计性能 设计审查 + 性能分析 + 回滚方案 ④ 他测 用户视角 提测文档 + Test Case + 修复后再比对 ⑤ 灰度 生产数据 时间窗口 + 分工 + DML 在线比对 ⑥ 上线 业务大盘 6 项指标 + 四方确认 → 第 ②④⑤ 阶段的"比对"动作,就是上一篇讲的"比对工具体系"。 → 第 ⑥ 阶段是大多数团队最常省的——本文重点讲它。 阶段拆分的核心标准 我自己的判断标准很简单: 两个阶段如果验证内容重叠 —— 说明阶段拆分错了。 举个例子:很多团队把"集成测试"和"他测"混在一起做—— 都让测试同事跑一遍。 但这两个阶段性质完全不同: 集成测试是 "跨网络"性质 —— 关心服务调用、数据穿透是否对 他测是 "用户视角"性质 —— 关心 case 覆盖、修复后再验证是否对 合在一起做的代价: 集成阶段没暴露的跨服务 bug,会被他测的"用户场景"掩盖 —— 等到灰度才发现,代价是集成阶段的 N 倍。 第 6 阶段最贵 —— 也最被忽视 很多团队的"上线观察"=刷一下监控大盘。 我的版本: 6 项指标 + 四方确认 。 6 项观测指标: 1. 产品功能有没有执行 2. 数据有没有问题 3. 系统有没有性能问题 4. 跨系统交互有没有影响 5. 财务大盘是否波动 ← 关键! 6. 业务大盘是否波动 ← 关键! ▌ 把"财务大盘 / 业务大盘波动" ▌ 作为发布观察指标 —— ▌ 这是大多数团队最常省的一步。 因为这两项指标"看起来不归技术管"。 但实际上 —— 80% 的"上线后才发现"的事故,在前 4 项指标 里全是绿的,只有第 5 、6 项暴露异常 。 例子: 某次上线某个改动,前 4 项指标全绿; 3 天后才发现财务对账差异—— 这种 bug 在 UT/集成/灰度 都看不出来 ,只有"业务大盘"能看见。 四方确认 —— 不是签字流程 四方确认 = 开发 / 测试 / 技术 TO / 产品 都同意才能"上线观察通过"。 听起来像 PPT 流程,但 反共识在于 : ▌ 测试同意 ≠ 验收通过 —— ▌ 业务大盘没波动,不代表产品认为"功能符合预期"。 ▌ 产品同意 ≠ 验收通过 —— ▌ 数据正常,不代表开发认为"性能达标"。 四方共同确认—— 任何一方说"我看到的不对"——就回退 。 我经历的项目里,真发生过 "3 方都过了,产品最后说不对" 的情况。如果没有四方流程,这个回退根本走不动。 反共识在哪 主流:测试 = UT + 集成 + 上线(3 阶段) 我的版本:6 阶段,每阶段独有验证 主流:每阶段都做"测试"动作 我的版本:每阶段对应 该阶段性质独有 的验证手段 主流:上线观察看"是否有大故障" 我的版本: 6 项观测指标 + 四方确认 主流:业务大盘归运营管 我的版本: 把"财务大盘 / 业务大盘"作为发布观察指标 主流:验收 = 测试通过 我的版本: 四方确认 (开发 / 测试 / 技术 TO / 产品) 什么时候不该用这套 也踩过坑。 某次内部小工具改动,代码量不到 200 行。 我也想搞 6 阶段——leader 直接说:"过度。" 事后是对的。 我的判断: 核心业务系统改造 → 必上(尤其涉及财务 / 业务大盘) 跨多研发角色的项目 → 必上(否则四方确认走不通) 内部工具 / 后台脚本 → 别上(单人项目,4 阶段够) DDL 类无法灰度的改动 → 跳过第 5 阶段(灰度),其余照走 不影响 KPI 的小项目 → 简化为 3 阶段(UT+集成+上线) 阴面 · 这套也有副作用 我自己用了这套 4 年,踩过的坑: 重型流程 —— 小项目用不上,6 阶段成本太高 跨公司不通用 —— 没有"四方确认 / 业务大盘"概念的公司套不进来 可能流于形式 —— 团队成员把 6 阶段当 6 个 checkbox 而非 6 类性质 决策慢 —— 至少 6 次评审 / 检查 最后一条最关键 —— **6 阶段的代价是"决策周期变长"**。 所以才有上面那句:"小项目别上 / 不影响 KPI 的项目简化为 3 阶段"。 写在最后 把测试拆 6 阶段,不是为了"显得专业"—— 是因为我经历过太多次: "你那阶段不是测过吗?怎么还出问题?" 仔细看,会发现: 那阶段测的不是这一类问题 。 每阶段性质不同 —— 验证手段就该不同。 6 阶段是"性质拆分",不是"动作拆分"。 跟"渐进式改造"和"比对工具"一样,这是一套 关心可逆性、关心 追溯性 的工程纪律。 写到这,我也不太确定 6 阶段对所有团队都成立。 我经历的项目都是"核心业务系统 + 跨多角色 + 业务大盘敏感"—— 这种场景 6 阶段几乎是必修。 但创业团队 / 内部工具 / 没有"业务大盘"这个概念的公司—— 搞这套可能反而是负担。 这点我自己也还在想。 下一篇打算写 17 类业务迁移分类—— 跟 6 阶段是一对:6 阶段是 纵向 (时间),17 类是 横向 (业务域)。 两者合起来才是完整的迁移管理体系。 (以上 SOP 都做了脱敏。 如果你做过核心系统改造,欢迎评论区聊聊你们的验收流程长什么样, 特别想听 6 阶段简化为 3 阶段后,踩过的坑 。)
主流的"测试" vs 我的"6 阶段" 很多团队的测试流程是 3 段式: UT → 集成 → 上线 每阶段都做"测试"——只是测试对象不同。 我的判断不一样: ▌ 测试不是"测一遍"—— ▌ 是按 6 个阶段性质拆分, ▌ 每阶段有"该阶段独有、其他阶段无法替代"的验证内容。 不是 6 次相同动作 —— 是 6 类不同性质的验证 。 6 阶段是什么 ┌──────────────────────────────────────────────────────────┐ │ │ │ ① 单元测试 ── 验证"函数内部" │ │ ↓ │ │ ② 集成测试 ── 验证"跨网络" │ │ ↓ ← 比对工具进场 │ │ ③ Code Review ─ 验证"设计 + 性能" │ │ ↓ │ │ ④ 他测 ────── 验证"用户视角" │ │ ↓ ← 比对工具回访 │ │ ⑤ 灰度 ────── 验证"生产数据兼容" │ │ ↓ ← 比对工具在线 │ │ ⑥ 上线观察 ── 验证"业务大盘波动" │ │ │ └──────────────────────────────────────────────────────────┘ 每阶段独有验证内容: 阶段 性质 独有验证 ① 单元 函数内部 UT 覆盖率 + 冒烟 + 功能埋点 ② 集成 跨网络 跨服务冒烟 + DML 比对 ③ Review 设计性能 设计审查 + 性能分析 + 回滚方案 ④ 他测 用户视角 提测文档 + Test Case + 修复后再比对 ⑤ 灰度 生产数据 时间窗口 + 分工 + DML 在线比对 ⑥ 上线 业务大盘 6 项指标 + 四方确认 → 第 ②④⑤ 阶段的"比对"动作,就是上一篇讲的"比对工具体系"。 → 第 ⑥ 阶段是大多数团队最常省的——本文重点讲它。 阶段拆分的核心标准 我自己的判断标准很简单: 两个阶段如果验证内容重叠 —— 说明阶段拆分错了。 举个例子:很多团队把"集成测试"和"他测"混在一起做—— 都让测试同事跑一遍。 但这两个阶段性质完全不同: 集成测试是 "跨网络"性质 —— 关心服务调用、数据穿透是否对 他测是 "用户视角"性质 —— 关心 case 覆盖、修复后再验证是否对 合在一起做的代价: 集成阶段没暴露的跨服务 bug,会被他测的"用户场景"掩盖 —— 等到灰度才发现,代价是集成阶段的 N 倍。 第 6 阶段最贵 —— 也最被忽视 很多团队的"上线观察"=刷一下监控大盘。 我的版本: 6 项指标 + 四方确认 。 6 项观测指标: 1. 产品功能有没有执行 2. 数据有没有问题 3. 系统有没有性能问题 4. 跨系统交互有没有影响 5. 财务大盘是否波动 ← 关键! 6. 业务大盘是否波动 ← 关键! ▌ 把"财务大盘 / 业务大盘波动" ▌ 作为发布观察指标 —— ▌ 这是大多数团队最常省的一步。 因为这两项指标"看起来不归技术管"。 但实际上 —— 80% 的"上线后才发现"的事故,在前 4 项指标 里全是绿的,只有第 5 、6 项暴露异常 。 例子: 某次上线某个改动,前 4 项指标全绿; 3 天后才发现财务对账差异—— 这种 bug 在 UT/集成/灰度 都看不出来 ,只有"业务大盘"能看见。 四方确认 —— 不是签字流程 四方确认 = 开发 / 测试 / 技术 TO / 产品 都同意才能"上线观察通过"。 听起来像 PPT 流程,但 反共识在于 : ▌ 测试同意 ≠ 验收通过 —— ▌ 业务大盘没波动,不代表产品认为"功能符合预期"。 ▌ 产品同意 ≠ 验收通过 —— ▌ 数据正常,不代表开发认为"性能达标"。 四方共同确认—— 任何一方说"我看到的不对"——就回退 。 我经历的项目里,真发生过 "3 方都过了,产品最后说不对" 的情况。如果没有四方流程,这个回退根本走不动。 反共识在哪 主流:测试 = UT + 集成 + 上线(3 阶段) 我的版本:6 阶段,每阶段独有验证 主流:每阶段都做"测试"动作 我的版本:每阶段对应 该阶段性质独有 的验证手段 主流:上线观察看"是否有大故障" 我的版本: 6 项观测指标 + 四方确认 主流:业务大盘归运营管 我的版本: 把"财务大盘 / 业务大盘"作为发布观察指标 主流:验收 = 测试通过 我的版本: 四方确认 (开发 / 测试 / 技术 TO / 产品) 什么时候不该用这套 也踩过坑。 某次内部小工具改动,代码量不到 200 行。 我也想搞 6 阶段——leader 直接说:"过度。" 事后是对的。 我的判断: 核心业务系统改造 → 必上(尤其涉及财务 / 业务大盘) 跨多研发角色的项目 → 必上(否则四方确认走不通) 内部工具 / 后台脚本 → 别上(单人项目,4 阶段够) DDL 类无法灰度的改动 → 跳过第 5 阶段(灰度),其余照走 不影响 KPI 的小项目 → 简化为 3 阶段(UT+集成+上线) 阴面 · 这套也有副作用 我自己用了这套 4 年,踩过的坑: 重型流程 —— 小项目用不上,6 阶段成本太高 跨公司不通用 —— 没有"四方确认 / 业务大盘"概念的公司套不进来 可能流于形式 —— 团队成员把 6 阶段当 6 个 checkbox 而非 6 类性质 决策慢 —— 至少 6 次评审 / 检查 最后一条最关键 —— **6 阶段的代价是"决策周期变长"**。 所以才有上面那句:"小项目别上 / 不影响 KPI 的项目简化为 3 阶段"。 写在最后 把测试拆 6 阶段,不是为了"显得专业"—— 是因为我经历过太多次: "你那阶段不是测过吗?怎么还出问题?" 仔细看,会发现: 那阶段测的不是这一类问题 。 每阶段性质不同 —— 验证手段就该不同。 6 阶段是"性质拆分",不是"动作拆分"。 跟"渐进式改造"和"比对工具"一样,这是一套 关心可逆性、关心 追溯性 的工程纪律。 写到这,我也不太确定 6 阶段对所有团队都成立。 我经历的项目都是"核心业务系统 + 跨多角色 + 业务大盘敏感"—— 这种场景 6 阶段几乎是必修。 但创业团队 / 内部工具 / 没有"业务大盘"这个概念的公司—— 搞这套可能反而是负担。 这点我自己也还在想。 下一篇打算写 17 类业务迁移分类—— 跟 6 阶段是一对:6 阶段是 纵向 (时间),17 类是 横向 (业务域)。 两者合起来才是完整的迁移管理体系。 (以上 SOP 都做了脱敏。 如果你做过核心系统改造,欢迎评论区聊聊你们的验收流程长什么样, 特别想听 6 阶段简化为 3 阶段后,踩过的坑 。)
主流的"测试" vs 我的"6 阶段" 很多团队的测试流程是 3 段式: UT → 集成 → 上线 每阶段都做"测试"——只是测试对象不同。 我的判断不一样: ▌ 测试不是"测一遍"—— ▌ 是按 6 个阶段性质拆分, ▌ 每阶段有"该阶段独有、其他阶段无法替代"的验证内容。 不是 6 次相同动作 —— 是 6 类不同性质的验证 。 6 阶段是什么 ┌──────────────────────────────────────────────────────────┐ │ │ │ ① 单元测试 ── 验证"函数内部" │ │ ↓ │ │ ② 集成测试 ── 验证"跨网络" │ │ ↓ ← 比对工具进场 │ │ ③ Code Review ─ 验证"设计 + 性能" │ │ ↓ │ │ ④ 他测 ────── 验证"用户视角" │ │ ↓ ← 比对工具回访 │ │ ⑤ 灰度 ────── 验证"生产数据兼容" │ │ ↓ ← 比对工具在线 │ │ ⑥ 上线观察 ── 验证"业务大盘波动" │ │ │ └──────────────────────────────────────────────────────────┘ 每阶段独有验证内容: 阶段 性质 独有验证 ① 单元 函数内部 UT 覆盖率 + 冒烟 + 功能埋点 ② 集成 跨网络 跨服务冒烟 + DML 比对 ③ Review 设计性能 设计审查 + 性能分析 + 回滚方案 ④ 他测 用户视角 提测文档 + Test Case + 修复后再比对 ⑤ 灰度 生产数据 时间窗口 + 分工 + DML 在线比对 ⑥ 上线 业务大盘 6 项指标 + 四方确认 → 第 ②④⑤ 阶段的"比对"动作,就是上一篇讲的"比对工具体系"。 → 第 ⑥ 阶段是大多数团队最常省的——本文重点讲它。 阶段拆分的核心标准 我自己的判断标准很简单: 两个阶段如果验证内容重叠 —— 说明阶段拆分错了。 举个例子:很多团队把"集成测试"和"他测"混在一起做—— 都让测试同事跑一遍。 但这两个阶段性质完全不同: 集成测试是 "跨网络"性质 —— 关心服务调用、数据穿透是否对 他测是 "用户视角"性质 —— 关心 case 覆盖、修复后再验证是否对 合在一起做的代价: 集成阶段没暴露的跨服务 bug,会被他测的"用户场景"掩盖 —— 等到灰度才发现,代价是集成阶段的 N 倍。 第 6 阶段最贵 —— 也最被忽视 很多团队的"上线观察"=刷一下监控大盘。 我的版本: 6 项指标 + 四方确认 。 6 项观测指标: 1. 产品功能有没有执行 2. 数据有没有问题 3. 系统有没有性能问题 4. 跨系统交互有没有影响 5. 财务大盘是否波动 ← 关键! 6. 业务大盘是否波动 ← 关键! ▌ 把"财务大盘 / 业务大盘波动" ▌ 作为发布观察指标 —— ▌ 这是大多数团队最常省的一步。 因为这两项指标"看起来不归技术管"。 但实际上 —— 80% 的"上线后才发现"的事故,在前 4 项指标 里全是绿的,只有第 5 、6 项暴露异常 。 例子: 某次上线某个改动,前 4 项指标全绿; 3 天后才发现财务对账差异—— 这种 bug 在 UT/集成/灰度 都看不出来 ,只有"业务大盘"能看见。 四方确认 —— 不是签字流程 四方确认 = 开发 / 测试 / 技术 TO / 产品 都同意才能"上线观察通过"。 听起来像 PPT 流程,但 反共识在于 : ▌ 测试同意 ≠ 验收通过 —— ▌ 业务大盘没波动,不代表产品认为"功能符合预期"。 ▌ 产品同意 ≠ 验收通过 —— ▌ 数据正常,不代表开发认为"性能达标"。 四方共同确认—— 任何一方说"我看到的不对"——就回退 。 我经历的项目里,真发生过 "3 方都过了,产品最后说不对" 的情况。如果没有四方流程,这个回退根本走不动。 反共识在哪 主流:测试 = UT + 集成 + 上线(3 阶段) 我的版本:6 阶段,每阶段独有验证 主流:每阶段都做"测试"动作 我的版本:每阶段对应 该阶段性质独有 的验证手段 主流:上线观察看"是否有大故障" 我的版本: 6 项观测指标 + 四方确认 主流:业务大盘归运营管 我的版本: 把"财务大盘 / 业务大盘"作为发布观察指标 主流:验收 = 测试通过 我的版本: 四方确认 (开发 / 测试 / 技术 TO / 产品) 什么时候不该用这套 也踩过坑。 某次内部小工具改动,代码量不到 200 行。 我也想搞 6 阶段——leader 直接说:"过度。" 事后是对的。 我的判断: 核心业务系统改造 → 必上(尤其涉及财务 / 业务大盘) 跨多研发角色的项目 → 必上(否则四方确认走不通) 内部工具 / 后台脚本 → 别上(单人项目,4 阶段够) DDL 类无法灰度的改动 → 跳过第 5 阶段(灰度),其余照走 不影响 KPI 的小项目 → 简化为 3 阶段(UT+集成+上线) 阴面 · 这套也有副作用 我自己用了这套 4 年,踩过的坑: 重型流程 —— 小项目用不上,6 阶段成本太高 跨公司不通用 —— 没有"四方确认 / 业务大盘"概念的公司套不进来 可能流于形式 —— 团队成员把 6 阶段当 6 个 checkbox 而非 6 类性质 决策慢 —— 至少 6 次评审 / 检查 最后一条最关键 —— **6 阶段的代价是"决策周期变长"**。 所以才有上面那句:"小项目别上 / 不影响 KPI 的项目简化为 3 阶段"。 写在最后 把测试拆 6 阶段,不是为了"显得专业"—— 是因为我经历过太多次: "你那阶段不是测过吗?怎么还出问题?" 仔细看,会发现: 那阶段测的不是这一类问题 。 每阶段性质不同 —— 验证手段就该不同。 6 阶段是"性质拆分",不是"动作拆分"。 跟"渐进式改造"和"比对工具"一样,这是一套 关心可逆性、关心 追溯性 的工程纪律。 写到这,我也不太确定 6 阶段对所有团队都成立。 我经历的项目都是"核心业务系统 + 跨多角色 + 业务大盘敏感"—— 这种场景 6 阶段几乎是必修。 但创业团队 / 内部工具 / 没有"业务大盘"这个概念的公司—— 搞这套可能反而是负担。 这点我自己也还在想。 下一篇打算写 17 类业务迁移分类—— 跟 6 阶段是一对:6 阶段是 纵向 (时间),17 类是 横向 (业务域)。 两者合起来才是完整的迁移管理体系。 (以上 SOP 都做了脱敏。 如果你做过核心系统改造,欢迎评论区聊聊你们的验收流程长什么样, 特别想听 6 阶段简化为 3 阶段后,踩过的坑 。)
主流的"测试" vs 我的"6 阶段" 很多团队的测试流程是 3 段式: UT → 集成 → 上线 每阶段都做"测试"——只是测试对象不同。 我的判断不一样: ▌ 测试不是"测一遍"—— ▌ 是按 6 个阶段性质拆分, ▌ 每阶段有"该阶段独有、其他阶段无法替代"的验证内容。 不是 6 次相同动作 —— 是 6 类不同性质的验证 。 6 阶段是什么 ┌──────────────────────────────────────────────────────────┐ │ │ │ ① 单元测试 ── 验证"函数内部" │ │ ↓ │ │ ② 集成测试 ── 验证"跨网络" │ │ ↓ ← 比对工具进场 │ │ ③ Code Review ─ 验证"设计 + 性能" │ │ ↓ │ │ ④ 他测 ────── 验证"用户视角" │ │ ↓ ← 比对工具回访 │ │ ⑤ 灰度 ────── 验证"生产数据兼容" │ │ ↓ ← 比对工具在线 │ │ ⑥ 上线观察 ── 验证"业务大盘波动" │ │ │ └──────────────────────────────────────────────────────────┘ 每阶段独有验证内容: 阶段 性质 独有验证 ① 单元 函数内部 UT 覆盖率 + 冒烟 + 功能埋点 ② 集成 跨网络 跨服务冒烟 + DML 比对 ③ Review 设计性能 设计审查 + 性能分析 + 回滚方案 ④ 他测 用户视角 提测文档 + Test Case + 修复后再比对 ⑤ 灰度 生产数据 时间窗口 + 分工 + DML 在线比对 ⑥ 上线 业务大盘 6 项指标 + 四方确认 → 第 ②④⑤ 阶段的"比对"动作,就是上一篇讲的"比对工具体系"。 → 第 ⑥ 阶段是大多数团队最常省的——本文重点讲它。 阶段拆分的核心标准 我自己的判断标准很简单: 两个阶段如果验证内容重叠 —— 说明阶段拆分错了。 举个例子:很多团队把"集成测试"和"他测"混在一起做—— 都让测试同事跑一遍。 但这两个阶段性质完全不同: 集成测试是 "跨网络"性质 —— 关心服务调用、数据穿透是否对 他测是 "用户视角"性质 —— 关心 case 覆盖、修复后再验证是否对 合在一起做的代价: 集成阶段没暴露的跨服务 bug,会被他测的"用户场景"掩盖 —— 等到灰度才发现,代价是集成阶段的 N 倍。 第 6 阶段最贵 —— 也最被忽视 很多团队的"上线观察"=刷一下监控大盘。 我的版本: 6 项指标 + 四方确认 。 6 项观测指标: 1. 产品功能有没有执行 2. 数据有没有问题 3. 系统有没有性能问题 4. 跨系统交互有没有影响 5. 财务大盘是否波动 ← 关键! 6. 业务大盘是否波动 ← 关键! ▌ 把"财务大盘 / 业务大盘波动" ▌ 作为发布观察指标 —— ▌ 这是大多数团队最常省的一步。 因为这两项指标"看起来不归技术管"。 但实际上 —— 80% 的"上线后才发现"的事故,在前 4 项指标 里全是绿的,只有第 5 、6 项暴露异常 。 例子: 某次上线某个改动,前 4 项指标全绿; 3 天后才发现财务对账差异—— 这种 bug 在 UT/集成/灰度 都看不出来 ,只有"业务大盘"能看见。 四方确认 —— 不是签字流程 四方确认 = 开发 / 测试 / 技术 TO / 产品 都同意才能"上线观察通过"。 听起来像 PPT 流程,但 反共识在于 : ▌ 测试同意 ≠ 验收通过 —— ▌ 业务大盘没波动,不代表产品认为"功能符合预期"。 ▌ 产品同意 ≠ 验收通过 —— ▌ 数据正常,不代表开发认为"性能达标"。 四方共同确认—— 任何一方说"我看到的不对"——就回退 。 我经历的项目里,真发生过 "3 方都过了,产品最后说不对" 的情况。如果没有四方流程,这个回退根本走不动。 反共识在哪 主流:测试 = UT + 集成 + 上线(3 阶段) 我的版本:6 阶段,每阶段独有验证 主流:每阶段都做"测试"动作 我的版本:每阶段对应 该阶段性质独有 的验证手段 主流:上线观察看"是否有大故障" 我的版本: 6 项观测指标 + 四方确认 主流:业务大盘归运营管 我的版本: 把"财务大盘 / 业务大盘"作为发布观察指标 主流:验收 = 测试通过 我的版本: 四方确认 (开发 / 测试 / 技术 TO / 产品) 什么时候不该用这套 也踩过坑。 某次内部小工具改动,代码量不到 200 行。 我也想搞 6 阶段——leader 直接说:"过度。" 事后是对的。 我的判断: 核心业务系统改造 → 必上(尤其涉及财务 / 业务大盘) 跨多研发角色的项目 → 必上(否则四方确认走不通) 内部工具 / 后台脚本 → 别上(单人项目,4 阶段够) DDL 类无法灰度的改动 → 跳过第 5 阶段(灰度),其余照走 不影响 KPI 的小项目 → 简化为 3 阶段(UT+集成+上线) 阴面 · 这套也有副作用 我自己用了这套 4 年,踩过的坑: 重型流程 —— 小项目用不上,6 阶段成本太高 跨公司不通用 —— 没有"四方确认 / 业务大盘"概念的公司套不进来 可能流于形式 —— 团队成员把 6 阶段当 6 个 checkbox 而非 6 类性质 决策慢 —— 至少 6 次评审 / 检查 最后一条最关键 —— **6 阶段的代价是"决策周期变长"**。 所以才有上面那句:"小项目别上 / 不影响 KPI 的项目简化为 3 阶段"。 写在最后 把测试拆 6 阶段,不是为了"显得专业"—— 是因为我经历过太多次: "你那阶段不是测过吗?怎么还出问题?" 仔细看,会发现: 那阶段测的不是这一类问题 。 每阶段性质不同 —— 验证手段就该不同。 6 阶段是"性质拆分",不是"动作拆分"。 跟"渐进式改造"和"比对工具"一样,这是一套 关心可逆性、关心 追溯性 的工程纪律。 写到这,我也不太确定 6 阶段对所有团队都成立。 我经历的项目都是"核心业务系统 + 跨多角色 + 业务大盘敏感"—— 这种场景 6 阶段几乎是必修。 但创业团队 / 内部工具 / 没有"业务大盘"这个概念的公司—— 搞这套可能反而是负担。 这点我自己也还在想。 下一篇打算写 17 类业务迁移分类—— 跟 6 阶段是一对:6 阶段是 纵向 (时间),17 类是 横向 (业务域)。 两者合起来才是完整的迁移管理体系。 (以上 SOP 都做了脱敏。 如果你做过核心系统改造,欢迎评论区聊聊你们的验收流程长什么样, 特别想听 6 阶段简化为 3 阶段后,踩过的坑 。)
枚举和注解 枚举 基础知识 枚举是一组常量的集合。枚举属于一种特殊的类,里面只包含一组有限的特定的对象。 其实枚举类是可以通过传统写法自定义的,写法为: 构造器私有化 不提供set方法 在类内部预先初始化好静态的实例,并且对外暴露 代码略,直接学习如何创建真正的枚举。 使用enum关键字来代替class 直接写FALL(“秋天”,“凉爽”),效果上等价于 public static final Season FALL = new Season(“秋天”,“凉爽”); 如果有多个常量对象,使用逗号间隔即可 使用 enum 实现枚举,必须把定义的常量对象写在枚举类的最前面 使用无参构造器时,可以把括号也省略,直接写FALL,举例 FALL, SPRING, SUMMER, WINTER; public class Enum { public static void main(String[] args) { System.out.println(Season.SPRING); } } enum Season{ SPRING("春天","温暖"), SUMMER("夏天","炎热"), FALL("秋天","凉爽"), WINTER("冬天","寒冷"); private String name; private String desc; Season(String name, String desc) { this.name = name; this.desc = desc; } @Override public String toString() { return "Season{" + "name='" + name + '\'' + ", desc='" + desc + '\'' + '}'; } } .java文件可以用 Javac 编译成.class文件,.class文件也可以用 Javap 反编译成字节码文件,通过观察先编译再反编译的结果,可以看到很多隐藏的细节。 对于 Seanon 类,反编译得到的代码如下 Compiled from "Enum.java" final class hspedu.inner.enumer.Season extends java.lang.Enum<hspedu.inner.enumer.Season> { public static final hspedu.inner.enumer.Season SPRING; public static final hspedu.inner.enumer.Season SUMMER; public static final hspedu.inner.enumer.Season FALL; public static final hspedu.inner.enumer.Season WINTER; public static hspedu.inner.enumer.Season[] values(); public static hspedu.inner.enumer.Season valueOf(java.lang.String); public java.lang.String toString(); static {}; } 值得关注的细节有: 枚举类是 final 类型的,因此不可被继承 枚举类默认继承 java.lang.Enum 类,因此不可继承其他类 每一个常量都默认是 public static final 类型的 简单练习 第一题 判断语法正误 enum Gender { BOY, GIRL; } 答案: 语法没有错,相当于一个“没有属性,只含有无参构造器”的枚举类 第二题 判断输出什么 enum Gender2 { BOY, GIRL; } Gender2 boy = Gender2.BOY; Gender2 boy2 = Gender2.BOY; System.out.println(boy); System.out.println(boy2 == boy); 答案: BOY true 分析: 首先,枚举类本质也是类,所以Gender2 boy = Gender2.BOY;这种写法肯定是对的 boy相当于拿到了枚举类里的public static final常量,因此boy和boy2肯定是一样的 System.out.println(boy)相当于调用Gender2的toString方法,但是显然它没有,就去找父类的toString方法,父类是java.lang.Enum(前面有提到) Enum类的成员方法 分别是 name、ordinary、values、valueOf、compareTo方法,建议自己写一写用一用,方法的效果都写在代码里了: public class Enum { public static void main(String[] args) { Season spring = Season.SPRING; // name方法,建议优先使用toString,效果类似 System.out.println(spring.name()); System.out.println(spring); // ordinary方法,输出该枚举对象的序号,从0开始 System.out.println(spring.ordinal()); // values方法,返回所有的枚举对象 Season[] values = Season.values(); for (Season value : values) { System.out.println(value); } // valueOf方法,返回指定名称的枚举对象 Season valueOf = Season.valueOf("FALL"); System.out.println(valueOf); // compareTo方法,比较两个枚举对象,返回它们的序号之差,在这里是spring的序号 - valueOf的序号 System.out.println(spring.compareTo(valueOf)); } } enum Season{ SPRING("春天","温暖"), SUMMER("夏天","炎热"), FALL("秋天","凉爽"), WINTER("冬天","寒冷"); private String name; private String desc; Season(String name, String desc) { this.name = name; this.desc = desc; } } 简单练习2 声明 Week 枚举类,其中包含星期一至星期日的定义; MONDAY, TUESDAY, WEDNESDAY, THURSDAY,FRIDAY, SATURDAY, SUNDAY; 使用 values 返回所有的枚举数组,并遍历,要求打印值为“星期一”而不是“MONDAY” public class Enum { public static void main(String[] args) { Week[] values = Week.values(); for (Week value : values) { System.out.println(value); } } } enum Week{ MONDAY("星期一"), TUESDAY("星期二"), WEDNESDAY("星期三"), THURSDAY("星期四"), FRIDAY("星期五"), SATURDAY("星期六"), SUNDAY("星期日"); private String name; Week(String name) { this.name = name; } @Override public String toString() { return name; } Enum类的接口 Enum类本身已经有了继承关系,因此不能继承其他类 但作为一个类,它仍然可以实现接口 interface Playing { void play(); } enum Music implements Playing { HARD_ROCK, POP, CLASSIC, ROCK, JAZZ; @Override public void play() { } } 注解 最基本的修饰符 最基本的三个修饰符分别是: Override:用来限定某个方法必须重写父类的方法,只能用于方法 SuppressWarnings:抑制编译器的警告 Deprecated:用来表示某个程序元素(比如类或者方法)已经过时 Override 其实对于正确的方法重写来说,加不加这个修饰符都可以。 但如果加了的话,编译器会检查你是否有正确地重写这个方法。如果不正确的话会报错,产生编译错误。 Override的源码如下,从 @Target (ElementType.METHOD) 上可以看出,这个修饰符只能用在方法上。 @interface 修饰的类都是注解类。 @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { } 顺带一提, @Target 是修饰注解的注解,也称为元注解。 Deprecated 用 @Deprecated 修饰符修饰的元素,暗示其已经过时了,不推荐再继续使用,但其实可以使用。 @Documented @Retention(RetentionPolicy.RUNTIME) @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE}) public @interface Deprecated { String since() default ""; boolean forRemoval() default false; } 从源码可以看出,该修饰符可以修饰方法、字段、包、参数等。 该关键字一般用于 JDK 版本更迭时,给过时的方法打上标注。 SuppressWarnings 用来抑制编译器警告,在 ( ) 中可以填抑制的警告类型。 因为懒得打字,我直接把文档粘在这: 参数名称 作用描述 all 抑制所有警告。 unchecked 抑制与泛型相关的“未经检查的操作”警告,例如在使用原始类型时。 deprecation 抑制使用了 @Deprecated 标记的过时类或方法的警告。 rawtypes 抑制使用了泛型但未指定具体类型的“原始类型”警告。 unused 抑制代码中存在但未被使用的变量、方法或类的警告。 serial 抑制可序列化的类未定义 serialVersionUID 的警告。 null 抑制与空值分析相关的警告(如潜在的空指针)。 cast 抑制与强制类型转换操作相关的警告。 fallthrough 抑制在 switch 语句中缺少 break 而导致“直通”的警告。 finally 抑制 finally 块无法正常返回的警告。 boxing 抑制与自动装箱(boxing)和拆箱(unboxing)操作相关的警告。 static-access 抑制不正确的静态成员访问方式的警告。 dep-ann 抑制使用过时注解的警告。 incomplete-switch 抑制 switch 语句中未覆盖所有枚举常量的警告。 javadoc 抑制与 Javadoc 相关的警告。 synthetic-access 抑制内部类访问未优化的警告。 resource 抑制与资源(如 Closeable )使用相关的警告。 restriction 抑制使用了不建议或禁止引用的警告。 使用示例,代码如下: @SuppressWarnings({"all"}) enum Music implements Playing { HARD_ROCK, POP, CLASSIC, ROCK, JAZZ; @Override public void play() { } } @SuppressWarnings是没有对使用位置限制的,从源码中也可以看出,它没有 @Target 去限制,源码如下: @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { String[] value(); } 元注解 注解的注解,看源码时可能遇到,没那么重要,快速过一下。 四种元注解: Retention:指定注解的作用范围,三种值SOURCE,CLASS,RUNTIME Target:指定注解可以在哪些地方使用 Documented:指定该注解是否会在javadoc体现,即在生成文档的时候,可以看到该注解 Inherited:子类会继承父类注解 这部分我战略性跳过了,稍微不太好理解,也有点深入了。 1 个帖子 - 1 位参与者 阅读完整话题
跟一个相亲对象见了面,感觉蛮好的,家里的各个环境和人都比较贴近自己的理想。就是自己没存啥钱,现在有点不敢继续往下走下去!也是害怕万一有感情了又满足不了对方怎么办? 【树洞】 7 个帖子 - 7 位参与者 阅读完整话题
大家的vscode中,做数据分析调试时,查看dataFrame对象,ndarray对象用啥插件呢,找了半天没找到,自己开发了一个 1 个帖子 - 1 位参与者 阅读完整话题
我对象今天又给我发了一个视频,就是讲社会对女生多么多么不公,对女生有多么多么歧视,对男生有多好多好,她之前就老是给我发这种,之前也有因为讨论这个吵起来的,然后我就跟她说我不喜欢看这种像是打拳的东西,我们自己过好自己的生活就好了,没想到今天又给我发了,我想问问各位老哥,她应该是什么意思呀,还有就是这种算是在打拳吗?我应该怎么跟她沟通呢? 31 个帖子 - 29 位参与者 阅读完整话题
今天给对象手机弄ai,找了一下选定了Rikkahub这个chat软件,看到L站也没有人说如何配置这个,我来简单说一下。 全图流 在外面图做的不太好 不过比较易懂哈 以我自己的公益站为例 选模型然后用就可以啦 1 个帖子 - 1 位参与者 阅读完整话题
谁不急头白脸的从实验室回来看到别人在自己宿舍大门口的楼梯上啃嘴子呢 佬,你们说像我们这样整天待实验室的带电工科生真的能找到对象么 求佬们支点招 10 个帖子 - 8 位参与者 阅读完整话题
实在是太久没有理发被对象嫌弃,这次出差在杭州住在滨江区附近,佬友们有没有认识靠谱的Tony老师呀 4 个帖子 - 3 位参与者 阅读完整话题
单例设计模式 什么是单例模式 所谓单例设计模式,就是在软件系统中,某个类只存在一个实例对象,并且也只有一个获得该实例的方法 单例模式有两种方式 饿汉式 懒汉式 步骤如下 构造器私有化 类的内部创建对象 对外暴露一个静态的public方法,用于返回唯一实例(getInstance) 饿汉式 饿汉式是在类加载时就创建并且初始化单例对象,这可能造成资源浪费 package com.hspedu.single; public class Test { public static void main(String[] args) { GirlFrind instance = GirlFrind.getInstance(); instance.show(); } } class GirlFrind{ private String name; private static final GirlFrind gf = new GirlFrind("小花"); private GirlFrind(String name) { this.name = name; } public static GirlFrind getInstance() { return gf; } public void show() { System.out.println(this.name); } } 可以看出,gf在类被加载的时候就已经初始化 懒汉式 懒汉式是在类首次调用获取实例的方法时,才创建对象的单例模式 package com.hspedu.single; public class Test { public static void main(String[] args) { System.out.println(GirlFrind.n1); } } class GirlFrind{ private String name; public static int n1 = 10; private static GirlFrind gf = null; private GirlFrind(String name) { System.out.println("构造器被调用"); this.name = name; } public static GirlFrind getInstance() { if (gf == null) { gf = new GirlFrind("小花"); } return gf; } public void show() { System.out.println(this.name); } } 只有当getInstance被调用时,才会创建gf。 执行可以发现,由于只调用了静态成员,因此只加载了类,因此没有调用构造器。 懒汉式和饿汉式的区别 饿汉式 懒汉式 线程安全 安全 不安全,需要额外处理 资源加载时机 类载入就创建实例 调用getInstance才创建 适用场景 单例对象简单、一定被使用 单例对象开销大 潜在问题 可能造成资源浪费 多线程环境下可能创建多个实例 懒汉式的线程安全版本后期补充 2 个帖子 - 2 位参与者 阅读完整话题
最近在某乎刷到这个问题,再联系到自己上一段感情,发现除了性行为,好像更多的就是生活中多了一个可以陪伴、可以聊天、可以分享自己大部分私密事情的那么一个人。(饭搭子也算把,毕竟一个人不好去吃双人餐了) 仿佛对象就是那么一个能参与、见证、分享你人生的人。 但是在分手后的这半年,我重新开始习惯一个人的生活,发现自己也能逐渐习惯独处的生活。这种感觉就像是“我现在一个人过得挺完整的”(虽然还是会被性欲影响,但飞机杯解决就完事了) 现在的我已经不是空的了,不再像曾经那样为了填补空虚而疯狂去找对象,现在我更多的是在想: 如果未来有个人加入我的生活,她能给我带来什么? 而我又能给她带来什么? 或许这就是我对这个问题的一点思考... 不知道你是怎么看待的?
最近在某乎刷到这个问题,再联系到自己上一段感情,发现除了性行为,好像更多的就是生活中多了一个可以陪伴、可以聊天、可以分享自己大部分私密事情的那么一个人。(饭搭子也算把,毕竟一个人不好去吃双人餐了) 仿佛对象就是那么一个能参与、见证、分享你人生的人。 但是在分手后的这半年,我重新开始习惯一个人的生活,发现自己也能逐渐习惯独处的生活。这种感觉就像是“我现在一个人过得挺完整的”(虽然还是会被性欲影响,但飞机杯解决就完事了) 现在的我已经不是空的了,不再像曾经那样为了填补空虚而疯狂去找对象,现在我更多的是在想: 如果未来有个人加入我的生活,她能给我带来什么? 而我又能给她带来什么? 或许这就是我对这个问题的一点思考... 不知道你是怎么看待的?
最近在某乎刷到这个问题,再联系到自己上一段感情,发现除了性行为,好像更多的就是生活中多了一个可以陪伴、可以聊天、可以分享自己大部分私密事情的那么一个人。(饭搭子也算把,毕竟一个人不好去吃双人餐了) 仿佛对象就是那么一个能参与、见证、分享你人生的人。 但是在分手后的这半年,我重新开始习惯一个人的生活,发现自己也能逐渐习惯独处的生活。这种感觉就像是“我现在一个人过得挺完整的”(虽然还是会被性欲影响,但飞机杯解决就完事了) 现在的我已经不是空的了,不再像曾经那样为了填补空虚而疯狂去找对象,现在我更多的是在想: 如果未来有个人加入我的生活,她能给我带来什么? 而我又能给她带来什么? 或许这就是我对这个问题的一点思考... 不知道你是怎么看待的?
最近在某乎刷到这个问题,再联系到自己上一段感情,发现除了性行为,好像更多的就是生活中多了一个可以陪伴、可以聊天、可以分享自己大部分私密事情的那么一个人。(饭搭子也算把,毕竟一个人不好去吃双人餐了) 仿佛对象就是那么一个能参与、见证、分享你人生的人。 但是在分手后的这半年,我重新开始习惯一个人的生活,发现自己也能逐渐习惯独处的生活。这种感觉就像是“我现在一个人过得挺完整的”(虽然还是会被性欲影响,但飞机杯解决就完事了) 现在的我已经不是空的了,不再像曾经那样为了填补空虚而疯狂去找对象,现在我更多的是在想: 如果未来有个人加入我的生活,她能给我带来什么? 而我又能给她带来什么? 或许这就是我对这个问题的一点思考... 不知道你是怎么看待的?
最近在某乎刷到这个问题,再联系到自己上一段感情,发现除了性行为,好像更多的就是生活中多了一个可以陪伴、可以聊天、可以分享自己大部分私密事情的那么一个人。(饭搭子也算把,毕竟一个人不好去吃双人餐了) 仿佛对象就是那么一个能参与、见证、分享你人生的人。 但是在分手后的这半年,我重新开始习惯一个人的生活,发现自己也能逐渐习惯独处的生活。这种感觉就像是“我现在一个人过得挺完整的”(虽然还是会被性欲影响,但飞机杯解决就完事了) 现在的我已经不是空的了,不再像曾经那样为了填补空虚而疯狂去找对象,现在我更多的是在想: 如果未来有个人加入我的生活,她能给我带来什么? 而我又能给她带来什么? 或许这就是我对这个问题的一点思考... 不知道你是怎么看待的?
最近在某乎刷到这个问题,再联系到自己上一段感情,发现除了性行为,好像更多的就是生活中多了一个可以陪伴、可以聊天、可以分享自己大部分私密事情的那么一个人。(饭搭子也算把,毕竟一个人不好去吃双人餐了) 仿佛对象就是那么一个能参与、见证、分享你人生的人。 但是在分手后的这半年,我重新开始习惯一个人的生活,发现自己也能逐渐习惯独处的生活。这种感觉就像是“我现在一个人过得挺完整的”(虽然还是会被性欲影响,但飞机杯解决就完事了) 现在的我已经不是空的了,不再像曾经那样为了填补空虚而疯狂去找对象,现在我更多的是在想: 如果未来有个人加入我的生活,她能给我带来什么? 而我又能给她带来什么? 或许这就是我对这个问题的一点思考... 不知道你是怎么看待的?
最近在某乎刷到这个问题,再联系到自己上一段感情,发现除了性行为,好像更多的就是生活中多了一个可以陪伴、可以聊天、可以分享自己大部分私密事情的那么一个人。(饭搭子也算把,毕竟一个人不好去吃双人餐了) 仿佛对象就是那么一个能参与、见证、分享你人生的人。 但是在分手后的这半年,我重新开始习惯一个人的生活,发现自己也能逐渐习惯独处的生活。这种感觉就像是“我现在一个人过得挺完整的”(虽然还是会被性欲影响,但飞机杯解决就完事了) 现在的我已经不是空的了,不再像曾经那样为了填补空虚而疯狂去找对象,现在我更多的是在想: 如果未来有个人加入我的生活,她能给我带来什么? 而我又能给她带来什么? 或许这就是我对这个问题的一点思考... 不知道你是怎么看待的?