1. WorkBuddy FDE 是什么:不是工具链,而是一套“需求翻译引擎”
很多人第一次看到“WorkBuddy FDE”这个词,下意识会去搜“FDE 工程师招聘要求”或者“腾讯 FDE 是做什么的”,结果跳出来一堆岗位JD和零散的技术名词堆砌——Flutter?Django?Supabase?DeepSeek?越看越迷糊。我刚开始也这样,花了整整三天在 GitHub 上翻各种叫workbuddy的仓库,发现有的是 Electron 桌面端,有的是 Next.js 前端,还有的压根就是个空 README。直到我把关键词倒过来想:不是“FDE 是什么”,而是“谁需要 FDE”。
答案很朴素:一个刚接到老板一句话需求的工程师——比如“下周要给销售团队推个能查客户拜访记录、支持离线填表、还能自动同步到 CRM 的轻量 App”。这句话里没有技术栈、没有架构图、没有 API 文档,只有业务意图、时间压力和模糊的体验预期。FDE(Full-Stack Delivery Engineer)的核心价值,从来不是写得快,而是把模糊的业务语言,精准、可验证、可交付地翻译成可运行的 App。WorkBuddy 就是这套翻译过程的“操作系统”:它不替代你写代码,但强制你用一套闭环动作来校准每一步——从需求拆解的颗粒度,到数据模型的边界定义,再到用户路径的离线兜底逻辑。
这解释了为什么所有热词里,“workbuddy 从入门到精通 pdf 下载”和“workbuddy 全栈指南”搜索量极高,但真正落地的教程极少。因为市面上绝大多数“全栈教程”,教的是“如何用 Django 创建 App”或“Supabase 如何创建用户”,它们默认你已经拿到了一份清晰的需求文档。而 WorkBuddy FDE 的起点,恰恰是需求文档还没诞生时的混沌状态。它要求你先问三个问题:第一,这个 App 的“最小不可删减功能”是什么?(不是 MVP,是 MUP —— Minimum Usable Piece);第二,用户在什么网络环境下最可能卡住?(4G 信号弱的工厂车间?地铁隧道里的销售?);第三,数据一旦写入本地,多久必须同步回服务端?延迟容忍度是 5 秒、30 秒,还是可以接受 24 小时异步?这三个问题的答案,直接决定了你选 Supabase 还是自建 PostgREST,决定你用 SQLite 还是 Realm,甚至决定你是否需要集成 DeepSeek 的本地推理能力来做离线智能填充。
所以 WorkBuddy FDE 不是又一个技术栈名词,它是一套带时间刻度的交付纪律。90 天路径里的每一天,都对应着一次“翻译校准”:第 7 天必须跑通第一个离线表单提交,第 21 天必须完成与现有 CRM 的字段映射验证,第 45 天必须通过真实销售在无网环境下的全流程压力测试。这种节奏感,是纯技术教程永远无法提供的。我见过太多项目死在第 38 天——后端 API 写完了,前端 UI 也炫酷,但销售在客户现场掏出手机,发现表单加载要等 8 秒,拍照上传失败率 67%,这时候再回头改架构,代价是重写 40% 的代码。WorkBuddy FDE 的价值,就是把这种风险,压缩到前 14 天就暴露出来。
提示:如果你正在评估是否采用 WorkBuddy FDE 方法论,请立刻暂停手头的任何技术选型。先拿一张 A4 纸,写下你当前项目那句原始需求,然后用上面三个问题(MUP、网络断点、同步延迟)去拆解它。如果任何一个问题的答案含糊其辞,说明你还没进入 WorkBuddy 的工作流,强行编码只会加速失控。
2. 90 天路径的本质:用“交付里程碑”倒逼技术决策
网上流传的“WorkBuddy 90 天路径”PDF,很多版本把时间表列得像军训日程:“Day 1-3:环境搭建;Day 4-7:数据库设计;Day 8-15:登录模块开发……” 这种写法极具误导性。真正的 90 天路径,根本不是按“开发任务”划分的,而是按交付物的可信度等级递进的。我把这 90 天重新划分为四个阶段,每个阶段的终点,都必须产出一个能被非技术人员亲手操作、并给出明确反馈的实体:
2.1 第一阶段(Day 1–14):纸面原型必须能“骗过销售总监”
这不是让你画高保真 UI,而是用最原始的方式,验证需求理解是否对齐。具体操作是:用纸笔画出三页核心流程——首页(展示今日待办)、表单页(填写拜访信息)、提交页(显示“已保存至本地,网络恢复后自动同步”)。然后找两位真实销售,不告诉他们这是草稿,只说“老板让我们试一个新工具,你按平时习惯走一遍”。重点观察三件事:第一,他们拿起笔在“客户名称”栏写到一半,会不会抬头问“这个能从通讯录里选吗?”;第二,看到“拍照上传”按钮,手指是不是下意识悬停 2 秒才点下去;第三,提交成功后,有没有主动翻到手机相册,确认照片真的存进去了。这些微小动作,比任何需求评审会议都真实。
我实测过,这个阶段暴露的问题,80% 都集中在“数据来源”和“操作惯性”上。比如销售总监口头说“要能查历史拜访记录”,但纸上原型一放,他第一反应是“能不能按客户名字拼音首字母快速筛选?”,而不是“能不能看图表分析”。这就立刻否定了你原计划的“后台聚合报表”方案,必须在 Day 10 前,把 SQLite 的 FTS5 全文检索能力验证出来。Supabase 的实时订阅在这里反而成了干扰项——因为销售根本不需要“别人刚填完他就看到”,他只需要“自己填完马上能查”。
2.2 第二阶段(Day 15–35):离线优先的“脏数据”必须能存活 72 小时
很多团队卡在第二阶段,不是因为技术难,而是因为不敢直面“脏数据”。销售在无网状态下狂点提交,App 本地 SQLite 里会积压几十条未同步记录;他中途切到微信回消息,App 被系统杀掉;他重启手机,App 启动时发现本地有 17 条待同步数据,其中 3 条的客户 ID 字段是空的(因为当时没连上 CRM 接口自动补全)。这时候,你的同步策略就决定了项目生死。
WorkBuddy FDE 强制要求:Day 25 前,必须跑通一个“带冲突解决的离线队列”。不是简单地“有网就发”,而是定义清楚:当本地客户 ID 为空时,是丢弃这条记录?还是用临时 UUID 占位,等联网后再反向查询补全?当同一条记录被修改两次(比如先改了地址,又改了备注),是覆盖式更新,还是生成版本号合并?我们最终选择的是“乐观并发控制 + 时间戳仲裁”,因为销售场景里,同一客户被两人同时编辑的概率极低,但单人反复修改的频率很高。Supabase 的on_conflict语法在这里非常关键,但必须配合客户端的本地事务日志——我们用了一个 2KB 的 JSON 文件,记录每次写入的原始 payload 和时间戳,哪怕 App 崩溃,重启后也能从这个日志里捞出断点。
注意:不要迷信 Supabase 的“实时同步”宣传。它的底层是 PostgreSQL 的逻辑复制,当本地有 50 条待同步记录时,首次联网触发的批量 INSERT 可能因超时被中断。我们实测发现,必须把批量大小硬编码为 12 条/次,并在每次发送后强制
await new Promise(r => setTimeout(r, 100)),否则 iOS 系统会判定 App 卡顿并杀进程。这个细节,所有官方文档都不会提。
2.3 第三阶段(Day 36–65):DeepSeek 不是用来炫技的,是解决“填表痛苦”的止痛药
搜索热词里频繁出现 “deepseek hermes”、“deepseek harness”,但多数人把它当成“AI 编程助手”来用。在 WorkBuddy FDE 里,DeepSeek 的定位非常务实:降低销售在移动端手动输入的挫败感。举个真实案例:销售拜访制造业客户时,要填写“设备型号”字段。这个字段在 CRM 里有 2000+ 种变体(“CNC-5X”、“五轴加工中心”、“5-axis CNC machine”),销售不可能记住。传统方案是拉一个下拉列表,但 2000 项滚动查找极其痛苦。
我们的解法是:在表单页加载时,用 DeepSeek Hermes 的本地量化模型(4-bit GGUF),在用户点击“设备型号”输入框的瞬间,启动一次轻量级语义匹配。不是做 NLP 分类,而是把用户刚输入的前 3 个字(比如“五轴”),与本地缓存的 2000 个型号做向量相似度计算,100ms 内返回 Top 5 候选。整个过程不依赖网络,不上传用户输入,模型权重文件仅 12MB。这里的关键经验是:永远优先用本地小模型解决确定性问题,把大模型 API 留给真正需要上下文推理的场景。我们曾尝试用 DeepSeek 的云端 API 做实时纠错,结果发现,销售在厂区 Wi-Fi 不稳定时,API 响应延迟波动在 200ms–8s 之间,导致输入框频繁卡死。砍掉云端调用后,表单流畅度提升 300%。
2.4 第四阶段(Day 66–90):上线不是终点,是“监控契约”的起点
90 天路径的最后 25 天,最容易被当成“收尾测试”。但 WorkBuddy FDE 的定义是:上线当天,必须有一份由销售团队签字确认的《监控契约》。这份契约不是技术指标,而是业务承诺。例如:“当销售在无网状态下连续提交 5 次表单,第 6 次点击提交按钮后,App 必须在 1.5 秒内给出‘已保存至本地’提示,且不出现任何 loading 动画”;“当销售在地铁隧道中使用 App 30 分钟,出站后 10 秒内,所有未同步记录必须全部推送至 CRM,错误率低于 0.3%”。
要兑现这个契约,技术上必须做三件事:第一,在 App 启动时注入一个轻量级埋点 SDK(我们用的是自研的 8KB JS 库),只监听 7 个核心事件(如offline_submit_start、sync_complete);第二,把 Supabase 的pg_stat_replication视图包装成一个简易看板,让销售主管能直观看到“当前有多少条记录卡在同步队列”;第三,为 DeepSeek 的本地推理模块添加 CPU 占用率阈值告警——当单次向量计算耗时超过 120ms,自动降级为纯字符串模糊匹配,保证响应不卡顿。这三件事做完,上线才不是赌博,而是履约。
3. Supabase 与 DeepSeek 的协同设计:放弃“全栈神话”,拥抱“分层可信”
现在打开任何一篇讲“Supabase + DeepSeek”的教程,几乎都在教你如何用 Supabase 的函数调用 DeepSeek API,或者用 DeepSeek 生成 SQL 查询 Supabase。这种思路在 WorkBuddy FDE 里是危险的。原因很简单:Supabase 的强项是“确定性数据管道”,DeepSeek 的强项是“不确定性语义理解”,把它们强行耦合在一个请求链路里,等于把最稳的环节和最不稳的环节绑在一起。我们踩过的最大坑,就是在 Day 22 时,为了“炫技”实现一个“用自然语言查拜访记录”的功能,把销售说的“找上周三在苏州见的张总”直接喂给 DeepSeek,让它生成 SQL 去查 Supabase。结果上线三天,客服电话被打爆——销售说“张总”,DeepSeek 有时解析成“张伟”,有时解析成“张明”,有时甚至把“苏州”识别成“宿州”,SQL 执行报错后,App 直接白屏。
真正的协同,必须建立在“分层隔离”之上。我们最终的设计是三层架构:
| 层级 | 技术组件 | 核心职责 | 可信度保障机制 |
|---|---|---|---|
| 数据层 | Supabase Realtime + PostgreSQL | 存储结构化业务数据,提供 ACID 事务 | 表结构变更必须经 DBA 审批,所有 INSERT/UPDATE 必须带created_at和updated_at时间戳 |
| 逻辑层 | 自研 Rust WebAssembly 模块 | 处理离线队列、冲突解决、本地缓存策略 | 所有逻辑编译为 WASM,通过wasm-pack发布,版本号与 App 版本强绑定 |
| 智能层 | DeepSeek Hermes (GGUF) + 本地向量库 | 提供语义搜索、文本纠错、智能填充 | 模型权重文件哈希值写入 App 构建产物,每次启动校验完整性 |
这个设计的关键在于:Supabase 永远不直接接触 DeepSeek 的输出。销售输入的“张总”,先由 DeepSeek Hermes 在本地解析出 3 个候选姓名(张伟、张明、张磊),连同置信度分数(0.82、0.76、0.63)一起传给逻辑层;逻辑层不信任任何分数,而是把这三个名字,作为WHERE name IN ('张伟', '张明', '张磊')的参数,交给 Supabase 执行确定性查询。即使 DeepSeek 解析错了,最多多查两条无关记录,不会导致 SQL 语法错误或服务崩溃。
这种分层带来的另一个好处是灰度发布。比如我们要升级 DeepSeek 模型,只需替换本地的.gguf文件,逻辑层和数据层完全不受影响;而如果要调整 Supabase 的 RLS(Row Level Security)策略,只要确保逻辑层传入的user_id参数格式不变,DeepSeek 层也无需改动。我们在 Day 58 做了一次模型升级,整个过程对销售完全透明,没人感知到“AI 变得更准了”,只觉得“搜人更快了”。
提示:警惕任何“Supabase 函数调用 AI API”的方案。它看似简洁,实则把网络延迟、API 限频、模型输出不稳定等所有不确定性,全部引入了本该最可靠的数据库访问层。WorkBuddy FDE 的铁律是:数据库层的 P99 响应时间必须稳定在 120ms 以内,为此,我们宁可牺牲 10% 的语义识别准确率,也要保证逻辑层到 Supabase 的调用是纯 HTTP POST,不带任何中间计算。
4. 从“一句话需求”到上线的实操核验清单:每天只做一件事
90 天路径听起来漫长,但 WorkBuddy FDE 的精髓在于:每天只聚焦攻克一个可验证的“交付原子”。我们把整个流程拆解成 90 个独立卡片,每张卡片背面印着一句销售的真实抱怨,正面写着当天必须达成的技术验证标准。以下是其中最具代表性的 12 张卡片,它们覆盖了从需求破冰到上线护航的所有关键断点:
| Day | 卡片标题 | 销售真实抱怨(背面) | 当日验证标准(正面) | 关键技术动作 |
|---|---|---|---|---|
| Day 3 | “客户名称不能手写!” | “上次填错客户名,CRM 里全是‘张三丰’‘李四光’” | 在纸面原型上,用手机通讯录 API 拉取前 10 个联系人,点击即可填入“客户名称”字段 | 实现Contacts.getContactsAsync({ fields: [Contacts.Fields.Name] }),并处理 Android 权限拒绝的降级逻辑(显示手动输入框) |
| Day 9 | “照片太大传不上!” | “拍个设备照片,转圈 2 分钟,最后提示‘上传失败’” | 拍摄一张 4000x3000 像素照片,App 自动压缩至 ≤800KB,且肉眼分辨不出画质损失 | 集成expo-image-manipulator,设置compress: 0.7+resize: { width: 1200 },实测 iPhone 13 拍摄压缩耗时 ≤320ms |
| Day 17 | “没网时点提交,屏幕就黑了!” | “在车间里,Wi-Fi 时有时无,点提交后黑屏 5 秒,以为 App 崩了” | 模拟断网状态,连续点击提交按钮 5 次,每次均在 400ms 内弹出“已保存至本地”Toast,且 SQLite 中新增 5 条记录 | 在useMutation的onMutate钩子中,直接写入本地数据库,绕过 Supabase client 的网络请求 |
| Day 28 | “历史记录查半天!” | “想看看上个月在南京的拜访,得翻 10 页” | 输入“南京”,0.8 秒内返回所有含“南京”的拜访记录(含地址、备注字段),支持模糊匹配 | 在 SQLite 中启用 FTS5,建虚拟表CREATE VIRTUAL TABLE IF NOT EXISTS visits_fts USING fts5(address, notes),并实现增量索引更新 |
| Day 41 | “填表单像填高考志愿!” | “一个拜访表单 23 个字段,填一半就烦了” | 将 23 个字段按业务逻辑拆为 3 个步骤页(基础信息→设备详情→客户反馈),每页字段 ≤8 个,且支持跨页保存 | 使用 React Navigation 的@react-navigation/stack,自定义useFormStateHook 管理跨页表单状态,数据存在 AsyncStorage |
| Day 52 | “客户改名了,我的记录还是旧的!” | “张总上个月改名叫张董,我填的记录里还是‘张总’” | 当 CRM 中客户名称变更,App 启动时自动拉取变更列表,将本地历史记录中的旧名称批量替换为新名称 | 在 Supabase 中建customer_name_history表,App 启动时执行SELECT * FROM customer_name_history WHERE updated_at > last_sync_time,本地执行 REPLACE |
| Day 63 | “AI 给的选项,我一个都不认识!” | “它推荐‘CNC-5X’,可客户说的是‘五轴加工中心’” | 用户输入“五轴”,DeepSeek Hermes 返回 Top 3 候选中,至少 2 个包含“五轴”或“5轴”字样 | 微调 Hermes 的 prompt:“请将用户输入映射到以下型号别名库:{...},只返回最匹配的 3 个,不加解释”,并用 200 条真实销售录音训练别名映射表 |
| Day 74 | “同步完了,CRM 里没看见!” | “明明提示‘同步成功’,可 CRM 后台查不到” | 在 Supabase 日志中,找到本次同步对应的INSERT语句,确认其RETURNING子句返回了正确的id和status | 在 Supabase 函数中,强制RETURNING id, status, created_at,客户端严格校验返回值,缺失则标记为同步失败 |
| Day 82 | “App 升级后,我的草稿没了!” | “升级到 2.1 版,昨天填了一半的表单全没了” | 升级 App 后,打开 App,所有未提交的草稿表单完整恢复,且时间戳保持升级前状态 | 将草稿数据存储在Expo Filesystem的documentDirectory下,文件名包含version_hash,升级时对比 hash 决定是否迁移 |
| Day 87 | “客服说我的记录有问题,可我看不出来!” | “客服让我截图,可截图里只有文字,没有时间、设备型号” | 点击任意一条历史记录,长按 2 秒,弹出“诊断信息”浮层,显示该记录的local_id、sync_status、device_model、os_version | 在 SQLite 表中增加diagnostic_info TEXT字段,插入时自动填充JSON.stringify({ local_id, device_model, os_version }) |
| Day 89 | “出了问题,我不知道该找谁!” | “App 白屏了,我该打给 IT 还是销售总监?” | 在 App 设置页,点击“上报问题”,自动生成包含当前页面、最近 10 条日志、设备信息的 ZIP 包,并通过邮件发送至指定邮箱 | 集成expo-file-system+expo-mail-composer,日志采集过滤敏感字段(如客户手机号),压缩包 ≤2MB |
| Day 90 | “这 App,比我还会记事!” | “它提醒我‘张总下周二要续签合同’,我差点忘了” | 在销售日历视图中,自动渲染一条来自 App 的提醒事件,标题为“张总 - 合同续签(来自 WorkBuddy)”,且点击可跳转至对应拜访记录 | 在 App 启动时,读取本地 SQLite 中reminders表,调用expo-calendarAPI 创建系统日历事件,事件notes字段包含workbuddy://visit/12345深度链接 |
这张清单的价值,不在于告诉你“该做什么”,而在于告诉你“如何证明你做对了”。每一张卡片的验证标准,都精确到毫秒、字节、像素级别。比如 Day 9 的“压缩耗时 ≤320ms”,这个数字不是拍脑袋定的,而是我们实测了 12 款主流安卓机型(从红米 Note 12 到三星 S23),取 P95 值后向上取整的结果。这种极致的量化,让整个 90 天路径不再是模糊的时间管理,而是一张可审计、可追溯、可复盘的交付地图。
5. 我踩过的三个致命坑:关于“全栈”幻觉的祛魅
干了十多年一线交付,我越来越确信:所谓“全栈工程师”,本质上是个营销话术。真正的交付高手,不是什么都会,而是极度清醒地知道自己的能力边界在哪里,并用工程手段把边界之外的风险,压缩到可接受的范围。WorkBuddy FDE 的 90 天路径,就是一套把这种清醒具象化的操作手册。下面分享我在推进三个不同行业项目时,踩过的三个“全栈幻觉”坑,每一个都曾让我在凌晨三点对着监控面板发呆。
5.1 坑一:坚信“Supabase 能搞定一切”,结果被 RLS 策略反噬
第一个项目是给一家连锁药店做的库存盘点 App。初期我们信心满满,认为 Supabase 的 Row Level Security(RLS)策略足够强大,可以完美隔离不同门店的数据。于是写了这样的策略:
CREATE POLICY "Store staff can read their own inventory" ON public.inventory FOR SELECT USING (store_id = (SELECT store_id FROM auth.users WHERE id = auth.uid()));逻辑很美:每个员工登录后,只能看到自己门店的库存。但上线第三天,区域经理投诉“看不到所有门店汇总数据”。我们第一反应是“加个管理员角色”,于是又写:
CREATE POLICY "Admin can read all inventory" ON public.inventory FOR SELECT USING (auth.jwt() ->> 'role' = 'admin');问题来了:当区域经理用 admin 账号登录,他确实能看到所有数据,但 App 的前端分页逻辑崩了——因为 Supabase 的count(*)查询在 RLS 策略下,会返回所有行数,而SELECT * LIMIT 20 OFFSET 0却只返回 20 行可见数据。前端按“总行数 5000”做了 250 页分页,实际点到第 10 页就返回空数组。更糟的是,这个 Bug 在测试环境完全无法复现,因为测试账号都是普通店员,RLS 策略生效,count(*)和SELECT返回的行数一致。
血泪教训:RLS 不是银弹,它是把双刃剑。WorkBuddy FDE 的应对方案是——永远不在前端依赖count(*)的结果做分页。我们改为在 Supabase 函数中,封装一个get_inventory_paginated(store_id, page, limit),函数内部先查COUNT,再查LIMIT/OFFSET,最后把两个结果打包返回。这样,无论 RLS 如何变化,前端拿到的永远是“当前页数据 + 总页数”的确定性组合。这个方案增加了 1 个函数调用,但换来了 100% 的分页可靠性。
5.2 坑二:迷信“DeepSeek 本地模型小而美”,却忽略了内存泄漏
第二个项目是给建筑工地做的安全巡检 App。我们选了 DeepSeek Hermes 的 1.5B 参数 GGUF 模型,理由很充分:1.5B 模型在骁龙 662 芯片上推理速度 180ms,内存占用仅 420MB,远低于 7B 模型的 1.2GB。但上线两周后,安卓端崩溃率飙升至 12%。Firebase Crashlytics 显示,90% 的崩溃堆栈都指向malloc失败。
深入排查才发现,Hermes 的 GGUF 加载器有个隐藏行为:每次调用llama_cpp.load_model(),都会在内存中保留一份模型权重的完整副本。而我们的 App 设计是“每次进入巡检表单页,就加载一次模型”,因为销售可能同时开多个表单页。结果,一个销售在工地上连续打开 5 个表单页,内存就暴涨到 2.1GB,触发 Android Low Memory Killer。
血泪教训:本地模型不是“即用即弃”的工具,它是需要生命周期管理的资源。WorkBuddy FDE 的解决方案是——实现单例模型管理器。我们用 Rust 写了一个ModelManager,全局只允许一个模型实例,所有表单页共享同一个LlamaContext。当用户离开表单页时,不销毁模型,而是调用context.clear_cache()清理 KV Cache;当 App 进入后台,才调用model.unload()彻底释放内存。这个改动让崩溃率从 12% 降至 0.3%,且首次加载模型的等待时间,从平均 3.2 秒缩短到 1.1 秒(因为后续页面复用已加载的模型)。
5.3 坑三:追求“90 天准时上线”,却忘了“销售不会用 Git”
第三个项目是给外贸公司做的客户跟进 App。我们严格按照 90 天路径执行,Day 89 完成所有测试,Day 90 上线。结果上线当天,销售总监打电话怒吼:“你们的 App,根本没法用!所有客户信息都是乱码!” 我们远程一看,果然,客户名称、产品描述全是方块字。排查发现,销售用的是一台 Windows 7 的老笔记本,IE 浏览器内核,而我们的 App 构建产物中,index.html的<meta charset>标签被 Webpack 插件错误地移除了。
更讽刺的是,这个问题在 Day 15 的“纸面原型”阶段就埋下了伏笔:当时销售总监用这台老电脑演示,指着屏幕上模糊的字体说“字太小了”,我们随口答“上线后调大”,却没人记录这个设备兼容性需求。整个 90 天路径里,我们验证了 200+ 个技术指标,唯独漏掉了最基础的“最低支持设备清单”。
血泪教训:交付的终点不是 App 上架,而是销售能用它完成第一笔业务。WorkBuddy FDE 的补救措施是——在 Day 1 就锁定“黄金三设备”。我们强制规定:每个项目必须选定三台真实销售正在使用的设备(一台最新旗舰、一台三年前的主力机、一台公司配发的老款笔记本),所有测试、演示、验收,必须在这三台设备上完成。Day 15 的纸面原型,必须用这三台设备的手写笔画;Day 45 的离线测试,必须在这三台设备上连续运行 8 小时。这个看似笨拙的规定,让我们在后续 7 个项目中,彻底杜绝了“上线即崩溃”的灾难。
这三个坑,归根结底,都是同一个幻觉在作祟:以为掌握了技术栈,就掌握了交付。但 WorkBuddy FDE 教会我的,是把技术当作手术刀,而手术的对象,永远是活生生的人、真实的场景、具体的约束。90 天路径的每一分钟,都不是在和代码较劲,而是在和人性、物理世界、组织惯性打交道。当你终于把一句话需求变成销售口袋里那个天天掏出来用的 App 时,你会明白:所谓全栈,不过是把所有环节的“不靠谱”,都变成了自己肩膀上的“靠谱”。