数据库 Schema 迁移怎么做:安全、可回滚、可验证

副标题 / 摘要 数据库 Schema 迁移是系统风险的高发点。本文给出可执行的迁移策略与检查清单。 目标读者 需要做数据库迁移的工程师 负责上线流程与稳定性的团队 做 DevOps / DBA 的开发者 背景 / 动机 很多线上事故来自“不可逆的 schema 变更”。 正确做法是分阶段、可回滚、可验证。 核心概念 前向兼容:新旧代码同时可用 可回滚:变更可撤销 灰度发布:逐步流量切换 迁移顺序:先扩展、后收缩 实践指南 / 步骤 先扩展再收缩(add column -> backfill -> cutover -> drop) 双写验证(新旧字段一致) 可回滚脚本 灰度切换 迁移后验证(行数/校验和) 可运行示例 -- 1) 扩展 ALTER TABLE users ADD COLUMN status_new VARCHAR(20); -- 2) 回填 UPDATE users SET status_new = status; -- 3) 切换代码使用新字段 -- 4) 收缩 ALTER TABLE users DROP COLUMN status; 解释与原理 “先扩展后收缩”能保证新旧版本共存,避免停机与回滚困难。 迁移过程中的双写与校验是降低风险的关键。 ...

2026年1月24日 · 1 分钟 · map[name:Jeanphilo]

分布式 vs 集中式版本控制:优势、劣势与适用场景

副标题 / 摘要 分布式版本控制把“历史”分散到每个开发者本地,带来更强的离线能力与分支灵活性,但也引入更高的协作复杂度。本文给出清晰对比。 目标读者 需要理解 Git / SVN 差异的工程师 负责制定团队工作流的技术负责人 正在从 SVN 迁移到 Git 的团队 背景 / 动机 版本控制不是工具问题,而是协作效率问题。 分布式与集中式的差异会直接影响团队工作流、代码评审与发布节奏。 核心概念 集中式 VCS:单一中央仓库(SVN) 分布式 VCS:每个开发者都有完整历史(Git) 分支模型:分支的创建、合并成本不同 实践指南 / 步骤 评估团队规模与协作模式 看是否需要离线工作 评估分支与合并频率 选择合适的工作流(GitFlow/GitHubFlow) 建立统一的代码评审与发布规范 可运行示例 比较 SVN 与 Git 的本地历史能力: # Git:离线查看历史 git log -5 # SVN:依赖服务器 svn log -l 5 解释与原理 分布式 VCS 把历史复制到本地,允许开发者离线查看与提交。 集中式 VCS 依赖中心仓库,操作更集中、权限更清晰,但分支成本高。 常见问题与注意事项 分布式 VCS 是否更安全? 历史分散降低单点风险,但也需要更强的权限策略。 集中式 VCS 是否更简单? 对小团队可能更简单,但扩展性差。 Git 学习成本高吗? 相对高,但收益巨大。 ...

2026年1月24日 · 1 分钟 · map[name:Jeanphilo]

为什么不该自己设计密码学:风险、误区与替代方案

副标题 / 摘要 自创密码学看似灵活,实则极易出错。本文解释为什么不应自己设计加密算法,并给出工程级替代方案。 目标读者 需要实现安全功能的工程师 想理解密码学风险的开发者 负责安全合规的技术负责人 背景 / 动机 密码学的可靠性来自数学证明与长期公开审计。 未经验证的自创算法,几乎一定存在未知漏洞,且往往在上线后才暴露。 核心概念 公开审计:安全算法需经长期社区验证 威胁模型:攻击者能力远超一般想象 实现安全:算法正确 ≠ 实现安全 实践指南 / 步骤 使用成熟标准(AES-GCM、ChaCha20-Poly1305) 使用成熟库(libsodium、OpenSSL) 明确威胁模型并选择合适协议 避免自定义模式/参数 做安全评审与渗透测试 可运行示例 下面用 Python 的标准库做安全加密示例(AES-GCM): from cryptography.hazmat.primitives.ciphers.aead import AESGCM import os key = AESGCM.generate_key(bit_length=128) aesgcm = AESGCM(key) nonce = os.urandom(12) plaintext = b"hello" ciphertext = aesgcm.encrypt(nonce, plaintext, None) print(ciphertext) 解释与原理 安全算法需要满足机密性、完整性、可验证性等多项指标。 自创算法往往忽略边界条件、随机性、密钥管理等关键问题。 常见问题与注意事项 算法简单就更安全吗? 不。简单可能意味着可被轻易破解。 自己设计能防止被破解吗? 不。攻击者会逆向、分析、利用弱点。 使用库就安全吗? 前提是正确使用(模式、随机数、密钥管理)。 最佳实践与建议 不要自创算法或自定义加密模式 使用经过审计的库与标准 关注密钥管理与随机数来源 小结 / 结论 自创密码学的风险远高于收益。 使用成熟算法和库,是工程安全的基本常识。 参考与延伸阅读 Cryptography Engineering libsodium / OpenSSL 官方文档 NIST 推荐算法列表 元信息 阅读时长:7~9 分钟 标签:密码学、安全、工程实践 SEO 关键词:不要自创密码学, 加密算法 元描述:解释为什么不应自创密码学,并给出替代方案。 行动号召(CTA) 检查一次你项目的加密实现,确认是否使用了标准算法与库。

2026年1月24日 · 1 分钟 · map[name:Jeanphilo]

为什么写软件很难:不确定性、复杂性与人

副标题 / 摘要 软件开发的难点不在写代码本身,而在持续变化的需求、系统复杂性与团队协作成本。本文拆解这些难点并给出应对策略。 目标读者 参与中大型项目的工程师 希望理解“复杂性来源”的开发者 负责交付与协作的技术负责人 背景 / 动机 软件系统面对的是“开放世界”:需求不断变化、环境不可预测、团队协作复杂。 这决定了软件开发天生不稳定,不可能像制造业一样高度可控。 核心概念 本质复杂性:问题本身就复杂 偶然复杂性:由工具、流程或实现带来的复杂 需求漂移:需求随时间变化 协作成本:沟通与一致性维护 实践指南 / 步骤 拆分问题域,减少单个模块复杂度 用边界隔离变化,把变化限制在局部 建立可观察性,缩短反馈周期 用自动化测试锁定行为 采用渐进式交付,降低一次性失败风险 可运行示例 下面示例展示“组合爆炸”带来的复杂性: from itertools import product def combos(n: int) -> int: return len(list(product([0, 1], repeat=n))) if __name__ == "__main__": for n in [5, 10, 15]: print(n, combos(n)) 解释与原理 功能越多、状态越多,组合空间指数级增长。 这意味着测试、调试与协作成本都在指数上升。 常见问题与注意事项 代码难度来自语言吗? 不是,更多来自需求与系统交互的复杂性。 加人能解决问题吗? 未必,沟通成本可能更高。 为什么需求总在变? 现实世界本身在变,软件只是映射它。 最佳实践与建议 优先减少复杂性,而不是堆叠功能 以反馈速度为核心指标 用小团队保持一致性 小结 / 结论 软件开发困难的根源是变化与复杂性。 工程实践的价值在于控制这些复杂性,让系统可演进。 参考与延伸阅读 The Mythical Man-Month (Brooks) No Silver Bullet (Brooks) Designing Data-Intensive Applications 元信息 阅读时长:7~9 分钟 标签:软件开发、复杂性、工程实践 SEO 关键词:软件开发, 复杂性, 需求变化 元描述:解析软件开发困难的核心原因,并给出缓解策略。 行动号召(CTA) 挑一个复杂模块,画出它的状态与边界,你会立刻看到优化空间。

2026年1月24日 · 1 分钟 · map[name:Jeanphilo]

任务编排为什么要放后端:让流程可控、可变、可回放

任务编排为什么要放后端:让流程可控、可变、可回放 副标题 / 摘要 在多步骤、可中断、可回放的业务流程中,把“流程顺序与状态机”放在后端,是系统长期可演进的关键。本文从真实工程痛点出发,解释为什么前端不应硬编码流程顺序,并给出一套可落地的后端 Pipeline 编排思路与最小实现。 目标读者 正在设计多步骤流程 / 向导式产品的后端工程师 需要支撑 Web / App / Admin 多端一致流程的技术负责人 在 AI / LLM 产品中处理“模型自动 + 人工确认”混合流程的团队 背景 / 动机:问题通常是怎么爆出来的? 很多系统一开始都很简单: 前端:第 1 步 → 第 2 步 → 第 3 步 后端:校验 + 存数据 但随着业务演进,以下需求几乎一定会出现: 步骤 变多:从 3 步变成 10+ 步 步骤 可选:根据条件跳过 / 插入新步骤 步骤 可中断:需要用户确认、补充信息、人工审核 步骤 可重试 / 可回放:失败后从中间继续,而不是全部重来 步骤 多端一致:Web / App / 内部工具共享同一流程 如果此时流程顺序仍然写在前端: 每次流程变更 = 多端发版 出问题时无法准确回答:现在卡在哪一步? 想加监控、审计、回放,发现无从下手 根因只有一个: ...

2026年1月13日 · 2 分钟 · map[name:Jeanphilo]

算法与业务的关系:把不确定性变成可交付(以 LLM 事实抽取为例)

摘要 很多团队做 AI 应用时会陷入一种痛苦:业务逻辑写了一堆,却始终看不到“算法到底抽出了什么”。根因往往不是代码能力,而是把算法阶段的探索,过早塞进业务工程。本文用“投标写作工具里的事实抽取(FactMention)”作为例子,讲清楚算法与业务的边界、如何用 JupyterLab 快速验证、以及何时进入工程化。 目标读者 正在做 LLM/RAG/信息抽取的工程师(初级到中级) 负责 AI 产品落地的技术负责人 / 架构师 经常在“写了半天流程,结果不知道抽取效果如何”的同学 背景与动机:为什么这个问题重要? 在传统系统里,大家习惯把“算法”理解为一个函数或模型文件,把“业务”理解为接口与流程。但在 LLM 时代,这个界限变得更模糊: 算法不仅是模型,还包括 prompt、schema、抽取策略、规则归一、置信度与去重策略 算法输出往往是 不确定、需要人类直觉评估 的 如果你把这些“不确定”的东西直接嵌进业务链路(router/service/db/cache),你会遇到: 调试成本爆炸:只看到最后 response,不知道中间发生了什么 逻辑迭代极慢:改一行抽取策略,要跑完整流程 团队协作困难:大家在黑箱里争论“到底准不准” 因此,需要一个更清晰的边界:算法负责收敛中间态,业务负责稳定交付。 核心概念:算法与业务到底分别是什么? 1)算法(Algorithm)的工程定义 算法负责把“模糊世界”压缩成“可用的结构化中间态”。 关键词:不确定性、探索、需要“看结果”、需要收敛。 在投标写作场景中,算法阶段的问题长这样: LLM 抽取出来的 payload 字段应该有哪些? norm_key 怎么设计才代表“同一事实”? 同一人多条命中(mentions)要不要合并? confidence 到底有没有意义?怎么校准? 这些问题的共同特点是:你必须看中间结果才能判断对不对。 2)业务(Business)的工程定义 业务负责在中间态稳定之后,把事情编排起来:什么时候取什么数据、走哪条链路、如何返回给用户。 关键词:确定性、可维护、可测试、可复用。 在投标写作场景中,业务阶段的问题长这样: retrive_type = personnel 时走事实检索,否则走原文档检索 接口响应结构固定,前端按协议渲染 存储从 MemoryTable 换成 DB,不影响上层调用 这些问题的共同特点是:输入输出清晰,错误是边界情况,而不是“我也不知道会不会抽出来”。 一条“贴墙上”的分界线 凡是你还说不清“中间结果长什么样”的阶段 → 用 JupyterLab。 凡是你能画出输入/输出 JSON 形态并写出测试用例的阶段 → 进工程。 实践指南:什么时候用 JupyterLab,什么时候用工程代码? 阶段 1:事实抽取建模期(强制用 JupyterLab) 适用信号: ...

2026年1月7日 · 3 分钟 · map[name:Jeanphilo]

别被 AI 牵着走:保持可独立完成的工程能力

讨论在使用 AI 辅助编码时如何避免复制粘贴依赖,结合费曼技巧、刻意练习与检索练习,给出可操作的自检清单与演练步骤。

2025年12月8日 · 1 分钟 · map[name:Jeanphilo]