在软件开发这个行当里,我们最不缺的就是“想得太多、写得太多、做出来却太少”。需求文档写了几十页,原型图改了七八版,技术方案评审了两轮,结果一上线,用户根本不买账。这种落差不是个例,而是普遍现象。问题出在哪里?很多人会归咎于需求不明确、技术选型不行、测试不充分,但我看到一个更底层的根因:我们一直在用“虚假的确定性”来取代“真实的反馈”。
这正是《Getting Real》这本书,或者说这套产品哲学,最刺痛人的地方。它由 37signals(也就是后来做出 Basecamp 的那家公司)在 2000 年代中期提出,核心就一句话:不要做纸面上的产品,不要靠想象做功能,要在真实的约束下,用最快的方式做出一个真正能运行的东西,让真实用户给你真实反馈。
这篇文章不会只做书摘。我想站在 CSDN 读者的角度,把“Getting Real”翻译成一套可以落地的工程实践:它是怎么解决开发效率问题的,适合什么团队、什么项目,不适合什么场景,以及当你决定用这套思路干活时,环境怎么搭、流程怎么拆、代码怎么写、效果怎么验证。
1. 这篇文章真正要解决的问题
我们每天写代码,大部分时间其实不是在解决技术难题,而是在应对“假需求”和“过度设计”带来的熵增。
举个很典型的场景:产品经理说“我们要做一个用户积分系统”,于是你开始设计数据库表,规划积分获取、消耗、过期、补发、对账、防作弊的复杂规则。你花了两周,终于把积分系统做得足够健壮。上线后发现,用户根本不关心积分,他们只想快速找到想要的功能。你花两周做出的东西,在产品方向上是错的。
为什么会这样?因为在动手之前,团队用一个“假想的用户痛点”替代了“真实的用户反馈”。大家都以为积分能提高留存,但没人先做一个最简单的积分入口,让用户点一下,看看数据是否变化。这就是 Getting Real 反对的“虚假需求”。
这本书真正解决的问题是:开发资源被严重浪费在未经验证的假设上。它要求团队用“真实软件”而不是“需求文档”来回答问题。你不需要写 50 页 PRD 去论证某个功能该不该做,你只需要用很短的时间做一个最简单、能运行的版本,放到用户面前,让数据告诉你答案。
这篇文章的读者,最可能是这几类人:
- 中小型 Web 产品、SaaS 工具的开发者,深受需求蔓延和返工之苦。
- 独立开发者、小团队技术负责人,需要一套轻量且能落地的产品开发方法。
- 对产品有兴趣的后端/前端工程师,不想只做一个“接需求写代码”的机器,想搞明白为什么有些功能不值得做。
读完这篇文章,你会得到一套可以立刻上手的操作框架:什么样的项目适合 Getting Real,一周迭代怎么排,功能怎么砍,验证怎么做的代码级示例,以及哪些坑是必须避开的。
2. Getting Real 到底是什么:本质是一套“反浪费”开发哲学
先做概念澄清。Getting Real 是一本书,更是一套产品开发方法论。它诞生的背景是 37signals 这家只有十几个人的公司,做出了 Basecamp、Backpack、Campfire 等产品。在当年的环境下,绝大多数创业公司还在用瀑布流式流程做软件,而 37signals 用极小的团队、极短的时间、极少的预算,把产品做出来了,并且盈利能力极强。
Getting Real 的核心思想可以拆成四条:
第一,Build only what's needed。只做真正需要的东西。不是“这个功能以后可能有用”就去做,而是“这个功能现在就能解决用户问题”才做。听起来简单,做起来极难,因为绝大多数团队的评价标准是“功能多 = 产品完整”,而不是“问题少 = 产品精准”。
第二,Use real constraints。利用真实约束。小团队、短时间、少预算,这不是缺点,而是过滤器。正因为资源有限,你才会被迫砍掉那些不重要的功能。如果你有无限预算和无限人手,很容易做出一个四不像的大杂烩。
第三,Iterate on real feedback。基于真实反馈迭代。不是内部评审,不是“我觉得用户会喜欢”,而是把真实的、不完整的产品版本放到用户面前,观察他们的行为,然后改。
第四,Say no to bloated process。拒绝臃肿流程。不以文档数量、会议数量、流程完整性作为项目健康度的指标,而以“有没有真实用户在用”“用户用得爽不爽”作为指标。
这三个字里,最容易被误读的是那个“Real”。很多人以为 Getting Real 就是“快速上线一个半成品,然后让用户当小白鼠”。这个理解是错的。
“真实”在这里指的不只是“真实用户”,还包括“真实的代码”“真实的数据”“真实的成本”。一个真实运行的系统,哪怕功能再少,也会产生真实日志、真实数据库记录、真实用户反馈。这些真实信息,是任何需求文档、原型图、流程图都无法提供的决策依据。
所以,Getting Real 本质上是一套用工程手段获取真实信息的方法论。它之所以对开发者有价值,不是因为“少写文档很爽”,而是因为它减少的正是开发中最昂贵的东西——返工。
一个功能,如果只停留在文档和原型阶段,你很难判断它是否值得做;直到你用代码把它实现出来,看到真实用户使用数据,你才知道当初的判断是错的。Getting Real 的意义,就是把“判断错误的成本”提前到了一个极低的位置。
3. 传统开发方式 vs Getting Real:四个关键差异
很多团队不是不想做得快,而是被流程绑架了。我们把传统开发方式和 Getting Real 放在一起对比,差异会非常直观。
| 维度 | 传统重流程开发 | Getting Real 式开发 |
|---|---|---|
| 需求确认 | 完整 PRD、需求评审、原型确认 | 一句话描述核心问题,直接做最小版本 |
| 产品形态 | 追求功能齐全、一次到位 | 只做解决核心问题的少数功能 |
| 反馈来源 | 内部评审、领导意见、竞品分析 | 真实用户使用行为和数据 |
| 文档 | 大量文档,文档先于代码 | 极简说明,代码先于文档 |
| 上线节奏 | 里程碑式大版本,周期长 | 小步快跑,持续小发布 |
| 失败成本 | 上线后发现方向错,重做成本极高 | 小版本上线,方向错,三天内可修正 |
这里有一个关键点:不是所有项目都适合这种模式。如果你的项目是航天器控制系统、银行核心账务系统、医疗设备嵌入式软件,那对不起,Getting Real 不适合你。这些系统一旦出错,损失是灾难性的,前置分析和严谨流程是必要的。
但如果你做的是 Web 应用、后台管理系统、SaaS 工具、内部效率工具、移动端 App 的 MVP版本,那 Getting Real 的收益远大于风险。CSDN 读者日常接触的大量 Java/Python/前端项目,绝大多数都属于这一类。
用一句话概括:Getting Real 适合“试错成本低、迭代频率高”的软件产品,不适合“错误代价极高”的严肃系统。
这也是为什么很多做企业级项目的工程师,看了 Getting Real 以后觉得“这书太理想主义”。那不是书的问题,而是场景不匹配。你需要做的,是抽取其中适合自己项目的方法,而不是全盘照搬。
4. 把 Getting Real 落地到工程流程:环境与前置条件
如果要在实际项目中实践 Getting Real,环境准备不是指装某个特定的 IDE 或数据库,而是指“让团队具备快速交付真实软件的基础设施”。我把这套前置条件列出清单。
操作系统、编程语言、数据库这些,完全取决于你的技术栈,没有统一答案。更重要的是下面几项:
4.1 一套能快速部署的流水线
Getting Real 的前提是你能每周甚至每天发布一个可运行版本。如果发布一次需要手动部署三小时,那就别谈快速迭代了。至少要做到:
- 代码提交后自动运行单元测试和构建。
- 构建成功后自动部署到测试环境或预览环境。
- 一键部署到生产环境,支持回滚。
GitLab CI/CD、GitHub Actions、Jenkins,随意选一个,关键是流程要顺。
4.2 一个能快速拿到用户反馈的入口
没有用户反馈,一切只能靠猜。Feedback 入口可以是:
- 页面底部一个“反馈问题”按钮。
- 一个最简化的用户行为埋点,记录核心事件。
- 一个固定入口的邮箱或 IM 群。
不需要复杂的数据产品,能拿到真实用户的一句话、一个点击记录就够了。
4.3 一套足够简单的项目看板
看板工具用 Trello、Jira、GitHub Projects 都可以。重点不是工具,而是泳道设计。Getting Real 的看板不需要十几个状态,四列就够:
- 待办(准备做)
- 进行中(正在做)
- 验证中(正在看真实反馈)
- 已放弃/已上线
注意,这里特意加了“已放弃”这一列。大多数团队没有这一列,导致一个没验证的功能久久悬挂在“待办”里,既占资源又制造焦虑。Getting Real 要求你明确地把某些东西定义为“不做”,这才是真正的减法。
4.4 一个单人可跑通的最小技术骨架
如果功能必须依赖别人才能启动,迭代速度就会卡在协作瓶颈上。要求团队能独立地把一个需求从数据库改到页面发布,一次性跑通。
这四点,是比任何具体技术栈都重要的“环境准备”。环境就绪后,下一步是把开发流程真正拆成可执行的节奏。
5. 核心流程拆解:一周一个真实迭代
Getting Real 的落地不需要多复杂的管理流程,它更像一个“做菜”的节奏。我把这套节奏拆成五个环节,大家可以对照自己的项目来调整。
5.1 第一步:选定一个核心问题,而不是一组功能
每周开始前,团队只确定一个问题。例如,“用户注册后不知道下一步该做什么,导致激活率低”。注意,这个问题不是功能,而是一个真实存在的用户障碍。
然后,针对这个问题给出“最小真实解决方案”。比如:在注册成功页加一个简短的引导流程,告诉用户下一步干什么。对比一下传统思路:为了提升激活率,产品经理会规划完整体验引导、新手任务列表、积分激励、教程视频,一个版本全做出来。而 Getting Real 只做最简单的那一步。
5.2 第二步:用“最小真实版本”定义范围
把解决方案翻译成一个可交付的开发任务。这个任务必须满足:
- 能被一个或两个开发者在一个迭代内完成。
- 能独立运行和验证,不依赖其他未完成功能。
- 能采集到至少一种真实数据来判断效果。
举个例子,如果目标是“降低用户注册后的流失率”,最小真实版本可以是一个简单的 Web 页面,页面顶部展示用户姓名,底部放一个“开始创建第一个项目”按钮。页面可以丑,逻辑可以简陋,但它必须真实运行。
5.3 第三步:快速实现,不追求完美
这个阶段最忌讳的是过度设计。不要引入复杂架构,不要做高可用,不要为了“以后扩展”而提前抽象。用你当前技术栈里最直接的方式,把这个功能做出来。
很多工程师这一步特别难受,因为代码写得丑会觉得丢脸。但 Getting Real 的逻辑很清楚:你代码写得再优雅,如果方向是错的,那优雅就只是华丽的浪费。先把东西跑起来,让数据和反馈告诉你,这个方向值不值得继续投入。
5.4 第四步:真实用户验证,不只靠内部评审
功能上线后,找 5 到 10 个真实用户(不是同事)使用它。观察他们会不会用、在哪里卡住、有没有主动反馈。
如果用户没有明显的“啊哈”反应,那这个功能大概率不值得继续优化。如果用户有正面反馈或者数据有积极变化,再进入下一步,把它打磨得更精细。
5.5 第五步:决定“继续”“调整”还是“砍掉”
每周结束时,团队要回答一个问题:这个功能经受住了真实世界的检验吗?
- 继续:数据向好,用户反馈正向,下周优化细节。
- 调整:方向可能对,但实现方式不对,换一种方式再试一轮。
- 砍掉:没有反馈、没有数据、用户无感,果断删除。
这一步是 Getting Real 的“残酷点”。大多数团队做不到砍掉自己做的功能,因为投入了时间和情感。但请记住一个事实:沉没成本不是成本,把错误的项目继续下去,才是最大的成本。
为了帮助实际操作,我给出下面这个“功能取舍检查清单”,可以直接当成团队内部评审模板来用:
# 功能取舍检查清单(Getting Real 版) 回答以下问题,超过两个是否,请重新考虑这个功能: - [ ] 是否明确解决一个真实用户问题,而不是“可能有用”? - [ ] 是否能在一个迭代周期内完成最小版本? - [ ] 是否能用 5-10 个真实用户快速验证? - [ ] 是否有清晰的成功指标(留存率、使用次数、反馈数量)? - [ ] 砍掉这个功能,用户会明显感到缺失吗? - [ ] 是否可以用更简单的方案替代(页面、文案、邮件)? - [ ] 如果这个功能上线后没人用,团队能接受删除吗? 当你不确定该不该做时,答案通常是不做。6. 完整示例:一个积分系统怎么做成 Getting Real
为了让流程更具象,假设我们要做一个用户积分系统。传统方式会直接设计完整数据模型。现在用 Getting Real 的流程走一遍。
6.1 初始问题定义
团队通过用户访谈发现,用户连续使用产品的动机不足。产品经理提出“做一个积分系统提升用户活跃度”。但注意,这个问题表述已经包含了答案——“积分”。Getting Real 要求我们把问题还原得更原始:
真实问题是:如何让用户在一周后仍然回访产品?
至于解决方案是积分、是签到、是优质内容推送、还是游戏化徽章,都需要验证。
6.2 最小功能定义
我们的第一个迭代不实现完整积分体系,只实现一个最小的闭环:用户在完成任意一个关键操作(比如创建了一个项目)后,在页面上收到一次“+10 能量值”的即时反馈。
为什么是这个?因为它只包含三个最小步骤:
- 记录一次用户关键行为。
- 更新一个简单的累计数字。
- 展示这个数字的即时变化。
6.3 Spring Boot 后端示例
我们先用一个简单的 Spring Boot 接口实现“记录一次积分增加”。注意,这里不做积分明细表、不做消费场景、不做防刷,只做最小闭环。
// 文件路径:src/main/java/com/example/points/PointsController.java @RestController @RequestMapping("/api/points") public class PointsController { private final PointsService pointsService; public PointsController(PointsService pointsService) { this.pointsService = pointsService; } /** * 用户完成一次关键动作,增加积分并返回最新值。 * 这是 Getting Real 最小闭环的第一步:真实记录 + 真实反馈。 */ @PostMapping("/reward") public ResponseEntity<Map<String, Object>> reward(@RequestBody RewardRequest request) { Long userId = request.getUserId(); Integer delta = 10; Integer currentPoints = pointsService.increasePoints(userId, delta); Map<String, Object> result = new HashMap<>(); result.put("userId", userId); result.put("rewarded", delta); result.put("currentPoints", currentPoints); return ResponseEntity.ok(result); } public static class RewardRequest { private Long userId; public Long getUserId() { return userId; } public void setUserId(Long userId) { this.userId = userId; } } }这里抛开了所有积分系统常见的复杂规则,真正的问题是:用户看到这个数字变化后,行为是否发生改变。
6.4 前端页面的最小执行
在这个阶段,前端只需要一个 Toast 提示。不需要积分商城,不需要积分记录页,不需要排行榜。如果是 Vue 或 React,几行代码就够。
// 文件路径:src/utils/pointsFeedback.js // 用户完成关键操作后,调用积分奖励接口并显示反馈 export async function rewardUserAfterAction(userId) { try { const response = await fetch('/api/points/reward', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ userId }), }); if (!response.ok) { // 即使接口失败,也不影响用户完成主流程 console.error('积分接口异常,忽略本次奖励'); return; } const data = await response.json(); // 在界面右下角显示轻提示,不打断用户 showToast(`能量值 +${data.rewarded},当前 ${data.currentPoints}`); } catch (error) { // 网络异常时静默失败,不让积分接口阻塞主业务 console.error(error); } }看到这段代码,有些工程师会问:积分接口失败了怎么办?要不要重试?要不要做消息队列?注意,这就是 Getting Real 要制止的冲动。当前阶段的核心是验证“积分反馈能不能提升活跃度”,而不是“积分系统是否稳定可靠”。如果连价值都没有验证,稳定可靠就是浪费。如果你担心失败影响主流程,那就用上面这个静默失败策略。
6.5 数据验证脚本
如果不想写前端,也可以直接用 curl 模拟用户行为,然后查数据库确认积分数值变化:
# 模拟用户 10001 完成一次关键行为 curl -X POST http://localhost:8080/api/points/reward \ -H "Content-Type: application/json" \ -d '{"userId": 10001}' # 预期返回 # {"userId":10001,"rewarded":10,"currentPoints":10} # 再调用一次,验证累计值得增加 curl -X POST http://localhost:8080/api/points/reward \ -H "Content-Type: application/json" \ -d '{"userId": 10001}' # 预期返回 # {"userId":10001,"rewarded":10,"currentPoints":20}运行成功的关键标志很简单:第二次请求的currentPoints比第一次多 10。这代表真实的积分累计链路已经通了。如果结果不对,依次检查:请求是否打到了正确的接口、数据库里是否真的更新了值、是否因为缺少事务导致写入失败。
7. 运行结果判断:怎么知道这个方向有没有价值
功能上线不是终点,拿到验证结论才是。
7.1 短期观察什么
上线一周后,你需要回答以下几个问题:
- 用户频率:这批用户一周内的回访次数,和没有看到积分反馈的对照组相比,有没有提升?
- 行为特征:用户是在意积分数字本身,还是只是因为“多了一个新鲜感入口”?
- 反馈质量:有没有用户主动问“这个能量值能做什么”?
如果用户根本没有注意到这个积分反馈,或者注意到了但没有行为变化,那就果断砍掉。这不是失败,这是用最便宜的方式证明了一个想法不成立。
7.2 如何用数据来验证
最理想的验证方式是 A/B 测试。但在最小团队和小产品阶段,做严格的 A/B 测试往往成本过高。一个务实做法是:上线后观察一周后台数据,对比前两周的活跃数据。
如果数据看不到明显趋势,直接找 5 到 10 个真实用户做一次 10 分钟的回访,看他们是否记得这个功能、是否愿意再次使用。这种定性的反馈,在验证早期方向时往往比数据更敏锐。
7.3 失败后的处理
如果结论是“这个功能没用”,就应该删除这个功能。不要因为是“已经做出来的功能”而舍不得删。真实软件的美妙之处在于,删除功能会降低系统复杂度和维护成本,这部分收益是实实在在的。
记住一句话:在 Getting Real 的流程里,“砍掉一个没用的功能”和“上线一个好功能”同样值得庆祝。两者都在消除浪费,只是方式不同。
8. 常见问题与排查思路
理论听上去很顺,落地总会遇到各种阻力。我梳理了实践中最高频的五个问题,以及对应的处理思路。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 团队不愿意做“半成品”功能 | 工程师误解了“最小”的含义,以为是不负责任 | 检查沟通中是否清晰传递了验证目标 | 明确说明最小版本是“为验证假设而做的实验”,并设定验证时间点 |
| 功能上线后运营团队想要立刻扩展一堆规则 | 过度设计冲动蔓延到了非技术角色 | 查看需求列表中是否出现过“顺便”二字 | 用功能取舍检查清单过滤,并要求拿到第一轮真实反馈后再讨论扩展 |
| 两个迭代后还是没有用户反馈 | 入口太少,用户不知道怎么反馈 | 检查产品内是否有反馈入口 | 在页面里加入简单的反馈按钮,或在首 10 个用户中主动做电话回访 |
| 工程师觉得“代码太丑,后面没法维护” | 把临时验证代码和长期产品代码混在一起 | 检查是否采用了合理的基础设施 | 在代码注释中明确标注“这是实验性代码”,并在验证取得正向结论后安排一次重构 |
| 砍掉某个功能后,有用户投诉 | 功能对少部分用户有真实价值 | 看投诉用户的占比和占比趋势 | 保留数据记录,后续可以作为新版本迭代的支撑,但在未确认规模之前不要重新全面排期 |
这些问题的核心,其实都指向同一个管理动作:把实验验证和产品建设明确区分开。验证阶段允许粗糙,建设阶段要求质量。很多团队在验证阶段就要求“生产级质量”,这是 Getting Real 落地最大的阻力。
9. 最佳实践与工程建议
如果要在团队里真正推行 Getting Real,下面这六条建议非常值得收藏。
9.1 用“问题句式”替代“功能句式”来描述需求
团队里所有需求描述,都要求以“用户遇到什么问题”开头,而不是“我们要做一个什么功能”。例如,把“我们要做一个数据库导出按钮”改成“用户想把数据在本地用 Excel 分析”。一句之差,会彻底改变方案设计的方向。
9.2 为每个新功能设置一个“验证截止时间”
在开始开发之前,就先确定验证的时间点和判断标准。比如,“功能上线后观察两周,如果核心动作完成率没有提升 5%,就删除该功能。”没有时间节点的验证,会无限期拖延,最后变成又一个僵尸功能。
9.3 把删除功能当成例行任务
每季度至少要有一次“功能清理日”,删除那些没有真实用户使用、没有数据支撑的功能。删除不只是删代码,还包括清理数据库表、文档、测试和关联任务。这能让系统长期保持轻盈。
9.4 日志先行,埋点先行
就算是最小版本,也要在功能中提前埋好关键的日志和埋点。否则功能上线后,你连“用户有没有用”都不知道,那这个验证就是无效的。
9.5 明确“不做清单”
团队里不仅要维护“待办列表”,还要维护“不做清单”。什么事情我们明确不做,这比“列出要做的 50 件事”更能减少开发资源浪费。
9.6 小团队自治,信任工程师的判断
Getting Real 非常依赖工程师对业务和用户的直接感知。如果所有决策都要等待上层批准,那迭代速度会立刻被打回原形。每一个工程师都应该能直接看到用户反馈、直接接触用户数据。
10. 总结与后续学习方向
Getting Real 不是一本教你写代码的工具书,而是一套关于“如何用软件真实运行来推动决策”的开发哲学。它的核心价值,在于把开发活动从“实现需求文档”变成“验证产品假设”。这看起来是流程上的改变,实际上改变了工程师的工作方式:你不再只是一个“需求翻译器”,而是产品验证闭环中的关键节点。
当你准备在下一个项目中实践 Getting Real,可以按以下顺序启动:
- 建立流水线,确保代码能在一小时内从提交变更为线上版本。
- 定义看板,明确增加“已放弃”一列。
- 为当前产品找出三个最关键的“真实用户问题”。
- 为每个问题设计一个最小可验证版本。
- 用文中的功能取舍检查清单,砍掉其中一个功能。
- 把剩下两个排入迭代,并在规定时间点判断去留。
需要提醒的是,Getting Real 的局限同样明显。它面向的是不确定性很高的产品探索期,而一旦产品方向被验证、进入需要稳定性和合规性的阶段,就需要重新补上质量保障、文档和架构设计。一切方法论都有适用边界,掌握边界,才叫真正的掌握。
后续如果还想继续深入,可以顺着这几个方向研究:精益创业与 MVP 设计模式、用户行为埋点与数据分析、Feature Toggle 与灰度发布技术、持续部署与快速回滚的工程实践。这些内容,都是让 Getting Real 从理念变成现实的技术底座。
对于还在纠结“该不该多做点功能”的团队,我最后送一句这本书留下的核心判断:你不需要做一个大而全的产品,你只需要做一个真实有人用的产品。真实用户的使用数据,比任何华丽的功能清单都有说服力。