子兮子兮
很多代码不是写坏的,而是“慢慢被时间拖坏的”。
做软件开发这些年,一个越来越深的体会是:
真正考验一个系统的,从来不是它刚写完时有多优雅,而是 一年、三年之后,它是否还能被安心地修改和维护。
这篇文章不讲具体框架,也不讲某个技巧,而是记录一些在实际项目中反复踩坑后,对「长期维护」这件事的理解,算是写给未来自己的备忘。
在项目早期,我们很容易被下面几个目标牵着走:
于是代码常常呈现出一种状态:
//TODO 留了一堆短期看没问题,但半年后再回头看:
func handle(a, b int) int {
if a == 1 {
// ...
}
return b
}
你会完全想不起来:
a 代表什么?可维护性的第一敌人不是复杂,而是“语义丢失”。
很多人低估了命名的重要性。
在长期维护的项目中,真正被阅读最多的不是 README,而是:
好的命名本质上是在回答三个问题:
例如在 Go 项目中:
GetUser()
和
GetUserByID()
差别非常大。
再比如:
Process()
几乎等于没说,而:
ProcessExpiredOrders()
即使不看实现,也能知道边界。
很多人在项目初期容易陷入“设计焦虑”:
但现实是:
大多数系统死于过度设计,而不是设计不足。
在长期维护中,我逐渐认可一种原则:
先让目录结构稳定,再谈模式和抽象。
例如在 Go 项目中:
/cmd
/internal
/service
/repo
/handler
/model
哪怕内部实现不断变化,只要这几个层次稳定:
稳定的“物理结构”,比聪明的抽象更抗时间。
很多系统的日志,要么太少,要么太多。
比较理想的日志应该满足:
例如:
log.Infof("create order failed, userID=%d, err=%v", userID, err)
比单纯的:
log.Error(err)
要有价值得多。
日志不是给机器看的,是给未来凌晨两点排障的自己看的。
一个很现实的问题是:
你现在写的代码,未来大概率还是你自己维护。
所以一个很实用的判断标准是:
如果三个月后再打开这段代码,你是否会骂当时的自己?
为了避免这种情况,我现在会刻意做几件小事:
代码不是炫技作品,而是长期资产。
维护,是软件生命周期中占比最长的一段时间,却往往最不被重视。
如果说写代码是在“解决问题”,那维护代码,其实是在“减少未来的问题”。
希望这篇文章,也能在未来某天被我自己翻出来时,仍然觉得:
嗯,这些话当时是真的想明白了。
| 内容声明 | |
|---|---|
| 标题: 关于“长期维护”的几条现实教训 | |
| 链接: https://zixizixi.cn/long-term-maintenance-engineering-experience | 来源: iTanken |
本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可,转载请保留此声明。
| |