Repository navigation
12 refactoring guide
omeyang edited this page Sep 16, 2026
·
1 revision
本文档定义代码重构的流程、兼容性保证、灰度发布和回滚策略。
- 功能等价 - 重构前后行为完全一致
- 上游透明 - 调用方无需修改代码
- 下游无感 - 依赖方接口保持兼容
- 渐进式 - 小步快跑,持续验证
重构期间旧代码必须可用。
实现新代码,但不删除旧代码。
- 单元测试覆盖率不低于 95%
- 集成测试验证上下游
- 回归测试确保旧功能不变
部分流量切到新代码,观察运行。
对比新旧代码的行为、性能、错误率。
确认无问题后,全量切到新代码。
删除旧代码、清理注释、更新文档。
保留旧接口,内部调用新实现:
// 旧接口:保留
func Query(id string) (*Order, error) {
return QueryWithOptions(id, nil)
}
// 新接口:扩展功能
func QueryWithOptions(id string, opts *QueryOptions) (*Order, error) {
// 新实现
}使用可选参数(Functional Options):
type QueryOption func(*QueryConfig)
func WithTimeout(d time.Duration) QueryOption {
return func(c *QueryConfig) { c.Timeout = d }
}
func Query(id string, opts ...QueryOption) (*Order, error) {
cfg := &QueryConfig{}
for _, opt := range opts {
opt(cfg)
}
// ...
}使用类型别名:
type OldOrder = Order // 别名
type Order struct { ... }提供转换函数:
func ConvertOldToNew(old *OldOrder) *NewOrder { ... }
func ConvertNewToOld(new *NewOrder) *OldOrder { ... }方案 1:别名
var OldFunctionName = NewFunctionName
func NewFunctionName() { ... }方案 2:适配器
func OldFunction(a int) { NewFunction(a) }
func NewFunction(a int) { ... }保留旧函数,内部调用拆分后的函数:
func ProcessData(data []byte) error {
if err := ValidateData(data); err != nil {
return err
}
if err := TransformData(data); err != nil {
return err
}
return SaveData(data)
}新函数,旧函数调用新函数:
// 旧签名:保留
func Query(id string) (*Order, error) {
return QueryWithContext(context.Background(), id)
}
// 新签名:增加 context
func QueryWithContext(ctx context.Context, id string) (*Order, error) {
// ...
}增加字段:向后兼容
type Order struct {
ID string
Name string
Tags []string // 新增字段,可以为空
}删除字段:标记废弃,延迟删除
type Order struct {
ID string
Name string
// Deprecated: use Tags instead
Tag string // 废弃字段,保留一段时间
Tags []string
}- 覆盖率不低于 95%
- 测试所有边界条件
- Mock 外部依赖
- 验证上下游集成
- 测试完整流程
- 使用真实依赖
- 对比新旧实现的输出
- 确保行为一致
- 记录差异并修复
# 基准测试
go test -bench=. -benchmem
# 对比新旧性能
go test -bench=BenchmarkOld -benchmem > old.txt
go test -bench=BenchmarkNew -benchmem > new.txt
benchcmp old.txt new.txtfunc Query(id string) (*Order, error) {
if rand.Intn(100) < 10 {
return queryNew(id) // 10% 新实现
}
return queryOld(id) // 90% 旧实现
}func Query(id string) (*Order, error) {
if config.EnableNewQuery {
return queryNew(id)
}
return queryOld(id)
}func Query(ctx context.Context, id string) (*Order, error) {
userID := getUserID(ctx)
if isInWhitelist(userID) {
return queryNew(id)
}
return queryOld(id)
}- 请求成功率
- 响应时间(P50/P90/P99)
- 错误率
- 业务指标
- 成功率下降超过 5%
- P99 响应时间增加超过 50%
- 错误率增加超过 10%
方案 1:配置回滚
enable_new_query: false方案 2:代码回滚
git revert <commit>
git push方案 3:流量切换
直接切回旧实现。
- 确认重构目标明确
- 评估风险和收益
- 准备回滚方案
- 旧代码保持运行
- 新代码完整测试
- 接口向后兼容
- 添加监控指标
- 单元测试覆盖率不低于 95%
- 集成测试通过
- 回归测试通过
- 性能测试无退化
- 灰度发布观察指标
- 监控无异常告警
- 上下游无反馈问题
- 全量后删除旧代码
- 禁止直接删除旧接口
- 禁止修改旧接口签名
- 禁止重构没有测试覆盖
- 禁止一次性全量切换
- 禁止没有监控和告警
- 禁止没有回滚方案
本页由 Maat 仓库的 scripts/sync-wiki.sh 自动生成,请勿直接编辑。