说实话,我一开始也看不起软件维护
2016年我进了一家做支付的公司,接手了一个Spring Boot 1.5.9 + MySQL 5.6的老系统,当时上线才半年。到了2024年,这系统还在跑,日交易量从1万涨到了30万。维护团队从5个人砍到2个人,但工单没少,平均每天15个,其中70%是“又出问题了”。我查过Standish Group的报告,软件维护成本占整个生命周期总成本的60%-80%,而我们这个系统,维护费用早就超过了当初的开发费用。你猜怎么着?开发新功能时大家抢着干,一到维护就没人愿意接,好像维护就是二等公民。但说实话,没有维护,再牛的系统也活不过三年。
四种维护类型,我拿我们系统给你对个账
软件维护一般分四类:纠正性、适应性、完善性、预防性。我们系统里,纠正性(修bug)大概占25%,适应性(比如升级JDK、适配新支付通道)占30%,完善性(加小功能、改界面)占40%,预防性(重构、加监控)只有5%。预防性最低,结果就是技术债务越滚越大。比如我们有个模块用了大量的存储过程,2019年想改成微服务,发现根本拆不动,因为业务逻辑全在数据库里。后来我强制每周五下午做“技术债务清理”,哪怕只改一个方法,也要把单元测试补上。坚持了半年,生产事故从每月8次降到了2次。这个数据我记在小本本上,绝对真实。
数据库死锁那个坑,我花了三天才爬出来
最头疼的一次是2022年双十一,凌晨两点系统告警,数据库死锁,订单表锁等待超时。当时监控用的是Prometheus + Grafana,告警阈值设的是innodb_lock_wait_timeout=50秒,结果大量请求卡死。我登上去一看,老代码里用了SELECT ... FOR UPDATE,而且事务里还调了外部HTTP接口,导致锁持有时间过长。解决步骤:第一步,先把innodb_lock_wait_timeout临时调到120秒,让积压请求先过去;第二步,改代码,把外部调用挪到事务外面,用乐观锁代替悲观锁,加version字段;第三步,升级MySQL到8.0,利用新的锁监控表performance_schema.data_locks。前后折腾了三天,但从此再没出过死锁。我跟你讲,维护老系统,你得比开发更懂数据库。
我的全新观点:维护不是修机器,是养孩子
很多人把软件维护当成修机器,坏了才修,修完就扔。我觉得不对。维护应该是养孩子,你得主动喂饭、体检、教育。我提出一个词叫“维护即开发”,每次维护都当成一个小版本迭代。具体怎么做?第一,所有修改必须走CI/CD,我们用Jenkins + GitLab CI,每次合并请求触发自动化测试,覆盖率要求70%以上,达不到就卡住。第二,用Feature Flag控制新功能,灰度发布先给1%用户,观察24小时再全量。第三,建立“维护看板”,把工单按类型分,纠正性工单超过30%就说明代码质量在下降。第四,每季度做一次“架构健康度评估”,用SonarQube扫描,技术债务比率超过5%就安排重构。这些步骤我们坚持了两年,现在维护团队虽然只有2个人,但能支撑30万日交易量。说实话,以前我想转开发,现在我觉得维护更有成就感,因为你救活的是一个真实运行的系统。
最后说几句大实话
如果你也在做软件维护,别觉得自己低人一等。开发是从0到1,维护是从1到100,难度一点不小。我见过太多公司,开发完新系统就把维护外包,结果三年后系统烂得没人敢动,只能推倒重来,成本是维护的10倍。所以我的建议是:第一,给维护工程师和开发一样的薪资和晋升通道;第二,把预防性维护写进KPI,哪怕只占10%的时间;第三,文档别写Word,用Markdown放Git里,跟代码一起版本控制。我们系统现在有1200个Markdown文档,每次改代码必须更新对应文档,否则代码评审不通过。这些细节看着小,但能救命。好了,就写这么多,希望对你有用。