Skip to main content
返回博客
可用语言:

失败软件项目救援:90 天内交付一款停滞的移动应用

MercTechs Team
MercTechs Team
工程团队
发布日期
2026年8月19日
阅读时长
1 分钟阅读
2024 年初,一家越南中型零售连锁企业找到我们,他们的内部指标讲述了一个我们已经见过太多次的故事。他们的客户忠诚度应用最初规划为六个月的开发周期,却已经推进了十四个月,预算超支约 180%,仍未准备好交付给他们的 40,000 名活跃会员。两家供应商已经先后退出。第三份报价刚刚送到 CEO…

2024 年初,一家越南中型零售连锁企业找到我们,他们的内部指标讲述了一个我们已经见过太多次的故事。他们的客户忠诚度应用最初规划为六个月的开发周期,却已经推进了十四个月,预算超支约 180%,仍未准备好交付给他们的 40,000 名活跃会员。两家供应商已经先后退出。第三份报价刚刚送到 CEO 的办公桌上,承诺再花九个月完成工作。他们没有接受,而是打电话请我们做一次为期两周的审计。九十天后,该应用正式上线 Apple App Store 和 Google Play,承载了年末的忠诚度营销活动,并在首月带来了超过 12,000 名新注册用户。

这就是我们如何走到这一步、真正的问题出在哪里,以及一次失败软件项目救援在剥离供应商政治之后究竟是什么样子的完整故事。

项目概况

该客户是一家专业零售品牌,在三个省份运营着 34 家门店,其忠诚度计划的复杂程度已经超出了原有 SMS 加塑料卡的基础设施所能承载的范围。愿景很直接:一款面向 iOS 和 Android 的原生移动应用,让会员可以查询积分余额、在销售点兑换奖励、接收个性化优惠并预约到店服务。从纸面上看,这是一个成熟库和清晰业务逻辑都能覆盖的、被充分理解过的项目。

最初的交付方案约定与一家胡志明市的工作室进行为期六个月的合作,之后再用三个月移交给内部团队。到了第十四个月,内部团队尚未招聘完成,第二家供应商已经把后端重写了两次,而应用本身在 Android 12 上进入忠诚度扫码流程后不到两分钟就会崩溃。客户的 CFO 估算直接成本已经超过 41 亿越南盾,这还没有计入忠诚度计划因仍在使用印刷代金券而损失的收入。

客户面临的问题

我们为期两周的审计浮现出三个截然不同的问题,而让客户领导团队感到意外的是,其中只有一个真正属于技术问题。

第一个问题是伪装成功能增长的范围漂移。原本 42 页的规格说明已经膨胀到 118 页,三位不同的干系人在没有正式变更流程的情况下不断添加新功能。移动端团队追逐着一个不断移动的目标,而后端团队则在为已经被重新设计过两次的界面构建接口。

第二个问题是一个为演示而搭建的后端,而不是为生产而搭建的后端。API 层构建在一个共享的 PHP 单体应用之上,该单体同时还为客户的电商网站提供服务。积分余额查询从一张有 210 万行、且在会员 ID 列上没有索引的 MySQL 表中拉取。兑换交易不具备幂等性,这意味着销售点上不稳定的 4G 信号可能会把一名会员的积分扣两次。前一家供应商知道这些问题,并把整体重写作为第三份报价的内容提出。

第三个问题,也是破坏性最强的问题,是一支已经无法与自己对话的团队。到第十二个月时,客户的产品负责人、设计代理商和交付供应商几乎只通过一份没人信任的共享电子表格来沟通。会议已经从决策论坛沦为互相追责的场合。

技术债务是真实存在的。但真正阻碍交付的,是信任和沟通的崩溃。

我们交付的解决方案

我们提出了一个为期 90 天、范围固定的救援方案,分为三个明确的阶段,并把商业条款锚定在客户 11 月零售旺季之前上线忠诚度营销活动这一目标上。

最初两周用于砍需求、冻结范围和重新确定基线计划。我们与客户的领导层协商达成了硬性的范围冻结:上线版本将交付规格中 118 项功能中的 31 项,选择的依据是这些功能覆盖了三条价值最高的会员旅程。其余一切都进入一份有明确负责人的、有记录的 v1.1 待办清单。仅这一个决定就挽回了大约六周的工程时间,否则这些时间会被用来追逐没人真正需要的边界情况。

接下来的六周用于重建有风险的部分并保留其余部分。我们保留了现有的 React Native 代码库,因为移动团队的工作其实是合理的,只是集成得不好。然后我们重建了两个结构性存在缺陷的组件。忠诚度 API 被从共享的 PHP 单体中抽取出来,成为一个使用自己独立 PostgreSQL 数据库的小型 Node.js 服务,会员查询有了合适的索引,兑换交易通过客户端生成的 UUID 实现幂等。我们引入了一份轻量的事件日志,使得每一笔积分交易都可以从原始事件重建,这意味着财务团队终于可以在不开工单的情况下审计余额。

最后一个月用于稳定化、测试和交接。我们在五家门店中对 200 名真实会员进行了两轮封闭 Beta 测试,随时修复浮现出的崩溃。我们为客户即将到位的内部团队编写了运行手册,记录了部署流水线,并培训了客户自己的两名工程师,让他们在交接之后能够拥有这份代码库。应用在第 87 天上架到两家应用商店,比营销活动的截止日期提前了三天。

让项目跑起来的技术亮点

有三项工程决策承担了大部分繁重工作。

幂等的兑换端点消除了一类困扰会员信任已久的重复扣分缺陷。移动客户端的每一次兑换请求都携带一个 UUID;后端把该 UUID 记录在唯一索引中,并对重复请求返回最初的响应。信号不好的 4G 环境下,一名会员可以连点三次「兑换」而只被扣一次积分。

事件溯源的积分账本用一份只追加的积分事件日志取代了可变的余额字段。余额成为派生状态,读时计算并做缓存。曾经是财务团队每月噩梦的对账工作,如今变成了一条 SQL 查询。这并不是什么新颖的模式;它是任何涉及金钱或类金钱价值场景中的正确模式。前面几家供应商跳过了它,因为解释它比构建它更费时。

iOS 与 Android 解耦的构建流水线把发布周期从一周压缩到不到一个小时。两个平台不再相互等待,一端的测试失败也只会阻止该端的发布。这在纸面上是一个小改动,但对于一支已经带着恐惧发版一整年的团队来说,是一次显著的士气转变。

结语

一个停滞的软件项目很少只因为单一原因而停滞。在这个案例中,技术债务可以在八周内修复;沟通的崩溃才是更棘手的问题,它需要一支来自外部、有立场说「不」并有信誉在 CEO 面前捍卫这一判断的团队。这次救援之所以成功,是因为客户愿意在冻结范围的同时并行重建信任,而不是因为我们引入了什么奇异的技术。

如果你的团队正在面对一个超支、逾期并且正在失去干系人信心的项目,答案几乎从来都不是再花九个月和一支更庞大的交付团队。答案通常是一次简短、诚实的审计,紧接着是一份围绕对业务而言真正重要的一次上线事件所构建的、范围固定的救援方案。这正是我们在 MerkTechs 承接的那类工作:为迷失方向的项目带来新鲜且有经验的视角,把它们不动声色地送回到生产环境中。

MercTechs Team

关于 MercTechs Team

致力于提供卓越软件的专家集体。

Twitter/XLinkedInGitHub